Java tutorial
/* * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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. */ package org.wso2.carbon.inbound.endpoint.protocol.http2.management; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelOption; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http2.Http2SecurityUtil; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.ApplicationProtocolConfig; import io.netty.handler.ssl.ApplicationProtocolNames; import io.netty.handler.ssl.OpenSsl; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.SupportedCipherSuiteFilter; import io.netty.handler.ssl.util.SelfSignedCertificate; import org.apache.log4j.Logger; import org.apache.synapse.SynapseException; import org.apache.synapse.inbound.InboundProcessorParams; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.inbound.endpoint.common.AbstractInboundEndpointManager; import org.wso2.carbon.inbound.endpoint.protocol.http2.InboundHttp2Configuration; import org.wso2.carbon.inbound.endpoint.protocol.http2.InboundHttp2EventExecutor; import org.wso2.carbon.inbound.endpoint.protocol.http2.InboundHttp2ServerInitializer; import org.wso2.carbon.inbound.endpoint.protocol.http2.common.InboundHttp2Constants; import org.wso2.carbon.inbound.endpoint.protocol.http2.configuration.NettyThreadPoolConfiguration; import org.wso2.carbon.inbound.endpoint.protocol.http2.ssl.SSLHandlerFactory; import org.wso2.carbon.inbound.endpoint.protocol.websocket.ssl.InboundWebsocketSSLConfiguration; import javax.net.ssl.SSLException; import java.security.cert.CertificateException; public class Http2EndpointManager extends AbstractInboundEndpointManager { private static final Logger log = Logger .getLogger(org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EndpointManager.class); private static org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EndpointManager instance = null; protected Http2EndpointManager() { super(); } public static org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EndpointManager getInstance() { if (instance == null) { instance = new org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EndpointManager(); } return instance; } public boolean startEndpoint(int port, String name, InboundProcessorParams params) { PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); String tenantDomain = carbonContext.getTenantDomain(); String epName = dataStore.getListeningEndpointName(port, tenantDomain); if (epName != null) { if (epName.equalsIgnoreCase(name)) { log.info(epName + " Endpoint is already started in port : " + port); } else { String msg = "Another endpoint named : " + epName + " is currently using this port: " + port; log.warn(msg); throw new SynapseException(msg); } } else { dataStore.registerListeningEndpoint(port, tenantDomain, InboundHttp2Constants.HTTP2, name, params); boolean start = startListener(port, name, params); if (!start) { dataStore.unregisterListeningEndpoint(port, tenantDomain); return false; } } return true; } public boolean startSSLEndpoint(int port, String name, InboundProcessorParams params) { PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); String tenantDomain = carbonContext.getTenantDomain(); String epName = dataStore.getListeningEndpointName(port, tenantDomain); if (epName != null) { if (epName.equalsIgnoreCase(name)) { log.info(epName + " Endpoint is already started in port : " + port); } else { String msg = "Another endpoint named : " + epName + " is currently using this port: " + port; log.warn(msg); throw new SynapseException(msg); } } else { dataStore.registerListeningEndpoint(port, tenantDomain, InboundHttp2Constants.HTTPS2, name, params); boolean start = startSSLListener(port, name, params); if (start) { //do nothing } else { dataStore.unregisterListeningEndpoint(port, tenantDomain); return false; } } return true; } public boolean startListener(int port, String name, InboundProcessorParams params) { if (org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EventExecutorManager.getInstance() .isRegisteredExecutor(port)) { log.info("Netty Listener already started on port " + port); return true; } InboundHttp2Configuration config = buildConfiguration(port, name, params); NettyThreadPoolConfiguration threadPoolConfig = new NettyThreadPoolConfiguration( config.getBossThreadPoolSize(), config.getWorkerThreadPoolSize()); if (config.isEnableServerPush()) { if (config.getDispatchSequence() == null || config.getErrorSequence() == null) { throw new SynapseException("dispatch.outflow.sequence and error.outflow.sequence " + "cannot be empty if server-push enabled"); } } InboundHttp2EventExecutor eventExecutor = new InboundHttp2EventExecutor(threadPoolConfig); org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EventExecutorManager.getInstance() .registerEventExecutor(port, eventExecutor); ServerBootstrap b = new ServerBootstrap(); b.option(ChannelOption.SO_BACKLOG, 1024); b.group(eventExecutor.getBossGroupThreadPool(), eventExecutor.getWorkerGroupThreadPool()) .channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new InboundHttp2ServerInitializer(null, config)); try { b.bind(config.getPort()).sync().channel(); log.info("Http2 Inbound started on Port : " + config.getPort()); return true; } catch (InterruptedException e) { log.error(e.getMessage(), e); return false; } } public boolean startSSLListener(int port, String name, InboundProcessorParams params) { if (org.wso2.carbon.inbound.endpoint.protocol.websocket.management.WebsocketEventExecutorManager .getInstance().isRegisteredExecutor(port)) { log.info("Netty Listener already started on port " + port); return true; } InboundHttp2Configuration config = buildConfiguration(port, name, params); InboundWebsocketSSLConfiguration SslConfig = buildSSLConfiguration(params); if (config.isEnableServerPush()) { if (config.getDispatchSequence() == null || config.getErrorSequence() == null) { throw new SynapseException("dispatch.outflow.sequence and error.outflow.sequence " + "cannot be empty if server-push enabled"); } } NettyThreadPoolConfiguration threadPoolConfig = new NettyThreadPoolConfiguration( config.getBossThreadPoolSize(), config.getWorkerThreadPoolSize()); InboundHttp2EventExecutor eventExecutor = new InboundHttp2EventExecutor(threadPoolConfig); org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EventExecutorManager.getInstance() .registerEventExecutor(port, eventExecutor); try { ServerBootstrap b = new ServerBootstrap(); b.option(ChannelOption.SO_BACKLOG, 1024); b.group(eventExecutor.getBossGroupThreadPool(), eventExecutor.getWorkerGroupThreadPool()) .channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new InboundHttp2ServerInitializer(getSSLContext(SslConfig), config)); b.bind(config.getPort()).sync().channel(); log.info("Http2-secure Inbound started on Port : " + config.getPort()); } catch (InterruptedException e) { log.error(e.getMessage(), e); } return true; } public void closeEndpoint(int port) { PrivilegedCarbonContext cc = PrivilegedCarbonContext.getThreadLocalCarbonContext(); String tenantDomain = cc.getTenantDomain(); dataStore.unregisterListeningEndpoint(port, tenantDomain); if (!org.wso2.carbon.inbound.endpoint.protocol.http2.management.Http2EventExecutorManager.getInstance() .isRegisteredExecutor(port)) { log.info("Listener Endpoint is not started"); return; } else if (dataStore.isEndpointRegistryEmpty(port)) { Http2EventExecutorManager.getInstance().shutdownExecutor(port); } } public InboundHttp2Configuration buildConfiguration(int port, String name, InboundProcessorParams params) { return new InboundHttp2Configuration.InboundHttp2ConfigurationBuilder(port, name, params).build(); } public SslContext getSSLContext(InboundWebsocketSSLConfiguration sslconfig) { SslContext sslContext = null; SslProvider provider = OpenSsl.isAlpnSupported() ? SslProvider.OPENSSL : SslProvider.JDK; try { SelfSignedCertificate ssc = new SelfSignedCertificate(); SSLHandlerFactory handlerFactory = new SSLHandlerFactory(sslconfig); sslContext = SslContextBuilder.forServer(handlerFactory.getKeyStoreFactory()) .trustManager(handlerFactory.getTrustStoreFactory()).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) .applicationProtocolConfig( new ApplicationProtocolConfig(ApplicationProtocolConfig.Protocol.ALPN, // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers. ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers. ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2, ApplicationProtocolNames.HTTP_1_1)) .build(); } catch (CertificateException e) { e.printStackTrace(); } catch (SSLException e) { e.printStackTrace(); } return sslContext; } public InboundWebsocketSSLConfiguration buildSSLConfiguration(InboundProcessorParams params) { return new InboundWebsocketSSLConfiguration.SSLConfigurationBuilder( params.getProperties().getProperty(InboundHttp2Constants.INBOUND_SSL_KEY_STORE_FILE), params.getProperties().getProperty(InboundHttp2Constants.INBOUND_SSL_KEY_STORE_PASS), params.getProperties().getProperty(InboundHttp2Constants.INBOUND_SSL_TRUST_STORE_FILE), params.getProperties().getProperty(InboundHttp2Constants.INBOUND_SSL_TRUST_STORE_PASS), params.getProperties().getProperty(InboundHttp2Constants.INBOUND_SSL_CERT_PASS)).build(); } }