[[programmatic_access]]

== Programmatic access to container

The `BeanContainer` and `BeanManager` interfaces allow programmatic access to the CDI container.

`BeanContainer` provides features that can be implemented in more restricted environments.
It is available in {cdi_lite} environment, and therefore also in {cdi_full} environment.

`BeanManager` extends `BeanContainer` and provides additional features.
It is only available in {cdi_full} environment.

In {cdi_lite} environment, obtaining a `BeanManager` is possible, but only methods inherited from `BeanContainer` may be invoked.
Invoking `BeanManager` methods that are not inherited from `BeanContainer` results in non-portable behavior.

[[beancontainer]]

=== The `BeanContainer` object

The interface `jakarta.enterprise.inject.spi.BeanContainer` provides operations for obtaining contextual references for beans, along with many other operations of use to applications.

The container provides a built-in bean with bean type `BeanContainer`, scope `@Dependent` and qualifier `@Default`.
Thus, any bean may obtain an instance of `BeanContainer` by injecting it:

[source, java]
----
@Inject BeanContainer container;
----

The operations of `BeanContainer` may be called at any time during the execution of the application.
// TODO Full has restrictions on when BeanManager methods can be called, do we want to reflect them here in some way?

[[provider]]

==== Obtaining a reference to the CDI container

Application objects sometimes interact directly with the container via programmatic API call.
The abstract class `jakarta.enterprise.inject.spi.CDI` provides access to the `BeanContainer` as well providing lookup of bean instances.

[source, java]
----
public abstract class CDI<T> implements Instance<T> {
   public static CDI<Object> current() { ... }
   public static void setCDIProvider(CDIProvider provider);
   public abstract BeanContainer getBeanContainer();
   public abstract BeanManager getBeanManager();
}
----

An object may obtain a reference to the current container by calling `CDI.current()`.
`CDI.getBeanContainer()`, as well as other methods on `CDI`, may be called after the application initialization is completed until the application shutdown starts.
If methods on `CDI` are called at any other time, non-portable behavior results.

`CDI` implements `jakarta.enterprise.inject.Instance` and therefore might be used to perform programmatic lookup as defined in <<dynamic_lookup>>.
If no qualifier is passed to `CDI.select()` method, the `@Default` qualifier is assumed.

When `CDI.current()` is called, `getCDI()` method is called on `jakarta.enterprise.inject.spi.CDIProvider`.

The `CDIProvider` to use may be set by the application or container using the `setCDIProvider()` method.
If the `setCDIProvider()` has not been called, the service provider with highest priority of the service `jakarta.enterprise.inject.spi.CDIProvider` declared in META-INF/services is used.
The order of more than one `CDIProvider` with the same priority is undefined.
If no provider is available an `IllegalStateException` is thrown.

[source, java]
----
public interface CDIProvider extends Prioritized {
   CDI<Object> getCDI();
   default int getPriority();
}
----

* `getPriority()` method is inherited from <<prioritized, `Prioritized` interface>> and returns the priority for the `CDIProvider`.
If this method is not implemented the default priority `0` is assumed.


[[bm_obtain_contextual_reference]]

==== Obtaining a contextual reference for a bean

The method `BeanContainer.getReference()` returns a contextual reference for a given bean and bean type, as defined in <<contextual_reference>>.

[source, java]
----
public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx);
----

The first parameter is the `Bean` object representing the bean.
The second parameter represents a bean type that must be implemented by any client proxy that is returned.
The third parameter is an instance of `CreationalContext` that may be used to destroy any object with scope `@Dependent` that is created.

If the given type is not a bean type of the given bean, an `IllegalArgumentException` is thrown.

[[bm_obtain_injectable_reference]]

==== Obtaining an injectable reference

The method `BeanContainer.getInjectableReference()` returns an injectable reference for a given injection point, as defined in <<injectable_reference>>.

[source, java]
----
public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx);
----

The first parameter represents the target injection point.
The second parameter is an instance of `CreationalContext` that may be used to destroy any object with scope `@Dependent` that is created.

If typesafe resolution results in an unsatisfied dependency, the container must throw an `UnsatisfiedResolutionException`. If typesafe resolution results in an unresolvable ambiguous dependency, the container must throw an `AmbiguousResolutionException`.

Implementations of `Bean` usually maintain a reference to an instance of `BeanContainer`. When the `Bean` implementation performs dependency injection, it must obtain the contextual instances to inject by calling `BeanContainer.getInjectableReference()`, passing an instance of `InjectionPoint` that represents the injection point and the instance of `CreationalContext` that was passed to `Bean.create()`.

[[bm_obtain_creationalcontext]]

==== Obtaining a `CreationalContext`

An instance of `CreationalContext` for a certain instance of `Contextual` may be obtained by calling `BeanContainer.createCreationalContext()`.

[source, java]
----
public <T> CreationalContext<T> createCreationalContext(Contextual<T> contextual);
----

An instance of `CreationalContext` for a non-contextual object may be obtained by passing a null value to `createCreationalContext()`.

[[bm_obtain_bean_by_type]]

==== Obtaining a `Bean` by type

The method `BeanContainer.getBeans()` returns the set of beans which have the given required type and qualifiers and are available for injection in the module or library containing the class into which the `BeanContainer` was injected, according to the rules for candidates of typesafe resolution defined in <<performing_typesafe_resolution>>.

[source, java]
----
public Set<Bean<?>> getBeans(Type beanType, Annotation... qualifiers);
----

The first parameter is a required bean type. The remaining parameters are required qualifiers.

If no qualifiers are passed to `getBeans()`, the default qualifier `@Default` is assumed.

If the given type represents a type variable, an `IllegalArgumentException` is thrown.

If two instances of the same non repeating qualifier type are given, an `IllegalArgumentException` is thrown.

If an instance of an annotation that is not a qualifier type is given, an `IllegalArgumentException` is thrown.

[[bm_obtain_bean_by_name]]

==== Obtaining a `Bean` by name

The method `BeanContainer.getBeans()` which accepts a string returns the set of beans which have the given bean name and are available for injection in the module or library containing the class into which the `BeanContainer` was injected, according to the rules of name resolution defined in <<name_resolution>>.

[source, java]
----
public Set<Bean<?>> getBeans(String name);
----

The parameter is a bean name.

[[bm_resolve_ambiguous_dep]]

==== Resolving an ambiguous dependency

The method `BeanContainer.resolve()` applies the ambiguous dependency resolution rules defined in <<unsatisfied_and_ambig_dependencies>> to a set of `Bean` s.

[source, java]
----
public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans);
----

If the ambiguous dependency resolution rules fail (as defined in <<unsatisfied_and_ambig_dependencies>>, the container must throw an `AmbiguousResolutionException`.

`BeanContainer.resolve()` must return null if:

* null is passed to `resolve()`, or
* no beans are passed to `resolve()`.

[[bm_fire_event]]

==== Firing an event

The method `BeanContainer.getEvent()` returns an instance of `Event` with specified type `java.lang.Object` and specified qualifier `@Default`.

[source, java]
----
Event<Object> getEvent();
----

The returned instance can be used like a standard `Event` as described in <<events>>.

[[bm_observer_method_resolution]]

==== Observer method resolution

The method `BeanContainer.resolveObserverMethods()` resolves observer methods for an event according to the rules of observer resolution defined in <<observer_resolution>>.

[source, java]
----
public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers);
----

The first parameter of `resolveObserverMethods()` is the event object.
The remaining parameters are event qualifiers.

If the runtime type of the event object contains a type variable, an `IllegalArgumentException` is thrown.

If two instances of the same non repeating qualifier type are given, an `IllegalArgumentException` is thrown.

If an instance of an annotation that is not a qualifier type is given, an `IllegalArgumentException` is thrown.

[[bm_interceptor_resolution]]

==== Interceptor resolution

The method `BeanContainer.resolveInterceptors()` returns the ordered list of interceptors for a set of interceptor bindings and a type of interception and which are enabled in the module or library containing the class into which the `BeanContainer` was injected, as defined in <<interceptor_resolution>>.

[source, java]
----
List<Interceptor<?>> resolveInterceptors(InterceptionType type,
                                         Annotation... interceptorBindings);
----

If two instances of the same non repeating interceptor binding type are given, an `IllegalArgumentException` is thrown.

If no interceptor binding type instance is given, an `IllegalArgumentException` is thrown.

If an instance of an annotation that is not an interceptor binding type is given, an `IllegalArgumentException` is thrown.

[[bm_determining_annotation]]

==== Determining if an annotation is a qualifier type, scope type, stereotype or interceptor binding type

An application may test an annotation to determine if it is a qualifier type, scope type, stereotype or interceptor binding type, or determine if a scope type is a normal scope.

[source, java]
----
public boolean isScope(Class<? extends Annotation> annotationType);
public boolean isNormalScope(Class<? extends Annotation> scopeType);

public boolean isQualifier(Class<? extends Annotation> annotationType);
public boolean isInterceptorBinding(Class<? extends Annotation> annotationType);
public boolean isStereotype(Class<? extends Annotation> annotationType);
----

[[bm_obtain_active_context]]

==== Obtaining the active `Context` for a scope

The method `BeanContainer.getContext()` retrieves an active context object associated with the given scope, as defined in <<active_context>>.

[source, java]
----
public Context getContext(Class<? extends Annotation> scopeType);
----

[[bm_obtain_instance]]

==== Obtain an `Instance`

The method `BeanContainer.createInstance()` returns an `Instance<Object>` to request bean instances programmatically as described in <<dynamic_lookup>>.

The returned `Instance` object can only access instances of  beans that are available for injection in the module or library containing the class into which the `BeanContainer` was injected, according to the rules defined in <<typesafe_resolution>>.

[source, java]
----
Instance<Object> createInstance();
----

Instances of dependent scoped beans obtained with this `Instance` object must be explicitly released by calling `Instance.destroy()` method.

If no qualifier is passed to `Instance.select()` method, the `@Default` qualifier is assumed.
