2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.framework;
10 import io.netty.util.concurrent.DefaultPromise;
11 import io.netty.util.concurrent.Future;
12 import io.netty.util.concurrent.FutureListener;
14 import java.net.InetSocketAddress;
16 import com.google.common.base.Preconditions;
18 final class ReconnectPromise<S extends ProtocolSession<?>, L extends SessionListener<?, ?, ?>> extends DefaultPromise<Void> {
19 private final AbstractDispatcher<S, L> dispatcher;
20 private final InetSocketAddress address;
21 private final ReconnectStrategyFactory strategyFactory;
22 private final ReconnectStrategy strategy;
23 private Future<?> pending;
24 private final SessionListenerFactory<L> lfactory;
26 public ReconnectPromise(final AbstractDispatcher<S, L> dispatcher, final InetSocketAddress address,
27 final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy,
28 final SessionListenerFactory<L> lfactory) {
30 this.dispatcher = Preconditions.checkNotNull(dispatcher);
31 this.address = Preconditions.checkNotNull(address);
32 this.strategyFactory = Preconditions.checkNotNull(connectStrategyFactory);
33 this.strategy = Preconditions.checkNotNull(reestablishStrategy);
34 this.lfactory = Preconditions.checkNotNull(lfactory);
37 synchronized void connect() {
38 final ReconnectStrategy cs = this.strategyFactory.createReconnectStrategy();
39 final ReconnectStrategy rs = new ReconnectStrategy() {
41 public Future<Void> scheduleReconnect(final Throwable cause) {
42 return cs.scheduleReconnect(cause);
46 public void reconnectSuccessful() {
47 cs.reconnectSuccessful();
51 public int getConnectTimeout() throws Exception {
52 final int cst = cs.getConnectTimeout();
53 final int rst = ReconnectPromise.this.strategy.getConnectTimeout();
61 return Math.min(cst, rst);
65 final Future<S> cf = this.dispatcher.createClient(this.address, rs, this.lfactory);
67 final Object lock = this;
70 cf.addListener(new FutureListener<S>() {
72 public void operationComplete(final Future<S> future) {
74 if (!future.isSuccess()) {
75 final Future<Void> rf = ReconnectPromise.this.strategy.scheduleReconnect(cf.cause());
76 ReconnectPromise.this.pending = rf;
78 rf.addListener(new FutureListener<Void>() {
80 public void operationComplete(final Future<Void> sf) {
83 * The promise we gave out could have been cancelled,
84 * which cascades to the reconnect attempt getting
85 * cancelled, but there is a slight race window, where
86 * the reconnect attempt is already enqueued, but the
87 * listener has not yet been notified -- if cancellation
88 * happens at that point, we need to catch it here.
94 setFailure(sf.cause());
102 * FIXME: we have a slight race window with cancellation
103 * here. Analyze and define its semantics.
105 ReconnectPromise.this.strategy.reconnectSuccessful();
114 public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
115 if (super.cancel(mayInterruptIfRunning)) {
116 this.pending.cancel(mayInterruptIfRunning);