/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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.elasticsearch.action.support; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ListenableActionFuture; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.threadpool.ThreadPool; import java.util.ArrayList; import java.util.List; /** * */ public abstract class AbstractListenableActionFuture<T, L> extends AdapterActionFuture<T, L> implements ListenableActionFuture<T> { private final static ESLogger logger = Loggers.getLogger(AbstractListenableActionFuture.class); final ThreadPool threadPool; volatile Object listeners; boolean executedListeners = false; protected AbstractListenableActionFuture(ThreadPool threadPool) { this.threadPool = threadPool; } public ThreadPool threadPool() { return threadPool; } @Override public void addListener(final ActionListener<T> listener) { internalAddListener(listener); } public void internalAddListener(ActionListener<T> listener) { listener = new ThreadedActionListener<>(logger, threadPool, ThreadPool.Names.LISTENER, listener); boolean executeImmediate = false; synchronized (this) { if (executedListeners) { executeImmediate = true; } else { Object listeners = this.listeners; if (listeners == null) { listeners = listener; } else if (listeners instanceof List) { ((List) this.listeners).add(listener); } else { Object orig = listeners; listeners = new ArrayList<>(2); ((List) listeners).add(orig); ((List) listeners).add(listener); } this.listeners = listeners; } } if (executeImmediate) { executeListener(listener); } } @Override protected void done() { super.done(); synchronized (this) { executedListeners = true; } Object listeners = this.listeners; if (listeners != null) { if (listeners instanceof List) { List list = (List) listeners; for (Object listener : list) { executeListener((ActionListener<T>) listener); } } else { executeListener((ActionListener<T>) listeners); } } } private void executeListener(final ActionListener<T> listener) { try { // we use a timeout of 0 to by pass assertion forbidding to call actionGet() (blocking) on a network thread. // here we know we will never block listener.onResponse(actionGet(0)); } catch (Throwable e) { listener.onFailure(e); } } }