io.helidon.integrations.oci.sdk.cdi.OciExtension Maven / Gradle / Ivy
/*
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.integrations.oci.sdk.cdi;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.System.Logger;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.oracle.bmc.ConfigFileReader.ConfigFile;
import com.oracle.bmc.Service;
import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider;
import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider;
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider;
import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder;
import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider;
import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider.ResourcePrincipalAuthenticationDetailsProviderBuilder;
import com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider;
import com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider.SessionTokenAuthenticationDetailsProviderBuilder;
import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider;
import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.SimpleAuthenticationDetailsProviderBuilder;
import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider;
import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder;
import com.oracle.bmc.common.ClientBuilderBase;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.event.Event;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.AmbiguousResolutionException;
import jakarta.enterprise.inject.CreationException;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.UnsatisfiedResolutionException;
import jakarta.enterprise.inject.literal.NamedLiteral;
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
import jakarta.enterprise.inject.spi.AfterDeploymentValidation;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.inject.spi.InjectionPoint;
import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
import jakarta.enterprise.util.TypeLiteral;
import jakarta.inject.Provider;
import jakarta.inject.Singleton;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import static io.helidon.integrations.oci.sdk.cdi.AdpStrategyDescriptors.DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS;
import static io.helidon.integrations.oci.sdk.cdi.AdpStrategyDescriptors.replaceElements;
import static io.helidon.integrations.oci.sdk.cdi.AdpStrategyDescriptors.strategyDescriptors;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING;
import static java.lang.invoke.MethodType.methodType;
/**
* A CDI portable
* extension that enables the {@linkplain jakarta.inject.Inject injection} of any service interface, service client, service client builder, asynchronous service interface, asynchronous service client, or asynchronous service client builder from the Oracle Cloud Infrastructure Java
* SDK.
*
* Terminology
*
* The terms service interface, service client, service client builder, asynchronous
* service interface, asynchronous service client, and asynchronous service client builder are
* defined as follows:
*
*
*
* - Service
*
* - An Oracle Cloud Infrastructure service supported by the Oracle Cloud Infrastructure Java SDK.
*
* - Service interface
*
* - A Java interface describing the functionality of a service. Distinguished from an asynchronous service interface.
*
*
For a hypothetical service named Cloud Example, the corresponding service interface will be in a
* package named com.oracle.bmc.
cloudexample
. The service interface's
* {@linkplain Class#getSimpleName() simple name} is often also named after the service,
* e.g. CloudExample
, but need not be.
*
* - Service client
*
* - A concrete Java class that implements the service interface and has the same
* {@linkplain Class#getPackageName() package name} as it. Distinguished from an asynchronous service client.
*
*
The service client's {@linkplain Class#getSimpleName() simple name} is formed by appending the {@linkplain
* Class#getSimpleName() simple name} of the service interface with Client
. The {@linkplain Class#getName()
* class name} for the service client for the hypothetical {@code com.oracle.bmc.cloudexample.CloudExample} service
* interface described above will thus be
* com.oracle.bmc.
cloudexample
.
CloudExampleClient
.
*
* - Service client builder
*
* - A concrete Java "builder" class that creates possibly customized instances of its corresponding service client. Distinguished from an asynchronous service client builder.
*
*
The service client builder is nearly always a nested class of the service client whose instances it builds with a
* {@linkplain Class#getSimpleName() simple name} of {@code Builder}. (In the single case in the entirety of the Oracle Cloud Infrastructure Java SDK where this pattern is not
* followed, the service client builder's {@linkplain Class#getSimpleName() simple name} is formed by adding {@code
* Builder} to the service client's {@linkplain Class#getSimpleName() simple name}.) The {@linkplain Class#getName()
* class name} for the service client builder for the hypothetical {@code
* com.oracle.bmc.cloudexample.CloudExampleClient} service client described above will thus be
* com.oracle.bmc.
cloudexample
.
CloudExampleClient$Builder
.
*
* - Asynchronous service interface
*
* - A Java interface describing the functionality of a service. Distinguished from a service interface.
*
*
For a hypothetical service named Cloud Example, the corresponding service interface will be in
* the same package as that of the service interface. The asynchronous service interface's {@linkplain
* Class#getSimpleName() simple name} is formed by adding {@code Async} to the service interface's {@linkplain
* Class#getSimpleName() simple name}. The {@linkplain Class#getName() class name} for the asynchronous service
* interface for the hypothetical {@code com.oracle.bmc.cloudexample.CloudExample} service interface described above
* will thus be
* com.oracle.bmc.
cloudexample
.
CloudExampleAsync
.
*
* - Asynchronous service client
*
* - A concrete Java class that implements the asynchronous service interface
* and has the same {@linkplain Class#getPackageName() package name} as it. Distinguised from a service client.
*
*
The asynchronous service client's {@linkplain Class#getSimpleName() simple name} is formed by appending the
* {@linkplain Class#getSimpleName() simple name} of the asynchronous service interface with Client
. The
* {@linkplain Class#getName() class name} for the asynchronous service client for the hypothetical {@code
* com.oracle.bmc.cloudexample.CloudExample} asynchronous service interface described above will thus be
* com.oracle.bmc.
cloudexample
.
CloudExampleAsyncClient
.
*
* - Asynchronous service client builder
*
* - A concrete Java "builder" class that creates possibly customized instances of its corresponding asynchronous service client. Distinguished from a service client builder.
*
*
The asynchronous service client builder is nearly always a nested class of the asynchronous service client whose
* instances it builds with a {@linkplain Class#getSimpleName() simple name} of {@code Builder}. (In the single case in the entirety of the Oracle Cloud Infrastructure Java SDK where this pattern is not
* followed, the asynchronous service client builder's {@linkplain Class#getName() class name} is formed by adding
* {@code Builder} to the asynchronous service client's {@linkplain Class#getName() class name}.) The {@linkplain
* Class#getName() class name} for the service client builder for the hypothetical {@code
* com.oracle.bmc.cloudexample.CloudExampleAsyncClient} service client described above will thus be
* com.oracle.bmc.
cloudexample
.
CloudExampleAsyncClient$Builder
.
*
*
*
* Additionally, for any given service interface, service client, service client builder, asynchronous service
* interface, asynchronous service client, or asynchronous service client builder, this {@linkplain Extension extension}
* also enables the {@linkplain jakarta.inject.Inject injection} of an appropriate {@link
* AbstractAuthenticationDetailsProvider}, which allows the corresponding service client to authenticate with the
* service.
*
* In all cases, user-supplied beans will be preferred over any otherwise installed by this {@linkplain Extension
* extension}.
*
* Basic Usage
*
* To use this extension, make sure it is on your project's runtime classpath. To {@linkplain jakarta.inject.Inject
* inject} a service interface named
* com.oracle.bmc.
cloudexample
.CloudExample
(or an analogous asynchronous service interface), you will also need to ensure that its containing
* artifact is on your compile classpath (e.g. oci-java-sdk-
cloudexample
-$VERSION.jar
,
* where {@code $VERSION} should be replaced by a suitable version number).
*
* Advanced Usage and Customization
*
* In the course of providing {@linkplain jakarta.inject.Inject injection support} for a service interface or an asynchronous service
* interface, this {@linkplain Extension extension} will also create service
* client builder and asynchronous service client builder instances by
* invoking the {@code static} {@code builder()} method that is present on all service
* client classes, and will then add those instances as beans. The resulting service client or asynchronous service
* client will be built by that builder's {@link ClientBuilderBase#build(AbstractAuthenticationDetailsProvider)
* build(AbstractAuthenticationDetailsProvider)} method and will itself be added as a bean.
*
* A user may wish to customize this builder so that the resulting service client or asynchronous service client
* reflects the customization. She has two options:
*
*
*
* - She may supply her own bean with the service client builder type (or asynchronous client builder type) as one of
* its bean
* types. In this case, this {@linkplain Extension extension} does not supply the service client builder (or
* asynchronous service client builder) and the user is in full control of how her service client (or asynchronous
* service client) is constructed.
*
* - She may customize the service client builder (or asynchronous service client builder) supplied by this
* {@linkplain Extension extension}. To do this, she declares an
* observer method that observes the service client builder object (or asynchronous service client builder object)
* that is returned from the {@code static} service client (or asynchronous service client) {@code builder()} method.
* In her observer method, she may call any method on the supplied service client builder (or asynchronous service
* client builder) and her customizations will be retained.
*
*
*
* Configuration
*
* This extension uses the following MicroProfile
* Config property names (note, however, that no configuration is required):
*
*
*
*
*
* Name
*
* Type
*
* Description
*
* Default Value
*
* Notes
*
*
*
*
*
*
*
*
*
* {@code oci.auth-strategies}
*
* {@link String String[]}
*
* A comma-separated list of descriptors describing the strategy, or strategies, to use to select an
* appropriate {@link AbstractAuthenticationDetailsProvider} when one is called for.
*
* {@code auto}
*
* Zero or more of the following:
*
*
* - {@code auto}
* - {@code config}
* - {@code config-file}
* - {@code instance-principals}
* - {@code oke-workload-identity}
* - {@code resource-principal}
* - {@code session-token-builder}
* - {@code session-token-config-file}
*
*
* A strategy descriptor of {@code config} will cause a {@link
* SimpleAuthenticationDetailsProvider} to be used, populated with other MicroProfile Config properties
* described here.
*
* A strategy descriptor of {@code config-file} will cause a {@link
* ConfigFileAuthenticationDetailsProvider} to be used, {@linkplain
* ConfigFileAuthenticationDetailsProvider#ConfigFileAuthenticationDetailsProvider(ConfigFile) loaded from} an
* OCI configuration file,
* with a loading process customized with other MicroProfile Config properties described here.
*
* A strategy descriptor of {@code instance-principals} will cause an {@link
* InstancePrincipalsAuthenticationDetailsProvider} to be used.
*
* A strategy descriptor of {@code oke-workload-identity} will cause a {@link
* OkeWorkloadIdentityAuthenticationDetailsProvider} to be used.
*
* A strategy descriptor of {@code resource-principal} will cause a {@link
* ResourcePrincipalAuthenticationDetailsProvider} to be used.
*
* A strategy descriptor of {@code session-token-builder} will cause a {@link
* SessionTokenAuthenticationDetailsProvider} to be used, {@linkplain
* SessionTokenAuthenticationDetailsProviderBuilder#build() built} from a {@link
* SessionTokenAuthenticationDetailsProviderBuilder SessionTokenAuthenticationDetailsProviderBuilder} instance,
* customizable using other facilities described in this documentation.
*
* A strategy descriptor of {@code session-token-config-file} will cause a {@link
* SessionTokenAuthenticationDetailsProvider} to be used, {@linkplain
* SessionTokenAuthenticationDetailsProvider#SessionTokenAuthenticationDetailsProvider(ConfigFile) loaded from}
* an OCI configuration
* file, with a loading process customized with other MicroProfile Config properties described here.
*
* If there are many strategy descriptors supplied, the first one that is deemed to be available or suitable
* will be used and all others will be ignored.
*
* If {@code auto} is present in the list, or if no value for this property can be found,
* the behavior will be as if {@code auto} were replaced with {@code
* config,config-file,session-token-config-file,session-token-builder,instance-principals,resource-principal,oke-workload-identity}
* instead. (The replacement values are subject to change in subsequent revisions of this class.)
*
*
*
*
*
* {@code oci.config.path}
*
* {@link String}
*
* A {@link String} that is {@linkplain com.oracle.bmc.ConfigFileReader#parse(String) a path to a valid OCI
* configuration file} A {@linkplain com.oracle.bmc.ConfigFileReader#parseDefault() default
* location}
*
* This configuration property has an effect only when either {@code config-file} or {@code
* session-token-config-file} is, explicitly or implicitly, present in the value for the {@code
* oci.auth-strategies} configuration property described elsewhere in this table.
*
*
*
*
*
* {@code oci.config.profile}
*
* {@link String}
*
* An OCI configuration file profile.
*
* {@link com.oracle.bmc.ConfigFileReader#DEFAULT_PROFILE_NAME DEFAULT}
*
* This configuration property has an effect only when either {@code config-file} or {@code
* session-token-config-file} is, explicitly or implicitly, present in the value for the {@code
* oci.auth-strategies} configuration property described elsewhere in this table.
*
*
*
*
*
* {@code oci.auth.fingerprint}
*
* {@link String}
*
* An API signing key's fingerprint.
*
*
*
* This configuration property has an effect only when {@code config} is, explicitly or implicitly, present in
* the value for the {@code oci.auth-strategies} configuration property described elsewhere in this table.
*
*
*
*
*
* {@code oci.auth.region}
*
* {@link com.oracle.bmc.Region} ({@link String} representation)
*
* A region identifier.
*
*
*
* This configuration property has an effect only when {@code config} is, explicitly or implicitly, present in
* the value for the {@code oci.auth-strategies} configuration property described elsewhere in this table.
*
*
*
*
*
* {@code oci.auth.tenant-id}
*
* {@link String}
*
* An OCID of a tenancy.
*
*
*
* This configuration property has an effect only when {@code config} is, explicitly or implicitly, present in
* the value for the {@code oci.auth-strategies} configuration property described elsewhere in this table.
*
*
*
*
*
* {@code oci.auth.user-id}
*
* {@link String}
*
* An OCID of a user.
*
*
*
* This configuration property has an effect only when {@code config} is, explicitly or implicitly, present in
* the value for the {@code oci.auth-strategies} configuration property described elsewhere in this table.
*
*
*
*
*
* {@code oci.extension.classname-vetoes}
*
* {@link String String[]}
*
* A comma-separated list of {@linkplain Class#getName() class names} beginning with {@code com.oracle.bmc.}
* that should be skipped, even if they match the service pattern described above.
*
*
*
* It is recommended not to supply a value for this property name except in extraordinary circumstances.
*
*
*
*
*
* {@code oci.extension.lenient-classloading}
*
* {@link Boolean boolean}
*
* If {@code true}, classes that cannot be loaded will not cause a definition error and will simply be skipped
* (recommended).
*
* {@code true}
*
* It is recommended not to supply a value for this property name except in extraordinary circumstances.
*
*
*
*
*
*
*
* @see Extension
*
* @see
*
*
*
* Oracle Cloud
* Infrastructure Java SDK
*/
public final class OciExtension implements Extension {
/*
* Static fields.
*/
/*
* Type and TypeLiteral constants, sorted as alphabetically as possible.
*/
private static final TypeLiteral>
ADP_SUPPLIER_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADP_SUPPLIER_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADP_SUPPLIER_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral>
ADP_SUPPLIER_CONFIG_FILE_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADP_SUPPLIER_CONFIG_FILE_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADP_SUPPLIER_CONFIG_FILE_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral>
ADP_SUPPLIER_INSTANCE_PRINCIPALS_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final TypeLiteral>
ADPSUPPLIER_OKEWORKLOADIDENTITYAUTHENTICATIONDETAILSPROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADPSUPPLIER_OKEWORKLOADIDENTITYAUTHENTICATIONDETAILSPROVIDER_TYPE =
(ParameterizedType) ADPSUPPLIER_OKEWORKLOADIDENTITYAUTHENTICATIONDETAILSPROVIDER_TYPE_LITERAL.getType();
private static final ParameterizedType ADP_SUPPLIER_INSTANCE_PRINCIPALS_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADP_SUPPLIER_INSTANCE_PRINCIPALS_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral>
ADP_SUPPLIER_RESOURCE_PRINCIPAL_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADP_SUPPLIER_RESOURCE_PRINCIPAL_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADP_SUPPLIER_RESOURCE_PRINCIPAL_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral>
ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral>
ADP_SUPPLIER_SIMPLE_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADP_SUPPLIER_SIMPLE_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADP_SUPPLIER_SIMPLE_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral>
ADPSUPPLIER_WILDCARD_EXTENDS_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType ADPSUPPLIER_WILDCARD_EXTENDS_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE =
(ParameterizedType) ADPSUPPLIER_WILDCARD_EXTENDS_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL.getType();
private static final TypeLiteral> EVENT_OBJECT_TYPE_LITERAL = new TypeLiteral<>() {};
private static final TypeLiteral> SUPPLIER_CONFIGFILE_TYPE_LITERAL = new TypeLiteral<>() {};
private static final ParameterizedType SUPPLIER_CONFIGFILE_TYPE =
(ParameterizedType) SUPPLIER_CONFIGFILE_TYPE_LITERAL.getType();
/*
* Other constants, sorted alphabetically.
*/
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
private static final Logger LOGGER = System.getLogger(OciExtension.class.getName());
// Evaluates to "com.oracle.bmc." (yes, bmc, not oci) as of the current version of the public OCI Java SDK.
private static final String OCI_PACKAGE_PREFIX = Service.class.getPackageName() + ".";
private static final Lookup PUBLIC_LOOKUP = MethodHandles.publicLookup();
// For any OCI service conceptually named "Example" in an OCI_PACKAGE_PREFIX subpackage named "example":
//
// Match Strings expected to be class names that start with OCI_PACKAGE_PREFIX...
//
// (1) ...followed by the service client package fragment ("example")...
// (2) ...followed by a period (".")...
// (3) ...followed by one or more of the following:
// "Example",
// "ExampleAsync",
// "ExampleAsyncClient",
// "ExampleAsyncClientBuilder", // ...bmc.streaming mistakenly doesn't use a nested Builder class; all other services do
// "ExampleAsyncClient$Builder",
// "ExampleClient",
// "ExampleClientBuilder",
// "ExampleClient$Builder"...
// (4) ...followed by the end of String.
//
// Capturing group 0: the matched substring ("example.ExampleClientBuilder")
// Capturing group 1: Capturing group 2 and base noun ("example.Example")
// Capturing group 2: "example"
private static final Pattern SERVICE_CLIENT_CLASS_NAME_SUBSTRING_PATTERN =
Pattern.compile("^(([^.]+)" // (1) (as many non-periods as possible)
+ "\\." // (2) (a single period)
+ ".+?)(?:Async)?(?:Client(?:\\$?Builder)?)?" // (3)
+ "$"); // (4)
/*
* Instance fields, sorted alphabetically.
*/
private final Set additionalVetoes;
private boolean lenientClassloading;
private final Set serviceTaqs;
private final Set unloadableClassNames;
/*
* Constructors.
*/
/**
* Creates a new {@link OciExtension}.
*
* @deprecated For {@link java.util.ServiceLoader} use only.
*/
@Deprecated // for java.util.ServiceLoader use only
public OciExtension() {
super();
this.lenientClassloading = true;
this.serviceTaqs = new HashSet<>();
this.additionalVetoes = new HashSet<>(7);
this.unloadableClassNames = new HashSet<>(7);
}
/*
* Container lifecycle observer methods.
*/
private void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event) {
Config c = ConfigProvider.getConfig();
try {
this.lenientClassloading =
c.getOptionalValue("oci.extension.lenient-classloading", Boolean.class)
.orElse(Boolean.TRUE)
.booleanValue();
} catch (IllegalArgumentException conversionException) {
if (LOGGER.isLoggable(DEBUG)) {
LOGGER.log(DEBUG, conversionException.getMessage(), conversionException);
}
this.lenientClassloading = true;
}
this.additionalVetoes.addAll(c.getOptionalValue("oci.extension.classname-vetoes", String[].class)
.map(Set::of)
.orElse(Set.of()));
}
private void processInjectionPoint(@Observes ProcessInjectionPoint, ?> event) {
InjectionPoint ip = event.getInjectionPoint();
processInjectionPoint(ip.getAnnotated().getBaseType(),
ip.getQualifiers(),
event::addDefinitionError);
}
private void processProviderInjectionPoint(@Observes ProcessInjectionPoint, ? extends Provider>> event) {
InjectionPoint ip = event.getInjectionPoint();
processInjectionPoint(((ParameterizedType) ip.getAnnotated().getBaseType()).getActualTypeArguments()[0],
ip.getQualifiers(),
event::addDefinitionError);
}
private void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager bm) {
if (!this.serviceTaqs.isEmpty()) {
for (ServiceTaqs serviceTaqs : this.serviceTaqs) {
Annotation[] qualifiers = serviceTaqs.qualifiers();
if (serviceTaqs.isEmpty()) {
installAdpMachinery(event, bm, qualifiers);
} else {
TypeAndQualifiers serviceClientBuilder = serviceTaqs.serviceClientBuilder();
TypeAndQualifiers serviceClient = serviceTaqs.serviceClient();
installServiceClientBuilder(event, bm, serviceClientBuilder, serviceClient, this.lenientClassloading);
installServiceClient(event, bm, serviceClient, serviceTaqs.serviceInterface(), serviceClientBuilder);
}
}
}
}
private void afterDeploymentValidation(@Observes AfterDeploymentValidation event) {
this.unloadableClassNames.clear();
this.additionalVetoes.clear();
this.serviceTaqs.clear();
}
/*
* Additional instance methods.
*/
/**
* Returns {@code true} if the supplied {@link Class} is known to not be directly related to an Oracle Cloud
* Infrastructure service.
*
* The check is fast and deliberately not exhaustive.
*
* @param c the {@link Class} in question; must not be {@code null}; will be a {@link Class} whose {@linkplain
* Class#getPackageName() package name} starts with the value of the {@link #OCI_PACKAGE_PREFIX} field
*
* @return {@code true} if the supplied {@link Class} is known to not be directly related to an Oracle Cloud
* Infrastructure service
*
* @exception NullPointerException if {@code c} is {@code null}
*/
private boolean isVetoed(Class> c) {
// See
// https://docs.oracle.com/en-us/iaas/tools/java/latest/overview-summary.html#:~:text=Oracle%20Cloud%20Infrastructure%20Common%20Runtime.
// None of these packages contains OCI service clients or service client interfaces or service client
// builders. There are other packages (com.oracle.bmc.encryption, as an arbitrary example) that should also
// conceptually be vetoed. This method does not currently veto all of them, nor is it clear that it ever could.
// The strategy employed here, however, vetoes quite a large number of them correctly and very efficiently
// before more sophisticated tests are employed.
//
// "Veto" in this context means only that this extension will not further process the class in question. The
// class remains eligible for further processing; i.e. this is not a CDI veto.
if (equals(Service.class.getProtectionDomain(), c.getProtectionDomain())
|| this.additionalVetoes.contains(c.getName())) {
if (LOGGER.isLoggable(DEBUG)) {
LOGGER.log(DEBUG, "Vetoed " + c);
}
return true;
}
return false;
}
private void processInjectionPoint(Type type,
Set qualifiers,
Consumer super ClassNotFoundException> errorHandler) {
if (!(type instanceof Class)) {
// Optimization: all OCI constructs we're interested in are non-generic classes (and not therefore
// ParameterizedTypes or GenericArrayTypes).
return;
}
Class> c = (Class>) type;
String className = c.getName();
if (!className.startsWith(OCI_PACKAGE_PREFIX)) {
// Optimization: the set of classes we're interested in is a subset of general OCI-related classes.
return;
}
if (AbstractAuthenticationDetailsProvider.class.isAssignableFrom(c) || isAdpBuilderClass(c)) {
// Register an "empty" ServiceTaqs as an indicator of demand for some kind of
// AbstractAuthenticationDetailsProvider (or a relevant builder).
this.serviceTaqs.add(new ServiceTaqs(qualifiers.toArray(EMPTY_ANNOTATION_ARRAY)));
return;
}
Matcher m = SERVICE_CLIENT_CLASS_NAME_SUBSTRING_PATTERN.matcher(className.substring(OCI_PACKAGE_PREFIX.length()));
if (!m.matches() || this.isVetoed(c)) {
return;
}
this.processServiceClientInjectionPoint(errorHandler,
c,
qualifiers,
OCI_PACKAGE_PREFIX + m.group(1));
}
private void processServiceClientInjectionPoint(Consumer super ClassNotFoundException> errorHandler,
Class> c,
Set qualifiers,
String serviceInterfaceName) {
Annotation[] qualifiersArray = qualifiers.toArray(EMPTY_ANNOTATION_ARRAY);
ServiceTaqs serviceTaqsForAuth = null;
boolean lenient = this.lenientClassloading;
// Create types-and-qualifiers for, e.g.:
// ....example.Example
// ....example.ExampleClient
// ....example.ExampleClient$Builder
Class> serviceInterfaceClass = toClassUnresolved(errorHandler, c, serviceInterfaceName, lenient);
if (serviceInterfaceClass != null && serviceInterfaceClass.isInterface()) {
String serviceClient = serviceInterfaceName + "Client";
Class> serviceClientClass = toClassUnresolved(errorHandler, c, serviceClient, lenient);
if (serviceClientClass != null && serviceInterfaceClass.isAssignableFrom(serviceClientClass)) {
Class> serviceClientBuilderClass = toClassUnresolved(errorHandler, c, serviceClient + "$Builder", true);
if (serviceClientBuilderClass == null) {
serviceClientBuilderClass = toClassUnresolved(errorHandler, serviceClient + "Builder", lenient);
}
if (serviceClientBuilderClass != null
&& ClientBuilderBase.class.isAssignableFrom(serviceClientBuilderClass)) {
this.serviceTaqs.add(new ServiceTaqs(qualifiersArray,
serviceInterfaceClass,
serviceClientClass,
serviceClientBuilderClass));
// Use an "empty" ServiceTaqs as an indicator of demand for some kind of
// AbstractAuthenticationDetailsProvider (or a relevant builder).
serviceTaqsForAuth = new ServiceTaqs(qualifiersArray);
this.serviceTaqs.add(serviceTaqsForAuth);
}
}
}
// Create types-and-qualifiers for, e.g.:
// ....example.ExampleAsync
// ....example.ExampleAsyncClient
// ....example.ExampleAsyncClient$Builder
String serviceAsyncInterface = serviceInterfaceName + "Async";
Class> serviceAsyncInterfaceClass = toClassUnresolved(errorHandler, c, serviceAsyncInterface, lenient);
if (serviceAsyncInterfaceClass != null && serviceAsyncInterfaceClass.isInterface()) {
String serviceAsyncClient = serviceAsyncInterface + "Client";
Class> serviceAsyncClientClass = toClassUnresolved(errorHandler, c, serviceAsyncClient, lenient);
if (serviceAsyncClientClass != null
&& serviceAsyncInterfaceClass.isAssignableFrom(serviceAsyncClientClass)) {
Class> serviceAsyncClientBuilderClass =
toClassUnresolved(errorHandler, c, serviceAsyncClient + "$Builder", true);
if (serviceAsyncClientBuilderClass == null) {
serviceAsyncClientBuilderClass = toClassUnresolved(errorHandler, serviceAsyncClient + "Builder", lenient);
}
if (serviceAsyncClientBuilderClass != null
&& ClientBuilderBase.class.isAssignableFrom(serviceAsyncClientBuilderClass)) {
this.serviceTaqs.add(new ServiceTaqs(qualifiersArray,
serviceAsyncInterfaceClass,
serviceAsyncClientClass,
serviceAsyncClientBuilderClass));
if (serviceTaqsForAuth == null) {
// Use an "empty" ServiceTaqs as an indicator of demand for some kind of
// AbstractAuthenticationDetailsProvider (or a relevant builder).
this.serviceTaqs.add(new ServiceTaqs(qualifiersArray));
}
}
}
}
}
private Class> toClassUnresolved(Consumer super ClassNotFoundException> errorHandler,
String name,
boolean lenient) {
return toClassUnresolved(errorHandler, null, name, lenient);
}
private Class> toClassUnresolved(Consumer super ClassNotFoundException> errorHandler,
Class> referenceClass,
String name,
boolean lenient) {
if (referenceClass != null && referenceClass.getName().equals(name)) {
return referenceClass;
}
try {
return loadClassUnresolved(name);
} catch (ClassNotFoundException classNotFoundException) {
if (lenient) {
if (this.unloadableClassNames.add(name)) {
if (LOGGER.isLoggable(DEBUG)) {
LOGGER.log(DEBUG, "class " + name + " not found");
}
}
} else {
errorHandler.accept(classNotFoundException);
}
return null;
}
}
/*
* Static methods.
*/
private static void installAdpMachinery(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// ConfigAccessor
installConfigAccessor(event, bm, qualifiers);
// Supplier/ConfigFile
installConfigFile(event, bm, qualifiers);
// ConfigFileAuthenticationDetailsProvider
installConfigFileAdp(event, bm, qualifiers);
// InstancePrincipalsAuthenticationDetailsProvider
installInstancePrincipalsAdp(event, bm, qualifiers);
// OkeWorkloadIdentityAuthenticationDetailsProvider
installOkeWorkloadIdentityAdp(event, bm, qualifiers);
// ResourcePrincipalAuthenticationDetailsProvider
installResourcePrincipalAdp(event, bm, qualifiers);
// SessionTokenAuthenticationDetailsProvider
installSessionTokenAdps(event, bm, qualifiers);
// SimpleAuthenticationDetailsProvider
installSimpleAdp(event, bm, qualifiers);
// CascadingAdpSupplier
installCascadingAdp(event, bm, qualifiers);
// AbstractAuthenticationDetailsProvider, BasicAuthenticationDetailsProvider
installBasicAdp(event, bm, qualifiers);
}
private static void installConfigAccessor(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// ConfigAccessor
if (isUnsatisfied(bm, ConfigAccessor.class, qualifiers)) {
event.addBean()
.addTransitiveTypeClosure(MicroProfileConfigConfigAccessor.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i ->
produceConfigAccessor(i, qualifiers));
}
}
private static void installConfigFile(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// Supplier
if (isUnsatisfied(bm, SUPPLIER_CONFIGFILE_TYPE, qualifiers)) {
event.addBean()
.types(SUPPLIER_CONFIGFILE_TYPE)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i ->
ConfigFiles.configFileSupplier(i.select(ConfigAccessor.class, qualifiers).get()));
}
// ConfigFile
if (isUnsatisfied(bm, ConfigFile.class, qualifiers)) {
event.addBean()
.types(ConfigFile.class)
.qualifiers(qualifiers)
.scope(Singleton.class) // if this were Dependent, we'd read the file every time
.produceWith(i ->
i.select(SUPPLIER_CONFIGFILE_TYPE_LITERAL, qualifiers).get());
}
}
private static void installConfigFileAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// AdpSupplier, ConfigFileAdpSupplier
if (isUnsatisfied(bm, ADP_SUPPLIER_CONFIG_FILE_AUTHENTICATION_DETAILS_PROVIDER_TYPE, qualifiers)) {
event.addBean()
.types(ADP_SUPPLIER_CONFIG_FILE_AUTHENTICATION_DETAILS_PROVIDER_TYPE, ConfigFileAdpSupplier.class)
.qualifiers(withName(qualifiers, "config-file"))
.scope(Singleton.class)
.produceWith(i ->
new ConfigFileAdpSupplier(i.select(SUPPLIER_CONFIGFILE_TYPE_LITERAL, qualifiers).get()));
}
// ConfigFileAuthenticationDetailsProvider
if (isUnsatisfied(bm, ConfigFileAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(ConfigFileAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i ->
new ConfigFileAuthenticationDetailsProvider(i.select(ConfigFile.class, qualifiers).get()));
}
}
private static void installInstancePrincipalsAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// AdpSupplier, InstancePrincipalsAdpSupplier
if (isUnsatisfied(bm, ADP_SUPPLIER_INSTANCE_PRINCIPALS_AUTHENTICATION_DETAILS_PROVIDER_TYPE, qualifiers)) {
event.addBean()
.types(ADP_SUPPLIER_INSTANCE_PRINCIPALS_AUTHENTICATION_DETAILS_PROVIDER_TYPE, InstancePrincipalsAdpSupplier.class)
.qualifiers(withName(qualifiers, "instance-principals"))
.scope(Singleton.class)
.produceWith(i ->
new InstancePrincipalsAdpSupplier(
i.select(ConfigAccessor.class, qualifiers).get(),
i.select(InstancePrincipalsAuthenticationDetailsProviderBuilder.class, qualifiers)::get));
}
// InstancePrincipalsAuthenticationDetailsProviderBuilder
if (isUnsatisfied(bm, InstancePrincipalsAuthenticationDetailsProviderBuilder.class, qualifiers)) {
event.addBean()
.types(InstancePrincipalsAuthenticationDetailsProviderBuilder.class)
.qualifiers(qualifiers)
.scope(Dependent.class)
.produceWith(i ->
fire(i, InstancePrincipalsAuthenticationDetailsProvider.builder(), qualifiers));
}
// InstancePrincipalsAuthenticationDetailsProvider
if (isUnsatisfied(bm, InstancePrincipalsAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(InstancePrincipalsAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i ->
i.select(InstancePrincipalsAuthenticationDetailsProviderBuilder.class, qualifiers).get()
.build());
}
}
private static void installOkeWorkloadIdentityAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// AdpSupplier, OkeWorkloadIdentityAdpSupplier
if (isUnsatisfied(bm, ADPSUPPLIER_OKEWORKLOADIDENTITYAUTHENTICATIONDETAILSPROVIDER_TYPE, qualifiers)) {
event.addBean()
.types(ADPSUPPLIER_OKEWORKLOADIDENTITYAUTHENTICATIONDETAILSPROVIDER_TYPE, OkeWorkloadIdentityAdpSupplier.class)
.qualifiers(withName(qualifiers, "oke-workload-identity"))
.scope(Singleton.class) // or Dependent?
.produceWith(i ->
new OkeWorkloadIdentityAdpSupplier(
i.select(OkeWorkloadIdentityAuthenticationDetailsProviderBuilder.class, qualifiers)::get));
}
// OkeWorkloadIdentityAuthenticationDetailsProviderBuilder
if (isUnsatisfied(bm, OkeWorkloadIdentityAuthenticationDetailsProviderBuilder.class, qualifiers)) {
event.addBean()
.types(OkeWorkloadIdentityAuthenticationDetailsProviderBuilder.class)
.qualifiers(qualifiers)
.scope(Dependent.class)
.produceWith(i ->
fire(i, OkeWorkloadIdentityAuthenticationDetailsProvider.builder(), qualifiers));
}
// OkeWorkloadIdentityAuthenticationDetailsProvider
if (isUnsatisfied(bm, OkeWorkloadIdentityAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(OkeWorkloadIdentityAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i -> i.select(OkeWorkloadIdentityAuthenticationDetailsProviderBuilder.class, qualifiers).get()
.build());
}
}
private static void installResourcePrincipalAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// AdpSupplier, ResourcePrincipalAdpSupplier
if (isUnsatisfied(bm, ADP_SUPPLIER_RESOURCE_PRINCIPAL_AUTHENTICATION_DETAILS_PROVIDER_TYPE, qualifiers)) {
event.addBean()
.types(ADP_SUPPLIER_RESOURCE_PRINCIPAL_AUTHENTICATION_DETAILS_PROVIDER_TYPE, ResourcePrincipalAdpSupplier.class)
.qualifiers(withName(qualifiers, "resource-principal"))
.scope(Singleton.class) // or Dependent?
.produceWith(i ->
new ResourcePrincipalAdpSupplier(
i.select(ResourcePrincipalAuthenticationDetailsProviderBuilder.class, qualifiers)::get));
}
// ResourcePrincipalAuthenticationDetailsProviderBuilder
if (isUnsatisfied(bm, ResourcePrincipalAuthenticationDetailsProviderBuilder.class, qualifiers)) {
event.addBean()
.types(ResourcePrincipalAuthenticationDetailsProviderBuilder.class)
.qualifiers(qualifiers)
.scope(Dependent.class)
.produceWith(i ->
fire(i, ResourcePrincipalAuthenticationDetailsProvider.builder(), qualifiers));
}
// ResourcePrincipalAuthenticationDetailsProvider
if (isUnsatisfied(bm, ResourcePrincipalAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(ResourcePrincipalAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i -> i.select(ResourcePrincipalAuthenticationDetailsProviderBuilder.class, qualifiers).get()
.build());
}
}
private static void installSessionTokenAdps(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// SessionTokenAuthenticationDetailsProviderBuilder
if (isUnsatisfied(bm, SessionTokenAuthenticationDetailsProviderBuilder.class, qualifiers)) {
event.addBean()
.types(SessionTokenAuthenticationDetailsProviderBuilder.class)
.qualifiers(qualifiers)
.scope(Dependent.class)
.produceWith(i ->
fire(i, SessionTokenAuthenticationDetailsProvider.builder(), qualifiers));
}
// AdpSupplier, SessionTokenAdpSupplier (from builder)
if (isUnsatisfied(bm, ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE, qualifiers)) {
event.addBean()
.types(ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE, SessionTokenAdpSupplier.class)
.qualifiers(withName(qualifiers, "session-token-builder"))
.scope(Singleton.class)
.produceWith(i ->
SessionTokenAdpSupplier
.ofBuilderSupplier(i.select(SessionTokenAuthenticationDetailsProviderBuilder.class,
qualifiers)::get));
}
Annotation[] qualifiersPlusNamePlusOciConfig;
if (qualifiers.length == 0) {
qualifiersPlusNamePlusOciConfig =
new Annotation[] {OciConfig.Literal.INSTANCE, NamedLiteral.of("session-token-config-file")};
} else {
qualifiersPlusNamePlusOciConfig = new Annotation[qualifiers.length + 2];
System.arraycopy(qualifiers, 0, qualifiersPlusNamePlusOciConfig, 0, qualifiers.length);
qualifiersPlusNamePlusOciConfig[qualifiers.length] = OciConfig.Literal.INSTANCE;
qualifiersPlusNamePlusOciConfig[qualifiers.length + 1] = NamedLiteral.of("session-token-config-file");
}
// AdpSupplier, SessionTokenAdpSupplier (from ConfigFile)
if (isUnsatisfied(bm, ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE, qualifiersPlusNamePlusOciConfig)) {
event.addBean()
.types(ADP_SUPPLIER_SESSION_TOKEN_AUTHENTICATION_DETAILS_PROVIDER_TYPE, SessionTokenAdpSupplier.class)
.qualifiers(qualifiersPlusNamePlusOciConfig)
.scope(Singleton.class)
.produceWith(i ->
SessionTokenAdpSupplier.ofConfigFileSupplier(i.select(SUPPLIER_CONFIGFILE_TYPE_LITERAL,
qualifiers).get()));
}
// SessionTokenAuthenticationDetailsProvider (from builder)
if (isUnsatisfied(bm, SessionTokenAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(SessionTokenAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i -> {
try {
return
fire(i,
i.select(SessionTokenAuthenticationDetailsProviderBuilder.class, qualifiers).get().build(),
qualifiers);
} catch (IOException e) {
throw new UncheckedIOException(e.getMessage(), e);
}
});
}
// SessionTokenAuthenticationDetailsProvider (from ConfigFile)
if (isUnsatisfied(bm, SessionTokenAuthenticationDetailsProvider.class, qualifiersPlusNamePlusOciConfig)) {
event.addBean()
.types(SessionTokenAuthenticationDetailsProvider.class)
.qualifiers(qualifiersPlusNamePlusOciConfig)
.scope(Singleton.class)
.produceWith(i -> {
try {
return
fire(i,
new SessionTokenAuthenticationDetailsProvider(i.select(SUPPLIER_CONFIGFILE_TYPE_LITERAL,
qualifiers).get()
.get()),
qualifiers);
} catch (IOException e) {
throw new UncheckedIOException(e.getMessage(), e);
}
});
}
}
private static void installSimpleAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// AdpSupplier, SimpleAdpSupplier
if (isUnsatisfied(bm, ADP_SUPPLIER_SIMPLE_AUTHENTICATION_DETAILS_PROVIDER_TYPE, qualifiers)) {
event.addBean()
.types(ADP_SUPPLIER_SIMPLE_AUTHENTICATION_DETAILS_PROVIDER_TYPE, SimpleAdpSupplier.class)
.qualifiers(withName(qualifiers, "config"))
.scope(Singleton.class)
.produceWith(i ->
new SimpleAdpSupplier(i.select(ConfigAccessor.class, qualifiers).get(),
i.select(SimpleAuthenticationDetailsProviderBuilder.class,
qualifiers)::get));
}
// SimpleAuthenticationDetailsProviderBuilder
if (isUnsatisfied(bm, SimpleAuthenticationDetailsProviderBuilder.class, qualifiers)) {
event.addBean()
.types(SimpleAuthenticationDetailsProviderBuilder.class)
.qualifiers(qualifiers)
.scope(Dependent.class)
.produceWith(i ->
fire(i, SimpleAuthenticationDetailsProvider.builder(), qualifiers));
}
// SimpleAuthenticationDetailsProvider
if (isUnsatisfied(bm, SimpleAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(SimpleAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i ->
i.select(SimpleAuthenticationDetailsProviderBuilder.class, qualifiers).get().build());
}
}
private static void installCascadingAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// CascadingAdpSupplier
if (isUnsatisfied(bm, CascadingAdpSupplier.class, qualifiers)) {
event.addBean()
.addTransitiveTypeClosure(CascadingAdpSupplier.class)
.qualifiers(withName(qualifiers, "auto"))
.scope(Singleton.class)
.produceWith(i ->
new CascadingAdpSupplier(n -> adpSupplierFromStrategyDescriptor(i, n, qualifiers),
replaceElements(strategyDescriptors(i.select(ConfigAccessor.class,
qualifiers).get()),
n -> "auto".equals(n)
? DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS
: List.of(n))));
}
}
private static void installBasicAdp(AfterBeanDiscovery event, BeanManager bm, Annotation[] qualifiers) {
// AbstractAuthenticationDetailsProvider, BasicAuthenticationDetailsProvider
if (isUnsatisfied(bm, BasicAuthenticationDetailsProvider.class, qualifiers)) {
event.addBean()
.types(AbstractAuthenticationDetailsProvider.class, BasicAuthenticationDetailsProvider.class)
.qualifiers(qualifiers)
.scope(Singleton.class)
.produceWith(i ->
i.select(ADP_SUPPLIER_BASIC_AUTHENTICATION_DETAILS_PROVIDER_TYPE_LITERAL, qualifiers).get()
.get()
.orElseThrow(UnsatisfiedResolutionException::new));
}
}
/**
* A method that selects an {@link AdpSupplier AdpSupplier<? extends BasicAuthenticationDetailsProvider>} by
* strategy descriptor (and possibly additional qualifiers).
*
* @param i an {@link Instance}; must not be {@code null}
*
* @param sd the strategy descriptor; must not be {@code null}
*
* @param qualifiers additional qualifier {@link Annotation}s; must not be {@code null}
*
* @return an {@link AdpSupplier AdpSupplier<? extends BasicAuthenticationDetailsProvider>}; never {@code
* null}
*
* @exception NullPointerException if any argument is {@code null}
*
* @exception UnsatisfiedResolutionException if there is no such {@link AdpSupplier}
*/
private static AdpSupplier extends BasicAuthenticationDetailsProvider>
adpSupplierFromStrategyDescriptor(Instance