/** * Returns a link for the remote address if already cached; otherwise, returns null. * * @param remoteAddr the remote address * @return a link if already cached; otherwise, null */ public <T> Link<T> get(final SocketAddress remoteAddr) { final LinkReference linkRef = this.addrToLinkRefMap.get(remoteAddr); return linkRef != null ? (Link<T>) linkRef.getLink() : null; }
/** * Returns a link for the remote address if cached; otherwise opens, caches and returns. When it * opens a link for the remote address, only one attempt for the address is made at a given time * * @param remoteAddr the remote socket address * @param encoder the encoder * @param listener the link listener * @return a link associated with the address */ @Override public <T> Link<T> open( final SocketAddress remoteAddr, final Encoder<? super T> encoder, final LinkListener<? super T> listener) throws IOException { Link<T> link = null; for (int i = 0; i <= this.numberOfTries; ++i) { LinkReference linkRef = this.addrToLinkRefMap.get(remoteAddr); if (linkRef != null) { link = (Link<T>) linkRef.getLink(); if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Link {0} for {1} found", new Object[] {link, remoteAddr}); } if (link != null) { return link; } } if (i == this.numberOfTries) { // Connection failure throw new ConnectException("Connection to " + remoteAddr + " refused"); } LOG.log( Level.FINE, "No cached link for {0} thread {1}", new Object[] {remoteAddr, Thread.currentThread()}); // no linkRef final LinkReference newLinkRef = new LinkReference(); final LinkReference prior = this.addrToLinkRefMap.putIfAbsent(remoteAddr, newLinkRef); final AtomicInteger flag = prior != null ? prior.getConnectInProgress() : newLinkRef.getConnectInProgress(); synchronized (flag) { if (!flag.compareAndSet(0, 1)) { while (flag.get() == 1) { try { flag.wait(); } catch (final InterruptedException ex) { LOG.log(Level.WARNING, "Wait interrupted", ex); } } } } linkRef = this.addrToLinkRefMap.get(remoteAddr); link = (Link<T>) linkRef.getLink(); if (link != null) { return link; } ChannelFuture connectFuture = null; try { connectFuture = this.clientBootstrap.connect(remoteAddr); connectFuture.syncUninterruptibly(); link = new NettyLink<>(connectFuture.channel(), encoder, listener); linkRef.setLink(link); synchronized (flag) { flag.compareAndSet(1, 2); flag.notifyAll(); } break; } catch (final Exception e) { if (e.getClass().getSimpleName().compareTo("ConnectException") == 0) { LOG.log( Level.WARNING, "Connection refused. Retry {0} of {1}", new Object[] {i + 1, this.numberOfTries}); synchronized (flag) { flag.compareAndSet(1, 0); flag.notifyAll(); } if (i < this.numberOfTries) { try { Thread.sleep(retryTimeout); } catch (final InterruptedException interrupt) { LOG.log( Level.WARNING, "Thread {0} interrupted while sleeping", Thread.currentThread()); } } } else { throw e; } } } return link; }