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 com.google.common.base.Preconditions;
11 import io.netty.bootstrap.Bootstrap;
12 import io.netty.channel.ChannelFuture;
13 import io.netty.channel.ChannelFutureListener;
14 import io.netty.channel.ChannelOption;
15 import io.netty.channel.EventLoop;
16 import io.netty.util.concurrent.DefaultPromise;
17 import io.netty.util.concurrent.EventExecutor;
18 import io.netty.util.concurrent.Future;
19 import io.netty.util.concurrent.Promise;
20 import java.net.InetSocketAddress;
21 import java.util.concurrent.TimeUnit;
23 import javax.annotation.concurrent.GuardedBy;
24 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.protocol.pcep.PCEPSession;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 public final class PCEPProtocolSessionPromise<S extends PCEPSession> extends DefaultPromise<S> {
32 private static final Logger LOG = LoggerFactory.getLogger(PCEPProtocolSessionPromise.class);
33 private InetSocketAddress address;
34 private final int retryTimer;
35 private final int connectTimeout;
36 private final Bootstrap b;
38 private Future<?> pending;
40 PCEPProtocolSessionPromise(final EventExecutor executor, final InetSocketAddress address,
41 final int retryTimer, final int connectTimeout, final Bootstrap b) {
43 this.address = Preconditions.checkNotNull(address);
44 this.retryTimer = retryTimer;
45 this.connectTimeout = connectTimeout;
46 this.b = Preconditions.checkNotNull(b);
49 synchronized void connect() {
50 final PCEPProtocolSessionPromise lock = this;
53 LOG.debug("Promise {} attempting connect for {}ms", lock, Integer.valueOf(this.connectTimeout));
54 if (this.address.isUnresolved()) {
55 this.address = new InetSocketAddress(this.address.getHostName(), this.address.getPort());
58 this.b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectTimeout);
59 this.b.remoteAddress(this.address);
60 final ChannelFuture connectFuture = this.b.connect();
61 connectFuture.addListener(new PCEPProtocolSessionPromise.BootstrapConnectListener(lock));
62 this.pending = connectFuture;
63 } catch (Exception e) {
64 LOG.info("Failed to connect to {}", this.address, e);
70 public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
71 if (super.cancel(mayInterruptIfRunning)) {
72 this.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 class BootstrapConnectListener implements ChannelFutureListener {
86 private final Object lock;
88 public BootstrapConnectListener(final Object lock) {
93 public void operationComplete(final ChannelFuture cf) throws Exception {
94 synchronized (this.lock) {
95 PCEPProtocolSessionPromise.LOG.debug("Promise {} connection resolved", this.lock);
96 Preconditions.checkState(PCEPProtocolSessionPromise.this.pending.equals(cf));
97 if (PCEPProtocolSessionPromise.this.isCancelled()) {
99 PCEPProtocolSessionPromise.LOG.debug("Closing channel for cancelled promise {}", this.lock);
100 cf.channel().close();
102 } else if (cf.isSuccess()) {
103 PCEPProtocolSessionPromise.LOG.debug("Promise {} connection successful", this.lock);
105 PCEPProtocolSessionPromise.LOG.debug("Attempt to connect to {} failed", PCEPProtocolSessionPromise.this.address, cf.cause());
107 if (PCEPProtocolSessionPromise.this.retryTimer == 0) {
108 PCEPProtocolSessionPromise.LOG.debug("Retry timer value is 0. Reconnection will not be attempted");
109 PCEPProtocolSessionPromise.this.setFailure(cf.cause());
113 final EventLoop loop = cf.channel().eventLoop();
114 loop.schedule(() -> {
115 PCEPProtocolSessionPromise.LOG.debug("Attempting to connect to {}", PCEPProtocolSessionPromise.this.address);
116 final Future reconnectFuture = PCEPProtocolSessionPromise.this.b.connect();
117 reconnectFuture.addListener(BootstrapConnectListener.this);
118 PCEPProtocolSessionPromise.this.pending = reconnectFuture;
119 }, PCEPProtocolSessionPromise.this.retryTimer, TimeUnit.SECONDS);
120 PCEPProtocolSessionPromise.LOG.debug("Next reconnection attempt in {}s", PCEPProtocolSessionPromise.this.retryTimer);