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

Draft changes for packaging/deployment/lifecycle. #540

Closed
wants to merge 3 commits into from
Closed
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
2 changes: 1 addition & 1 deletion spec/src/main/asciidoc/architecture.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ For example, the container might be a Jakarta EE container or an embeddable Jaka
<<injection_and_resolution>>, <<contexts>>, <<lifecycle>>, <<events>> and <<interceptor_resolution>> define the semantics and behavior of the services, the responsibilities of the container implementation and the APIs used by the application to interact directly with the container.
{cdi_full} adds <<decorators>>.

<<packaging_deployment_lite>> and <<packaging_deployment>> defines how applications that use the services defined by this specification must be packaged into bean archives, and the responsibilities of the container implementation at application initialization time.
<<packaging_deployment>> and <<packaging_deployment_full>> defines how applications that use the services defined by this specification must be packaged into bean archives, and the responsibilities of the container implementation at application initialization time.

<<spi>>, <<spi_lite>>, <<contextual>> and <<context>> define an SPI that allows portable extensions to integrate with the container.

Expand Down
4 changes: 2 additions & 2 deletions spec/src/main/asciidoc/cdi-spec.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ include::core/beanmanager_lite.asciidoc[]

include::core/spi_lite.asciidoc[]

include::core/packagingdeployment_lite.asciidoc[]
include::core/packagingdeployment.asciidoc[]

:leveloffset: -1

Expand All @@ -81,7 +81,7 @@ include::core/events_full.asciidoc[]

include::core/spi.asciidoc[]

include::core/packagingdeployment.asciidoc[]
include::core/packagingdeployment_full.asciidoc[]

:leveloffset: -1

Expand Down
5 changes: 2 additions & 3 deletions spec/src/main/asciidoc/core/injectionandresolution.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ The container is not required to support circular chains of dependencies where e

Beans and their clients may be deployed in _modules_ in a module architecture.
manovotn marked this conversation as resolved.
Show resolved Hide resolved
In a module architecture, certain modules are considered _bean archives_.
The library may be an explicit bean archive or an implicit bean archive, as defined in <<bean_archive>>.
In {cdi_lite}, libraries that are bean archives are always implicit bean archives.
// TODO this all depends on how we define packaging and deployment for Lite, so this paragraph must be revisited!
In {cdi_lite}, a library that is a bean archive is always an implicit bean archive, as defined in <<bean_archive>>.
manovotn marked this conversation as resolved.
Show resolved Hide resolved
Other kinds of bean archives exist in {cdi_full}.

A bean packaged in a certain module is available for injection, lookup and name resolution to classes packaged in some other module if and only if the bean class of the bean is required to be _accessible_ to the other module by the class accessibility requirements of the module architecture.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

In addition to rules defined in <<selection>>, the following rules apply.

An alternative is not available for injection, lookup or name resolution to classes in a module unless the module is a bean archive and the alternative is explicitly _selected_ for the bean archive or the application.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this sentence needs to be added back. I'll do it locally, just FYI.

A library may be an explicit bean archive or an implicit bean archive, as defined in <<bean_archive_full>>.

[[declaring_selected_alternatives_full]]

Expand Down
181 changes: 33 additions & 148 deletions spec/src/main/asciidoc/core/packagingdeployment.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,50 @@

== Packaging and deployment

When an application is started, the container must perform _bean discovery_, detect definition errors and deployment problems and raise events that allow portable extensions to integrate with the deployment lifecycle.
Before an application is started, or during application startup, the container must perform _bean discovery_, execute build compatible extensions, and detect definition errors and deployment problems.

Bean discovery is the process of determining:

* The bean archives that exist in the application, and the beans they contain
* Which alternatives, interceptors and decorators are _enabled_ for each bean archive
* The _ordering_ of enabled interceptors and decorators
* Bean archives within application, and any beans contained within them
* Which alternatives and interceptors are _enabled_
* The _ordering_ of enabled interceptors


Additional beans may be registered programmatically with the container by the application or a portable extension after the automatic bean discovery completes.
Portable extensions may even integrate with the process of building the `Bean` object for a bean, to enhance the container's built-in functionality.
Additional beans may be registered programmatically via <<spi_lite>>.

[[bean_archive]]

=== Bean archives

Bean classes of enabled beans must be deployed in _bean archives_.

A bean archive has a _bean discovery mode_ of `all`, `annotated` or `none`. A bean archive which contains a `beans.xml` file with no version has a default bean discovery mode of `all`. A bean archive which contains a `beans.xml` file with version 1.1 (or later) must specify the `bean-discovery-mode` attribute. The default value for the attribute is `annotated`.
A bean archive has a _bean discovery mode_ of either `annotated` or `none`.
This is governed by presence of `beans.xml` file which can be either empty or it can declare the `bean-discovery-mode` attribute.
Default value for this attribute is `annotated`.

An archive which:

* contains a `beans.xml` file with the `bean-discovery-mode` of `none`, or,
* contains an extension and no `beans.xml` file
* contains a portable or build compatible extension and no `beans.xml` file

is not a bean archive.

An _explicit bean archive_ is an archive which contains a `beans.xml` file:

* with a version number of `1.1` (or later), with the `bean-discovery-mode` of `all`, or,
* with no version number.

An _implicit bean archive_ is:

* an archive which contains a `beans.xml` file that is empty, or,
* any other archive which contains one or more bean classes with a bean defining annotation as defined in <<bean_defining_annotations>>.
* an archive which contains a `beans.xml` file that has `bean-discovery-mode` attribute set to `annotated`

When determining which archives are bean archives, the container must consider:

* Library jars
* Directories in the JVM classpath

Non Jakarta EE containers may or may not provide support for war, EJB jar or rar bean archives.
When determining which archives are bean archives, the container must consider all archives that constitute the application.
Implementations are encouraged to document how the candidate JAR archives are found in more detail.

The `beans.xml` file must be named:

* `META-INF/beans.xml`.

For compatibility with CDI versions prior to 4.0, {cdi_full} products must contain an option that causes an archive with empty beans.xml to be considered an explicit bean archive.

The container searches for beans in all bean archives in the application classpath.
The container searches for beans in all bean archives discovered as described above.

If a bean class is deployed in two different bean archives, non-portable behavior results.
Portable applications must deploy each bean class in no more than one bean archive.

Explicit bean archives may contain classes which are not deployed as beans.
For example a bean archive might contain an abstract class not annotated with `@Decorator`.

Implicit bean archives are likely to contain classes which are not deployed as beans.

An extension may be deployed in any archive, including those that are not bean archives.
Expand All @@ -68,28 +54,16 @@ An extension may be deployed in any archive, including those that are not bean a

=== Application initialization lifecycle

When an application is started, the container performs the following steps:

* First, the container must search for service providers for the service `jakarta.enterprise.inject.spi.Extension` defined in <<init_events>>, instantiate a single instance of each service provider, and search the service provider class for observer methods of initialization events.
* Next, the container must fire an event of type `BeforeBeanDiscovery`, as defined in <<before_bean_discovery>>.
* Next, the container must perform type discovery, as defined in <<type_discovery_steps>>.
* Next, the container must fire an event of type `AfterTypeDiscovery`, as defined in <<after_type_discovery>>.
* Next, the container must perform bean discovery, as defined in <<bean_discovery_steps>>.
* Next, the container must fire an event of type `AfterBeanDiscovery`, as defined in <<after_bean_discovery>>, and abort initialization of the application if any observer registers a definition error.
* Next, the container must detect deployment problems by validating bean dependencies and specialization and abort initialization of the application if any deployment problems exist, as defined in <<exceptions>>.
* Next, the container must fire an event of type `AfterDeploymentValidation`, as defined in <<after_deployment_validation>>, and abort initialization of the application if any observer registers a deployment problem.
* Finally, the container begins directing requests to the application.

// TODO related to https://github.com/eclipse-ee4j/cdi/issues/482
// also related to https://github.com/eclipse-ee4j/cdi/issues/496
// Capture init process WRT build compatible extensions + type discovery + bean discovery
// see <<initialization>> for format that is used for CDI Full

[[shutdown]]

=== Application shutdown lifecycle

When an application is stopped, the container performs the following steps:

* First, the container must destroy all contexts.
* Finally, the container must fire an event of type `BeforeShutdown`, as defined in <<before_shutdown>>.

When an application is stopped, the container must destroy all contexts.

[[type_bean_discovery]]

Expand All @@ -102,93 +76,11 @@ The container automatically discovers managed beans (according to the rules of <
==== Type discovery

First the container must discover types.
The container discovers:

* each Java class, interface (excluding the special kind of interface declaration _annotation type_) or enum deployed in an explicit bean archive, and
* each Java class with a bean defining annotation in an implicit bean archive.

that is not excluded from discovery by an _exclude filter_ as defined in <<exclude_filters>>.

Then, for every type discovered the container must create an `AnnotatedType` representing the type and fire an event of type `ProcessAnnotatedType`, as defined in <<process_annotated_type>>.

If an extension calls `BeforeBeanDiscovery.addAnnotatedType()` or `AfterTypeDiscovery.addAnnotatedType()`, the type passed must be added to the set of discovered types and the container must fire an event of type `ProcessSyntheticAnnotatedType` for every type added, as defined in <<process_annotated_type>>+

[[exclude_filters]]

==== Exclude filters

Exclude filters are defined by `<exclude>` elements in the `beans.xml` for the bean archive as children of the `<scan>` element.
By default an exclude filter is active. If the exclude filter definition contains:

* a child element named `<if-class-available>` with a `name` attribute, and the classloader for the bean archive can not load a class for that name, or
* a child element named `<if-class-not-available>` with a `name` attribute, and the classloader for the bean archive can load a class for that name, or
* a child element named `<if-system-property>` with a `name` attribute, and there is no system property defined for that name, or
* a child element named `<if-system-property>` with a `name` attribute and a `value` attribute, and there is no system property defined for that name with that value.

then the filter is inactive.

If the filter is active, and:

* the fully qualified name of the type being discovered matches the value of the name attribute of the exclude filter, or
* the package name of the type being discovered matches the value of the name attribute with a suffix ".*" of the exclude filter, or
* the package name of the type being discovered starts with the value of the name attribute with a suffix ".**" of the exclude filter

then we say that the type is excluded from discovery.

For example, consider the follow `beans.xml` file:

[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
bean-discovery-mode="all" version="3.0">

<scan>
<exclude name="com.acme.rest.*" />

<exclude name="com.acme.faces.**">
<if-class-not-available name="jakarta.faces.context.FacesContext"/>
</exclude>

<exclude name="com.acme.verbose.*">
<if-system-property name="verbosity" value="low"/>
</exclude>

<exclude name="com.acme.ejb.**">
<if-class-available name="jakarta.enterprise.inject.Model"/>
<if-system-property name="exclude-ejbs"/>
</exclude>
</scan>

</beans>
----

The first exclude filter will exclude all classes in `com.acme.rest` package. The second exclude filter will exclude all classes in the `com.acme.faces` package, and any subpackages, but only if JSF is not available. The third exclude filter will exclude all classes in the `com.acme.verbose` package if the system property `verbosity` has the value `low`. The fourth exclude filter will exclude all classes in the `com.acme.ejb` package, and any subpackages if the system property `exclude-ejbs` is set (with any value) and at the same time, the `jakarta.enterprise.inject.Model` class is available to the classloader.


[[trimmed_bean_archive]]

==== Trimmed bean archive

An explicit bean archive may be marked as 'trimmed' by adding the `<trim />` element to its `beans.xml` file:

[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
version="3.0">

<trim/>
</beans>
----

If an explicit bean archive contains the `<trim/>` element in its `beans.xml` file, types that don't have either a bean defining annotation (as defined in <<bean_defining_annotations>>) or any scope annotation, are removed from the set of discovered types.

The container discovers each Java class with a bean defining annotation in an implicit bean archive.

// TODO at this point, we should probably mention build compatible extensions and how you can get notified of events and change these types
// we should mention Enhancement phase here and link to the relevant doc part
// related to https://github.com/eclipse-ee4j/cdi/issues/483

[[bean_discovery_steps]]

Expand All @@ -198,32 +90,25 @@ For every type in the set of discovered types (as defined in <<type_discovery_st

* inspect the type metadata to determine if it is a bean, and then
* detect definition errors by validating the class and its metadata, and then
* if the class is a managed bean, fire an event of type `ProcessInjectionPoint` for each injection point in the class, as defined in <<process_injection_point>>, and then
* if the class is a managed bean, fire an event of type `ProcessInjectionTarget`, as defined in <<process_injection_target>>, and then
* determine which alternatives, interceptors and decorators are enabled, according to the rules defined in <<enablement>>, <<enabled_interceptors>> and <<enabled_decorators>>, and then
* if the class is an enabled bean, interceptor or decorator, fire an event of type `ProcessBeanAttributes`, as defined in <<process_bean_attributes>>, and then
* if the class is an enabled bean, interceptor or decorator and if `ProcessBeanAttributes.veto()` wasn't called in previous step, fire an event which is a subtype of `ProcessBean`, as defined in <<process_bean>>.
* determine which alternatives and interceptors are enabled, according to the rules defined in <<enablement>>.
// TODO mention any events we fire for build compatible extensions at this point - Processing
// e.g. if we have an equivalent of ProcessBeanAttributes and/or ProcessBean
// related to https://github.com/eclipse-ee4j/cdi/issues/483

For each enabled bean, the container must search the class for producer methods and fields, as defined in <<producer_method>> and in <<producer_field>>, including resources, and for each producer:

* if it is a producer method, fire an event of type `ProcessInjectionPoint` for each injection point in the method parameters, as defined in <<process_injection_point>>, and then
* fire an event of type `ProcessProducer`, as defined in <<process_producer>>, and then
* if the producer method or field is enabled, fire an event of type `ProcessBeanAttributes`, as defined in <<process_bean_attributes>>, and then
* if the producer method or field is enabled and if `ProcessBeanAttributes.veto()` wasn't called in previous step, fire an event which is a subtype of `ProcessBean`, as defined in <<process_bean>>.

For each enabled bean, the container must search for disposer methods as defined in <<disposer_method>>, and for each disposer method:

* fire an event of type `ProcessInjectionPoint` for each injection point in the method parameters, as defined in <<process_injection_point>>.
// TODO mention any events we fire for build compatible extensions at this point - Processing
// e.g. if we have an equivalent of ProcessInjectionPoint and/or ProcessProducer and/or ProcessBeanAttributes and/or ProcessBean
// related to https://github.com/eclipse-ee4j/cdi/issues/483

For each enabled bean, the container must search the class for observer methods, and for each observer method:

* fire an event of type `ProcessInjectionPoint` for each injection point in the method parameters, as defined in <<process_injection_point>>, and then
* fire an event of type `ProcessObserverMethod`, as defined in <<process_observer_method>>.
// TODO mention build compatible extension equivalent - Processing
// e.g. if we have an equivalent of ProcessObserverMethod
// related to https://github.com/eclipse-ee4j/cdi/issues/483

Then, the container registers the `Bean` and `ObserverMethod` objects:

* For each enabled bean that is not an interceptor or decorator, the container registers an instance of the `Bean` interface defined in <<bean>>.
* For each enabled bean that is not an interceptor, the container registers an instance of the `Bean` interface defined in <<bean>>.
* For each enabled interceptor, the container registers an instance of the `Interceptor` interface defined in <<interceptor>>.
* For each enabled decorator, the container registers an instance of the `Decorator` interface defined in <<decorator>>.
* For each observer method of every enabled bean, the container registers an instance of the `ObserverMethod` interface defined in <<observer_method>>.

Loading