org.glassfish.jersey.internal.util.PropertiesHelper 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) 2012, 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.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.ws.rs.RuntimeType;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.internal.LocalizationMessages;
/**
* Helper class containing convenience methods for reading
* {@code org.glassfish.jersey.server.ResourceConfig} and {@link jakarta.ws.rs.core.Configuration} properties.
*
* @author Martin Matula
*/
public final class PropertiesHelper {
private static final Logger LOGGER = Logger.getLogger(PropertiesHelper.class.getName());
private static final boolean METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT = false;
private static final boolean JAXRS_SERVICE_LOADING_ENABLE_DEFAULT = true;
private static final String RUNTIME_SERVER_LOWER = RuntimeType.SERVER.name().toLowerCase(Locale.ROOT);
private static final String RUNTIME_CLIENT_LOWER = RuntimeType.CLIENT.name().toLowerCase(Locale.ROOT);
/**
* Get system properties.
*
* This method delegates to {@link System#getProperties()} while running it in a privileged
* code block.
*
* @return privileged action to obtain system properties.
*/
public static PrivilegedAction getSystemProperties() {
return new PrivilegedAction() {
@Override
public Properties run() {
return System.getProperties();
}
};
}
/**
* Get system property.
*
* This method delegates to {@link System#getProperty(String)} while running it in a privileged
* code block.
*
* @param name system property name.
* @return privileged action to obtain system property value that will return {@code null}
* if there's no such system property.
*/
public static PrivilegedAction getSystemProperty(final String name) {
return new PrivilegedAction() {
@Override
public String run() {
return System.getProperty(name);
}
};
}
/**
* Get system property.
*
* This method delegates to {@link System#getProperty(String)} while running it in a privileged
* code block.
*
* @param name system property name.
* @param def default property value.
* @return privileged action to obtain system property value that will return the default value
* if there's no such system property.
*/
public static PrivilegedAction getSystemProperty(final String name, final String def) {
return new PrivilegedAction() {
@Override
public String run() {
return System.getProperty(name, def);
}
};
}
/**
* Return value of a specified property. If the property is not set or the real value type is not compatible with
* defaultValue type, the specified defaultValue is returned. Calling this method is equivalent to calling
* {@code PropertyHelper.getValue(properties, key, defaultValue, (Class) defaultValue.getClass())}
*
* @param properties Map of properties to get the property value from.
* @param key Name of the property.
* @param defaultValue Default value to be returned if the specified property is not set or cannot be read.
* @param Type of the property value.
* @param legacyMap Legacy fallback map, where key is the actual property name, value is the old property name
* @return Value of the property or defaultValue.
*/
public static T getValue(Map properties, String key, T defaultValue, Map legacyMap) {
return getValue(properties, null, key, defaultValue, legacyMap);
}
/**
* Return value of a specified property. If the property is not set or the real value type is not compatible with
* defaultValue type, the specified defaultValue is returned. Calling this method is equivalent to calling
* {@code PropertyHelper.getValue(properties, runtimeType, key, defaultValue, (Class) defaultValue.getClass())}
*
* @param properties Map of properties to get the property value from.
* @param runtimeType Runtime type which is used to check whether there is a property with the same
* {@code key} but post-fixed by runtime type (.server
* or {@code .client}) which would override the {@code key} property.
* @param key Name of the property.
* @param defaultValue Default value to be returned if the specified property is not set or cannot be read.
* @param Type of the property value.
* @param legacyMap Legacy fallback map, where key is the actual property name, value is the old property name
* @return Value of the property or defaultValue.
*/
@SuppressWarnings("unchecked")
public static T getValue(Map properties,
RuntimeType runtimeType,
String key,
T defaultValue,
Map legacyMap) {
return getValue(properties, runtimeType, key, defaultValue, (Class) defaultValue.getClass(), legacyMap);
}
/**
* Returns value of a specified property. If the property is not set or the real value type is not compatible with
* the specified value type, returns defaultValue.
*
* @param properties Map of properties to get the property value from.
* @param key Name of the property.
* @param defaultValue Default value of the property.
* @param type Type to retrieve the value as.
* @param Type of the property value.
* @param legacyMap Legacy fallback map, where key is the actual property name, value is the old property name
* @return Value of the property or null.
*/
public static T getValue(Map properties,
String key,
T defaultValue,
Class type,
Map legacyMap) {
return getValue(properties, null, key, defaultValue, type, legacyMap);
}
/**
* Returns value of a specified property. If the property is not set or the real value type is not compatible with
* the specified value type, returns defaultValue.
*
* @param properties Map of properties to get the property value from.
* @param runtimeType Runtime type which is used to check whether there is a property with the same
* {@code key} but post-fixed by runtime type (.server
* or {@code .client}) which would override the {@code key} property.
* @param key Name of the property.
* @param defaultValue Default value of the property.
* @param type Type to retrieve the value as.
* @param Type of the property value.
* @param legacyMap Legacy fallback map, where key is the actual property name, value is the old property name
* @return Value of the property or null.
*/
public static T getValue(Map properties, RuntimeType runtimeType, String key,
T defaultValue, Class type, Map legacyMap) {
T value = getValue(properties, runtimeType, key, type, legacyMap);
if (value == null) {
value = defaultValue;
}
return value;
}
/**
* Returns value of a specified property. If the property is not set or the real value type is not compatible with
* the specified value type, returns null.
*
* @param properties Map of properties to get the property value from.
* @param key Name of the property.
* @param type Type to retrieve the value as.
* @param Type of the property value.
* @param legacyMap Legacy fallback map, where key is the actual property name, value is the old property name
* @return Value of the property or null.
*/
public static T getValue(Map properties, String key, Class type, Map legacyMap) {
return getValue(properties, null, key, type, legacyMap);
}
/**
* Returns value of a specified property. If the property is not set or the real value type is not compatible with
* the specified value type, returns null.
*
* @param properties Map of properties to get the property value from.
* @param runtimeType Runtime type which is used to check whether there is a property with the same
* {@code key} but post-fixed by runtime type (.server
* or {@code .client}) which would override the {@code key} property.
* @param key Name of the property.
* @param type Type to retrieve the value as.
* @param Type of the property value.
* @return Value of the property or null.
*/
public static T getValue(Map properties, RuntimeType runtimeType, String key, Class type,
Map legacyMap) {
Object value = null;
if (runtimeType != null) {
String runtimeAwareKey = getPropertyNameForRuntime(key, runtimeType);
if (key.equals(runtimeAwareKey)) {
// legacy behaviour
runtimeAwareKey = key + "." + toLowerCase(runtimeType);
}
value = properties.get(runtimeAwareKey);
}
if (value == null) {
value = properties.get(key);
}
if (value == null) {
value = getLegacyFallbackValue(properties, legacyMap, key);
}
if (value == null) {
return null;
}
return convertValue(value, type);
}
/**
* Returns specific property value for given {@link RuntimeType}.
*
* Some properties have complementary client and server versions along with a common version (effective for both environments,
* if the specific one is not set). This methods returns a specific name for the environment (determined by convention),
* if runtime is not null, the property is a Jersey property name (starts with {@code jersey.config}) and does not contain
* a runtime specific part already. If those conditions are not met, original property name is returned.
*
* @param key property name
* @param runtimeType runtime type
* @return runtime-specific property name, where possible, original key in other cases.
* original key
*/
public static String getPropertyNameForRuntime(String key, RuntimeType runtimeType) {
if (runtimeType != null && key.startsWith("jersey.config")) {
RuntimeType[] types = RuntimeType.values();
for (RuntimeType type : types) {
if (key.startsWith("jersey.config." + toLowerCase(type))) {
return key;
}
}
return key.replace("jersey.config", "jersey.config." + toLowerCase(runtimeType));
}
return key;
}
private static Object getLegacyFallbackValue(Map properties, Map legacyFallbackMap, String key) {
if (legacyFallbackMap == null || !legacyFallbackMap.containsKey(key)) {
return null;
}
String fallbackKey = legacyFallbackMap.get(key);
Object value = properties.get(fallbackKey);
if (value != null && LOGGER.isLoggable(Level.CONFIG)) {
LOGGER.config(LocalizationMessages.PROPERTIES_HELPER_DEPRECATED_PROPERTY_NAME(fallbackKey, key));
}
return value;
}
/**
* Convert {@code Object} value to a value of the specified class type.
*
* @param value {@code Object} value to convert.
* @param type conversion type.
* @param converted value type.
* @return value converted to the specified class type.
*/
public static T convertValue(Object value, Class type) {
if (((type.equals(Integer.class)) || (type.equals(int.class))) && Number.class.isInstance(value)) {
final Integer number2Int = ((Number) value).intValue();
return (T) number2Int;
} else if (((type.equals(Long.class)) || (type.equals(long.class))) && Number.class.isInstance(value)) {
final Long number2Long = ((Number) value).longValue();
return (T) number2Long;
}
if (!type.isInstance(value)) {
// TODO: Move string value readers from server to common and utilize them here
final Constructor constructor = AccessController.doPrivileged(ReflectionHelper.getStringConstructorPA(type));
if (constructor != null) {
try {
return type.cast(constructor.newInstance(value));
} catch (Exception e) {
// calling the constructor wasn't successful - ignore and try valueOf()
}
}
final Method valueOf = AccessController.doPrivileged(ReflectionHelper.getValueOfStringMethodPA(type));
if (valueOf != null) {
try {
return type.cast(valueOf.invoke(null, value));
} catch (Exception e) {
// calling valueOf wasn't successful
}
}
// at this point we don't know what to return -> return null
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning(LocalizationMessages.PROPERTIES_HELPER_GET_VALUE_NO_TRANSFORM(String.valueOf(value),
value.getClass().getName(), type.getName()));
}
return null;
}
return type.cast(value);
}
/**
* Determine whether {@link CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE} does not globally
* disable META-INF/services lookup on client/server.
*
* @param properties map containing application properties. May be {@code null}
* @param runtimeType runtime (client or server) where the service finder binder is used.
* @return {@code true} if the {@link CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE} is not se to true
*/
public static boolean isMetaInfServicesEnabled(Map properties, RuntimeType runtimeType) {
boolean disableMetaInfServicesLookup = METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT;
if (properties != null) {
disableMetaInfServicesLookup = CommonProperties.getValue(properties, runtimeType,
CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT, Boolean.class);
}
return !disableMetaInfServicesLookup;
}
/**
* Check whether loading of JAX-RS services is allowed or not. Services shall implement Feature or DynamicFeature
* interface and be listed as SPI in an application
*
* @param properties list of properties to be checked
* @return false if loading of JAX-RS services is not enabled
*
* @since 2.35
*/
public static boolean isJaxRsServiceLoadingEnabled(Map properties) {
boolean enableServicesLoading = JAXRS_SERVICE_LOADING_ENABLE_DEFAULT;
if (properties != null) {
enableServicesLoading = CommonProperties.getValue(properties,
CommonProperties.JAXRS_SERVICE_LOADING_ENABLE, JAXRS_SERVICE_LOADING_ENABLE_DEFAULT);
}
return enableServicesLoading;
}
/**
* Get the value of the property with a given name converted to {@code boolean}. Returns {@code false} if the value is
* not convertible.
*
* @param properties key-value map of properties.
* @param name property name.
* @return {@code boolean} property value or {@code false} if the property is not convertible.
*/
public static boolean isProperty(final Map properties, final String name) {
return properties.containsKey(name) && isProperty(properties.get(name));
}
/**
* Get the value of the property converted to {@code boolean}. Returns {@code false} if the value is not convertible.
*
* @param value property value.
* @return {@code boolean} property value or {@code false} if the property is not convertible.
*/
public static boolean isProperty(final Object value) {
if (value instanceof Boolean) {
return Boolean.class.cast(value);
} else {
return value != null && Boolean.parseBoolean(value.toString());
}
}
/**
* Faster replacement of {@code RuntimeType#name().toLowerCase(Locale.ROOT)}
* @param runtimeType The runtime type to lower case
* @return the lower-cased variant of the {@link RuntimeType}.
*/
private static String toLowerCase(RuntimeType runtimeType) {
switch (runtimeType) {
case CLIENT:
return RUNTIME_CLIENT_LOWER;
default:
return RUNTIME_SERVER_LOWER;
}
}
/**
* Prevent instantiation.
*/
private PropertiesHelper() {
}
}