| /* |
| * Copyright (c) 2012, 2019 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 javax.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 javax.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; |
| |
| /** |
| * 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<Properties> getSystemProperties() { |
| return new PrivilegedAction<Properties>() { |
| @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<String> getSystemProperty(final String name) { |
| return new PrivilegedAction<String>() { |
| @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<String> getSystemProperty(final String name, final String def) { |
| return new PrivilegedAction<String>() { |
| @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<T>) 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 <T> 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> T getValue(Map<String, ?> properties, String key, T defaultValue, Map<String, String> 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<T>) 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 (<tt>.server</tt> |
| * 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 <T> 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> T getValue(Map<String, ?> properties, |
| RuntimeType runtimeType, |
| String key, |
| T defaultValue, |
| Map<String, String> legacyMap) { |
| return getValue(properties, runtimeType, key, defaultValue, (Class<T>) 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 <T> 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> T getValue(Map<String, ?> properties, |
| String key, |
| T defaultValue, |
| Class<T> type, |
| Map<String, String> 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 (<tt>.server</tt> |
| * 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 <T> 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> T getValue(Map<String, ?> properties, RuntimeType runtimeType, String key, |
| T defaultValue, Class<T> type, Map<String, String> 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 <T> 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> T getValue(Map<String, ?> properties, String key, Class<T> type, Map<String, String> 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 (<tt>.server</tt> |
| * 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 <T> Type of the property value. |
| * @return Value of the property or null. |
| */ |
| public static <T> T getValue(Map<String, ?> properties, RuntimeType runtimeType, String key, Class<T> type, |
| Map<String, String> legacyMap) { |
| Object value = null; |
| if (runtimeType != null) { |
| String runtimeAwareKey = getPropertyNameForRuntime(key, runtimeType); |
| if (key.equals(runtimeAwareKey)) { |
| // legacy behaviour |
| runtimeAwareKey = key + "." + runtimeType.name().toLowerCase(Locale.ROOT); |
| } |
| 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." + type.name().toLowerCase(Locale.ROOT))) { |
| return key; |
| } |
| } |
| return key.replace("jersey.config", "jersey.config." + runtimeType.name().toLowerCase(Locale.ROOT)); |
| } |
| return key; |
| } |
| |
| private static Object getLegacyFallbackValue(Map<String, ?> properties, Map<String, String> 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 <T> converted value type. |
| * @return value converted to the specified class type. |
| */ |
| public static <T> T convertValue(Object value, Class<T> type) { |
| 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<String, Object> 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; |
| } |
| |
| /** |
| * 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<String, Object> 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()); |
| } |
| } |
| |
| /** |
| * Prevent instantiation. |
| */ |
| private PropertiesHelper() { |
| } |
| } |