001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.concurrent;
016    
017    import java.util.Set;
018    import java.util.concurrent.Callable;
019    import java.util.concurrent.CopyOnWriteArraySet;
020    import java.util.concurrent.Future;
021    import java.util.concurrent.FutureTask;
022    import java.util.concurrent.atomic.AtomicBoolean;
023    
024    /**
025     * @author Shuyang Zhou
026     */
027    public class DefaultNoticeableFuture<T>
028            extends FutureTask<T> implements NoticeableFuture<T> {
029    
030            @SuppressWarnings("unchecked")
031            public DefaultNoticeableFuture() {
032                    super((Callable<T>)_emptyCallable);
033            }
034    
035            public DefaultNoticeableFuture(Callable<T> callable) {
036                    super(callable);
037            }
038    
039            public DefaultNoticeableFuture(Runnable runnable, T result) {
040                    super(runnable, result);
041            }
042    
043            @Override
044            public boolean addFutureListener(FutureListener<T> futureListener) {
045                    if (futureListener == null) {
046                            throw new NullPointerException("Future listener is null");
047                    }
048    
049                    futureListener = new OnceFutureListener<>(futureListener);
050    
051                    if (_futureListeners.add(futureListener)) {
052                            if (isDone()) {
053                                    futureListener.complete(this);
054                            }
055    
056                            return true;
057                    }
058    
059                    return false;
060            }
061    
062            @Override
063            public boolean removeFutureListener(FutureListener<T> futureListener) {
064                    if (futureListener == null) {
065                            throw new NullPointerException("Future listener is null");
066                    }
067    
068                    return _futureListeners.remove(
069                            new OnceFutureListener<T>(futureListener));
070            }
071    
072            @Override
073            public void set(T t) {
074                    super.set(t);
075            }
076    
077            @Override
078            public void setException(Throwable t) {
079                    super.setException(t);
080            }
081    
082            @Override
083            protected void done() {
084                    for (FutureListener<T> futureListener : _futureListeners) {
085                            futureListener.complete(this);
086                    }
087            }
088    
089            private static final Callable<Object> _emptyCallable =
090                    new Callable<Object>() {
091    
092                            @Override
093                            public Object call() {
094                                    return null;
095                            }
096    
097                    };
098    
099            private final Set<FutureListener<T>> _futureListeners =
100                    new CopyOnWriteArraySet<>();
101    
102            private static class OnceFutureListener<V> implements FutureListener<V> {
103    
104                    public OnceFutureListener(FutureListener<V> futureListener) {
105                            _futureListener = futureListener;
106                    }
107    
108                    @Override
109                    public void complete(Future<V> future) {
110                            if (_ran.compareAndSet(false, true)) {
111                                    _futureListener.complete(future);
112                            }
113                    }
114    
115                    @Override
116                    public boolean equals(Object obj) {
117                            OnceFutureListener<V> onceFutureListener =
118                                    (OnceFutureListener<V>)obj;
119    
120                            return _futureListener.equals(onceFutureListener._futureListener);
121                    }
122    
123                    @Override
124                    public int hashCode() {
125                            return _futureListener.hashCode();
126                    }
127    
128                    private final FutureListener<V> _futureListener;
129                    private final AtomicBoolean _ran = new AtomicBoolean();
130    
131            }
132    
133    }