Skip to content

Commit

Permalink
Allow for passing in additional property files to configure additiona…
Browse files Browse the repository at this point in the history
…l configs

Signed-off-by: jansupol <[email protected]>
  • Loading branch information
jansupol authored and senivam committed Feb 11, 2022
1 parent 9dbc693 commit 2299c0b
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 105 deletions.
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

0 comments on commit 2299c0b

Please sign in to comment.