ratpack.server.internal.DefaultServerConfigBuilder Maven / Gradle / Ivy
/*
* Copyright 2014 the original author or authors.
*
* 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 ratpack.server.internal;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.ByteSource;
import com.google.common.reflect.TypeToken;
import ratpack.config.*;
import ratpack.config.internal.DefaultConfigData;
import ratpack.config.internal.DefaultConfigDataBuilder;
import ratpack.config.internal.module.SSLContextDeserializer;
import ratpack.config.internal.module.ServerConfigDataDeserializer;
import ratpack.file.FileSystemBinding;
import ratpack.func.Action;
import ratpack.impose.ForceDevelopmentImposition;
import ratpack.impose.ForceServerListenPortImposition;
import ratpack.impose.Impositions;
import ratpack.impose.ServerConfigImposition;
import ratpack.server.ServerConfig;
import ratpack.server.ServerConfigBuilder;
import javax.net.ssl.SSLContext;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class DefaultServerConfigBuilder implements ServerConfigBuilder {
private final DefaultConfigDataBuilder configDataBuilder;
private final Map> required = Maps.newHashMap();
private final BaseDirSupplier baseDirSupplier = new BaseDirSupplier();
private final ServerEnvironment serverEnvironment;
private final Impositions impositions;
public DefaultServerConfigBuilder(ServerEnvironment serverEnvironment, Impositions impositions) {
this.impositions = impositions;
this.configDataBuilder = new DefaultConfigDataBuilder(serverEnvironment);
this.serverEnvironment = serverEnvironment;
}
private DefaultServerConfigBuilder(DefaultConfigDataBuilder configDataBuilder, Map> required, BaseDirSupplier baseDirSupplier, ServerEnvironment serverEnvironment, Impositions impositions) {
this.configDataBuilder = configDataBuilder.copy();
this.required.putAll(required);
this.baseDirSupplier.baseDir = baseDirSupplier.baseDir;
this.serverEnvironment = serverEnvironment;
this.impositions = impositions;
}
private DefaultServerConfigBuilder copy() {
return new DefaultServerConfigBuilder(configDataBuilder, required, baseDirSupplier, serverEnvironment, impositions);
}
@Override
public ObjectMapper getObjectMapper() {
return configDataBuilder.getObjectMapper();
}
@Override
public ServerConfigBuilder baseDir(Path baseDir) {
this.baseDirSupplier.baseDir = FileSystemBinding.of(baseDir);
return this;
}
private ServerConfigBuilder addToServer(Consumer super ObjectNode> action) {
addToServer(configDataBuilder, action);
return this;
}
private static void addToServer(ConfigDataBuilder configDataBuilder, Consumer super ObjectNode> action) {
configDataBuilder.add((m, f) -> {
ObjectNode rootNode = new ObjectNode(configDataBuilder.getObjectMapper().getNodeFactory());
ObjectNode server = rootNode.putObject("server");
action.accept(server);
return rootNode;
});
}
@Override
public ServerConfigBuilder port(int port) {
return addToServer(n -> n.put("port", port));
}
@Override
public ServerConfigBuilder address(InetAddress address) {
return addToServer(n -> n.putPOJO("address", address));
}
@Override
public ServerConfigBuilder development(boolean development) {
return addToServer(n -> n.put("development", development));
}
@Override
public ServerConfigBuilder threads(int threads) {
if (threads < 1) {
throw new IllegalArgumentException("'threads' must be > 0");
}
return addToServer(n -> n.put("threads", threads));
}
@Override
public ServerConfigBuilder publicAddress(URI publicAddress) {
return addToServer(n -> n.putPOJO("publicAddress", publicAddress));
}
@Override
public ServerConfigBuilder maxContentLength(int maxContentLength) {
return addToServer(n -> n.put("maxContentLength", maxContentLength));
}
@Override
public ServerConfigBuilder maxChunkSize(int maxChunkSize) {
return addToServer(n -> n.put("maxChunkSize", maxChunkSize));
}
@Override
public ServerConfigBuilder maxInitialLineLength(int maxInitialLineLength) {
return addToServer(n -> n.put("maxInitialLineLength", maxInitialLineLength));
}
@Override
public ServerConfigBuilder maxHeaderSize(int maxHeaderSize) {
return addToServer(n -> n.put("maxHeaderSize", maxHeaderSize));
}
@Override
public ServerConfigBuilder connectTimeoutMillis(int connectTimeoutMillis) {
return addToServer(n -> n.put("connectTimeoutMillis", connectTimeoutMillis));
}
@Override
public ServerConfigBuilder maxMessagesPerRead(int maxMessagesPerRead) {
return addToServer(n -> n.put("maxMessagesPerRead", maxMessagesPerRead));
}
@Override
public ServerConfigBuilder receiveBufferSize(int receiveBufferSize) {
return addToServer(n -> n.put("receiveBufferSize", receiveBufferSize));
}
@Override
public ServerConfigBuilder writeSpinCount(int writeSpinCount) {
return addToServer(n -> n.put("writeSpinCount", writeSpinCount));
}
@Override
public ServerConfigBuilder ssl(SSLContext sslContext) {
return addToServer(n -> n.putPOJO("ssl", sslContext));
}
@Override
public ServerConfigBuilder requireClientSslAuth(boolean requireClientSslAuth) {
return addToServer(n -> n.put("requireClientSslAuth", requireClientSslAuth));
}
@Override
public ServerConfigBuilder configureObjectMapper(Action action) {
configDataBuilder.configureObjectMapper(action);
return this;
}
@Override
public ServerConfigBuilder add(ConfigSource configSource) {
configDataBuilder.add(configSource);
return this;
}
@Override
public ServerConfigBuilder env(String prefix, ratpack.func.Function mapFunc) {
configDataBuilder.env(prefix, mapFunc);
return this;
}
@Override
public ServerConfigBuilder env(EnvironmentParser environmentParser) {
configDataBuilder.env(environmentParser);
return this;
}
@Override
public ServerConfigBuilder env() {
configDataBuilder.env();
return this;
}
@Override
public ServerConfigBuilder env(String prefix) {
configDataBuilder.env(prefix);
return this;
}
@Override
public ServerConfigBuilder args(String[] args) {
configDataBuilder.args(args);
return this;
}
@Override
public ServerConfigBuilder args(String separator, String[] args) {
configDataBuilder.args(separator, args);
return this;
}
@Override
public ServerConfigBuilder args(String prefix, String separator, String[] args) {
configDataBuilder.args(prefix, separator, args);
return this;
}
@Override
public ServerConfigBuilder json(ByteSource byteSource) {
configDataBuilder.json(byteSource);
return this;
}
@Override
public ServerConfigBuilder json(Path path) {
configDataBuilder.json(path);
return this;
}
@Override
public ServerConfigBuilder json(URL url) {
configDataBuilder.json(url);
return this;
}
@Override
public ServerConfigBuilder props(ByteSource byteSource) {
configDataBuilder.props(byteSource);
return this;
}
@Override
public ServerConfigBuilder props(Path path) {
configDataBuilder.props(path);
return this;
}
@Override
public ServerConfigBuilder props(Properties properties) {
configDataBuilder.props(properties);
return this;
}
@Override
public ServerConfigBuilder props(URL url) {
configDataBuilder.props(url);
return this;
}
@Override
public ServerConfigBuilder props(Map map) {
configDataBuilder.props(map);
return this;
}
@Override
public ServerConfigBuilder sysProps() {
configDataBuilder.sysProps();
return this;
}
@Override
public ServerConfigBuilder sysProps(String prefix) {
configDataBuilder.sysProps(prefix);
return this;
}
@Override
public ServerConfigBuilder yaml(ByteSource byteSource) {
configDataBuilder.yaml(byteSource);
return this;
}
@Override
public ServerConfigBuilder yaml(Path path) {
configDataBuilder.yaml(path);
return this;
}
@Override
public ServerConfigBuilder yaml(URL url) {
configDataBuilder.yaml(url);
return this;
}
@Override
public ServerConfigBuilder object(String path, Object object) {
configDataBuilder.object(path, object);
return this;
}
@Override
public ServerConfigBuilder require(String pointer, TypeToken> type) {
TypeToken> previous = required.put(
Objects.requireNonNull(pointer, "pointer cannot be null"),
Objects.requireNonNull(type, "type cannot be null")
);
if (previous != null) {
throw new IllegalArgumentException("Cannot require config of type '" + type + "' at '" + pointer + "' as '" + previous + " has already been registered for this path");
}
return this;
}
@Override
public ServerConfigBuilder onError(Action super Throwable> errorHandler) {
configDataBuilder.onError(errorHandler);
return this;
}
@Override
public ServerConfigBuilder json(String path) {
configDataBuilder.json(path);
return this;
}
@Override
public ServerConfigBuilder props(String path) {
configDataBuilder.props(path);
return this;
}
@Override
public ServerConfigBuilder yaml(String path) {
configDataBuilder.yaml(path);
return this;
}
@Override
public ImmutableList getConfigSources() {
return configDataBuilder.getConfigSources();
}
@Override
public ServerConfig build() {
DefaultServerConfigBuilder copy = copy();
impositions.get(ServerConfigImposition.class)
.ifPresent(c -> c.apply(copy));
impositions.get(ForceServerListenPortImposition.class)
.map(ForceServerListenPortImposition::getPort)
.ifPresent(copy::port);
impositions.get(ForceDevelopmentImposition.class)
.map(ForceDevelopmentImposition::isDevelopment)
.ifPresent(copy::development);
copy.configDataBuilder.jacksonModules(new ConfigModule(copy.serverEnvironment, copy.baseDirSupplier));
ConfigData configData = new DefaultConfigData(copy.configDataBuilder.getObjectMapper(), copy.getConfigSources(), MoreObjects.firstNonNull(copy.baseDirSupplier.baseDir, FileSystemBinding.root()));
ImmutableSet> requiredConfig = extractRequiredConfig(configData, copy.required);
return new DefaultServerConfig(configData, requiredConfig);
}
private static ImmutableSet> extractRequiredConfig(ConfigData configData, Map> required) {
RuntimeException badConfig = new IllegalStateException("Failed to build required config items");
ImmutableSet.Builder> config = ImmutableSet.builder();
for (Map.Entry> requiredConfig : required.entrySet()) {
String path = requiredConfig.getKey();
TypeToken> type = requiredConfig.getValue();
try {
config.add(configData.getAsConfigObject(path, type));
} catch (Exception e) {
badConfig.addSuppressed(new IllegalStateException("Could not bind config at '" + path + "' to '" + type + "'", e));
}
}
if (badConfig.getSuppressed().length > 0) {
throw badConfig;
} else {
return config.build();
}
}
public static class ConfigModule extends SimpleModule {
public ConfigModule(ServerEnvironment serverEnvironment, Supplier baseDirSupplier) {
super("ratpack");
addDeserializer(ServerConfigData.class, new ServerConfigDataDeserializer(
serverEnvironment.getPort(),
serverEnvironment.isDevelopment(),
serverEnvironment.getPublicAddress(),
baseDirSupplier
));
addDeserializer(SSLContext.class, new SSLContextDeserializer());
}
}
private static class BaseDirSupplier implements Supplier {
private FileSystemBinding baseDir;
@Override
public FileSystemBinding get() {
return baseDir;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy