/*
* Copyright 2013 Julien Viet
*
* 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 vietj.promises;
import java.util.concurrent.atomic.AtomicReference;
/** @author Julien Viet */
public class Deferred<V> {
/** . */
private final AtomicReference<Status<V>> current = new AtomicReference<Status<V>>(null);
private static class Status<V> {
/**
* A pending status.
*
* @param <V>
*/
static class Pending<V, R> extends Status<V> {
final Deferred<R> deferred;
final PromisingCallback<V, Void> resolve;
final PromisingCallback<Exception, Void> reject;
Pending(final PromisingCallback<V, R> onFulfilled, final PromisingCallback<Exception, R> onRejected, final Pending<V, ?> previous) {
PromisingCallback<V, Void> resolve = new PromisingCallback<V, Void>() {
public Promise<Void> call(V arg) throws Exception {
if (previous != null) {
previous.resolve.call(arg);
}
try {
Promise<R> result = onFulfilled.call(arg);
deferred.resolve(result);
}
catch (Exception e) {
deferred.reject(e);
}
return null;
}
};
PromisingCallback<Exception, Void> reject = new PromisingCallback<Exception, Void>() {
public Promise<Void> call(Exception arg) throws Exception {
if (previous != null) {
previous.reject.call(arg);
}
try {
Promise<R> result = onRejected.call(arg);
deferred.resolve(result);
}
catch (Exception e) {
deferred.reject(e);
}
return null;
}
};
this.deferred = new Deferred<R>();
this.resolve = resolve;
this.reject = reject;
}
}
static class Resolved<V> extends Status<V> {
final Promise<V> value;
Resolved(Promise<V> value) {
if (value == null) {
throw new NullPointerException();
}
this.value = value;
}
}
}
public void resolve(final V value) {
resolve(new Promise<V>() {
public <Void> Promise<Void> then(PromisingCallback<V, Void> onFulfilled, PromisingCallback<Exception, Void> onRejected) {
try {
onFulfilled.call(value);
}
catch (Exception e) {
// ??
}
return null;
}
});
}
public void reject(final Exception reason) {
resolve(new Promise<V>() {
public <Void> Promise<Void> then(PromisingCallback<V, Void> onFulfilled, PromisingCallback<Exception, Void> onRejected) {
try {
onRejected.call(reason);
}
catch (Exception e) {
// ??
}
return null;
}
});
}
public void resolve(Promise<V> value) {
while (true) {
Status<V> status = current.get();
if (status == null || status instanceof Status.Pending<?, ?>) {
Status.Resolved<V> resolved = new Status.Resolved<V>(value);
if (current.compareAndSet(status, resolved)) {
Status.Pending<V, ?> pending = (Status.Pending<V, ?>)status;
if (pending != null) {
value.then(pending.resolve, pending.reject);
}
}
} else {
break;
}
}
}
public final Promise<V> promise = new Promise<V>() {
public <R> Promise<R> then(PromisingCallback<V, R> onFulfilled, PromisingCallback<Exception, R> onRejected) {
while (true) {
Status<V> status = current.get();
if (status == null || status instanceof Status.Pending<?, ?>) {
Status.Pending<V, ?> previous = (Status.Pending<V, ?>)status;
Status.Pending<V, R> next = new Status.Pending<V, R>(onFulfilled, onRejected, previous);
if (current.compareAndSet(status, next)) {
return next.deferred.promise;
}
} else if (status instanceof Status.Resolved<?>) {
Status.Resolved<V> resolved = (Status.Resolved<V>)status;
return resolved.value.then(onFulfilled, onRejected);
} else {
throw new UnsupportedOperationException("todo");
}
}
}
};
}