Get rid of JSR305 annotations
[bgpcep.git] / pcep / pcc-mock / src / main / java / org / opendaylight / protocol / pcep / pcc / mock / protocol / PCCReconnectPromise.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.pcep.pcc.mock.protocol;
9
10 import static java.util.Objects.requireNonNull;
11
12 import io.netty.bootstrap.Bootstrap;
13 import io.netty.channel.ChannelFuture;
14 import io.netty.channel.ChannelFutureListener;
15 import io.netty.channel.ChannelOption;
16 import io.netty.channel.EventLoop;
17 import io.netty.util.concurrent.DefaultPromise;
18 import io.netty.util.concurrent.Future;
19 import io.netty.util.concurrent.GlobalEventExecutor;
20 import io.netty.util.concurrent.Promise;
21 import java.net.InetSocketAddress;
22 import java.util.concurrent.TimeUnit;
23 import org.checkerframework.checker.lock.qual.GuardedBy;
24 import org.opendaylight.protocol.pcep.PCEPSession;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 final class PCCReconnectPromise extends DefaultPromise<PCEPSession> {
29     private static final Logger LOG = LoggerFactory.getLogger(PCCReconnectPromise.class);
30
31     private final InetSocketAddress address;
32     private final int retryTimer;
33     private final int connectTimeout;
34     private final Bootstrap bootstrap;
35
36     @GuardedBy("this")
37     private Future<?> pending;
38
39     PCCReconnectPromise(final InetSocketAddress address, final int retryTimer,
40                         final int connectTimeout, final Bootstrap bootstrap) {
41         super(GlobalEventExecutor.INSTANCE);
42         this.address = address;
43         this.retryTimer = retryTimer;
44         this.connectTimeout = connectTimeout;
45         this.bootstrap = bootstrap;
46     }
47
48     @SuppressWarnings("checkstyle:IllegalCatch")
49     synchronized void connect() {
50         try {
51             this.bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectTimeout);
52             this.bootstrap.remoteAddress(this.address);
53             final ChannelFuture cf = this.bootstrap.connect();
54             cf.addListener(new BootstrapConnectListener(this));
55             this.pending = cf;
56         } catch (final Exception e) {
57             LOG.info("Failed to connect to {}", this.address, e);
58             this.setFailure(e);
59         }
60     }
61
62     @Override
63     public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
64         if (super.cancel(mayInterruptIfRunning)) {
65             this.pending.cancel(mayInterruptIfRunning);
66             return true;
67         }
68
69         return false;
70     }
71
72     @Override
73     public synchronized Promise<PCEPSession> setSuccess(final PCEPSession result) {
74         final Promise<PCEPSession> promise = super.setSuccess(result);
75         LOG.debug("Promise {} completed", this);
76         return promise;
77     }
78
79     synchronized boolean isInitialConnectFinished() {
80         requireNonNull(this.pending);
81         return this.pending.isDone() && this.pending.isSuccess();
82     }
83
84     private final class BootstrapConnectListener implements ChannelFutureListener {
85
86         @GuardedBy("this")
87         private final Object lock;
88
89         BootstrapConnectListener(final Object lock) {
90             this.lock = lock;
91         }
92
93         @Override
94         public void operationComplete(final ChannelFuture cf) {
95             synchronized (this.lock) {
96                 if (PCCReconnectPromise.this.isCancelled()) {
97                     if (cf.isSuccess()) {
98                         PCCReconnectPromise.LOG.debug("Closing channels for cancelled promise {}",
99                                 PCCReconnectPromise.this);
100                         cf.channel().close();
101                     }
102                 } else if (cf.isSuccess()) {
103                     PCCReconnectPromise.LOG.debug("Promise connection is successful.");
104                 } else {
105                     PCCReconnectPromise.LOG.debug("Attempt to connect to {} failed",
106                             PCCReconnectPromise.this.address, cf.cause());
107
108                     if (PCCReconnectPromise.this.retryTimer == 0) {
109                         PCCReconnectPromise.LOG.debug("Retry timer value is 0. Reconnection will not be attempted");
110                         PCCReconnectPromise.this.setFailure(cf.cause());
111                         return;
112                     }
113
114                     final EventLoop loop = cf.channel().eventLoop();
115                     loop.schedule(() -> {
116                         synchronized (PCCReconnectPromise.this) {
117                             PCCReconnectPromise.LOG.debug("Attempting to connect to {}",
118                                     PCCReconnectPromise.this.address);
119                             final Future<Void> reconnectFuture = PCCReconnectPromise.this.bootstrap.connect();
120                             reconnectFuture.addListener(this);
121                             PCCReconnectPromise.this.pending = reconnectFuture;
122                         }
123                     }, PCCReconnectPromise.this.retryTimer, TimeUnit.SECONDS);
124                     PCCReconnectPromise.LOG.debug("Next reconnection attempt in {}s",
125                             PCCReconnectPromise.this.retryTimer);
126                 }
127             }
128         }
129     }
130 }