package com.tesora.dve.concurrent; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; public class PEDefaultPromise<T> implements CompletionTarget<T>, CompletionHandle<T>, CompletionNotifier<T> { static final Object NO_RESULT = new Object(); static Logger logger = Logger.getLogger( PEDefaultPromise.class ); static AtomicInteger nextId = new AtomicInteger(); int thisId = nextId.incrementAndGet(); AtomicReference<PromiseState> state = new AtomicReference<>(new PromiseState()); @SuppressWarnings("unchecked") @Override public void addListener(CompletionTarget<T> listener) { do { PromiseState<T> current = state.get(); if (current.isFinished()) { if (current.isSuccess()) listener.success((T)current.result); else listener.failure(current.error); break; } else { PromiseState next = new PromiseState(listener,current); if (state.compareAndSet(current,next)) break; } } while (true); } @SuppressWarnings("unchecked") @Override public void success(T returnValue) { do { PromiseState<T> current = state.get(); if (current.isFinished()) break; PromiseState<T> next = new PromiseState<>(returnValue,current); if (state.compareAndSet(current, next)) { notifyListeners(next); break; } } while (true); } private void notifyListeners(PromiseState<T> finishState) { if (finishState.isSuccess()) notifySuccess(finishState); else notifyFailure(finishState); } @SuppressWarnings("unchecked") private void notifySuccess(PromiseState<T> finishState) { T result = (T)finishState.result; while (finishState != null){ if (finishState.listener != null) finishState.listener.success(result); finishState = finishState.next; } } private void notifyFailure(PromiseState<T> finishState) { Exception error = finishState.error; while (finishState != null){ if (finishState.listener != null) finishState.listener.failure(error); finishState = finishState.next; } } @SuppressWarnings("unchecked") @Override public boolean trySuccess(T returnValue) { do { PromiseState<T> current = state.get(); if (current.isFinished()) return false; PromiseState<T> next = new PromiseState<>(returnValue,current); if (state.compareAndSet(current, next)) { notifyListeners(next); break; } } while (true); return true; } @SuppressWarnings("unchecked") @Override public void failure(Exception t) { do { PromiseState<T> current = state.get(); if (current.isFinished()) break; PromiseState<T> next = new PromiseState<>(t,current); if (state.compareAndSet(current, next)) { notifyListeners(next); break; } } while (true); } @Override public boolean isFulfilled() { return state.get().isFinished(); } @Override public String toString() { return "PEDefaultPromise{"+thisId+"}"; } static class PromiseState<T> { final Object result; final Exception error; final CompletionTarget<T> listener; final PromiseState<T> next; public PromiseState() { this.result = NO_RESULT; this.error = null; this.listener = null; this.next = null; } public PromiseState(CompletionTarget<T> listener, PromiseState<T> current) { this.result = NO_RESULT; this.error = null; this.listener = listener; this.next = current; } public PromiseState(T result, PromiseState<T> current) { this.result = result; this.error = null; this.listener = null; this.next = current; } public PromiseState(Exception error, PromiseState<T> current) { this.result = NO_RESULT; this.error = error; this.listener = null; this.next = current; } public boolean isFinished(){ return isError() || isSuccess(); } public boolean isError(){ return error != null; } public boolean isSuccess(){ return result != NO_RESULT; } } }