All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.undertow.Undertow Maven / Gradle / Ivy

There is a newer version: 5.3.4
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.
 */

package io.undertow;

import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.undertow.httpcore.BufferAllocator;
import io.undertow.httpcore.UndertowEngine;
import io.undertow.httpcore.UndertowOption;
import io.undertow.httpcore.UndertowOptionMap;
import io.undertow.httpcore.UndertowOptions;
import io.undertow.server.DefaultExchangeHandler;
import io.undertow.server.HttpHandler;

/**
 * Convenience class used to build an Undertow server.
 * 

* * @author Stuart Douglas */ public final class Undertow { private final int ioThreads; private final int workerThreads; private final List listeners = new ArrayList<>(); private volatile List listenerInfo; private final HttpHandler rootHandler; private final UndertowOptionMap serverOptions; private final int bufferSize; private final boolean directBuffers; /** * Will be true when a executor instance was NOT provided to the {@link Builder}. * When true, a new worker will be created during {@link Undertow#start()}, * and shutdown when {@link Undertow#stop()} is called. *

* Will be false when a executor instance was provided to the {@link Builder}. * When false, the provided {@link #worker} will be used instead of creating a new one in {@link Undertow#start()}. * Also, when false, the {@link #worker} will NOT be shutdown when {@link Undertow#stop()} is called. */ private final boolean internalWorker; private ExecutorService worker; UndertowEngine.EngineInstance engineInstance; private Undertow(Builder builder) { this.ioThreads = builder.ioThreads; this.workerThreads = builder.workerThreads; this.listeners.addAll(builder.listeners); this.rootHandler = builder.handler; this.worker = builder.worker; this.bufferSize = builder.bufferSize; this.directBuffers = builder.directBuffers; this.internalWorker = builder.worker == null; this.serverOptions = builder.serverOptions.getMap(); } /** * @return A builder that can be used to create an Undertow server instance */ public static Builder builder() { return new Builder(); } public synchronized void start() { UndertowLogger.ROOT_LOGGER.debugf("starting undertow server %s", this); UndertowEngine engine = ServiceLoader.load(UndertowEngine.class).iterator().next(); BufferAllocator allocator = new BufferAllocator() { @Override public ByteBuf allocateBuffer() { return PooledByteBufAllocator.DEFAULT.buffer(bufferSize); } @Override public ByteBuf allocateBuffer(boolean direct) { if (direct) { return PooledByteBufAllocator.DEFAULT.directBuffer(bufferSize); } else { return PooledByteBufAllocator.DEFAULT.heapBuffer(bufferSize); } } @Override public ByteBuf allocateBuffer(int bufferSize) { return PooledByteBufAllocator.DEFAULT.buffer(bufferSize); } @Override public ByteBuf allocateBuffer(boolean direct, int bufferSize) { if (direct) { return PooledByteBufAllocator.DEFAULT.directBuffer(bufferSize); } else { return PooledByteBufAllocator.DEFAULT.heapBuffer(bufferSize); } } @Override public int getBufferSize() { return bufferSize; } }; try { if (internalWorker) { worker = Executors.newFixedThreadPool(workerThreads); } engineInstance = engine.start(ioThreads, worker, allocator); DefaultExchangeHandler handler = new DefaultExchangeHandler(rootHandler); listenerInfo = new ArrayList<>(); for (ListenerConfig listener : listeners) { UndertowLogger.ROOT_LOGGER.debugf("Configuring listener with getProtocol %s for interface %s and port %s", listener.type, listener.host, listener.port); if (listener.type == ListenerType.HTTP) { engine.bindHttp(engineInstance, handler, listener.port, listener.host, listener.options); } else if (listener.type == ListenerType.HTTPS) { engine.bindHttps(engineInstance, handler, listener.port, listener.host, listener.keyStore, listener.keyStorePassword, listener.trustStore, listener.trustStorePassword, listener.options); } } } catch (Exception e) { if (internalWorker && worker != null) { worker.shutdownNow(); } throw new RuntimeException(e); } } public synchronized void stop() { UndertowLogger.ROOT_LOGGER.debugf("stopping undertow server %s", this); if(engineInstance == null) { return; } engineInstance.close(); engineInstance = null; /* * Only shutdown the worker if it was created during start() */ if (internalWorker && worker != null) { Integer shutdownTimeoutMillis = serverOptions.get(UndertowOptions.SHUTDOWN_TIMEOUT); worker.shutdown(); try { if (shutdownTimeoutMillis == null) { //worker.awaitTermination(); } else { if (!worker.awaitTermination(shutdownTimeoutMillis, TimeUnit.MILLISECONDS)) { worker.shutdownNow(); } } } catch (InterruptedException e) { worker.shutdownNow(); throw new RuntimeException(e); } worker = null; } listenerInfo = null; } public ExecutorService getWorker() { return worker; } public List getListenerInfo() { if (listenerInfo == null) { throw UndertowMessages.MESSAGES.serverNotStarted(); } return Collections.unmodifiableList(listenerInfo); } public enum ListenerType { HTTP, HTTPS } private static class ListenerConfig { final ListenerType type; final int port; final String host; final String keyStore; final String trustStore; final String keyStorePassword; final String trustStorePassword; final Object options; private ListenerConfig(final ListenerBuilder listenerBuilder) { this.type = listenerBuilder.type; this.port = listenerBuilder.port; this.host = listenerBuilder.host; this.keyStorePassword = listenerBuilder.keyStorePassword; this.trustStorePassword = listenerBuilder.trustStorePassword; this.trustStore = listenerBuilder.trustStore; this.keyStore = listenerBuilder.keyStore; this.options = listenerBuilder.options; } } public static final class ListenerBuilder { ListenerType type; int port; String host; String keyStore; String trustStore; String keyStorePassword; String trustStorePassword; Object options; HttpHandler rootHandler; public ListenerBuilder setType(ListenerType type) { this.type = type; return this; } public ListenerBuilder setPort(int port) { this.port = port; return this; } public ListenerBuilder setHost(String host) { this.host = host; return this; } public ListenerBuilder setRootHandler(HttpHandler rootHandler) { this.rootHandler = rootHandler; return this; } public ListenerType getType() { return type; } public int getPort() { return port; } public String getHost() { return host; } public String getKeyStore() { return keyStore; } public ListenerBuilder setKeyStore(String keyStore) { this.keyStore = keyStore; return this; } public String getTrustStore() { return trustStore; } public ListenerBuilder setTrustStore(String trustStore) { this.trustStore = trustStore; return this; } public String getKeyStorePassword() { return keyStorePassword; } public ListenerBuilder setKeyStorePassword(String keyStorePassword) { this.keyStorePassword = keyStorePassword; return this; } public String getTrustStorePassword() { return trustStorePassword; } public ListenerBuilder setTrustStorePassword(String trustStorePassword) { this.trustStorePassword = trustStorePassword; return this; } public Object getOptions() { return options; } public ListenerBuilder setOptions(Object options) { this.options = options; return this; } public HttpHandler getRootHandler() { return rootHandler; } } public static final class Builder { int bufferSize; int ioThreads; int workerThreads; boolean directBuffers; final List listeners = new ArrayList<>(); HttpHandler handler; ExecutorService worker; final UndertowOptionMap.Builder serverOptions = UndertowOptionMap.builder(); private Builder() { ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2); workerThreads = ioThreads * 8; long maxMemory = Runtime.getRuntime().maxMemory(); //smaller than 64mb of ram we use 512b buffers if (maxMemory < 64 * 1024 * 1024) { //use 512b buffers directBuffers = false; bufferSize = 512; } else if (maxMemory < 128 * 1024 * 1024) { //use 1k buffers directBuffers = true; bufferSize = 1024; } else { //use 16k buffers for best performance //as 16k is generally the max amount of data that can be sent in a single write() call directBuffers = true; bufferSize = 1024 * 16 - 20; //the 20 is to allow some space for getProtocol headers, see UNDERTOW-1209 } } public Undertow build() { return new Undertow(this); } public Builder addListener(ListenerBuilder listenerBuilder) { listeners.add(new ListenerConfig(listenerBuilder)); return this; } public Builder addHttpListener(int port, String host) { listeners.add(new ListenerConfig(new ListenerBuilder().setType(ListenerType.HTTP).setHost(host).setPort(port))); return this; } public Builder setBufferSize(final int bufferSize) { this.bufferSize = bufferSize; return this; } public Builder setIoThreads(final int ioThreads) { this.ioThreads = ioThreads; return this; } public Builder setWorkerThreads(final int workerThreads) { this.workerThreads = workerThreads; return this; } public Builder setDirectBuffers(final boolean directBuffers) { this.directBuffers = directBuffers; return this; } public Builder setHandler(final HttpHandler handler) { this.handler = handler; return this; } public Builder setServerOption(final UndertowOption option, final T value) { serverOptions.set(option, value); return this; } public Builder setWorker(ExecutorService worker) { this.worker = worker; return this; } } public static class ListenerInfo { private final String protcol; private final SocketAddress address; public ListenerInfo(String protcol, SocketAddress address) { this.protcol = protcol; this.address = address; } public String getProtcol() { return protcol; } public SocketAddress getAddress() { return address; } public SSLContext getSslContext() { return null; } @Override public String toString() { return "ListenerInfo{" + "protcol='" + protcol + '\'' + ", address=" + address + ", sslContext=" + getSslContext() + '}'; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy