Skip to content

Commit

Permalink
Arc - Revisit BeanContainer API
Browse files Browse the repository at this point in the history
  • Loading branch information
manovotn committed Sep 6, 2023
1 parent 339020d commit ef3c0b7
Show file tree
Hide file tree
Showing 23 changed files with 136 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ public void setBeanContainer(BeanContainer container) {
*/
public static void handle(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
if (streamHandlerClass != null) {
RequestStreamHandler handler = beanContainer.beanInstance(streamHandlerClass);
RequestStreamHandler handler = beanContainer.resolveBean(streamHandlerClass);
handler.handleRequest(inputStream, outputStream, context);
} else {
Object request = objectReader.readValue(inputStream);
RequestHandler handler = beanContainer.beanInstance(handlerClass);
RequestHandler handler = beanContainer.resolveBean(handlerClass);
Object response = handler.handleRequest(request, context);
objectWriter.writeValue(outputStream, response);
}
Expand Down Expand Up @@ -163,7 +163,7 @@ public void startPollLoop(ShutdownContext context, LaunchMode launchMode) {

@Override
protected Object processRequest(Object input, AmazonLambdaContext context) throws Exception {
RequestHandler handler = beanContainer.beanInstance(handlerClass);
RequestHandler handler = beanContainer.resolveBean(handlerClass);
return handler.handleRequest(input, context);
}

Expand All @@ -185,7 +185,7 @@ protected boolean isStream() {
@Override
protected void processRequest(InputStream input, OutputStream output, AmazonLambdaContext context)
throws Exception {
RequestStreamHandler handler = beanContainer.beanInstance(streamHandlerClass);
RequestStreamHandler handler = beanContainer.resolveBean(streamHandlerClass);
handler.handleRequest(input, output, context);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.lang.annotation.Annotation;

import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.ManagedContext;

/**
Expand All @@ -10,35 +12,41 @@
public interface BeanContainer {

/**
* Returns a bean instance for given bean type and qualifiers.
* <p/>
* This method follows standard CDI rules meaning that if there are two or more eligible beans, an ambiguous
* dependency exception is thrown.
* Note that the method is allowed to return {@code null} if there is no matching bean which allows
* for fallback implementations.
* A convenience method returning an instance of {@link ArcContainer} which is an entry point to the CDI container.
*
* @param type
* @param qualifiers
* @return a bean instance or {@code null} if no matching bean is found
* @return instance of {@link ArcContainer}
*/
default <T> T beanInstance(Class<T> type, Annotation... qualifiers) {
return beanInstanceFactory(type, qualifiers).create().get();
default ArcContainer container() {
return Arc.container();
}

/**
* This method is deprecated and will be removed in future versions.
* Use {@link #beanInstance(Class, Annotation...)} instead.
* </p>
* As opposed to {@link #beanInstance(Class, Annotation...)}, this method does <b>NOT</b> follow CDI
* resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter.
* Attempts to resolve a bean instance for given bean type and qualifiers.
* <p/>
* Note that the method deliberately returns {@code null} if there is no matching bean found allowing caller to
* detect such case and implement arbitrary fallback logic.
* <p/>
* Ambiguities are resolved as per CDI specification, possibly leading to an exception if there are multiple
* matching beans.
*
* @param type
* @param qualifiers
* @param beanType type of the bean
* @param beanQualifiers bean qualifiers
* @return a bean instance or {@code null} if no matching bean is found
*/
@Deprecated
default <T> T instance(Class<T> type, Annotation... qualifiers) {
return instanceFactory(type, qualifiers).create().get();
<T> T tryResolveBean(Class<T> beanType, Annotation... beanQualifiers);

/**
* Resolves a bean instance for given bean type and qualifiers.
* <p/>
* Performs standard CDI resolution meaning it either returns a bean instance or throws a corresponding exception
* if the dependency is either unsatisfied or ambiguous.
*
* @param beanType type of the bean
* @param beanQualifiers bean qualifiers
* @return a bean instance; never {@code null}
*/
default <T> T resolveBean(Class<T> beanType, Annotation... beanQualifiers) {
return container().select(beanType, beanQualifiers).get();
}

/**
Expand All @@ -55,20 +63,6 @@ default <T> T instance(Class<T> type, Annotation... qualifiers) {
*/
<T> Factory<T> beanInstanceFactory(Class<T> type, Annotation... qualifiers);

/**
* This method is deprecated and will be removed in future versions.
* Use {@link #beanInstanceFactory(Class, Annotation...)} instead.
* </p>
* As opposed to {@link #beanInstanceFactory(Class, Annotation...)}, this method does <b>NOT</b> follow CDI
* resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter.
*
* @param type
* @param qualifiers
* @return a bean instance factory, never {@code null}
*/
@Deprecated
<T> Factory<T> instanceFactory(Class<T> type, Annotation... qualifiers);

/**
* <pre>
* ManagedContext requestContext = beanContainer.requestContext();
Expand All @@ -89,6 +83,58 @@ default <T> T instance(Class<T> type, Annotation... qualifiers) {
*/
ManagedContext requestContext();

/**
* This method is deprecated and will be removed in future versions.
* Use {@link #tryResolveBean(Class, Annotation...)} instead.
* </p>
* Returns a bean instance for given bean type and qualifiers.
* <p/>
* This method follows standard CDI rules meaning that if there are two or more eligible beans, an ambiguous
* dependency exception is thrown.
* Note that the method is allowed to return {@code null} if there is no matching bean which allows
* for fallback implementations.
*
* @param type
* @param qualifiers
* @return a bean instance or {@code null} if no matching bean is found
*/
@Deprecated(forRemoval = true)
default <T> T beanInstance(Class<T> type, Annotation... qualifiers) {
return beanInstanceFactory(type, qualifiers).create().get();
}

/**
* This method is deprecated and will be removed in future versions.
* Use {@link #tryResolveBean(Class, Annotation...)} instead.
* </p>
* Use {@link #beanInstance(Class, Annotation...)} instead.
* </p>
* As opposed to {@link #beanInstance(Class, Annotation...)}, this method does <b>NOT</b> follow CDI
* resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter.
*
* @param type
* @param qualifiers
* @return a bean instance or {@code null} if no matching bean is found
*/
@Deprecated(forRemoval = true)
default <T> T instance(Class<T> type, Annotation... qualifiers) {
return instanceFactory(type, qualifiers).create().get();
}

/**
* This method is deprecated and will be removed in future versions.
* Use {@link #beanInstanceFactory(Class, Annotation...)} instead.
* </p>
* As opposed to {@link #beanInstanceFactory(Class, Annotation...)}, this method does <b>NOT</b> follow CDI
* resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter.
*
* @param type
* @param qualifiers
* @return a bean instance factory, never {@code null}
*/
@Deprecated(forRemoval = true)
<T> Factory<T> instanceFactory(Class<T> type, Annotation... qualifiers);

interface Factory<T> {

Factory<Object> EMPTY = new Factory<Object>() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.quarkus.arc.runtime;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.function.Supplier;

Expand All @@ -21,6 +20,17 @@ class BeanContainerImpl implements BeanContainer {
this.container = container;
}

@Override
public ArcContainer container() {
return container;
}

@Override
public <T> T tryResolveBean(Class<T> beanType, Annotation... beanQualifiers) {
Supplier<InstanceHandle<T>> instanceHandleSupplier = container.beanInstanceSupplier(beanType, beanQualifiers);
return instanceHandleSupplier == null ? null : instanceHandleSupplier.get().get();
}

@Override
public <T> Factory<T> beanInstanceFactory(Class<T> type, Annotation... qualifiers) {
Supplier<InstanceHandle<T>> handleSupplier = container.beanInstanceSupplier(type, qualifiers);
Expand All @@ -38,7 +48,8 @@ private <T> Factory<T> createFactory(Supplier<InstanceHandle<T>> handleSupplier,
LOGGER.debugf(
"No matching bean found for type %s and qualifiers %s. The bean might have been marked as unused and removed during build.",
type, Arrays.toString(qualifiers));
return new DefaultInstanceFactory<>(type);
// factories can return null if there is no bean, so we return empty factory
return (Factory<T>) Factory.EMPTY;
}
return new Factory<T>() {
@Override
Expand All @@ -64,28 +75,4 @@ public ManagedContext requestContext() {
return container.requestContext();
}

private static final class DefaultInstanceFactory<T> implements BeanContainer.Factory<T> {

private final Class<T> type;

DefaultInstanceFactory(Class<T> type) {
this.type = type;
}

@Override
public BeanContainer.Instance<T> create() {
try {
T instance = type.getDeclaredConstructor().newInstance();
return new BeanContainer.Instance<T>() {
@Override
public T get() {
return instance;
}
};
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void runLoadTask(Runnable runnable) {
}

public void setDomainForIdentityProvider(BeanContainer bc, RuntimeValue<SecurityDomain> domain) {
bc.beanInstance(ElytronSecurityDomainManager.class).setDomain(domain.getValue());
bc.resolveBean(ElytronSecurityDomainManager.class).setDomain(domain.getValue());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class FunqyCloudFunctionsBindingRecorder {

public void init(BeanContainer bc) {
beanContainer = bc;
objectMapper = beanContainer.beanInstance(ObjectMapper.class);
objectMapper = beanContainer.resolveBean(ObjectMapper.class);

for (FunctionInvoker invoker : FunctionRecorder.registry.invokers()) {
if (invoker.hasInput()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void initGrpcSecurityInterceptor(Map<String, List<String>> serviceClassTo

// service to full method names
var svcToMethods = new HashMap<String, List<String>>();
var services = container.beanInstance(GrpcContainer.class).getServices();
var services = container.resolveBean(GrpcContainer.class).getServices();
for (BindableService service : services) {
var className = getImplementationClassName(service);
var blockingMethods = serviceClassToBlockingMethod.get(className);
Expand All @@ -40,7 +40,7 @@ public void initGrpcSecurityInterceptor(Map<String, List<String>> serviceClassTo
}
}

container.beanInstance(GrpcSecurityInterceptor.class).init(svcToMethods);
container.resolveBean(GrpcSecurityInterceptor.class).init(svcToMethods);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public Supplier<JPAConfig> jpaConfigSupplier(HibernateOrmRuntimeConfig config) {
}

public void startAllPersistenceUnits(BeanContainer beanContainer) {
beanContainer.beanInstance(JPAConfig.class).startAll();
beanContainer.resolveBean(JPAConfig.class).startAll();
}

public Function<SyntheticCreationalContext<SessionFactory>, SessionFactory> sessionFactorySupplier(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class InfinispanRecorder {

public BeanContainerListener configureInfinispan(@RelaxedValidation Map<String, Properties> properties) {
return container -> {
InfinispanClientProducer instance = container.beanInstance(InfinispanClientProducer.class);
InfinispanClientProducer instance = container.resolveBean(InfinispanClientProducer.class);
instance.setProperties(properties);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void setAttributes(
String serviceName,
String serviceVersion) {

DelayedAttributes delayedAttributes = beanContainer.beanInstance(DelayedAttributes.class);
DelayedAttributes delayedAttributes = beanContainer.resolveBean(DelayedAttributes.class);

delayedAttributes.setAttributesDelegate(Resource.getDefault()
.merge(Resource.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public Consumer<VertxOptions> getVertxTracingOptions() {

/* RUNTIME INIT */
public void setupVertxTracer(BeanContainer beanContainer) {
OpenTelemetry openTelemetry = beanContainer.beanInstance(OpenTelemetry.class);
OpenTelemetry openTelemetry = beanContainer.resolveBean(OpenTelemetry.class);
OpenTelemetryVertxTracer openTelemetryVertxTracer = new OpenTelemetryVertxTracer(List.of(
new HttpInstrumenterVertxTracer(openTelemetry),
new EventBusInstrumenterVertxTracer(openTelemetry),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,22 @@ public String toString() {
@Override
public BeanInstance<T> createInstance() {
BeanContainer.Instance<T> instance;
try {
instance = factory.create();
return new BeanInstance<T>() {
@Override
public T getInstance() {
return instance.get();
}

@Override
public void close() {
instance.close();
}
};
} catch (Exception e) {
if (factory.getClass().getName().contains("DefaultInstanceFactory")) {
throw new IllegalArgumentException(
"Unable to create class '" + targetClassName
+ "'. To fix the problem, make sure this class is a CDI bean.",
e);
}
throw e;
instance = factory.create();
if (instance == null) {
throw new IllegalArgumentException(
"Unable to create class '" + targetClassName
+ "'. To fix the problem, make sure this class is a CDI bean.");
}
return new BeanInstance<T>() {
@Override
public T getInstance() {
return instance.get();
}

@Override
public void close() {
instance.close();
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public RuntimeValue<Deployment> createDeployment(DeploymentInfo info,
}

CurrentRequestManager
.setCurrentRequestInstance(new QuarkusCurrentRequest(beanContainer.beanInstance(CurrentVertxRequest.class)));
.setCurrentRequestInstance(new QuarkusCurrentRequest(beanContainer.resolveBean(CurrentVertxRequest.class)));

BlockingOperationSupport.setIoThreadDetector(new BlockingOperationSupport.IOThreadDetector() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public WebAuthnRecorder(RuntimeValue<HttpConfiguration> httpConfiguration, Runti
}

public void setupRoutes(BeanContainer beanContainer, RuntimeValue<Router> routerValue, String prefix) {
WebAuthnSecurity security = beanContainer.beanInstance(WebAuthnSecurity.class);
WebAuthnAuthenticationMechanism authMech = beanContainer.beanInstance(WebAuthnAuthenticationMechanism.class);
IdentityProviderManager identityProviderManager = beanContainer.beanInstance(IdentityProviderManager.class);
WebAuthnSecurity security = beanContainer.resolveBean(WebAuthnSecurity.class);
WebAuthnAuthenticationMechanism authMech = beanContainer.resolveBean(WebAuthnAuthenticationMechanism.class);
IdentityProviderManager identityProviderManager = beanContainer.resolveBean(IdentityProviderManager.class);
WebAuthnController controller = new WebAuthnController(security, config.getValue(), identityProviderManager, authMech);
Router router = routerValue.getValue();
BodyHandler bodyHandler = BodyHandler.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
public class SmallRyeGraphQLRecorder {

public RuntimeValue<Boolean> createExecutionService(BeanContainer beanContainer, Schema schema) {
GraphQLProducer graphQLProducer = beanContainer.beanInstance(GraphQLProducer.class);
GraphQLProducer graphQLProducer = beanContainer.resolveBean(GraphQLProducer.class);
GraphQLSchema graphQLSchema = graphQLProducer.initialize(schema);
return new RuntimeValue<>(graphQLSchema != null);
}
Expand Down
Loading

0 comments on commit ef3c0b7

Please sign in to comment.