1 /* 2 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.net.http.common; 27 28 import java.util.concurrent.atomic.AtomicLong; 29 30 /** 31 * Encapsulates operations with demand (Reactive Streams). 32 * 33 * <p> Demand is the aggregated number of elements requested by a Subscriber 34 * which is yet to be delivered (fulfilled) by the Publisher. 35 */ 36 public final class Demand { 37 38 private final AtomicLong val = new AtomicLong(); 39 40 /** 41 * Increases this demand by the specified positive value. 42 * 43 * @param n 44 * increment {@code > 0} 45 * 46 * @return {@code true} iff prior to this operation this demand was fulfilled 47 */ 48 public boolean increase(long n) { 49 if (n <= 0) { 50 throw new IllegalArgumentException(String.valueOf(n)); 51 } 52 long prev = val.getAndAccumulate(n, (p, i) -> p + i < 0 ? Long.MAX_VALUE : p + i); 53 return prev == 0; 54 } 55 56 /** 57 * Tries to decrease this demand by the specified positive value. 58 * 59 * <p> The actual value this demand has been decreased by might be less than 60 * {@code n}, including {@code 0} (no decrease at all). 61 * 62 * @param n 63 * decrement {@code > 0} 64 * 65 * @return a value {@code m} ({@code 0 <= m <= n}) this demand has been 66 * actually decreased by 67 */ 68 public long decreaseAndGet(long n) { 69 if (n <= 0) { 70 throw new IllegalArgumentException(String.valueOf(n)); 71 } 72 long p, d; 73 do { 74 d = val.get(); 75 p = Math.min(d, n); 76 } while (!val.compareAndSet(d, d - p)); 77 return p; 78 } 79 80 /** 81 * Tries to decrease this demand by {@code 1}. 82 * 83 * @return {@code true} iff this demand has been decreased by {@code 1} 84 */ 85 public boolean tryDecrement() { 86 return decreaseAndGet(1) == 1; 87 } 88 89 /** 90 * @return {@code true} iff there is no unfulfilled demand 91 */ 92 public boolean isFulfilled() { 93 return val.get() == 0; 94 } 95 96 /** 97 * Resets this object to its initial state. 98 */ 99 public void reset() { 100 val.set(0); 101 } 102 103 /** 104 * Returns the current value of this demand. 105 * 106 * @return the current value of this demand 107 */ 108 public long get() { 109 return val.get(); 110 } 111 112 @Override 113 public String toString() { 114 return String.valueOf(val.get()); 115 } 116 }