Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPI Config API for Jersey #4116

Merged
merged 3 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@
<artifactId>jersey-metainf-services</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mp-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ public final class CommonProperties {
*/
public static final String OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER = "jersey.config.server.contentLength.buffer";

/**
* Property which allows (if true) default System properties configuration provider.
*
* Effective if there are no any external properties providers
*
* Shall be set (if used) in system properties.
* @since 2.29
*/

public static final String ALLOW_SYSTEM_PROPERTIES_PROVIDER = "jersey.config.allowSystemPropertiesProvider";

/**
* Prevent instantiation.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.spi.AutoDiscoverable;

import javax.annotation.Priority;
import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.core.FeatureContext;

@ConstrainedTo(RuntimeType.CLIENT) //server is configured directly in ResourceConfig
@Priority(AutoDiscoverable.DEFAULT_PRIORITY)
public class ExternalPropertiesAutoDiscoverable implements AutoDiscoverable {
@Override
public void configure(FeatureContext context) {
if (!context.getConfiguration().isRegistered(ExternalPropertiesConfigurationFeature.class)) {
context.register(ExternalPropertiesConfigurationFeature.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* 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.Priorities;
import javax.ws.rs.core.Configurable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
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 static final List<ExternalConfigurationProvider> EXTERNAL_CONFIGURATION_PROVIDERS =
getExternalConfigurations();


/**
* Map of merged properties from all found providers
*
* @return map of merged properties from all found/plugged providers
*/
static Map<String, Object> readExternalPropertiesMap() {

final ExternalConfigurationProvider provider = mergeConfigs(EXTERNAL_CONFIGURATION_PROVIDERS);
return provider == null ? Collections.emptyMap() : 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
* @return true if configured false otherwise
*/

public static boolean configure(Configurable config) {

if (config instanceof ExternalConfigurationModel) {
return false; //shall not configure itself
}

final Map<String, Object> properties = readExternalPropertiesMap();

properties.forEach((k, v) -> config.property(k, v));

return true;
}

/**
* Merged config model from all found configuration models
*
* @return merged Model object with all properties
*/
static 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)
*/
private static 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 static 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 static Set<ExternalConfigurationProvider> orderConfigs(List<ExternalConfigurationProvider> configurations) {

final SortedSet<ExternalConfigurationProvider> sortedSet = new TreeSet<>(new ConfigComparator());
sortedSet.addAll(configurations);
return Collections.unmodifiableSortedSet(sortedSet);
}

private static class ConfigComparator implements Comparator<ExternalConfigurationProvider> {

@Override
public int compare(ExternalConfigurationProvider config1, ExternalConfigurationProvider config2) {

boolean config1PriorityPresent = config1.getClass().isAnnotationPresent(Priority.class);
boolean config2PriorityPresent = config2.getClass().isAnnotationPresent(Priority.class);

int priority1 = Priorities.USER;
int priority2 = Priorities.USER;

if (config1PriorityPresent) {
priority1 = config1.getClass().getAnnotation(Priority.class).value();
}
if (config2PriorityPresent) {
priority2 = config2.getClass().getAnnotation(Priority.class).value();
}

if (priority1 == priority2) {
return config1.getClass().getName().compareTo(config2.getClass().getName());
}
return Integer.compare(priority1, priority2);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;

public class ExternalPropertiesConfigurationFeature implements Feature {

@Override
public boolean configure(FeatureContext configurableContext) {
return ExternalPropertiesConfigurationFactory.configure(configurableContext);
}

}
Loading