org.glassfish.jersey.internal.config.SystemPropertiesConfigurationModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jersey-common Show documentation
Show all versions of jersey-common Show documentation
Jersey core common packages
/*
* 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.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
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;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.core.Feature;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.util.PropertiesHelper;
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 {
private static final Logger LOGGER = Logger.getLogger(SystemPropertiesConfigurationModel.class.getName());
private static final Map converters = new HashMap<>();
private final Map properties = new HashMap<>();
private final AtomicBoolean gotProperties = new AtomicBoolean(false);
private final List propertyClassNames;
static {
converters.put(String.class, (Function) s -> s);
converters.put(Integer.class, (Function) s -> Integer.valueOf(s));
converters.put(Long.class, (Function) s -> Long.parseLong(s));
converters.put(Boolean.class, (Function) s -> s.equalsIgnoreCase("1")
? true
: Boolean.parseBoolean(s));
}
/**
* Create new {@link ExternalConfigurationModel} for properties defined by classes in {@code propertyClassNames} list.
* @param propertyClassNames List of property defining class names.
*/
public SystemPropertiesConfigurationModel(List propertyClassNames) {
this.propertyClassNames = propertyClassNames;
}
protected List getPropertyClassNames() {
return propertyClassNames;
}
@Override
public T as(String name, Class clazz) {
if (converters.get(clazz) == null) {
throw new IllegalArgumentException("Unsupported class type");
}
return (name != null && clazz != null && hasProperty(name))
? clazz.cast(converters.get(clazz).apply(getSystemProperty(name)))
: null;
}
@Override
public Optional getOptionalProperty(String name, Class clazz) {
return Optional.of(as(name, clazz));
}
@Override
public ExternalConfigurationModel mergeProperties(Map inputProperties) {
inputProperties.forEach((k, v) -> properties.put(k, v));
return this;
}
@Override
public Void getConfig() {
return null;
}
@Override
public boolean isProperty(String name) {
String property = getSystemProperty(name);
return property != null && (
"0".equals(property) || "1".equals(property)
|| "true".equalsIgnoreCase(property) || "false".equalsIgnoreCase(property)
);
}
@Override
public RuntimeType getRuntimeType() {
return null;
}
@Override
public Map getProperties() {
final Boolean allowSystemPropertiesProvider = as(
CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER, Boolean.class
);
if (!Boolean.TRUE.equals(allowSystemPropertiesProvider)) {
LOGGER.finer(LocalizationMessages.WARNING_PROPERTIES());
return properties;
}
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 properties;
}
private Map getExpectedSystemProperties() {
final Map result = new HashMap<>();
for (String propertyClass : getPropertyClassNames()) {
mapFieldsToProperties(result,
AccessController.doPrivileged(
ReflectionHelper.classForNamePA(propertyClass)
)
);
}
return result;
}
private static void mapFieldsToProperties(Map properties, Class clazz) {
if (clazz == null) {
return;
}
final Field[] fields = AccessController.doPrivileged(
ReflectionHelper.getDeclaredFieldsPA(clazz)
);
for (final Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) && field.getType().isAssignableFrom(String.class)) {
final String propertyValue = getPropertyNameByField(field);
if (propertyValue != null) {
String value = getSystemProperty(propertyValue);
if (value != null) {
properties.put(propertyValue, value);
}
}
}
}
}
private static String getPropertyNameByField(Field field) {
return AccessController.doPrivileged((PrivilegedAction) () -> {
try {
return (String) field.get(null);
} catch (IllegalAccessException e) {
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 getPropertyNames() {
return AccessController.doPrivileged(PropertiesHelper.getSystemProperties()).stringPropertyNames();
}
@Override
public boolean isEnabled(Feature feature) {
return false;
}
@Override
public boolean isEnabled(Class featureClass) {
return false;
}
@Override
public boolean isRegistered(Object component) {
return false;
}
@Override
public boolean isRegistered(Class componentClass) {
return false;
}
@Override
public Map, Integer> getContracts(Class componentClass) {
return null;
}
@Override
public Set> getClasses() {
return null;
}
@Override
public Set