Java tutorial
/* * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. * * Copyright 2017 Nextdoor.com, Inc * */ package com.nextdoor.bender.ipc.http; import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.config.SocketConfig; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicHeader; import com.nextdoor.bender.config.AbstractConfig; import com.nextdoor.bender.ipc.TransportBuffer; import com.nextdoor.bender.ipc.TransportException; import com.nextdoor.bender.ipc.TransportFactory; import com.nextdoor.bender.ipc.TransportFactoryInitException; import com.nextdoor.bender.ipc.TransportSerializer; import com.nextdoor.bender.ipc.UnpartitionedTransport; import com.nextdoor.bender.ipc.generic.GenericTransportBuffer; public abstract class AbstractHttpTransportFactory implements TransportFactory { protected AbstractHttpTransportConfig config; protected TransportSerializer serializer; protected CloseableHttpClient client; abstract protected String getPath(); abstract protected TransportSerializer getSerializer(); @Override public void setConf(AbstractConfig config) { this.config = (AbstractHttpTransportConfig) config; this.serializer = getSerializer(); this.client = getClient(this.config.isUseSSL(), this.getUrl(), this.getHeaders(), this.config.getTimeout()); } protected String getUrl() { String url = ""; if (this.config.isUseSSL()) { url += "https://"; } else { url += "http://"; } url += this.config.getHostname() + ":" + this.config.getPort() + this.getPath(); return url; } protected Map<String, String> getHeaders() { return this.config.getHttpStringHeaders(); } /** * There isn't an easy way in java to trust non-self signed certs. Just allow all until java * KeyStore functionality is added to Bender. * * @return a context that trusts all SSL certs */ private SSLContext getSSLContext() { /* * Create SSLContext and TrustManager that will trust all SSL certs. * * Copy pasta from http://stackoverflow.com/a/4837230 */ TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; SSLContext ctx; try { ctx = SSLContext.getInstance("TLS"); } catch (NoSuchAlgorithmException e) { throw new TransportFactoryInitException("JVM does not have proper libraries for TSL"); } try { ctx.init(null, new TrustManager[] { tm }, new java.security.SecureRandom()); } catch (KeyManagementException e) { throw new TransportFactoryInitException("Unable to init SSLContext with TrustManager", e); } return ctx; } protected HttpClientBuilder getClientBuilder(boolean useSSL, String url, Map<String, String> stringHeaders, int socketTimeout) { HttpClientBuilder cb = HttpClientBuilder.create(); /* * Setup SSL */ if (useSSL) { /* * All trusting SSL context */ try { cb.setSSLContext(getSSLContext()); } catch (Exception e) { throw new RuntimeException(e); } /* * All trusting hostname verifier */ cb.setSSLHostnameVerifier(new HostnameVerifier() { public boolean verify(String s, SSLSession sslSession) { return true; } }); } /* * Add default headers */ ArrayList<BasicHeader> headers = new ArrayList<BasicHeader>(stringHeaders.size()); stringHeaders.forEach((k, v) -> headers.add(new BasicHeader(k, v))); cb.setDefaultHeaders(headers); /* * Set socket timeout and transport threads */ SocketConfig sc = SocketConfig.custom().setSoTimeout(socketTimeout).build(); cb.setDefaultSocketConfig(sc); cb.setMaxConnPerRoute(this.config.getThreads()); cb.setMaxConnTotal(this.config.getThreads()); return cb; } protected CloseableHttpClient getClient(boolean useSSL, String url, Map<String, String> stringHeaders, int socketTimeout) { return getClientBuilder(useSSL, url, stringHeaders, socketTimeout).build(); } @Override public int getMaxThreads() { return this.config.getThreads(); } @Override public void close() { } @Override public UnpartitionedTransport newInstance() throws TransportFactoryInitException { return new HttpTransport(this.client, this.getUrl(), this.config.isUseGzip(), this.config.getRetryCount(), this.config.getRetryDelay()); } @Override public TransportBuffer newTransportBuffer() throws TransportException { try { return new GenericTransportBuffer(this.config.getBatchSize(), this.config.isUseGzip(), this.serializer); } catch (IOException e) { throw new TransportException("error creating GenericTransportBuffer", e); } } }