/*
* The MIT License (MIT)
* Copyright © 2013 Englishtown <opensource@englishtown.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the “Software”), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.englishtown.vertx.jersey.impl;
import com.englishtown.vertx.jersey.JerseyOptions;
import com.englishtown.vertx.jersey.JerseyServerOptions;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.JksOptions;
import javax.inject.Inject;
import java.net.URI;
import java.util.*;
import java.util.function.Consumer;
/**
* Default {@link com.englishtown.vertx.jersey.JerseyOptions} implementation
*/
public class DefaultJerseyOptions implements JerseyOptions, JerseyServerOptions {
public final static String CONFIG_HOST = "host";
public final static String CONFIG_PORT = "port";
public final static String CONFIG_SSL = "ssl";
public final static String CONFIG_JKS_OPTIONS = "jks_options";
public final static String CONFIG_RECEIVE_BUFFER_SIZE = "receive_buffer_size";
public final static String CONFIG_BACKLOG_SIZE = "backlog_size";
public final static String CONFIG_RESOURCE_CONFIG = "resource_config";
public final static String CONFIG_PROPERTIES = "properties";
public final static String CONFIG_COMPRESSION_SUPPORTED = "compression_supported";
public static final String CONFIG_BASE_PATH = "base_path";
public static final String CONFIG_MAX_BODY_SIZE = "max_body_size";
public static final String CONFIG_RESOURCES = "resources";
public static final String CONFIG_PACKAGES = "packages";
public static final String CONFIG_FEATURES = "features";
public static final String CONFIG_COMPONENTS = "components";
public static final String CONFIG_BINDERS = "binders";
public static final String CONFIG_INSTANCES = "instances";
public static final int DEFAULT_MAX_BODY_SIZE = 1024 * 1000; // Default max body size to 1MB
private JsonObject config;
private HttpServerOptions serverOptions;
@Inject
public DefaultJerseyOptions(Vertx vertx) {
this(getConfig(vertx));
}
public DefaultJerseyOptions(JsonObject config) {
this.config = config;
}
private static JsonObject getConfig(Vertx vertx) {
JsonObject config = vertx.getOrCreateContext().config();
return config.getJsonObject("jersey", config);
}
/**
* Returns a list of packages to be scanned for resources and components
*
* @return
*/
@Override
public List<String> getPackages() {
List<String> list = new ArrayList<>();
Consumer<JsonArray> reader = array -> {
if ((array != null && !array.isEmpty())) {
for (int i = 0; i < array.size(); i++) {
list.add(array.getString(i));
}
}
};
JsonArray resources = config.getJsonArray(CONFIG_RESOURCES, null);
JsonArray packages = config.getJsonArray(CONFIG_PACKAGES, null);
reader.accept(resources);
reader.accept(packages);
return list;
}
/**
* Optional additional properties to be applied to Jersey resource configuration
*
* @return
*/
@Override
public Map<String, Object> getProperties() {
JsonObject json = null;
JsonObject tmp;
tmp = config.getJsonObject(CONFIG_PROPERTIES);
if (tmp != null) {
json = tmp;
}
tmp = config.getJsonObject(CONFIG_RESOURCE_CONFIG);
if (tmp != null) {
if (json == null) {
json = tmp;
} else {
json.mergeIn(tmp);
}
}
return json == null ? null : json.getMap();
}
/**
* List of components to be registered (features etc.)
*
* @return
*/
@Override
public Set<Class<?>> getComponents() {
Set<Class<?>> set = new HashSet<>();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Consumer<JsonArray> reader = array -> {
if (array != null && array.size() > 0) {
for (int i = 0; i < array.size(); i++) {
try {
set.add(cl.loadClass(array.getString(i)));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
};
JsonArray features = config.getJsonArray(CONFIG_FEATURES, null);
JsonArray components = config.getJsonArray(CONFIG_COMPONENTS, null);
reader.accept(features);
reader.accept(components);
return set;
}
/**
* Optional list of singleton instances to be registered (hk2 binders etc.)
*
* @return
*/
@Override
public Set<Object> getInstances() {
Set<Object> set = new HashSet<>();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Consumer<JsonArray> reader = array -> {
if (array != null && array.size() > 0) {
for (int i = 0; i < array.size(); i++) {
try {
Class<?> clazz = cl.loadClass(array.getString(i));
set.add(clazz.newInstance());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
};
JsonArray binders = config.getJsonArray(CONFIG_BINDERS, null);
JsonArray instances = config.getJsonArray(CONFIG_INSTANCES, null);
reader.accept(binders);
reader.accept(instances);
return set;
}
/**
* The http web server host
*
* @return the http web server host to listen to
*/
public String getHost() {
return config.getString(CONFIG_HOST, "0.0.0.0");
}
/**
* The http web server port
*
* @return the http web server port to listen to
*/
public int getPort() {
return config.getInteger(CONFIG_PORT, 80);
}
/**
* Whether the web server should be https.
*
* @return whether the web server should be https.
*/
public boolean getSSL() {
return config.getBoolean(CONFIG_SSL, false);
}
/**
* Vert.x http server key store options
*
* @return Java key store options
*/
public JksOptions getKeyStoreOptions() {
JsonObject json = config.getJsonObject(CONFIG_JKS_OPTIONS);
return json == null ? null : new JksOptions(json);
}
/**
* The TCP receive buffer size for connections in bytes
*
* @return buffer size in bytes
*/
public Integer getReceiveBufferSize() {
return config.getInteger(CONFIG_RECEIVE_BUFFER_SIZE);
}
/**
* The accept backlog
*
* @return the accept backlog
*/
public int getAcceptBacklog() {
return config.getInteger(CONFIG_BACKLOG_SIZE, 10000);
}
/**
* Returns the base URI used by Jersey
*
* @return base URI
*/
@Override
public URI getBaseUri() {
String basePath = config.getString(CONFIG_BASE_PATH, "/");
if (!basePath.endsWith("/")) {
basePath += "/";
}
return URI.create(basePath);
}
/**
* The max body size in bytes when reading the vert.x input stream
*
* @return the max body size bytes
*/
@Override
public int getMaxBodySize() {
return config.getInteger(CONFIG_MAX_BODY_SIZE, DEFAULT_MAX_BODY_SIZE);
}
/**
* Gets whether the server supports compression (defaults to false)
*
* @return whether compression is supported
*/
public boolean getCompressionSupported() {
return config.getBoolean(CONFIG_COMPRESSION_SUPPORTED, false);
}
/**
* Gets the {@link HttpServerOptions} used to set up the vert.x http server
*
* @return
*/
@Override
public HttpServerOptions getServerOptions() {
if (serverOptions == null) {
serverOptions = createServerOptions();
}
return serverOptions;
}
protected HttpServerOptions createServerOptions() {
// Setup the http server options
HttpServerOptions serverOptions = new HttpServerOptions()
.setHost(getHost())
.setPort(getPort())
.setAcceptBacklog(getAcceptBacklog()) // Performance tweak
.setCompressionSupported(getCompressionSupported());
// Enable https
if (getSSL()) {
serverOptions.setSsl(true);
}
if (getKeyStoreOptions() != null) {
serverOptions.setKeyStoreOptions(getKeyStoreOptions());
}
Integer receiveBufferSize = getReceiveBufferSize();
if (receiveBufferSize != null && receiveBufferSize > 0) {
// TODO: This doesn't seem to actually affect buffer size for dataHandler. Is this being used correctly or is it a Vertx bug?
serverOptions.setReceiveBufferSize(receiveBufferSize);
}
return serverOptions;
}
}