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 }