2 * Copyright (c) 2015 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
9 package org.opendaylight.protocol.pcep.pcc.mock.protocol;
11 import static java.util.Objects.requireNonNull;
13 import io.netty.bootstrap.Bootstrap;
14 import io.netty.channel.ChannelFuture;
15 import io.netty.channel.ChannelFutureListener;
16 import io.netty.channel.ChannelOption;
17 import io.netty.channel.EventLoop;
18 import io.netty.util.concurrent.DefaultPromise;
19 import io.netty.util.concurrent.Future;
20 import io.netty.util.concurrent.GlobalEventExecutor;
21 import io.netty.util.concurrent.Promise;
22 import java.net.InetSocketAddress;
23 import java.util.concurrent.TimeUnit;
24 import javax.annotation.concurrent.GuardedBy;
25 import org.opendaylight.protocol.pcep.PCEPSession;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 final class PCCReconnectPromise extends DefaultPromise<PCEPSession> {
30 private static final Logger LOG = LoggerFactory.getLogger(PCCReconnectPromise.class);
32 private final InetSocketAddress address;
33 private final int retryTimer;
34 private final int connectTimeout;
35 private final Bootstrap b;
38 private Future<?> pending;
40 PCCReconnectPromise(final InetSocketAddress address, final int retryTimer,
41 final int connectTimeout, final Bootstrap b) {
42 super(GlobalEventExecutor.INSTANCE);
43 this.address = address;
44 this.retryTimer = retryTimer;
45 this.connectTimeout = connectTimeout;
49 synchronized void connect() {
51 this.b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectTimeout);
52 this.b.remoteAddress(this.address);
53 final ChannelFuture cf = this.b.connect();
54 cf.addListener(new BootstrapConnectListener(this));
56 } catch (final Exception e) {
57 LOG.info("Failed to connect to {}", this.address, e);
63 public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
64 if (super.cancel(mayInterruptIfRunning)) {
65 this.pending.cancel(mayInterruptIfRunning);
73 public synchronized Promise<PCEPSession> setSuccess(final PCEPSession result) {
74 final Promise<PCEPSession> promise = super.setSuccess(result);
75 LOG.debug("Promise {} completed", this);
79 synchronized boolean isInitialConnectFinished() {
80 requireNonNull(this.pending);
81 return this.pending.isDone() && this.pending.isSuccess();
84 private final class BootstrapConnectListener implements ChannelFutureListener {
87 private final Object lock;
89 BootstrapConnectListener(final Object lock) {
94 public void operationComplete(final ChannelFuture cf) throws Exception {
95 synchronized (this.lock) {
96 if (PCCReconnectPromise.this.isCancelled()) {
98 PCCReconnectPromise.LOG.debug("Closing channels for cancelled promise {}");
101 } else if (cf.isSuccess()) {
102 PCCReconnectPromise.LOG.debug("Promise connection is successful.");
104 PCCReconnectPromise.LOG.debug("Attempt to connect to {} failed", PCCReconnectPromise.this.address, cf.cause());
106 if (PCCReconnectPromise.this.retryTimer == 0) {
107 PCCReconnectPromise.LOG.debug("Retry timer value is 0. Reconnection will not be attempted");
108 PCCReconnectPromise.this.setFailure(cf.cause());
112 final EventLoop loop = cf.channel().eventLoop();
113 loop.schedule(() -> {
114 synchronized (PCCReconnectPromise.this) {
115 PCCReconnectPromise.LOG.debug("Attempting to connect to {}", PCCReconnectPromise.this.address);
116 final Future<Void> reconnectFuture = PCCReconnectPromise.this.b.connect();
117 reconnectFuture.addListener(this);
118 PCCReconnectPromise.this.pending = reconnectFuture;
120 }, PCCReconnectPromise.this.retryTimer, TimeUnit.SECONDS);
121 PCCReconnectPromise.LOG.debug("Next reconnection attempt in {}s", PCCReconnectPromise.this.retryTimer);