View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.AtomicReference;
25  
26  import org.eclipse.jetty.util.Callback;
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.util.log.Logger;
29  
30  
31  /* ------------------------------------------------------------ */
32  /** 
33   * A Utility class to help implement {@link EndPoint#fillInterested(Callback)}
34   * by keeping state and calling the context and callback objects.
35   * 
36   */
37  public abstract class FillInterest
38  {
39      private final static Logger LOG = Log.getLogger(FillInterest.class);
40      private final AtomicReference<Callback> _interested = new AtomicReference<>(null);
41  
42      /* ------------------------------------------------------------ */
43      protected FillInterest()
44      {
45      }
46  
47      /* ------------------------------------------------------------ */
48      /** Call to register interest in a callback when a read is possible.
49       * The callback will be called either immediately if {@link #needsFill()} 
50       * returns true or eventually once {@link #fillable()} is called.
51       * @param callback
52       * @throws ReadPendingException
53       */
54      public <C> void register(Callback callback) throws ReadPendingException
55      {
56          if (callback==null)
57              throw new IllegalArgumentException();
58          
59          if (!_interested.compareAndSet(null,callback))
60          {
61              LOG.warn("Read pending for "+_interested.get()+" pervented "+callback);
62              throw new ReadPendingException();
63          }
64          try
65          {
66              if (needsFill())
67                  fillable();
68          }
69          catch(IOException e)
70          {
71              onFail(e);
72          }
73      }
74  
75      /* ------------------------------------------------------------ */
76      /** Call to signal that a read is now possible.
77       */
78      public void fillable()
79      {
80          Callback callback=_interested.get();
81          if (callback!=null && _interested.compareAndSet(callback,null))
82              callback.succeeded();
83      }
84  
85      /* ------------------------------------------------------------ */
86      /**
87       * @return True if a read callback has been registered
88       */
89      public boolean isInterested()
90      {
91          return _interested.get()!=null;
92      }
93      
94      /* ------------------------------------------------------------ */
95      /** Call to signal a failure to a registered interest
96       * @return true if the cause was passed to a {@link Callback} instance
97       */
98      public boolean onFail(Throwable cause)
99      {
100         Callback callback=_interested.get();
101         if (callback!=null && _interested.compareAndSet(callback,null))
102         {
103             callback.failed(cause);
104             return true;
105         }
106         return false;
107     }
108     
109     /* ------------------------------------------------------------ */
110     public void onClose()
111     {
112         Callback callback=_interested.get();
113         if (callback!=null && _interested.compareAndSet(callback,null))
114             callback.failed(new ClosedChannelException());
115     }
116     
117     /* ------------------------------------------------------------ */
118     @Override
119     public String toString()
120     {
121         return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_interested.get());
122     }
123     
124     /* ------------------------------------------------------------ */
125     /** Register the read interest 
126      * Abstract method to be implemented by the Specific ReadInterest to
127      * enquire if a read is immediately possible and if not to schedule a future
128      * call to {@link #fillable()} or {@link #onFail(Throwable)}
129      * @return true if a read is possible
130      * @throws IOException
131      */
132     abstract protected boolean needsFill() throws IOException;
133     
134     
135 }