List of usage examples for io.netty.handler.ssl SslContextBuilder forClient
public static SslContextBuilder forClient()
From source file:com.floragunn.searchguard.ssl.DefaultSearchGuardKeyStore.java
License:Apache License
private SslContext buildSSLClientContext(final File _key, final File _cert, final File _trustedCerts, final String pwd, final Iterable<String> ciphers, final SslProvider sslProvider) throws SSLException { final SslContextBuilder _sslClientContextBuilder = SslContextBuilder.forClient().ciphers(ciphers) .applicationProtocolConfig(ApplicationProtocolConfig.DISABLED).sessionCacheSize(0).sessionTimeout(0) .sslProvider(sslProvider).trustManager(_trustedCerts).keyManager(_cert, _key, pwd); return buildSSLContext0(_sslClientContextBuilder); }
From source file:com.floragunn.searchguard.ssl.SearchGuardKeyStore.java
License:Apache License
private void initSSLConfig() { final Environment env = new Environment(settings); log.info("Config directory is {}/, from there the key- and truststore files are resolved relatively", env.configFile().toAbsolutePath()); if (transportSSLEnabled) { final String keystoreFilePath = env.configFile() .resolve(settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_FILEPATH, "")) .toAbsolutePath().toString(); final String keystoreType = settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_TYPE, DEFAULT_STORE_TYPE);/*from ww w . ja v a2 s . c om*/ final String keystorePassword = settings .get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_PASSWORD, DEFAULT_STORE_PASSWORD); final String keystoreAlias = settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_ALIAS, null); final String truststoreFilePath = env.configFile() .resolve(settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, "")) .toAbsolutePath().toString(); if (settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_FILEPATH, null) == null) { throw new ElasticsearchException(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_FILEPATH + " must be set if transport ssl is reqested."); } checkStorePath(keystoreFilePath); if (settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, null) == null) { throw new ElasticsearchException(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_FILEPATH + " must be set if transport ssl is reqested."); } checkStorePath(truststoreFilePath); final String truststoreType = settings.get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_TYPE, DEFAULT_STORE_TYPE); final String truststorePassword = settings .get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_PASSWORD, DEFAULT_STORE_PASSWORD); final String truststoreAlias = settings .get(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_ALIAS, null); try { final KeyStore ks = KeyStore.getInstance(keystoreType); ks.load(new FileInputStream(new File(keystoreFilePath)), (keystorePassword == null || keystorePassword.length() == 0) ? null : keystorePassword.toCharArray()); transportKeystoreCert = SSLCertificateHelper.exportCertificateChain(ks, keystoreAlias); transportKeystoreKey = SSLCertificateHelper.exportDecryptedKey(ks, keystoreAlias, (keystorePassword == null || keystorePassword.length() == 0) ? null : keystorePassword.toCharArray()); if (transportKeystoreKey == null) { throw new ElasticsearchException( "No key found in " + keystoreFilePath + " with alias " + keystoreAlias); } if (transportKeystoreCert != null && transportKeystoreCert.length > 0) { //TODO create sensitive log property /*for (int i = 0; i < transportKeystoreCert.length; i++) { X509Certificate x509Certificate = transportKeystoreCert[i]; if(x509Certificate != null) { log.info("Transport keystore subject DN no. {} {}",i,x509Certificate.getSubjectX500Principal()); } }*/ } else { throw new ElasticsearchException( "No certificates found in " + keystoreFilePath + " with alias " + keystoreAlias); } final KeyStore ts = KeyStore.getInstance(truststoreType); ts.load(new FileInputStream(new File(truststoreFilePath)), (truststorePassword == null || truststorePassword.length() == 0) ? null : truststorePassword.toCharArray()); trustedTransportCertificates = SSLCertificateHelper.exportCertificateChain(ts, truststoreAlias); if (trustedTransportCertificates == null) { throw new ElasticsearchException("No truststore configured for server"); } final SslContextBuilder sslServerContextBuilder = SslContextBuilder .forServer(transportKeystoreKey, transportKeystoreCert) .ciphers(getEnabledSSLCiphers(this.sslTransportServerProvider, false)) .applicationProtocolConfig(ApplicationProtocolConfig.DISABLED) .clientAuth(ClientAuth.REQUIRE) // https://github.com/netty/netty/issues/4722 .sessionCacheSize(0).sessionTimeout(0).sslProvider(this.sslTransportServerProvider) .trustManager(trustedTransportCertificates); transportServerSslContext = buildSSLContext(sslServerContextBuilder); if (trustedTransportCertificates == null) { throw new ElasticsearchException("No truststore configured for client"); } final SslContextBuilder sslClientContextBuilder = SslContextBuilder.forClient() .ciphers(getEnabledSSLCiphers(sslTransportClientProvider, false)) .applicationProtocolConfig(ApplicationProtocolConfig.DISABLED).sessionCacheSize(0) .sessionTimeout(0).sslProvider(sslTransportClientProvider) .trustManager(trustedTransportCertificates) .keyManager(transportKeystoreKey, transportKeystoreCert); transportClientSslContext = buildSSLContext(sslClientContextBuilder); } catch (final Exception e) { throw new ElasticsearchSecurityException( "Error while initializing transport SSL layer: " + e.toString(), e); } } final boolean client = !"node".equals(this.settings.get(SearchGuardSSLPlugin.CLIENT_TYPE)); if (!client && httpSSLEnabled) { final String keystoreFilePath = env.configFile() .resolve(settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_KEYSTORE_FILEPATH, "")) .toAbsolutePath().toString(); final String keystoreType = settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_KEYSTORE_TYPE, DEFAULT_STORE_TYPE); final String keystorePassword = settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_KEYSTORE_PASSWORD, DEFAULT_STORE_PASSWORD); final String keystoreAlias = settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_KEYSTORE_ALIAS, null); httpClientAuthMode = ClientAuth.valueOf(settings .get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.OPTIONAL.toString())); //TODO remove with next version String _enforceHTTPClientAuth = settings.get("searchguard.ssl.http.enforce_clientauth"); if (_enforceHTTPClientAuth != null) { log.error("{} is deprecated and replaced by {}", "searchguard.ssl.http.enforce_clientauth", SSLConfigConstants.SEARCHGUARD_SSL_HTTP_CLIENTAUTH_MODE); throw new RuntimeException("searchguard.ssl.http.enforce_clientauth is deprecated"); } log.info("HTTPS client auth mode {}", httpClientAuthMode); final String truststoreFilePath = env.configFile() .resolve(settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_FILEPATH, "")) .toAbsolutePath().toString(); if (settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_KEYSTORE_FILEPATH, null) == null) { throw new ElasticsearchException(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_KEYSTORE_FILEPATH + " must be set if https is reqested."); } checkStorePath(keystoreFilePath); if (httpClientAuthMode == ClientAuth.REQUIRE) { if (settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_FILEPATH, null) == null) { throw new ElasticsearchException(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_FILEPATH + " must be set if http ssl and client auth is reqested."); } } try { final KeyStore ks = KeyStore.getInstance(keystoreType); ks.load(new FileInputStream(new File(keystoreFilePath)), (keystorePassword == null || keystorePassword.length() == 0) ? null : keystorePassword.toCharArray()); httpKeystoreCert = SSLCertificateHelper.exportCertificateChain(ks, keystoreAlias); httpKeystoreKey = SSLCertificateHelper.exportDecryptedKey(ks, keystoreAlias, (keystorePassword == null || keystorePassword.length() == 0) ? null : keystorePassword.toCharArray()); if (httpKeystoreKey == null) { throw new ElasticsearchException( "No key found in " + keystoreFilePath + " with alias " + keystoreAlias); } if (httpKeystoreCert != null && httpKeystoreCert.length > 0) { //TODO create sensitive log property /*for (int i = 0; i < httpKeystoreCert.length; i++) { X509Certificate x509Certificate = httpKeystoreCert[i]; if(x509Certificate != null) { log.info("HTTP keystore subject DN no. {} {}",i,x509Certificate.getSubjectX500Principal()); } }*/ } else { throw new ElasticsearchException( "No certificates found in " + keystoreFilePath + " with alias " + keystoreAlias); } if (settings.get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_FILEPATH, null) != null) { checkStorePath(truststoreFilePath); final String truststoreType = settings .get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_TYPE, DEFAULT_STORE_TYPE); final String truststorePassword = settings.get( SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_PASSWORD, DEFAULT_STORE_PASSWORD); final String truststoreAlias = settings .get(SSLConfigConstants.SEARCHGUARD_SSL_HTTP_TRUSTSTORE_ALIAS, null); final KeyStore ts = KeyStore.getInstance(truststoreType); ts.load(new FileInputStream(new File(truststoreFilePath)), (truststorePassword == null || truststorePassword.length() == 0) ? null : truststorePassword.toCharArray()); trustedHTTPCertificates = SSLCertificateHelper.exportCertificateChain(ts, truststoreAlias); } final SslContextBuilder sslContextBuilder = SslContextBuilder .forServer(httpKeystoreKey, httpKeystoreCert) .ciphers(getEnabledSSLCiphers(this.sslHTTPProvider, true)) .applicationProtocolConfig(ApplicationProtocolConfig.DISABLED) .clientAuth(Objects.requireNonNull(httpClientAuthMode)) // https://github.com/netty/netty/issues/4722 .sessionCacheSize(0).sessionTimeout(0).sslProvider(this.sslHTTPProvider); if (trustedHTTPCertificates != null && trustedHTTPCertificates.length > 0) { sslContextBuilder.trustManager(trustedHTTPCertificates); } httpSslContext = buildSSLContext(sslContextBuilder); } catch (final Exception e) { throw new ElasticsearchSecurityException("Error while initializing HTTP SSL layer: " + e.toString(), e); } } }
From source file:com.flysoloing.learning.network.netty.binary.MemcacheClient.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {// ww w . j ava 2 s .c om sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT)); } p.addLast(new BinaryMemcacheClientCodec()); p.addLast(new BinaryMemcacheObjectAggregator(Integer.MAX_VALUE)); p.addLast(new MemcacheClientHandler()); } }); // Start the connection attempt. Channel ch = b.connect(HOST, PORT).sync().channel(); // Read commands from the stdin. System.out.println("Enter commands (quit to end)"); System.out.println("get <key>"); System.out.println("set <key> <value>"); ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (;;) { String line = in.readLine(); if (line == null) { break; } if ("quit".equals(line.toLowerCase())) { ch.close().sync(); break; } // Sends the received line to the server. lastWriteFuture = ch.writeAndFlush(line); } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.sync(); } } finally { group.shutdownGracefully(); } }
From source file:com.flysoloing.learning.network.netty.factorial.FactorialClient.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {// w w w.j a va 2 s. c om sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new FactorialClientInitializer(sslCtx)); // Make a new connection. ChannelFuture f = b.connect(HOST, PORT).sync(); // Get the handler instance to retrieve the answer. FactorialClientHandler handler = (FactorialClientHandler) f.channel().pipeline().last(); // Print out the answer. System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial()); } finally { group.shutdownGracefully(); } }
From source file:com.flysoloing.learning.network.netty.http2.helloworld.client.Http2Client.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {//from www . j a v a2 s . c o m SslProvider provider = OpenSsl.isAlpnSupported() ? SslProvider.OPENSSL : SslProvider.JDK; sslCtx = SslContextBuilder.forClient().sslProvider(provider) /* NOTE: the cipher filter may not include all ciphers required by the HTTP/2 specification. * Please refer to the HTTP/2 specification for cipher requirements. */ .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE) .trustManager(InsecureTrustManagerFactory.INSTANCE) .applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN, // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers. SelectorFailureBehavior.NO_ADVERTISE, // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers. SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2, ApplicationProtocolNames.HTTP_1_1)) .build(); } else { sslCtx = null; } EventLoopGroup workerGroup = new NioEventLoopGroup(); Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx, Integer.MAX_VALUE); try { // Configure the client. Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.remoteAddress(HOST, PORT); b.handler(initializer); // Start the client. Channel channel = b.connect().syncUninterruptibly().channel(); System.out.println("Connected to [" + HOST + ':' + PORT + ']'); // Wait for the HTTP/2 upgrade to occur. Http2SettingsHandler http2SettingsHandler = initializer.settingsHandler(); http2SettingsHandler.awaitSettings(5, TimeUnit.SECONDS); HttpResponseHandler responseHandler = initializer.responseHandler(); int streamId = 3; HttpScheme scheme = SSL ? HttpScheme.HTTPS : HttpScheme.HTTP; AsciiString hostName = new AsciiString(HOST + ':' + PORT); System.err.println("Sending request(s)..."); if (URL != null) { // Create a simple GET request. FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, URL); request.headers().add(HttpHeaderNames.HOST, hostName); request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name()); request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP); request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE); responseHandler.put(streamId, channel.write(request), channel.newPromise()); streamId += 2; } if (URL2 != null) { // Create a simple POST request with a body. FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, URL2, wrappedBuffer(URL2DATA.getBytes(CharsetUtil.UTF_8))); request.headers().add(HttpHeaderNames.HOST, hostName); request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name()); request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP); request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE); responseHandler.put(streamId, channel.write(request), channel.newPromise()); } channel.flush(); responseHandler.awaitResponses(5, TimeUnit.SECONDS); System.out.println("Finished HTTP/2 request(s)"); // Wait until the connection is closed. channel.close().syncUninterruptibly(); } finally { workerGroup.shutdownGracefully(); } }
From source file:com.flysoloing.learning.network.netty.spdy.client.SpdyClient.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE) .applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.NPN, // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers. SelectorFailureBehavior.NO_ADVERTISE, // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers. SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.SPDY_3_1, ApplicationProtocolNames.HTTP_1_1)) .build();/*from www. j a v a 2s .co m*/ HttpResponseClientHandler httpResponseHandler = new HttpResponseClientHandler(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.remoteAddress(HOST, PORT); b.handler(new SpdyClientInitializer(sslCtx, httpResponseHandler)); // Start the client. Channel channel = b.connect().syncUninterruptibly().channel(); System.out.println("Connected to " + HOST + ':' + PORT); // Create a GET request. HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, ""); request.headers().set(HttpHeaderNames.HOST, HOST); request.headers().set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP); // Send the GET request. channel.writeAndFlush(request).sync(); // Waits for the complete HTTP response httpResponseHandler.queue().take().sync(); System.out.println("Finished SPDY HTTP GET"); // Wait until the connection is closed. channel.close().syncUninterruptibly(); } finally { workerGroup.shutdownGracefully(); } }
From source file:com.flysoloing.learning.network.netty.telnet.TelnetClient.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {//from w ww. j a v a 2s. c o m sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new TelnetClientInitializer(sslCtx)); // Start the connection attempt. Channel ch = b.connect(HOST, PORT).sync().channel(); // Read commands from the stdin. ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (;;) { String line = in.readLine(); if (line == null) { break; } // Sends the received line to the server. lastWriteFuture = ch.writeAndFlush(line + "\r\n"); // If user typed the 'bye' command, wait until the server closes // the connection. if ("bye".equals(line.toLowerCase())) { ch.closeFuture().sync(); break; } } // Wait until all messages are flushed before closing the channel. if (lastWriteFuture != null) { lastWriteFuture.sync(); } } finally { group.shutdownGracefully(); } }
From source file:com.flysoloing.learning.network.netty.worldclock.WorldClockClient.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {//ww w . jav a2 s. co m sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new WorldClockClientInitializer(sslCtx)); // Make a new connection. Channel ch = b.connect(HOST, PORT).sync().channel(); // Get the handler instance to initiate the request. WorldClockClientHandler handler = ch.pipeline().get(WorldClockClientHandler.class); // Request and get the response. List<String> response = handler.getLocalTimes(CITIES); // Close the connection. ch.close(); // Print the response at last but not least. for (int i = 0; i < CITIES.size(); i++) { System.out.format("%28s: %s%n", CITIES.get(i), response.get(i)); } } finally { group.shutdownGracefully(); } }
From source file:com.gdut.Netty_testing.dongjun.client.Client.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {//from w w w. java2 s . c o m sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new ClientInitializer(sslCtx)); // Make a new connection. Channel ch = b.connect(HOST, PORT).sync().channel(); ch.writeAndFlush("108B01008C163543653432532432"); // Get the handler instance to initiate the request. // ClientHandler handler = ch.pipeline().get(ClientHandler.class); // Request and get the response. // List<String> response = handler.getLocalTimes(CITIES); // Close the connection. ch.close(); // Print the response at last but not least. } finally { group.shutdownGracefully(); } }
From source file:com.gdut.Netty_testing.t2.client.WorldClockClient.java
License:Apache License
public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) {/* w w w.ja va2 s .com*/ sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { sslCtx = null; } EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).handler(new WorldClockClientInitializer(sslCtx)); // Make a new connection. Channel ch = b.connect(HOST, PORT).sync().channel(); // Get the handler instance to initiate the request. WorldClockClientHandler handler = ch.pipeline().get(WorldClockClientHandler.class); for (int j = 0; j < 6; j++) { // Request and get the response. List<String> response = handler.getLocalTimes(CITIES); Thread.sleep(2000); // Print the response at last but not least. for (int i = 0; i < CITIES.size(); i++) { System.out.format("%28s: %s%n", CITIES.get(i), response.get(i)); } } // Close the connection. ch.close(); } finally { group.shutdownGracefully(); } }