/*
* Copyright 2008-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nominanuda.zen.reactivestreams;
import static com.nominanuda.zen.reactivestreams.ReactiveUtils.cappedSum;
import static java.lang.Long.MAX_VALUE;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class SubscriptionImpl implements TrackingSubscription {
private volatile long outstanding = 0;
private volatile boolean valid = true;
private CountDownLatch latch = new CountDownLatch(1);
@Override
public void request(long n) {
if(valid) {
if(n < 0) {
//TODO onError(new IllegalArgumentException("TODO rule n..."));
} else if(n > 0){
boolean doRelease = outstanding == 0;
outstanding = cappedSum(outstanding, n);
if(doRelease) {
gateOpen();
}
}
}
}
@Override
public void cancel() {
if(valid) {
valid = false;
}
}
@Override
public long peekDemand() {
return outstanding;
}
@Override
public long awaitDemand() throws InterruptedException {
if(outstanding == 0) {
latch.await();
}
return outstanding;
}
@Override
public long awaitDemand(long timeout, TimeUnit unit) throws InterruptedException {
if(outstanding == 0) {
latch.await(timeout, unit);
}
return outstanding;
}
private void gateClose() {
latch = new CountDownLatch(1);
}
private void gateOpen() {
latch.countDown();
}
@Override
public boolean unrequest() {
if(valid) {
if(outstanding == 0) {
return false;
} else if(outstanding < MAX_VALUE) {
if(--outstanding == 0) {
gateClose();
}
return true;
} else {
return true;
}
} else {
return false;
}
}
@Override
public boolean isValid() {
return valid;
}
@Override
public boolean isCanceled() {
return ! valid;
}
}