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
8 package org.opendaylight.protocol.pcep.impl;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.Preconditions;
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.EventExecutor;
20 import io.netty.util.concurrent.Future;
21 import io.netty.util.concurrent.Promise;
22 import java.net.InetSocketAddress;
23 import java.util.concurrent.TimeUnit;
24 import org.checkerframework.checker.lock.qual.GuardedBy;
25 import org.opendaylight.protocol.pcep.PCEPSession;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 // This class is thread-safe
30 public final class PCEPProtocolSessionPromise<S extends PCEPSession> extends DefaultPromise<S> {
31 private static final Logger LOG = LoggerFactory.getLogger(PCEPProtocolSessionPromise.class);
32 private InetSocketAddress address;
33 private final int retryTimer;
34 private final int connectTimeout;
35 private final Bootstrap bootstrap;
37 private Future<?> pending;
39 PCEPProtocolSessionPromise(final EventExecutor executor, final InetSocketAddress address,
40 final int retryTimer, final int connectTimeout, final Bootstrap bootstrap) {
42 this.address = requireNonNull(address);
43 this.retryTimer = retryTimer;
44 this.connectTimeout = connectTimeout;
45 this.bootstrap = requireNonNull(bootstrap);
48 @SuppressWarnings("checkstyle:IllegalCatch")
49 synchronized void connect() {
50 final PCEPProtocolSessionPromise<?> lock = this;
53 LOG.debug("Promise {} attempting connect for {}ms", lock, connectTimeout);
54 if (address.isUnresolved()) {
55 address = new InetSocketAddress(address.getHostName(), address.getPort());
58 bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
59 bootstrap.remoteAddress(address);
60 final ChannelFuture connectFuture = bootstrap.connect();
61 connectFuture.addListener(new BootstrapConnectListener());
62 pending = connectFuture;
63 } catch (RuntimeException e) {
64 LOG.info("Failed to connect to {}", address, e);
70 public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
71 if (super.cancel(mayInterruptIfRunning)) {
72 pending.cancel(mayInterruptIfRunning);
80 public synchronized Promise<S> setSuccess(final S result) {
81 LOG.debug("Promise {} completed", this);
82 return super.setSuccess(result);
85 private final class BootstrapConnectListener implements ChannelFutureListener {
87 public void operationComplete(final ChannelFuture cf) {
88 synchronized (PCEPProtocolSessionPromise.this) {
89 PCEPProtocolSessionPromise.LOG.debug("Promise {} connection resolved",
90 PCEPProtocolSessionPromise.this);
91 Preconditions.checkState(PCEPProtocolSessionPromise.this.pending.equals(cf));
94 PCEPProtocolSessionPromise.LOG.debug("Closing channel for cancelled promise {}",
95 PCEPProtocolSessionPromise.this);
98 } else if (cf.isSuccess()) {
99 PCEPProtocolSessionPromise.LOG.debug("Promise {} connection successful",
100 PCEPProtocolSessionPromise.this);
102 PCEPProtocolSessionPromise.LOG.debug("Attempt to connect to {} failed",
103 PCEPProtocolSessionPromise.this.address, cf.cause());
105 if (PCEPProtocolSessionPromise.this.retryTimer == 0) {
106 PCEPProtocolSessionPromise.LOG
107 .debug("Retry timer value is 0. Reconnection will not be attempted");
108 setFailure(cf.cause());
112 final EventLoop loop = cf.channel().eventLoop();
113 loop.schedule(() -> {
114 synchronized (PCEPProtocolSessionPromise.this) {
115 PCEPProtocolSessionPromise.LOG.debug("Attempting to connect to {}",
116 PCEPProtocolSessionPromise.this.address);
117 final Future<Void> reconnectFuture = PCEPProtocolSessionPromise.this.bootstrap.connect();
118 reconnectFuture.addListener(BootstrapConnectListener.this);
119 PCEPProtocolSessionPromise.this.pending = reconnectFuture;
121 }, PCEPProtocolSessionPromise.this.retryTimer, TimeUnit.SECONDS);
122 PCEPProtocolSessionPromise.LOG.debug("Next reconnection attempt in {}s",
123 PCEPProtocolSessionPromise.this.retryTimer);