##### Coverage Report - com.sun.grizzly.suspendable.SuspendableFilter

Classes in this File | Line Coverage | Branch Coverage | Complexity
SuspendableFilter |
82 % | 84/103
62 % | 25/40
| 0.0;0
SuspendableFilter$1 |
0 % | 0/4
N/A | N/A
| 0.0;0
SuspendableFilter$KeyHandler |
100 % | 17/17
N/A | N/A
| 0.0;0
SuspendableFilter$Suspend |
100 % | 1/1
N/A | N/A
| 0.0;0
SuspendableFilter$SuspendableHandlerWrapper |
63 % | 19/30
N/A | N/A
| 0.0;0

1 |  |
     /*
2 |  |
      *
3 |  |
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 |  |
      *
5 |  |
      * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
6 |  |
      *
7 |  |
      * The contents of this file are subject to the terms of either the GNU
8 |  |
      * General Public License Version 2 only ("GPL") or the Common Development
9 |  |
      * and Distribution License("CDDL") (collectively, the "License").  You
10 |  |
      * may not use this file except in compliance with the License. You can obtain
11 |  |
      * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
12 |  |
      * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
13 |  |
      * language governing permissions and limitations under the License.
14 |  |
      *
15 |  |
      * When distributing the software, include this License Header Notice in each
16 |  |
      * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
17 |  |
      * Sun designates this particular file as subject to the "Classpath" exception
18 |  |
      * as provided by Sun in the GPL Version 2 section of the License file that
19 |  |
      * accompanied this code.  If applicable, add the following below the License
20 |  |
      * Header, with the fields enclosed by brackets [] replaced by your own
21 |  |
      * identifying information: "Portions Copyrighted [year]
22 |  |
      * [name of copyright owner]"
23 |  |
      *
24 |  |
      * Contributor(s):
25 |  |
      *
26 |  |
      * If you wish your version of this file to be governed by only the CDDL or
27 |  |
      * only the GPL Version 2, indicate your decision by adding "[Contributor]
28 |  |
      * elects to include this software in this distribution under the [CDDL or GPL
29 |  |
      * Version 2] license."  If you don't indicate a single choice of license, a
30 |  |
      * recipient has the option to distribute your version of this file under
31 |  |
      * either the CDDL, the GPL Version 2 or to extend the choice of license to
32 |  |
      * its licensees as provided above.  However, if you add GPL Version 2 code
33 |  |
      * and therefore, elected the GPL Version 2 license, then the option applies
34 |  |
      * only if the new code is made subject to such option by the copyright
35 |  |
      * holder.
36 |  |
      *
37 |  |
      */
38 |  |
39 |  |
     package com.sun.grizzly.suspendable;
40 |  |
41 |  |
     import com.sun.grizzly.Context;
42 |  |
     import com.sun.grizzly.PipelineFullException;
43 |  |
     import com.sun.grizzly.ProtocolFilter;
44 |  |
     import com.sun.grizzly.Context.KeyRegistrationState;
45 |  |
     import com.sun.grizzly.Controller;
46 |  |
     import com.sun.grizzly.DefaultProtocolChain;
47 |  |
     import com.sun.grizzly.SelectorHandler;
48 |  |
     import com.sun.grizzly.util.ThreadAttachment;
49 |  |
     import com.sun.grizzly.util.ThreadAttachment.Mode;
50 |  |
     import com.sun.grizzly.util.Utils;
51 |  |
     import com.sun.grizzly.util.WorkerThread;
52 |  |
     import java.io.IOException;
53 |  |
     import java.nio.ByteBuffer;
54 |  |
     import java.nio.channels.SelectionKey;
55 |  |
     import java.util.Iterator;
56 |  |
     import java.util.concurrent.ConcurrentHashMap;
57 |  |
     import java.util.logging.Level;
58 |  |
     import java.util.logging.Logger;
59 |  |
60 |  |
     /**
61 |  |
      * Suspend the processing of the request and associated {@link ProtocolChain}
62 |  |
      *
63 |  |
      * <p>
64 |  |
      * When a connection is suspended, the framework will not continue the execution
65 |  |
      * of the ProtocolChain and its associated {@link ProtocolFilter}. Instead the
66 |  |
      * framework will wait until either {@link Suspendable#resume} is called,
67 |  |
      * {@link Suspendable#cancel} is called or the passed timeout expires.
68 |  |
      *
69 |  |
      * If {@link Suspendable#resume} is called or the timeout expires
70 |  |
      * then the ProtocolChain will be resumed from where it has been suspended.
71 |  |
      *
72 |  |
      * If {@link Suspendable#cancel} is called, the ProtocolChain execution will
73 |  |
      * not be interrupted and the connection automatically closed.
74 |  |
      * </p>
75 |  |
      *
76 |  |
      * <p>
77 |  |
      * A connection can be suspended  before ({@link #Suspend.BEFORE}) the
78 |  |
      * ProtocolChain invoke the next ProtocolFilter, or after ({@link #Suspend.AFTER})
79 |  |
      * all ProtocolFilter has been called (e.g. when {@link #postExecute} is invoked).
80 |  |
      * </p>
81 |  |
      *
82 |  |
      * <p> This ProtocolFilter <strong>must always</strong> be invoked after some
83 |  |
      * read operation has occurred.</p>
84 |  |
      *
85 |  |
      * <p> A common usage of SuspendableFilter could be: </p>
86 |  |
      * <p><pre><code>
87 |  |
             final ProtocolFilter readFilter = new ReadFilter();
88 |  |
             final SuspendableFilter suspendFilter = new SuspendableFilter();
89 |  |
             final ProtocolFilter yourProtocolFilter = new YourProtocolFilter();
90 |  |
      *
91 |  |
             Suspendable suspendable =
92 |  |
      *          suspendFilter.suspend("YOUR TOKEN", timeout, attachment, new SuspendableHandler() {
93 |  |
94 |  |
                 public void interupted(A attachment) {
95 |  |
                     // Add if you need write something before the connection get closed
96 |  |
                 }
97 |  |
98 |  |
                 public void resumed(A attachment) {
99 |  |
                     // When the connection is resumed
100 |  |
                 }
101 |  |
102 |  |
                 public void expired(A attachment) {
103 |  |
                     // When the connection is expired.
104 |  |
             }, {@link #Suspend);
105 |  |
      *
106 |  |
      * As an example, all client that send the bytes 'grizzly is cool' will be
107 |  |
      * suspended for 5 seconds before the {@link EchoFilter} is called.
108 |  |
      *
109 |  |
             final ProtocolFilter readFilter = new ReadFilter();
110 |  |
             final SuspendableFilter suspendFilter = new SuspendableFilter();
111 |  |
             final ProtocolFilter echoFilter = new EchoFilter();
112 |  |
      *
113 |  |
             suspendable
114 |  |
                     = suspendFilter.suspend("grizzly is cool", 5000, null, new SuspendableHandler() {
115 |  |
116 |  |
                 public void interupted(Object attachment) {
117 |  |
                     System.out.println("interrupted");
118 |  |
                 }
119 |  |
120 |  |
                 public void resumed(Object attachment) {
121 |  |
                     System.out.println("resumed");
122 |  |
                 }
123 |  |
124 |  |
                 public void expired(Object attachment) {
125 |  |
                     System.out.println("expired");
126 |  |
                 }
127 |  |
             }, Suspend.BEFORE);
128 |  |
      * </code></pre></p>
129 |  |
      *
130 |  |
      * TODO: Add a better patern matching algorithm
131 |  |
      *       Allow OP_WRITE operation to be suspended as well.
132 |  |
      *
133 |  |
      * @author Jeanfrancois Arcand
134 |  |
      * @since 1.7.3
135 |  |
      */
136 |  |
     public class SuspendableFilter<T> implements ProtocolFilter {
137 |  |
138 |  |
         /**
139 |  |
          * Suspend the connection BEFORE of AFTER
140 |  |
          */
141 | 3 |
         public enum Suspend {BEFORE,AFTER}
142 |  |
143 |  |
144 |  |
         /**
145 |  |
          * Cache the pattern and its associated {@link SuspendableHandler} wrapper.
146 |  |
          */
147 | 6 |
         private ConcurrentHashMap<byte[],SuspendableHandlerWrapper<? extends T>> suspendCandidates
148 |  |
                 = new ConcurrentHashMap<byte[],SuspendableHandlerWrapper<? extends T>>();
149 |  |
150 |  |
151 |  |
         /**
152 |  |
          * The current list of suspended {@link SelectionKey}.
153 |  |
          */
154 | 6 |
         protected ConcurrentHashMap<SelectionKey,KeyHandler> suspendedKeys
155 |  |
                 = new ConcurrentHashMap<SelectionKey,KeyHandler>();
156 |  |
157 |  |
158 |  |
         /**
159 |  |
          * Monitor suspended {@link SelectionKey}
160 |  |
          */
161 | 1 |
         private static SuspendableMonitor suspendableMonitor = new SuspendableMonitor();
162 |  |
163 |  |
164 |  |
         /**
165 |  |
          * Logger
166 |  |
          */
167 | 1 |
         private static Logger logger = Controller.logger();
168 |  |
169 |  |
         /**
170 |  |
          * Controller
171 |  |
          */
172 |  |
         private Controller controller;
173 |  |
174 |  |
         /**
175 |  |
          * {@link DefaultProtocolChain} used to execute resumed connection.
176 |  |
          */
177 |  |
         private DefaultProtocolChain protocolChain;
178 |  |
179 |  |
180 |  |
         /**
181 |  |
          * The next {@link ProtocolFilter} to invoke when resuming a connection.
182 |  |
          */
183 | 6 |
         private int nextFilterPosition = 2;
184 |  |
185 |  |
186 |  |
         // -------------------------------------------------- Constructor ------- //
187 |  |
188 |  |
189 | 6 |
         public SuspendableFilter(){
190 | 6 |
         }
191 |  |
192 |  |
193 |  |
         /**
194 |  |
          * Create a new SuspendableFilter, and resume its associated {@link DefaultProtocolChain}
195 |  |
          * from position {@link #nextFilterPosition}
196 |  |
          * @param nextFilterPosition {@link #nextFilterPosition}
197 |  |
          */
198 | 0 |
         public SuspendableFilter(int nextFilterPosition){
199 | 0 |
             this.nextFilterPosition = nextFilterPosition;
200 | 0 |
         }
201 |  |
202 |  |
203 |  |
         // -------------------------------------------------- Suspend API ------- //
204 |  |
205 |  |
         /**
206 |  |
          * Suspend a connection based on a String. Evevry bytes read from the connection
207 |  |
          * will be inspected and if the String match, the connection will be suspended.
208 |  |
          * @param match The String used to decide if a connection and its associated
209 |  |
          * bytes need to be suspended. By default, the connection will be resumed
210 |  |
          * after 60 seconds.
211 |  |
          * @return A {@link Suspendable}
212 |  |
          */
213 |  |
         public Suspendable suspend(String match){
214 | 0 |
             return suspend(match, 60000, null, null);
215 |  |
         }
216 |  |
217 |  |
218 |  |
         /**
219 |  |
          * Suspend a connection based on a String. Evevry bytes read from the connection
220 |  |
          * will be inspected and if the String match, the connection will be suspended.
221 |  |
          * @param match The String used to decide if a connection and its associated
222 |  |
          * bytes need to be suspended.
223 |  |
          * @param expireTime the time in milliseconds before a connection is resumed.
224 |  |
          * @param attachment The object that will be returned when the {@link SuspendableHandler}
225 |  |
          * methods are invoked.
226 |  |
          * @param handler A {@link SuspendableHandler} used to get notification about the suspended
227 |  |
          * connection state.
228 |  |
          * @return A {@link Suspendable}
229 |  |
          */
230 |  |
         public Suspendable suspend(String match,long expireTime,
231 |  |
                 T attachement,SuspendableHandler<? extends T> sh){
232 | 0 |
             return suspend(match,expireTime,attachement,sh,Suspend.AFTER);
233 |  |
         }
234 |  |
235 |  |
236 |  |
         /**
237 |  |
          * Suspend a connection based on a String. Evevry bytes read from the connection
238 |  |
          * will be inspected and if the String match, the connection will be suspended.
239 |  |
          * @param match The String used to decide if a connection and its associated
240 |  |
          * bytes need to be suspended.
241 |  |
          * @param expireTime the time in milliseconds before a connection is resumed.
242 |  |
          * @param attachment The object that will be returned when the {@link SuspendableHandler}
243 |  |
          * methods are invoked.
244 |  |
          * @param handler A {@link SuspendableHandler} used to get notification about the suspended
245 |  |
          * connection state.
246 |  |
          * @param suspendWhen Suspend before or after the next ProtocolChain execution,
247 |  |
          * @return A {@link Suspendable}
248 |  |
          */
249 |  |
         public Suspendable suspend(String match,long expireTime,
250 |  |
                 T attachement,SuspendableHandler<? extends T> sh, Suspend suspendWhen){
251 | 6 |
             Suspendable s = new Suspendable(this);
252 | 6 |
             suspendCandidates.put(match.getBytes(),  new SuspendableHandlerWrapper(
253 |  |
                     sh,attachement, expireTime,s,suspendWhen));
254 | 6 |
             return s;
255 |  |
         }
256 |  |
257 |  |
258 |  |
         // ----------------------------------------------ProtocolFilter API ------- //
259 |  |
260 |  |
261 |  |
         /**
262 |  |
          * Excute the pattern matching algorithm to determine if a the current
263 |  |
          * connection must be suspended or not, and when.
264 |  |
          *
265 |  |
          * @param ctx The current {@link Context}
266 |  |
          * @return true if the ProtocolChain should continue its execution,
267 |  |
          * false if the connection has been suspended.
268 |  |
          * @throws java.io.IOException
269 |  |
          */
270 |  |
         public boolean execute(Context ctx) throws IOException {
271 | 9 |
             WorkerThread wt = (WorkerThread)Thread.currentThread();
272 | 9 |
             ByteBuffer bb = wt.getByteBuffer();
273 | 9 |
             controller = ctx.getController();
274 |  |
275 | 9 |
             if (ctx.getProtocol() == Controller.Protocol.TCP){
276 | 9 |
                 ctx.getSelectionKey().attach(null);
277 |  |
             } else {
278 | 0 |
                 wt.getAttachment().setTimeout(null);
279 |  |
             }
280 |  |
281 | 9 |
             if (protocolChain == null){
282 | 6 |
                 if (ctx.getProtocolChain() instanceof DefaultProtocolChain){
283 | 6 |
                     protocolChain = (DefaultProtocolChain)ctx.getProtocolChain();
284 |  |
                 } else {
285 | 0 |
                     throw new IllegalStateException("SuspendableFilter cannot be " +
286 |  |
                             "used without the DefaultProtocolChain");
287 |  |
                 }
288 |  |
             }
289 |  |
290 | 9 |
             log("Trying to match " + ctx.getSelectionKey());
291 |  |
292 |  |
             // This will be quite slow if a lot of registration.
293 |  |
             // TODO: Need a better algorithm.
294 | 9 |
             SuspendableHandlerWrapper<? extends T> sh = null;
295 | 9 |
             Iterator<byte[]> iterator = suspendCandidates.keySet().iterator();
296 | 9 |
             byte[] matchBytes = null;
297 | 9 |
             while(iterator.hasNext()){
298 | 9 |
                 matchBytes = iterator.next();
299 | 9 |
                 if (Utils.findBytes(bb,matchBytes) > -1){
300 | 9 |
                     log("Find match: " + (new String(matchBytes))
301 |  |
                                 + " Suspending: " + ctx.getSelectionKey());
302 | 9 |
                     sh = suspendCandidates.get(matchBytes);
303 | 9 |
                     break;
304 |  |
                 }
305 |  |
             }
306 |  |
307 | 9 |
             if (sh != null){
308 | 9 |
                 KeyHandler kh = new KeyHandler();
309 | 9 |
                 kh.setSuspendableHandler(sh);
310 | 9 |
                 suspendedKeys.put(ctx.getSelectionKey(),kh);
311 | 9 |
                 if (sh.getSuspendWhen() == Suspend.BEFORE){
312 | 4 |
                     suspend(ctx,true);
313 | 4 |
                     log("-----> " + ctx.getKeyRegistrationState());
314 | 4 |
                     return false;
315 |  |
                 }
316 |  |
             }
317 |  |
318 | 5 |
             return true;
319 |  |
         }
320 |  |
321 |  |
322 |  |
         /**
323 |  |
          * Excute the pattern matching algorithm to determine if a the current
324 |  |
          * connection must be suspended or not, and when.
325 |  |
          *
326 |  |
          * @param ctx The current {@link Context}
327 |  |
          * @return true if the ProtocolChain should continue its execution,
328 |  |
          * false if the connection has been suspended.
329 |  |
          * @throws java.io.IOException
330 |  |
          */
331 |  |
         public boolean postExecute(Context ctx) throws IOException {
332 | 12 |
             log("<----- " + ctx.getKeyRegistrationState());
333 |  |
334 | 12 |
             if (!suspendedKeys.isEmpty()
335 |  |
                     && ctx.getKeyRegistrationState() == KeyRegistrationState.REGISTER){
336 | 5 |
                 suspend(ctx,false);
337 | 5 |
                 return false;
338 |  |
             }
339 | 7 |
             return true;
340 |  |
         }
341 |  |
342 |  |
343 |  |
         // -------------------------------------------------- Implementation ------- //
344 |  |
345 |  |
         /**
346 |  |
          * Suspend the request by creating the appropriate structure so the state
347 |  |
          * of the current connection is not lost.
348 |  |
          * @param ctx The current {@link Context}
349 |  |
          * @param incomingRequest suspend now of after.
350 |  |
          */
351 |  |
         private void suspend(Context ctx, boolean incomingRequest){
352 |  |
             try {
353 | 9 |
                 SelectionKey key = ctx.getSelectionKey();
354 | 9 |
                 KeyHandler kh = suspendedKeys.get(key);
355 |  |
356 | 9 |
                 SuspendableHandlerWrapper<? extends T> sh = null;
357 | 9 |
                 if (kh != null){
358 | 9 |
                     sh = kh.getSuspendableHandler();
359 |  |
                 } else {
360 | 0 |
                     kh = new KeyHandler();
361 |  |
                 }
362 |  |
363 | 9 |
                 if (kh != null && !incomingRequest){
364 | 5 |
                     if (sh.getSuspendWhen() == Suspend.BEFORE){
365 | 0 |
                         return;
366 |  |
                     }
367 |  |
                 }
368 |  |
369 |  |
                 // If the users didn't want to be notified.
370 | 9 |
                 if (sh == null) {
371 |  |
                     // TODO: Configurable.
372 | 0 |
                     sh = new SuspendableHandlerWrapper(new SuspendableHandler() {
373 |  |
374 |  |
                         public void interupted(Object attachment) {
375 | 0 |
                         }
376 |  |
377 |  |
                         public void expired(Object attachment) {
378 | 0 |
                         }
379 |  |
380 |  |
                         public void resumed(Object attachment) {
381 | 0 |
                         }
382 |  |
                     }, null, 30000, new Suspendable(this), Suspend.AFTER);
383 |  |
                 }
384 | 9 |
                 sh.setSuspendableFilter(this);
385 | 9 |
                 sh.suspendable.setKey(key);
386 | 9 |
                 sh.setSelectorHandler(ctx.getSelectorHandler());
387 |  |
388 | 9 |
                 kh.setSuspendableHandler(sh);
389 | 9 |
                 kh.setKey(key);
390 | 9 |
                 WorkerThread workerThread = (WorkerThread) Thread.currentThread();
391 | 9 |
                 ThreadAttachment attachment = workerThread.getAttachment();
392 | 9 |
                 attachment.setMode(Mode.STORE_ALL);
393 | 9 |
                 kh.setThreadAttachment(workerThread.detach());
394 | 9 |
                 ctx.setKeyRegistrationState(KeyRegistrationState.NONE);
395 |  |
396 | 9 |
                 suspendableMonitor.suspend(kh);
397 | 0 |
             } catch (Throwable ex) {
398 | 0 |
                 if (logger.isLoggable(Level.FINE)){
399 | 0 |
                     logger.log(Level.FINE,"suspend",ex);
400 |  |
                 }
401 | 9 |
             }
402 | 9 |
         }
403 |  |
404 |  |
405 |  |
         /**
406 |  |
          * Resume the connection by register back the SelectionKey for OP event.
407 |  |
          * @param key
408 |  |
          * @return true if the connection was resumed.
409 |  |
          */
410 |  |
         protected boolean resume(SelectionKey key){
411 | 5 |
             KeyHandler kh = suspendedKeys.remove(key);
412 | 5 |
             if (kh.getSuspendableHandler() == null){
413 | 0 |
                 return false;
414 |  |
             }
415 | 5 |
             log("Resuming: " + kh.getSuspendableHandler());
416 |  |
417 | 5 |
             kh.getSuspendableHandler().getSuspendableHandler().
418 |  |
                     resumed(kh.getSuspendableHandler().getAttachment());
419 |  |
420 | 5 |
             if (kh.getSuspendableHandler().getSuspendWhen() == Suspend.AFTER){
421 | 2 |
                 kh.getSuspendableHandler().getSelectorHandler()
422 |  |
                         .register(key.channel(), SelectionKey.OP_READ);
423 |  |
             } else {
424 |  |
                 try {
425 | 3 |
                     Context ctx = controller.pollContext(key);
426 | 3 |
                     controller.configureContext(ctx,
427 |  |
                             kh.getSuspendableHandler().getSelectorHandler());
428 | 3 |
                     ctx.execute(SuspendableContextTask.poll(
429 |  |
                             protocolChain,kh.getThreadAttachment(),nextFilterPosition));
430 | 0 |
                 } catch (PipelineFullException ex) {
431 | 0 |
                     logger.log(Level.SEVERE,"resume exception", ex);
432 | 3 |
                 }
433 |  |
             }
434 |  |
435 | 5 |
             return true;
436 |  |
         }
437 |  |
438 |  |
439 |  |
         /**
440 |  |
          * Cancel the connection by internalling cancelling the associated
441 |  |
          * {@link ReadableChannel} and it associated {@link SelectionKey}
442 |  |
          * @param key
443 |  |
          */
444 |  |
         protected void cancel(SelectionKey key){
445 | 2 |
             log("Cancelling: " + key);
446 | 2 |
             KeyHandler kh = suspendedKeys.remove(key);
447 | 2 |
             if (kh == null){
448 | 0 |
                 return;
449 |  |
             }
450 |  |
451 | 2 |
             if (kh.getSuspendableHandler() == null){
452 | 0 |
                 return;
453 |  |
             }
454 | 2 |
             kh.getSuspendableHandler().getSuspendableHandler()
455 |  |
                     .interupted(kh.getSuspendableHandler().getAttachment());
456 | 2 |
             kh.getSuspendableHandler().getSelectorHandler()
457 |  |
                     .getSelectionKeyHandler().cancel(key);
458 | 2 |
             kh.setThreadAttachment(null);
459 | 2 |
         }
460 |  |
461 |  |
462 |  |
463 |  |
         /**
464 |  |
          * Wrapper class around a {@link SuspendableHandler} with add some connection
465 |  |
          * state.
466 |  |
          */
467 | 9 |
         protected class SuspendableHandlerWrapper<A>{
468 |  |
             public SuspendableHandlerWrapper(SuspendableHandler<A> sh, A attachment,
469 | 6 |
                     long expireTime, Suspendable suspendable, Suspend suspendWhen){
470 | 6 |
                 this.suspendableHandler = sh;
471 | 6 |
                 this.attachment = attachment;
472 | 6 |
                 this.expireTime = expireTime;
473 | 6 |
                 this.suspendable = suspendable;
474 | 6 |
                 this.suspendWhen = suspendWhen;
475 | 6 |
             }
476 |  |
477 |  |
             private SuspendableHandler<A> suspendableHandler;
478 |  |
             private A attachment;
479 | 6 |
             private long expireTime = 0L;
480 |  |
             private SuspendableFilter suspendableFilter;
481 |  |
             private Suspendable suspendable;
482 |  |
             private SelectorHandler selectorHandler;
483 |  |
             private Suspend suspendWhen;
484 |  |
485 |  |
             protected
486 |  |
487 |  |
             SuspendableHandler<A> getSuspendableHandler() {
488 | 10 |
                 return suspendableHandler;
489 |  |
             }
490 |  |
491 |  |
             protected void setSuspendableHandler(SuspendableHandler<A> suspendableHandler) {
492 | 0 |
                 this.suspendableHandler = suspendableHandler;
493 | 0 |
             }
494 |  |
495 |  |
             protected A getAttachment() {
496 | 10 |
                 return attachment;
497 |  |
             }
498 |  |
499 |  |
             protected void setAttachment(A attachment) {
500 | 0 |
                 this.attachment = attachment;
501 | 0 |
             }
502 |  |
503 |  |
             protected long getExpireTime() {
504 | 349137 |
                 return expireTime;
505 |  |
             }
506 |  |
507 |  |
             protected void setExpireTime(long expireTime) {
508 | 0 |
                 this.expireTime = expireTime;
509 | 0 |
             }
510 |  |
511 |  |
             protected SuspendableFilter getSuspendableFilter() {
512 | 3 |
                 return suspendableFilter;
513 |  |
             }
514 |  |
515 |  |
             protected void setSuspendableFilter(SuspendableFilter suspendableFilter) {
516 | 9 |
                 this.suspendableFilter = suspendableFilter;
517 | 9 |
             }
518 |  |
519 |  |
             protected Suspendable getSuspendable() {
520 | 0 |
                 return suspendable;
521 |  |
             }
522 |  |
523 |  |
             protected void setSuspendable(Suspendable suspendable) {
524 | 0 |
                 this.suspendable = suspendable;
525 | 0 |
             }
526 |  |
527 |  |
             protected SelectorHandler getSelectorHandler() {
528 | 7 |
                 return selectorHandler;
529 |  |
             }
530 |  |
531 |  |
             protected void setSelectorHandler(SelectorHandler selectorHandler) {
532 | 9 |
                 this.selectorHandler = selectorHandler;
533 | 9 |
             }
534 |  |
535 |  |
             protected Suspend getSuspendWhen() {
536 | 19 |
                 return suspendWhen;
537 |  |
             }
538 |  |
539 |  |
             protected void setSuspendWhen(Suspend suspendWhen) {
540 | 0 |
                 this.suspendWhen = suspendWhen;
541 | 0 |
             }
542 |  |
         }
543 |  |
544 |  |
545 |  |
         /**
546 |  |
          * Struc to keep state of the current suspended Connection.
547 |  |
          */
548 | 9 |
         protected class KeyHandler{
549 |  |
             private SelectionKey key;
550 |  |
             private SelectionKey foreignKey;
551 |  |
             private SuspendableHandlerWrapper handler;
552 |  |
             private ThreadAttachment threadAttachment;
553 | 9 |
             private long registrationTime = 0L;
554 |  |
555 |  |
             protected
556 |  |
557 |  |
             SelectionKey getKey() {
558 | 21 |
                 return key;
559 |  |
             }
560 |  |
561 |  |
             protected void setKey(SelectionKey key) {
562 | 9 |
                 this.key = key;
563 | 9 |
             }
564 |  |
565 |  |
             protected SelectionKey getForeignKey() {
566 | 9 |
                 return foreignKey;
567 |  |
             }
568 |  |
569 |  |
             protected void setForeignKey(SelectionKey foreignKey) {
570 | 9 |
                 this.foreignKey = foreignKey;
571 | 9 |
             }
572 |  |
573 |  |
             protected SuspendableHandlerWrapper getSuspendableHandler() {
574 | 349193 |
                 return handler;
575 |  |
             }
576 |  |
577 |  |
             protected void setSuspendableHandler(SuspendableHandlerWrapper sh) {
578 | 18 |
                 this.handler = sh;
579 | 18 |
             }
580 |  |
581 |  |
             protected ThreadAttachment getThreadAttachment() {
582 | 3 |
                 return threadAttachment;
583 |  |
             }
584 |  |
585 |  |
             protected void setThreadAttachment(ThreadAttachment threadAttachment) {
586 | 11 |
                 this.threadAttachment = threadAttachment;
587 | 11 |
             }
588 |  |
589 |  |
             protected long getRegistrationTime() {
590 | 349160 |
                 return registrationTime;
591 |  |
             }
592 |  |
593 |  |
             protected void setRegistrationTime(long registrationTime) {
594 | 12 |
                 this.registrationTime = registrationTime;
595 | 12 |
             }
596 |  |
         }
597 |  |
598 |  |
599 |  |
         private void log(String message){
600 | 41 |
             if (logger.isLoggable(Level.FINE)) {
601 | 0 |
                 logger.log(Level.FINE, message);
602 |  |
             }
603 | 41 |
         }
604 |  |
     }