| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.qpid.protonj2.client.futures; |
| |
| import java.util.Objects; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; |
| |
| import org.apache.qpid.protonj2.client.exceptions.ClientException; |
| |
| /** |
| * Asynchronous Client Future class. |
| * |
| * @param <V> the eventual result type for this Future |
| */ |
| public abstract class ClientFuture<V> implements Future<V>, AsyncResult<V> { |
| |
| protected final ClientSynchronization<V> synchronization; |
| |
| // States used to track progress of this future |
| protected static final int INCOMPLETE = 0; |
| protected static final int COMPLETING = 1; |
| protected static final int SUCCESS = 2; |
| protected static final int FAILURE = 3; |
| protected static final int CANCELLED = 4; |
| |
| @SuppressWarnings("rawtypes") |
| protected static final AtomicIntegerFieldUpdater<ClientFuture> STATE_FIELD_UPDATER = |
| AtomicIntegerFieldUpdater.newUpdater(ClientFuture.class,"state"); |
| |
| private volatile int state = INCOMPLETE; |
| protected ExecutionException error; |
| protected int waiting; |
| protected V result; |
| |
| protected ClientFuture(ClientSynchronization<V> synchronization) { |
| this.synchronization = synchronization; |
| } |
| |
| @Override |
| public boolean cancel(boolean mayInterruptIfRunning) { |
| if (STATE_FIELD_UPDATER.compareAndSet(this, INCOMPLETE, COMPLETING)) { |
| STATE_FIELD_UPDATER.lazySet(this, CANCELLED); |
| |
| synchronized(this) { |
| if (waiting > 0) { |
| notifyAll(); |
| } |
| } |
| |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * @return true if the {@link Future} operation failed. |
| */ |
| public boolean isFailed() { |
| return error != null; |
| } |
| |
| /** |
| * @return the resulting value of the operation upon successful completion. |
| */ |
| public V getResult() { |
| return result; |
| } |
| |
| @Override |
| public boolean isCancelled() { |
| return state > FAILURE; |
| } |
| |
| @Override |
| public boolean isDone() { |
| return isComplete() || isCancelled() || isFailed(); |
| } |
| |
| @Override |
| public boolean isComplete() { |
| return state > COMPLETING; |
| } |
| |
| protected boolean isNotComplete() { |
| return state <= COMPLETING; |
| } |
| |
| /** |
| * @return the current {@link ClientFuture} state as if this call. |
| */ |
| protected int getState() { |
| return state; |
| } |
| |
| @Override |
| public void failed(ClientException result) { |
| Objects.requireNonNull(result, "Cannot fail the Future type without providing an error cause"); |
| |
| if (STATE_FIELD_UPDATER.compareAndSet(this, INCOMPLETE, COMPLETING)) { |
| error = new ExecutionException(result); |
| |
| if (synchronization != null) { |
| try { |
| synchronization.onPendingFailure(error); |
| } catch(Exception ignored) {} |
| } |
| |
| STATE_FIELD_UPDATER.lazySet(this, FAILURE); |
| |
| synchronized(this) { |
| if (waiting > 0) { |
| notifyAll(); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void complete(V result) { |
| if (STATE_FIELD_UPDATER.compareAndSet(this, INCOMPLETE, COMPLETING)) { |
| this.result = result; |
| |
| if (synchronization != null) { |
| try { |
| synchronization.onPendingSuccess(result); |
| } catch(Exception ignored) {} |
| } |
| |
| STATE_FIELD_UPDATER.lazySet(this, SUCCESS); |
| |
| synchronized(this) { |
| if (waiting > 0) { |
| notifyAll(); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public abstract V get() throws InterruptedException, ExecutionException; |
| |
| @Override |
| public abstract V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; |
| |
| /** |
| * TODO - Provide hook to run on the event loop to do whatever it means to cancel this task and |
| * update the task state in a thread safe manner. |
| */ |
| protected void tryCancelTask() { |
| |
| } |
| } |