1 /*
2 * Copyright 2002-2014 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.foxinmy.weixin4j.util;
18
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.FutureTask;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import java.util.concurrent.atomic.AtomicReference;
26
27 /**
28 * A {@link org.springframework.util.concurrent.ListenableFuture
29 * ListenableFuture} whose value can be set via {@link #set(Object)} or
30 * {@link #setException(Throwable)}. It may also be cancelled.
31 *
32 * <p>
33 * Inspired by {@code com.google.common.util.concurrent.SettableFuture}.
34 *
35 * @author Mattias Severson
36 * @author Rossen Stoyanchev
37 * @since 4.1
38 */
39 public class SettableFuture<T> implements Future<T> {
40
41 private final SettableTask<T> settableTask;
42
43 private final FutureTask<T> futureTask;
44
45 public SettableFuture() {
46 this.settableTask = new SettableTask<T>();
47 this.futureTask = new FutureTask<T>(this.settableTask);
48 }
49
50 /**
51 * Set the value of this future. This method will return {@code true} if the
52 * value was set successfully, or {@code false} if the future has already
53 * been set or cancelled.
54 *
55 * @param value
56 * the value that will be set.
57 * @return {@code true} if the value was successfully set, else
58 * {@code false}.
59 */
60 public boolean set(T value) {
61 boolean success = this.settableTask.setValue(value);
62 if (success) {
63 this.futureTask.run();
64 }
65 return success;
66 }
67
68 /**
69 * Set the exception of this future. This method will return {@code true} if
70 * the exception was set successfully, or {@code false} if the future has
71 * already been set or cancelled.
72 *
73 * @param exception
74 * the value that will be set.
75 * @return {@code true} if the exception was successfully set, else
76 * {@code false}.
77 */
78 public boolean setException(Throwable exception) {
79 boolean success = this.settableTask.setException(exception);
80 if (success) {
81 this.futureTask.run();
82 }
83 return success;
84 }
85
86 @Override
87 public boolean cancel(boolean mayInterruptIfRunning) {
88 this.settableTask.setCancelled();
89 boolean cancelled = this.futureTask.cancel(mayInterruptIfRunning);
90 if (cancelled && mayInterruptIfRunning) {
91 interruptTask();
92 }
93 return cancelled;
94 }
95
96 @Override
97 public boolean isCancelled() {
98 return this.futureTask.isCancelled();
99 }
100
101 @Override
102 public boolean isDone() {
103 return this.futureTask.isDone();
104 }
105
106 /**
107 * Retrieve the value.
108 * <p>
109 * Will return the value if it has been set via {@link #set(Object)}, throw
110 * an {@link java.util.concurrent.ExecutionException} if it has been set via
111 * {@link #setException(Throwable)} or throw a
112 * {@link java.util.concurrent.CancellationException} if it has been
113 * cancelled.
114 *
115 * @return The value associated with this future.
116 */
117 @Override
118 public T get() throws InterruptedException, ExecutionException {
119 return this.futureTask.get();
120 }
121
122 /**
123 * Retrieve the value.
124 * <p>
125 * Will return the value if it has been set via {@link #set(Object)}, throw
126 * an {@link java.util.concurrent.ExecutionException} if it has been set via
127 * {@link #setException(Throwable)} or throw a
128 * {@link java.util.concurrent.CancellationException} if it has been
129 * cancelled.
130 *
131 * @param timeout
132 * the maximum time to wait.
133 * @param unit
134 * the time unit of the timeout argument.
135 * @return The value associated with this future.
136 */
137 @Override
138 public T get(long timeout, TimeUnit unit) throws InterruptedException,
139 ExecutionException, TimeoutException {
140 return this.futureTask.get(timeout, unit);
141 }
142
143 /**
144 * Subclasses can override this method to implement interruption of the
145 * future's computation. The method is invoked automatically by a successful
146 * call to {@link #cancel(boolean) cancel(true)}.
147 * <p>
148 * The default implementation does nothing.
149 */
150 protected void interruptTask() {
151 }
152
153 private static class SettableTask<T> implements Callable<T> {
154
155 private static final String NO_VALUE = SettableFuture.class
156 .getName() + ".NO_VALUE";
157
158 private final AtomicReference<Object> value = new AtomicReference<Object>(
159 NO_VALUE);
160
161 private volatile boolean cancelled = false;
162
163 public boolean setValue(T value) {
164 if (this.cancelled) {
165 return false;
166 }
167 return this.value.compareAndSet(NO_VALUE, value);
168 }
169
170 public boolean setException(Throwable exception) {
171 if (this.cancelled) {
172 return false;
173 }
174 return this.value.compareAndSet(NO_VALUE, exception);
175 }
176
177 public void setCancelled() {
178 this.cancelled = true;
179 }
180
181 @SuppressWarnings("unchecked")
182 @Override
183 public T call() throws Exception {
184 if (value.get() instanceof Exception) {
185 throw (Exception) value.get();
186 }
187 return (T) value.get();
188 }
189 }
190
191 }