Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for passing in additional property files to configure additional configs #4982

Merged
merged 1 commit into from
Feb 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 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.internal.config;

import org.glassfish.jersey.spi.ExternalConfigurationModel;
import org.glassfish.jersey.spi.ExternalConfigurationProvider;

import java.util.Map;

public class ExternalConfigurationProviderImpl implements ExternalConfigurationProvider {

protected final ExternalConfigurationModel<?> model;

protected ExternalConfigurationProviderImpl(ExternalConfigurationModel<?> model) {
this.model = model;
}

@Override
public Map<String, Object> getProperties() {
return model.getProperties();
}

@Override
public ExternalConfigurationModel getConfiguration() {
return model;
}

@Override
public ExternalConfigurationModel merge(ExternalConfigurationModel input) {
return input == null ? model : model.mergeProperties(input.getProperties());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 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
Expand Down Expand Up @@ -32,6 +32,7 @@
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.BiConsumer;

/**
* Factory for external properties providers
Expand All @@ -50,12 +51,20 @@ public class ExternalPropertiesConfigurationFactory {
* @return map of merged properties from all found/plugged providers
*/
static Map<String, Object> readExternalPropertiesMap() {
return readExternalPropertiesMap(EXTERNAL_CONFIGURATION_PROVIDERS);
}

final ExternalConfigurationProvider provider = mergeConfigs(EXTERNAL_CONFIGURATION_PROVIDERS);
/**
* Map of merged properties from all given providers
*
* @param externalConfigProviders list of providers to use
* @return map of merged properties from {@code externalConfigProviders} providers
*/
private static Map<String, Object> readExternalPropertiesMap(List<ExternalConfigurationProvider> externalConfigProviders) {
final ExternalConfigurationProvider provider = mergeConfigs(externalConfigProviders);
return provider == null ? Collections.emptyMap() : provider.getProperties();
}


/**
* Input Configurable object shall be provided in order to be filled with all found properties
*
Expand All @@ -64,14 +73,28 @@ static Map<String, Object> readExternalPropertiesMap() {
*/

public static boolean configure(Configurable config) {
return configure((k, v) -> config.property(k, v), EXTERNAL_CONFIGURATION_PROVIDERS);
}

/**
* Key Value pairs gathered by {@link ExternalConfigurationProvider}s are applied to a given {@code config}. The
* {@code config} can be for instance {@code (k,v) -> configurable.property(k,v)} of a
* {@link Configurable#property(String, Object) Configurable structure}, or {@code (k,v) -> properties.put(k,v)} of a
* {@link java.util.Properties#put(Object, Object) Properties structure}.
*
* @param config
* @param externalConfigurationProviders the providers to grab the properties from it.
* @return true if configured false otherwise.
*/
public static boolean configure(BiConsumer<String, Object> config,
List<ExternalConfigurationProvider> externalConfigurationProviders) {
if (config instanceof ExternalConfigurationModel) {
return false; //shall not configure itself
}

final Map<String, Object> properties = readExternalPropertiesMap();
final Map<String, Object> properties = readExternalPropertiesMap(externalConfigurationProviders);

properties.forEach((k, v) -> config.property(k, v));
properties.forEach((k, v) -> config.accept(k, v));

return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2019, 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.internal.config;

import java.util.Arrays;
import java.util.List;

class JerseySystemPropertiesConfigurationModel extends SystemPropertiesConfigurationModel {

static final List<String> PROPERTY_CLASSES = Arrays.asList(
"org.glassfish.jersey.CommonProperties",
"org.glassfish.jersey.ExternalProperties",
"org.glassfish.jersey.server.ServerProperties",
"org.glassfish.jersey.client.ClientProperties",
"org.glassfish.jersey.servlet.ServletProperties",
"org.glassfish.jersey.message.MessageProperties",
"org.glassfish.jersey.apache.connector.ApacheClientProperties",
"org.glassfish.jersey.helidon.connector.HelidonClientProperties",
"org.glassfish.jersey.jdk.connector.JdkConnectorProperties",
"org.glassfish.jersey.jetty.connector.JettyClientProperties",
"org.glassfish.jersey.netty.connector.NettyClientProperties",
"org.glassfish.jersey.media.multipart.MultiPartProperties",
"org.glassfish.jersey.server.oauth1.OAuth1ServerProperties");

JerseySystemPropertiesConfigurationModel() {
super(PROPERTY_CLASSES);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 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
Expand Down Expand Up @@ -27,6 +27,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.logging.Logger;

Expand All @@ -39,57 +40,58 @@
import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.spi.ExternalConfigurationModel;

/**
* The External Configuration Model that supports {@code System} properties. The properties are listed in a property class
* in a form of {@code public static final String} property name. The {@code String} value of the property name is searched
* among the {@code System} properties. The property scan is performed only when
* {@link CommonProperties#ALLOW_SYSTEM_PROPERTIES_PROVIDER} is set to {@code true}.
*/
public class SystemPropertiesConfigurationModel implements ExternalConfigurationModel<Void> {

class SystemPropertiesConfigurationModel implements ExternalConfigurationModel<Void> {

private static final Logger log = Logger.getLogger(SystemPropertiesConfigurationModel.class.getName());
static final List<String> PROPERTY_CLASSES = Arrays.asList(
"org.glassfish.jersey.ExternalProperties",
"org.glassfish.jersey.server.ServerProperties",
"org.glassfish.jersey.client.ClientProperties",
"org.glassfish.jersey.servlet.ServletProperties",
"org.glassfish.jersey.message.MessageProperties",
"org.glassfish.jersey.apache.connector.ApacheClientProperties",
"org.glassfish.jersey.helidon.connector.HelidonClientProperties",
"org.glassfish.jersey.jdk.connector.JdkConnectorProperties",
"org.glassfish.jersey.jetty.connector.JettyClientProperties",
"org.glassfish.jersey.netty.connector.NettyClientProperties",
"org.glassfish.jersey.media.multipart.MultiPartProperties",
"org.glassfish.jersey.server.oauth1.OAuth1ServerProperties");

private static final Logger LOGGER = Logger.getLogger(SystemPropertiesConfigurationModel.class.getName());

private static final Map<Class, Function> converters = new HashMap<>();
private final Map<String, Object> properties = new HashMap<>();
private final AtomicBoolean gotProperties = new AtomicBoolean(false);
private final List<String> propertyClassNames;
static {
converters.put(String.class, (Function<String, String>) s -> s);
converters.put(Integer.class, (Function<String, Integer>) s -> Integer.valueOf(s));
converters.put(Long.class, (Function<String, Long>) s -> Long.parseLong(s));
converters.put(Boolean.class, (Function<String, Boolean>) s -> s.equalsIgnoreCase("1")
? true
: Boolean.parseBoolean(s));
}

private String getSystemProperty(String name) {
return AccessController.doPrivileged(PropertiesHelper.getSystemProperty(name));
/**
* Create new {@link ExternalConfigurationModel} for properties defined by classes in {@code propertyClassNames} list.
* @param propertyClassNames List of property defining class names.
*/
public SystemPropertiesConfigurationModel(List<String> propertyClassNames) {
this.propertyClassNames = propertyClassNames;
}

protected List<String> getPropertyClassNames() {
return propertyClassNames;
}

@Override
public <T> T as(String name, Class<T> clazz) {
if (converters.get(clazz) == null) {
throw new IllegalArgumentException("Unsupported class type");
}
return (name != null && clazz != null && isProperty(name))
return (name != null && clazz != null && hasProperty(name))
? clazz.cast(converters.get(clazz).apply(getSystemProperty(name)))
: null;
}



@Override
public <T> Optional<T> getOptionalProperty(String name, Class<T> clazz) {
return Optional.of(as(name, clazz));
}

@Override
public ExternalConfigurationModel mergeProperties(Map<String, Object> inputProperties) {
inputProperties.forEach((k, v) -> properties.put(k, v));
return this;
}

Expand All @@ -100,11 +102,11 @@ public Void getConfig() {

@Override
public boolean isProperty(String name) {
return Optional.ofNullable(
AccessController.doPrivileged(
PropertiesHelper.getSystemProperty(name)
)
).isPresent();
String property = getSystemProperty(name);
return property != null && (
"0".equals(property) || "1".equals(property)
|| "true".equalsIgnoreCase(property) || "false".equalsIgnoreCase(property)
);
}

@Override
Expand All @@ -114,30 +116,29 @@ public RuntimeType getRuntimeType() {

@Override
public Map<String, Object> getProperties() {
final Map<String, Object> result = new HashMap<>();

final Boolean allowSystemPropertiesProvider = as(
CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER, Boolean.class
);
if (!Boolean.TRUE.equals(allowSystemPropertiesProvider)) {
log.finer(LocalizationMessages.WARNING_PROPERTIES());
return result;
LOGGER.finer(LocalizationMessages.WARNING_PROPERTIES());
return properties;
}

try {
AccessController.doPrivileged(PropertiesHelper.getSystemProperties())
.forEach((k, v) -> result.put(String.valueOf(k), v));
} catch (SecurityException se) {
log.warning(LocalizationMessages.SYSTEM_PROPERTIES_WARNING());
return getExpectedSystemProperties();
if (gotProperties.compareAndSet(false, true)) {
try {
AccessController.doPrivileged(PropertiesHelper.getSystemProperties())
.forEach((k, v) -> properties.put(String.valueOf(k), v));
} catch (SecurityException se) {
LOGGER.warning(LocalizationMessages.SYSTEM_PROPERTIES_WARNING());
return getExpectedSystemProperties();
}
}
return result;
return properties;
}

private Map<String, Object> getExpectedSystemProperties() {
final Map<String, Object> result = new HashMap<>();
mapFieldsToProperties(result, CommonProperties.class);
for (String propertyClass : PROPERTY_CLASSES) {
for (String propertyClass : getPropertyClassNames()) {
mapFieldsToProperties(result,
AccessController.doPrivileged(
ReflectionHelper.classForNamePA(propertyClass)
Expand All @@ -148,7 +149,7 @@ private Map<String, Object> getExpectedSystemProperties() {
return result;
}

private <T> void mapFieldsToProperties(Map<String, Object> properties, Class<T> clazz) {
private static <T> void mapFieldsToProperties(Map<String, Object> properties, Class<T> clazz) {
if (clazz == null) {
return;
}
Expand All @@ -170,25 +171,29 @@ private <T> void mapFieldsToProperties(Map<String, Object> properties, Class<T>
}
}

private String getPropertyNameByField(Field field) {
private static String getPropertyNameByField(Field field) {
return AccessController.doPrivileged((PrivilegedAction<String>) () -> {
try {
return (String) field.get(null);
} catch (IllegalAccessException e) {
log.warning(e.getLocalizedMessage());
LOGGER.warning(e.getLocalizedMessage());
}
return null;
});
}

private static String getSystemProperty(String name) {
return AccessController.doPrivileged(PropertiesHelper.getSystemProperty(name));
}

@Override
public Object getProperty(String name) {
return getSystemProperty(name);
}

@Override
public Collection<String> getPropertyNames() {
return PropertiesHelper.getSystemProperties().run().stringPropertyNames();
return AccessController.doPrivileged(PropertiesHelper.getSystemProperties()).stringPropertyNames();
}

@Override
Expand Down Expand Up @@ -225,4 +230,9 @@ public Set<Class<?>> getClasses() {
public Set<Object> getInstances() {
return null;
}

// Jersey 2.x
private boolean hasProperty(String name) {
return getProperty(name) != null;
}
}
Loading