-
Notifications
You must be signed in to change notification settings - Fork 356
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MicroprofileConfig SPI API for Jersey
Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
- Loading branch information
Showing
31 changed files
with
1,512 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
...ain/java/org/glassfish/jersey/internal/config/ExternalPropertiesConfigurationFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/* | ||
* Copyright (c) 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.config; | ||
|
||
import org.glassfish.jersey.internal.ServiceFinder; | ||
import org.glassfish.jersey.spi.ExternalConfigurationModel; | ||
import org.glassfish.jersey.spi.ExternalConfigurationProvider; | ||
|
||
import javax.annotation.Priority; | ||
import javax.ws.rs.core.Configurable; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.SortedSet; | ||
import java.util.TreeSet; | ||
|
||
/** | ||
* Factory for external properties providers | ||
* Offers methods to work with properties loaded from providers or | ||
* just configure Jersey's Configurables with loaded properties from providers | ||
*/ | ||
public class ExternalPropertiesConfigurationFactory { | ||
|
||
private ExternalPropertiesConfigurationFactory() { | ||
} | ||
|
||
private static final ExternalPropertiesConfigurationFactory factory = new ExternalPropertiesConfigurationFactory(); | ||
|
||
public static ExternalPropertiesConfigurationFactory getFactory() { | ||
return factory; | ||
} | ||
|
||
/** | ||
* Map of merged properties from all found providers | ||
* | ||
* @return map of merged properties from all found/plugged providers | ||
*/ | ||
public Map<String, Object> readExternalPropertiesMap() { | ||
|
||
final ExternalConfigurationProvider provider = mergeConfigs(getExternalConfigurations()); | ||
return provider == null ? new HashMap<>() : provider.getProperties(); | ||
} | ||
|
||
|
||
/** | ||
* Input Configurable object shall be provided in order to be filled with all found properties | ||
* | ||
* @param config Input Configurable initialised object to be filled with properties | ||
*/ | ||
public void confiure(Configurable config) { | ||
|
||
if (config instanceof ExternalConfigurationModel) { | ||
throw new IllegalArgumentException("Config shall not be from external properties"); | ||
} | ||
|
||
final Map<String, Object> properties = readExternalPropertiesMap(); | ||
properties.forEach((k, v) -> config.property(k, v)); | ||
|
||
} | ||
|
||
/** | ||
* Merged config model from all found configuration models | ||
* | ||
* @return merged Model object with all properties | ||
*/ | ||
public ExternalConfigurationModel getConfig() { | ||
final ExternalConfigurationProvider provider = mergeConfigs(getExternalConfigurations()); | ||
return provider == null ? null : provider.getConfiguration(); | ||
} | ||
|
||
/** | ||
* List of all found models as they are found by Jersey | ||
* | ||
* @return list of models (or empty list) | ||
*/ | ||
public List<ExternalConfigurationProvider> getExternalConfigurations() { | ||
final List<ExternalConfigurationProvider> providers = new ArrayList<>(); | ||
final ServiceFinder<ExternalConfigurationProvider> finder = | ||
ServiceFinder.find(ExternalConfigurationProvider.class); | ||
if (finder.iterator().hasNext()) { | ||
finder.forEach(providers::add); | ||
} else { | ||
providers.add(new SystemPropertiesConfigurationProvider()); | ||
} | ||
return providers; | ||
} | ||
|
||
private ExternalConfigurationProvider mergeConfigs(List<ExternalConfigurationProvider> configurations) { | ||
final Set<ExternalConfigurationProvider> orderedConfigurations = orderConfigs(configurations); | ||
final Iterator<ExternalConfigurationProvider> configurationIterator = orderedConfigurations.iterator(); | ||
if (!configurationIterator.hasNext()) { | ||
return null; | ||
} | ||
final ExternalConfigurationProvider firstConfig = configurationIterator.next(); | ||
while (configurationIterator.hasNext()) { | ||
final ExternalConfigurationProvider nextConfig = configurationIterator.next(); | ||
firstConfig.merge(nextConfig.getConfiguration()); | ||
} | ||
|
||
return firstConfig; | ||
} | ||
|
||
private Set<ExternalConfigurationProvider> orderConfigs(List<ExternalConfigurationProvider> configurations) { | ||
|
||
final SortedSet<ExternalConfigurationProvider> sortedSet = new TreeSet<>((config1, config2) -> { | ||
|
||
if ( | ||
config1.getClass().isAnnotationPresent(Priority.class) | ||
&& config2.getClass().isAnnotationPresent(Priority.class) | ||
) { | ||
int priority1 = config1.getClass().getAnnotation(Priority.class).value(); | ||
int priority2 = config2.getClass().getAnnotation(Priority.class).value(); | ||
if (priority1 == priority2) { | ||
return config1.getClass().getName().compareTo(config2.getClass().getName()); | ||
} | ||
return Integer.compare(priority1, priority2); | ||
} | ||
return config1.getClass().getName().compareTo(config2.getClass().getName()); | ||
}); | ||
sortedSet.addAll(configurations); | ||
return Collections.unmodifiableSortedSet(sortedSet); | ||
} | ||
|
||
} |
216 changes: 216 additions & 0 deletions
216
...rc/main/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
/* | ||
* Copyright (c) 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.config; | ||
|
||
import org.glassfish.jersey.CommonProperties; | ||
import org.glassfish.jersey.internal.util.PropertiesHelper; | ||
import org.glassfish.jersey.internal.util.ReflectionHelper; | ||
import org.glassfish.jersey.spi.ExternalConfigurationModel; | ||
|
||
import javax.ws.rs.RuntimeType; | ||
import javax.ws.rs.core.Feature; | ||
import java.lang.reflect.Field; | ||
import java.security.AccessController; | ||
import java.security.PrivilegedAction; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
import java.util.function.Function; | ||
import java.util.logging.Logger; | ||
|
||
|
||
public class SystemPropertiesConfigurationModel implements ExternalConfigurationModel<Void> { | ||
|
||
private static final Logger log = Logger.getLogger(SystemPropertiesConfigurationModel.class.getName()); | ||
|
||
|
||
private static final Map<Class, Function> converters = new HashMap<>(); | ||
static { | ||
converters.put(String.class, (Function<String, String>) s -> s); | ||
converters.put(Integer.class, (Function<String, Integer>) s -> Integer.valueOf(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)); | ||
} | ||
|
||
@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)) | ||
? 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) { | ||
return this; | ||
} | ||
|
||
@Override | ||
public Void getConfig() { | ||
return null; | ||
} | ||
|
||
@Override | ||
public boolean isProperty(String name) { | ||
return Optional.ofNullable( | ||
AccessController.doPrivileged( | ||
PropertiesHelper.getSystemProperty(name) | ||
) | ||
).isPresent(); | ||
} | ||
|
||
@Override | ||
public RuntimeType getRuntimeType() { | ||
return null; | ||
} | ||
|
||
@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("System properties configuration provider not allowed"); | ||
return result; | ||
} | ||
|
||
try { | ||
AccessController.doPrivileged(PropertiesHelper.getSystemProperties()) | ||
.forEach((k, v) -> result.put(String.valueOf(k), v)); | ||
} catch (SecurityException se) { | ||
log.warning(se.getLocalizedMessage()); | ||
return getExpectedSystemProperties(); | ||
} | ||
return result; | ||
} | ||
|
||
private Map<String, Object> getExpectedSystemProperties() { | ||
|
||
|
||
final Map<String, Object> result = new HashMap<>(); | ||
|
||
mapFieldsToProperties(result, CommonProperties.class); | ||
|
||
|
||
|
||
mapFieldsToProperties(result, | ||
AccessController.doPrivileged( | ||
ReflectionHelper.classForNamePA("org.glassfish.jersey.server.ServerProperties") | ||
) | ||
); | ||
|
||
mapFieldsToProperties(result, | ||
AccessController.doPrivileged( | ||
ReflectionHelper.classForNamePA("org.glassfish.jersey.client.ClientProperties") | ||
) | ||
); | ||
|
||
|
||
return result; | ||
} | ||
|
||
private <T> void mapFieldsToProperties(Map<String, Object> properties, Class<T> clazz) { | ||
if (clazz == null) { | ||
return; | ||
} | ||
|
||
final Field[] fields = AccessController.doPrivileged( | ||
ReflectionHelper.getDeclaredFieldsPA(clazz) | ||
); | ||
|
||
for (final Field field : fields) { | ||
if (field.getType().isAssignableFrom(String.class)) { | ||
final String propertyValue = getPropertyNameByField(field); | ||
properties.put(propertyValue, PropertiesHelper.getSystemProperty(propertyValue)); | ||
} | ||
} | ||
} | ||
|
||
private String getPropertyNameByField(Field field) { | ||
return AccessController.doPrivileged((PrivilegedAction<String>) () -> { | ||
try { | ||
return (String) field.get(null); | ||
} catch (IllegalAccessException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
}); | ||
} | ||
|
||
@Override | ||
public Object getProperty(String name) { | ||
return getSystemProperty(name); | ||
} | ||
|
||
@Override | ||
public Collection<String> getPropertyNames() { | ||
return PropertiesHelper.getSystemProperties().run().stringPropertyNames(); | ||
} | ||
|
||
@Override | ||
public boolean isEnabled(Feature feature) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean isEnabled(Class<? extends Feature> featureClass) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean isRegistered(Object component) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean isRegistered(Class<?> componentClass) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public Map<Class<?>, Integer> getContracts(Class<?> componentClass) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public Set<Class<?>> getClasses() { | ||
return null; | ||
} | ||
|
||
@Override | ||
public Set<Object> getInstances() { | ||
return null; | ||
} | ||
} |
Oops, something went wrong.