org.glassfish.jersey.server.JerseySeBootstrapConfiguration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxrs-ri Show documentation
Show all versions of jaxrs-ri Show documentation
A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle
(jaxrs-ri.jar).
Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and
contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external
RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source
bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external
RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI
sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from
the command line.
/*
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.jersey.server;
import jakarta.ws.rs.SeBootstrap;
import jakarta.ws.rs.core.UriBuilder;
import org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFactory;
import org.glassfish.jersey.internal.config.SystemPropertiesConfigurationModel;
import org.glassfish.jersey.internal.util.PropertiesClass;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.WebServer;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.logging.Logger;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
/**
* Jersey implementation of {@link SeBootstrap.Configuration} implementing arbitrary methods for acquiring
* the configuration settings.
* @since 3.1.0
*/
public final class JerseySeBootstrapConfiguration implements SeBootstrap.Configuration {
private static final Logger LOGGER = Logger.getLogger(JerseySeBootstrapConfiguration.class.getName());
protected static final Random RANDOM = new Random();
private final SeBootstrap.Configuration configuration;
private JerseySeBootstrapConfiguration(SeBootstrap.Configuration configuration) {
this.configuration = configuration;
}
@Override
public Object property(String name) {
return configuration.property(name);
}
/**
* Compose {@link URI} based on properties defined in this configuration.
* @param resolveDefaultPort if {@code true} the port is not set, it is resolved as
* {@link Container#DEFAULT_HTTP_PORT} or {@link Container#DEFAULT_HTTPS_PORT}
* based on the protocol scheme.
* @return Composed {@link URI} based on properties defined in this configuration.
*/
public URI uri(boolean resolveDefaultPort) {
final String protocol = configuration.protocol();
final String host = configuration.host();
final int port = resolveDefaultPort ? resolvePort() : configuration.port();
final String rootPath = configuration.rootPath();
final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath)
.build();
return uri;
}
private int resolvePort() {
final int configPort = configuration.port();
final int basePort = allowPrivilegedPorts() ? 0 : 8000;
final int port;
switch (configPort) {
case SeBootstrap.Configuration.DEFAULT_PORT:
port = basePort + (isHttps() ? Container.DEFAULT_HTTPS_PORT : Container.DEFAULT_HTTP_PORT);
break;
case SeBootstrap.Configuration.FREE_PORT:
port = _resolvePort(basePort == 0);
break;
default:
port = configPort;
break;
}
return port;
}
private int _resolvePort(boolean allowPrivilegedPort) {
final int basePort = allowPrivilegedPort ? 0 : 1024;
// Get the initial range parameters
final int lower = basePort;
final int range = 0xFFFF;
// Select a start point in the range
final int initialOffset = RANDOM.nextInt(range - lower);
// Loop the offset through all ports in the range and attempt
// to bind to each
int offset = initialOffset;
ServerSocket socket;
do {
final int port = lower + offset;
try {
socket = new ServerSocket(port);
socket.close();
return port;
} catch (IOException caught) {
// Swallow exceptions until the end
}
offset = (offset + 1) % range;
} while (offset != initialOffset);
// If a port can't be bound, throw the exception
throw new IllegalArgumentException(LocalizationMessages.COULD_NOT_BIND_TO_ANY_PORT());
}
/**
* Return {@link SSLContext} in the configuration if the protocol scheme is {@code HTTPS}.
* @return the SSLContext in the configuration.
*/
@Override
public SSLContext sslContext() {
final SSLContext sslContext = configuration.sslContext();
return isHttps() ? sslContext : null;
}
/**
* If the protocol schema is {@code HTTPS}, return {@code true}.
* @return {@code true} when the protocol schema is {@code HTTPS}.
*/
public boolean isHttps() {
return "HTTPS".equalsIgnoreCase(configuration.protocol());
}
/**
* Defines if the {@link WebServer} should automatically start.
* @return false if {@link ServerProperties#WEBSERVER_AUTO_START} is {@code false}, {@code true} otherwise.
*/
public boolean autoStart() {
final boolean autoStart = Optional.ofNullable(
(Boolean) configuration.property(ServerProperties.WEBSERVER_AUTO_START))
.orElse(TRUE);
return autoStart;
}
/**
* Defines if the {@link WebServer} should start on a privileged port when port is not set.
* @return true if {@link ServerProperties#WEBSERVER_AUTO_START} is {@code true}, {@code false} otherwise.
*/
public boolean allowPrivilegedPorts() {
return Optional.ofNullable(
(Boolean) configuration.property(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS))
.orElse(FALSE);
}
/**
* Factory method creating {@code JerseySeBootstrapConfiguration} wrapper around {@link SeBootstrap.Configuration}.
* @param configuration wrapped configuration
* @return {@code JerseySeBootstrapConfiguration} wrapper around {@link SeBootstrap.Configuration}.
*/
public static JerseySeBootstrapConfiguration from(SeBootstrap.Configuration configuration) {
return JerseySeBootstrapConfiguration.class.isInstance(configuration)
? (JerseySeBootstrapConfiguration) configuration
: new JerseySeBootstrapConfiguration(configuration);
}
/**
* Return a Jersey instance of {@link SeBootstrap.Configuration.Builder} with prefilled values.
* @return a Jersey instance of {@link SeBootstrap.Configuration.Builder}.
*/
public static Builder builder() {
return new Builder();
}
public static final class Builder implements SeBootstrap.Configuration.Builder {
private static final Map> PROPERTY_TYPES = new HashMap<>();
static {
PROPERTY_TYPES.put(SeBootstrap.Configuration.PROTOCOL, String.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.HOST, String.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.PORT, Integer.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.ROOT_PATH, String.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.SSL_CONTEXT, SSLContext.class);
PROPERTY_TYPES.put(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION, SSLClientAuthentication.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, Boolean.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_AUTO_START, Boolean.class);
PROPERTY_TYPES.put(ServerProperties.WEBSERVER_CLASS, Class.class);
}
private final Map properties = new HashMap<>();
private Builder() {
this.properties.put(SeBootstrap.Configuration.PROTOCOL, "HTTP"); // upper case mandated by javadoc
this.properties.put(SeBootstrap.Configuration.HOST, "localhost");
this.properties.put(SeBootstrap.Configuration.PORT, -1); // Auto-select port 8080 for HTTP or 8443 for HTTPS
this.properties.put(SeBootstrap.Configuration.ROOT_PATH, "/");
this.properties.put(ServerProperties.WEBSERVER_CLASS, WebServer.class); // Auto-select first provider
try {
this.properties.put(SeBootstrap.Configuration.SSL_CONTEXT, SSLContext.getDefault());
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
this.properties.put(SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION,
SeBootstrap.Configuration.SSLClientAuthentication.NONE);
this.properties.put(ServerProperties.WEBSERVER_AUTO_START, TRUE);
this.properties.put(ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS, FALSE);
SystemPropertiesConfigurationModel propertiesConfigurationModel = new SystemPropertiesConfigurationModel(
Collections.singletonList(Properties.class.getName())
);
from((name, aClass) -> String.class.equals(aClass) || Integer.class.equals(aClass) || Boolean.class.equals(aClass)
? propertiesConfigurationModel.getOptionalProperty(name, aClass)
: Optional.empty()
);
}
@Override
public JerseySeBootstrapConfiguration build() {
return JerseySeBootstrapConfiguration.from(this.properties::get);
}
@Override
public Builder property(String name, Object value) {
this.properties.put(name, value);
return this;
}
/**
* Set the the respective {@link WebServer} class to be used by the
* {@link org.glassfish.jersey.server.spi.WebServerProvider}.
* @param webServerClass the class implementing {@link WebServer}.
* @return the updated builder.
*/
public Builder webServerClass(Class extends WebServer> webServerClass) {
return property(ServerProperties.WEBSERVER_CLASS, webServerClass);
}
/**
* Define if the {@link WebServer} should auto-start at bootstrap.
* @param autostart the auto-start flag.
* @return the updated builder.
*/
public Builder autoStart(Boolean autostart) {
return property(ServerProperties.WEBSERVER_AUTO_START, autostart);
}
@Override
public JerseySeBootstrapConfiguration.Builder from(BiFunction, Optional> configProvider) {
PROPERTY_TYPES.forEach(
(propertyName, propertyType) -> configProvider.apply(propertyName, (Class) propertyType)
.ifPresent(propertyValue -> this.properties.put(propertyName, propertyValue)));
return this;
}
@Override
public JerseySeBootstrapConfiguration.Builder from(Object externalConfig) {
if (SeBootstrap.Configuration.class.isInstance(externalConfig)) {
final SeBootstrap.Configuration other = (SeBootstrap.Configuration) externalConfig;
from((name, clazz) -> {
final Object property = other.property(name);
if (property != null) {
if (clazz.equals(property.getClass())) {
return Optional.of(property);
} else {
LOGGER.warning(LocalizationMessages.IGNORE_SEBOOTSTRAP_CONFIGURATION_PROPERTY(name, clazz));
}
}
return Optional.empty();
});
}
return this;
}
}
/**
* Name the properties to be internally read from System properties by {@link ExternalPropertiesConfigurationFactory}.
* This is required just when SecurityManager is on, otherwise all system properties are read.
*/
@PropertiesClass
private static class Properties {
/**
* See {@link SeBootstrap.Configuration#PROTOCOL} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_PROTOCOL = SeBootstrap.Configuration.PROTOCOL;
/**
* See {@link SeBootstrap.Configuration#HOST} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_HOST = SeBootstrap.Configuration.HOST;
/**
* See {@link SeBootstrap.Configuration#PORT} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_PORT = SeBootstrap.Configuration.PORT;
/**
* See {@link SeBootstrap.Configuration#ROOT_PATH} property.
*/
public static final String SE_BOOTSTRAP_CONFIGURATION_ROOT_PATH = SeBootstrap.Configuration.ROOT_PATH;
/**
* See {@link ServerProperties#WEBSERVER_ALLOW_PRIVILEGED_PORTS} property.
*/
public static final String WEBSERVER_ALLOW_PRIVILEGED_PORTS = ServerProperties.WEBSERVER_ALLOW_PRIVILEGED_PORTS;
/**
* See {@link ServerProperties#WEBSERVER_AUTO_START} property.
*/
public static final String WEBSERVER_AUTO_START = ServerProperties.WEBSERVER_AUTO_START;
}
}