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 import java.util.concurrent.atomic.AtomicReference;
26
27 import org.eclipse.jetty.util.Callback;
28
29
30 /* ------------------------------------------------------------ */
31 /**
32 * A Utility class to help implement {@link EndPoint#fillInterested(Callback)}
33 * by keeping state and calling the context and callback objects.
34 *
35 */
36 public abstract class FillInterest
37 {
38 private final AtomicReference<Callback> _interested = new AtomicReference<>(null);
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 (callback==null)
56 throw new IllegalArgumentException();
57
58 if (!_interested.compareAndSet(null,callback))
59 throw new ReadPendingException();
60 try
61 {
62 if (needsFill())
63 fillable();
64 }
65 catch(IOException e)
66 {
67 onFail(e);
68 }
69 }
70
71 /* ------------------------------------------------------------ */
72 /** Call to signal that a read is now possible.
73 */
74 public void fillable()
75 {
76 Callback callback=_interested.get();
77 if (callback!=null && _interested.compareAndSet(callback,null))
78 callback.succeeded();
79 }
80
81 /* ------------------------------------------------------------ */
82 /**
83 * @return True if a read callback has been registered
84 */
85 public boolean isInterested()
86 {
87 return _interested.get()!=null;
88 }
89
90 /* ------------------------------------------------------------ */
91 /** Call to signal a failure to a registered interest
92 */
93 public void onFail(Throwable cause)
94 {
95 Callback callback=_interested.get();
96 if (callback!=null && _interested.compareAndSet(callback,null))
97 callback.failed(cause);
98 }
99
100 /* ------------------------------------------------------------ */
101 public void onClose()
102 {
103 Callback callback=_interested.get();
104 if (callback!=null && _interested.compareAndSet(callback,null))
105 callback.failed(new ClosedChannelException());
106 }
107
108 /* ------------------------------------------------------------ */
109 @Override
110 public String toString()
111 {
112 return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_interested.get());
113 }
114
115 /* ------------------------------------------------------------ */
116 /** Register the read interest
117 * Abstract method to be implemented by the Specific ReadInterest to
118 * enquire if a read is immediately possible and if not to schedule a future
119 * call to {@link #fillable()} or {@link #onFail(Throwable)}
120 * @return true if a read is possible
121 * @throws IOException
122 */
123 abstract protected boolean needsFill() throws IOException;
124
125
126 }