Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
SuspendableFilter |
|
| 0.0;0 | ||||
SuspendableFilter$1 |
|
| 0.0;0 | ||||
SuspendableFilter$KeyHandler |
|
| 0.0;0 | ||||
SuspendableFilter$Suspend |
|
| 0.0;0 | ||||
SuspendableFilter$SuspendableHandlerWrapper |
|
| 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 | } |