1 //
2 // ========================================================================
3 // Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.io;
20
21 import java.io.IOException;
22 import java.nio.channels.ClosedChannelException;
23 import java.nio.channels.ReadPendingException;
24 import java.util.concurrent.atomic.AtomicBoolean;
25
26 import org.eclipse.jetty.util.Callback;
27
28
29 /* ------------------------------------------------------------ */
30 /**
31 * A Utility class to help implement {@link EndPoint#fillInterested(Callback)}
32 * by keeping state and calling the context and callback objects.
33 *
34 */
35 public abstract class FillInterest
36 {
37 private final AtomicBoolean _interested = new AtomicBoolean(false);
38 private volatile Callback _callback;
39
40 /* ------------------------------------------------------------ */
41 protected FillInterest()
42 {
43 }
44
45 /* ------------------------------------------------------------ */
46 /** Call to register interest in a callback when a read is possible.
47 * The callback will be called either immediately if {@link #needsFill()}
48 * returns true or eventually once {@link #fillable()} is called.
49 * @param context
50 * @param callback
51 * @throws ReadPendingException
52 */
53 public <C> void register(Callback callback) throws ReadPendingException
54 {
55 if (!_interested.compareAndSet(false,true))
56 throw new ReadPendingException();
57 _callback=callback;
58 try
59 {
60 if (needsFill())
61 fillable();
62 }
63 catch(IOException e)
64 {
65 onFail(e);
66 }
67 }
68
69 /* ------------------------------------------------------------ */
70 /** Call to signal that a read is now possible.
71 */
72 public void fillable()
73 {
74 if (_interested.compareAndSet(true,false))
75 {
76 Callback callback=_callback;
77 _callback=null;
78 callback.succeeded();
79 }
80 }
81
82 /* ------------------------------------------------------------ */
83 /**
84 * @return True if a read callback has been registered
85 */
86 public boolean isInterested()
87 {
88 return _interested.get();
89 }
90
91 /* ------------------------------------------------------------ */
92 /** Call to signal a failure to a registered interest
93 */
94 public void onFail(Throwable cause)
95 {
96 if (_interested.compareAndSet(true,false))
97 {
98 Callback callback=_callback;
99 _callback=null;
100 callback.failed(cause);
101 }
102 }
103
104 /* ------------------------------------------------------------ */
105 public void onClose()
106 {
107 if (_interested.compareAndSet(true,false))
108 {
109 Callback callback=_callback;
110 _callback=null;
111 callback.failed(new ClosedChannelException());
112 }
113 }
114
115 /* ------------------------------------------------------------ */
116 @Override
117 public String toString()
118 {
119 return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_callback);
120 }
121
122 /* ------------------------------------------------------------ */
123 /** Register the read interest
124 * Abstract method to be implemented by the Specific ReadInterest to
125 * enquire if a read is immediately possible and if not to schedule a future
126 * call to {@link #fillable()} or {@link #onFail(Throwable)}
127 * @return true if a read is possible
128 * @throws IOException
129 */
130 abstract protected boolean needsFill() throws IOException;
131
132
133 }