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

Allow for registering HK2 AbstractBinder #4122

Merged
merged 2 commits into from
May 15, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.inject.spi;

import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.model.ContractProvider;

import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;

/**
* Factory class creating instances of {@link BinderConfiguration} classes used to configure Binders registered
* to a configuration. While it is created for a backward compatibility with HK2 {@code AbstractBinder} to be
* able to be registered to a configuration (while HK2 injection module is on the classpath), a factory
* implementing this interface is used for registering Jersey {@code AbstractBinder}, too.
*
* @since 2.29
*/
public interface BinderConfigurationFactory {

/**
* Creates a {@link BinderConfiguration} instance that has a reference to {@code getInstances} function returning all
* registered instances filtered by provided {@link Predicate<ContractProvider>} that can be further traversed and configured.
*
* @param getInstances a function returning filtered instances registered to a configuration. The
* {@link Predicate<ContractProvider>} is used to filter out all the instances not to be further processed by the
* {@link BinderConfiguration}.
* @return {@link BinderConfiguration} instance used to register/configure the provided filtered instances.
*/
BinderConfiguration createBinderConfiguration(Function<Predicate<ContractProvider>, Set<Object>> getInstances);

/**
* This configuration object configure all the instances provided by the {@code getInstances} function passed from the
* factory {@link BinderConfigurationFactory#createBinderConfiguration(Function)} method.
* <p>
* The implementation possibly can hold a list of already configured {@code Binders} so that consecutive calls do
* not register the already registered {@code Binders} again.
*/
interface BinderConfiguration {
/**
* The provided {@code getInstances} function is used to get registered (filtered) instances in a
* {@link javax.ws.rs.core.Configuration}
*
* @param injectionManager {@link InjectionManager} to be used to configure the {@code Binder}
* @return {@code true} if a {@code Binder} has been configured.
*/
boolean configureBinders(InjectionManager injectionManager);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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
*/

/**
* Common Jersey core injection SPI classes.
*/
package org.glassfish.jersey.inject.spi;
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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.inject;

import org.glassfish.jersey.inject.spi.BinderConfigurationFactory;
import org.glassfish.jersey.model.ContractProvider;
import org.glassfish.jersey.model.internal.ComponentBag;

import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* An implementation of {@link BinderConfigurationFactory} used to configure {@link Binder} instances.
*/
public class JerseyBinderConfigurationFactory implements BinderConfigurationFactory {

@Override
public BinderConfiguration createBinderConfiguration(Function<Predicate<ContractProvider>, Set<Object>> getInstances) {
return new JerseyBinderConfiguration(getInstances);
}

private static class JerseyBinderConfiguration implements BinderConfiguration {
private Set<Binder> configuredBinders = Collections.emptySet();
private final Function<Predicate<ContractProvider>, Set<Object>> getInstances;
private static final Function<Object, Binder> CAST_TO_BINDER = Binder.class::cast;

private JerseyBinderConfiguration(Function<Predicate<ContractProvider>, Set<Object>> getInstances) {
this.getInstances = getInstances;
}

@Override
public boolean configureBinders(InjectionManager injectionManager) {
configuredBinders = configureBinders(injectionManager, configuredBinders);
return !configuredBinders.isEmpty();
}

private Set<Binder> configureBinders(InjectionManager injectionManager, Set<Binder> configured) {
Set<Binder> allConfigured = Collections.newSetFromMap(new IdentityHashMap<>());
allConfigured.addAll(configured);

Collection<Binder> binders = getBinder(configured);
if (!binders.isEmpty()) {
injectionManager.register(CompositeBinder.wrap(binders));
allConfigured.addAll(binders);
}

return allConfigured;
}

private Collection<Binder> getBinder(Set<Binder> configured) {
return getInstances
.apply(ComponentBag.BINDERS_ONLY)
.stream()
.map(CAST_TO_BINDER)
.filter(binder -> !configured.contains(binder))
.collect(Collectors.toList());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.Priorities;
Expand All @@ -44,11 +42,11 @@
import javax.annotation.Priority;

import org.glassfish.jersey.ExtendedConfig;
import org.glassfish.jersey.inject.spi.BinderConfigurationFactory;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.ServiceFinder;
import org.glassfish.jersey.internal.inject.Binder;
import org.glassfish.jersey.internal.inject.CompositeBinder;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.inject.JerseyBinderConfigurationFactory;
import org.glassfish.jersey.internal.inject.ProviderBinder;
import org.glassfish.jersey.internal.spi.AutoDiscoverable;
import org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable;
Expand All @@ -66,7 +64,6 @@
public class CommonConfig implements FeatureContext, ExtendedConfig {

private static final Logger LOGGER = Logger.getLogger(CommonConfig.class.getName());
private static final Function<Object, Binder> CAST_TO_BINDER = Binder.class::cast;

/**
* Configuration runtime type.
Expand Down Expand Up @@ -100,6 +97,42 @@ public class CommonConfig implements FeatureContext, ExtendedConfig {
*/
private boolean disableMetaProviderConfiguration;

/**
* A utility class that binds binders on all {@link BinderConfigurationFactory.BinderConfiguration BinderConfiguration}
* created upon creation of this BinderConfigurations from all {@link BinderConfigurationFactory BinderConfigurationFactories}
*/
private static final class BinderConfigurations {
private static final List<BinderConfigurationFactory> BINDER_CONFIGURATION_FACTORIES;
static {
final ServiceFinder<BinderConfigurationFactory> factoriesFinder =
ServiceFinder.find(BinderConfigurationFactory.class);
final List<BinderConfigurationFactory> configurationFactories = new LinkedList<>();
configurationFactories.add(new JerseyBinderConfigurationFactory());
for (BinderConfigurationFactory configurationFactory : factoriesFinder) {
configurationFactories.add(configurationFactory);
}
BINDER_CONFIGURATION_FACTORIES = Collections.unmodifiableList(configurationFactories);
}

private final List<BinderConfigurationFactory.BinderConfiguration> binderConfigurations;

private BinderConfigurations(ComponentBag componentBag) {
binderConfigurations = new LinkedList<>();
for (BinderConfigurationFactory factory : BINDER_CONFIGURATION_FACTORIES) {
BinderConfigurationFactory.BinderConfiguration configuration =
factory.createBinderConfiguration(componentBag::getInstances);
binderConfigurations.add(configuration);
}
}

private void configureBinders(InjectionManager injectionManager) {
for (BinderConfigurationFactory.BinderConfiguration configuration : binderConfigurations) {
configuration.configureBinders(injectionManager);
}
}

}

/**
* A single feature registration record.
*/
Expand Down Expand Up @@ -619,7 +652,8 @@ public void configureAutoDiscoverableProviders(final InjectionManager injectionM
*/
public void configureMetaProviders(InjectionManager injectionManager, ManagedObjectsFinalizer finalizer) {
// First, configure existing binders
Set<Binder> configuredBinders = configureBinders(injectionManager, Collections.emptySet());
BinderConfigurations binderConfigurations = new BinderConfigurations(componentBag);
binderConfigurations.configureBinders(injectionManager);

// Check whether meta providers have been initialized for a config this config has been loaded from.
if (!disableMetaProviderConfiguration) {
Expand All @@ -628,29 +662,8 @@ public void configureMetaProviders(InjectionManager injectionManager, ManagedObj
// Next, configure all features
configureFeatures(injectionManager, new HashSet<>(), resetRegistrations(), finalizer);
// At last, configure any new binders added by features
configureBinders(injectionManager, configuredBinders);
}
}

private Set<Binder> configureBinders(InjectionManager injectionManager, Set<Binder> configured) {
Set<Binder> allConfigured = Collections.newSetFromMap(new IdentityHashMap<>());
allConfigured.addAll(configured);

Collection<Binder> binders = getBinder(configured);
if (!binders.isEmpty()) {
injectionManager.register(CompositeBinder.wrap(binders));
allConfigured.addAll(binders);
binderConfigurations.configureBinders(injectionManager);
}

return allConfigured;
}

private Collection<Binder> getBinder(Set<Binder> configured) {
return componentBag.getInstances(ComponentBag.BINDERS_ONLY)
.stream()
.map(CAST_TO_BINDER)
.filter(binder -> !configured.contains(binder))
.collect(Collectors.toList());
}

private void configureExternalObjects(InjectionManager injectionManager) {
Expand Down
Loading