While the use of “java:comp/ValidatorFactory” during application start may work for some Jakarta EE container implementations,
it may not work for others, at least not without some changes to
those implementation. The Jakarta EE specification only requires “java:comp/ValidatorFactory” (and other similar things in java:comp) to be available in the context of Jakarta EE component; namely EJBs and Servlets.
When an application calls into an EJB method, then the thread is running in the context of that Jakarta EE Component, and thus “java:comp/ValidatorFactory” will be available.
Similarly, when starting a specific EJB or servlet, the “java:comp” JNDI context will be well defined.
However, during application start when all the PersistenceUnits are being processed…. which java:comp JNDI name context is used?
Per the Jakarta EE specification, every EJB has a different “java:comp” JNDI context, and different things may be bound into each.
The point is, if during an EJB method call an EntityManager or EntityManagerFactory is used, then the “java:comp” JNDI context is well defined, but during application start, when we don’t know which EJB will use an EntityManager, then how does the Container
know which “java:comp” context to use? Will the container have even created all the “java:comp” contexts for all the EJBs in the application.
However, I will admit that “java:comp/ValidatoryFactory” and perhaps “java:comp/BeanManager” might be treated specially, as the value returned on lookup is likely the same for all Jakarta EE Components.
So, a Container implementation could create a “special” “java:comp” JNDI context that could be used during application start to make this work, even though the Jakarta EE Platform specification doesn’t seem to require it.
In other cases, this may not work. For example, “java:comp/UserTransaction” is NOT available for any EJB that has container managed transactions.
I’m not aware that Jakarta Persistence implementations would ever use this, but it just points out that “java:comp” may vary per component.
Similarly, CDI suffers from the same problem.
CDI beans are not defined as Jakarta EE Components in the Platform specification, at least not like servlets and EJBs.
That is, CDI bean do not have a defined “java:comp” JNDI context.
Instead, CDI bean just happen to always run in the context of either a servlet or EJB, so either the Web Container or EJB Container will have established a “java:comp” that CDI can access.
Since we are discussing the integration of CDI and Jakarta Persistence, it seems rather odd to rely on “java:comp”, which isn’t defined for either.
I’m not saying it wouldn’t work, but if we were to go with this approach, then the two specifications (and perhaps the Platform specification) should be updated to indicate that the “Container” needs to make some “java:comp” JNDI context available to
CDI and Persistence during application start, and what needs to be available in that context.
Tracy Burroughs
(tkb@xxxxxxxxxx)
WebSphere Application Server Development
IBM Rochester, Dept AAW, Bldg H315/050-2
2800 37th Street NW, Rochester MN 55901-4441
From: Arjan Tijms <arjan.tijms@xxxxxxxxxxx>
Sent: Tuesday, November 21, 2023 7:17 AM
To: Tracy Burroughs <tkb@xxxxxxxxxx>
Cc: jpa developer discussions <jpa-dev@xxxxxxxxxxx>; Scott Marlow <smarlow@xxxxxxxxxx>; Emily Jiang <emijiang6@xxxxxxxxxxxxxx>
Subject: [EXTERNAL] Re: [jpa-dev] Jakarta Persistence container responsibilities and impact on management of a transaction-scoped persistence context...
Tracy, just wondering what your comments are about this: - ValidatorFactory : how would the Jakarta Persistence provide obtain the one provided by the container?
InitialContext. doLookup("java: comp/ValidatorFactory")?See https: //jakarta. ee/specifications/bean-validation/3. 0/jakarta-bean-validation-spec-3. 0#integration-jakartaeeIt's
This Message Is From an External Sender
|
This message came from outside your organization.
|
|
|
Tracy, just wondering what your comments are about this:
- ValidatorFactory : how would the Jakarta Persistence provide obtain the one provided by the container?
It's a small piece of the entire reply, but it illustrates the tried and proven solution for a lot of other things you thought were concerns.
Hi,
Starting with the API the containers currently use:
EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map)
I wonder how the JPA provider could provide an implementation that could determine the two seemingly simple parameters without a loss of function.
- PersistenceUnitInfo : the provider can parse a persistence.xml file to create one of these, but the real trick is how does the provider know how to locate all of the persistence.xml files? The Jakara Persistence specification has very specific rules where
persistence.xml files may be located within an EAR or WAR, which a provider could seemly implement… but what if a vendor wishes to explode an EAR on disk when deploying an application; would a provider be expected to support the fact the files are not JAR’d
into an EAR any longer at runtime?
That's a very good point, that does get to the core of some of the issues.
First of all, indeed, in the original thread in the beginning of it, it was asked whether not much of the reason to have so much (duplicated) integration code inside the Jakarta EE container is just to support the concept of EARs. I know
we can't abandon them nilly willy, but there's an awful lot of complicated code needed to support these, with relatively little benefit. At least in my experience, I see most shops only use WARs today, or even the jar approach (such as in Helidon or Piranha).
Secondly, would a provider support the fact the files are not JAR’d? Another excellent point. The answer in practice is "yes", and this signals an omission in the Jakarta EE specifications. In Piranha for example we have a similar problem,
where at runtime we have references to ShrinkWrap archives in an isolated class loader, which obviously libraries that do scanning don't know about either.
It's not just Jakarta Persistence that needs to locate specific files, Jakarta Faces and Jakarta Pages for instance also need to do this. There, implementations resort to some classpath magic and heuristics.
URLs and input streams are just about abstract enough with some heuristics for WaSP and Mojarra to load from jar files, files on disk, and more abstract in-memory representations.
In their case, the container (WildFly, GlassFish, ...) does not have to know how to parse .tld files, or faces-config.xml files.
In case of Jakarta Persistence, knowledge about how to parse persistence.xml files is duplicated. Both the Jakarta Persistence implementation contains code to do this, and the container contains code to do this, which is IMHO architecturally
wrong.
What we probably need is one or more of the following things:
1. A better abstraction and specification of iterating over available files and their deployment units
2. A standard platform indexing service like Jandex
For (1), the Servlet API has a basic API that comes pretty close to this with "jakarta.servlet.ServletContext.getResourcePaths(String)". Indeed, library implementations like Weld use this to universally scan inside a web container.
For (2), this has been discussed before. It ties in with not having to duplicate support for complicated multi-release jars at various places, and to support build-time scanning and populating of such index. Many Jakarta EE servers/runtimes
among which WildFly, Open Liberty and Piranha already use Jandex.
The specification specifically supports this by providing PersistenceUnitInfo.getJarFileUrls(), and since the container is in control, it has the flexibility to place the application
on disk however it chooses. Or would vendors just no longer be able to provide this feature to their customers starting with Jakarta EE 11. I guess more specifically, this would just not work with CDI @Inject.
This is what Jakarta Faces has been doing to be able to inject the EntityManagerFactory in its own artefacts for a long time.
This is what was mentioned before as well; the CDI Bean<T> doesn't need to concern itself with "createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map)" at all. It just needs to grab the EntityManagerFactory that was created
in the traditional way from a well known location. It effectively automates the pattern that user code has been using for a long time to make the EntityManager or EntityManagerFactory injectable via a producer.
It's the reason why this one works and isn't a chicken-egg problem:
@ApplicationScoped
public class ApplicationEntityManager {
@Produces
@PersistenceContext(unitName = "some-pu-name")
private EntityManager entityManager;
}
PersistenceUnitInfo.getNewTempClassLoader() – How would the provider provide an implementation of this; only the container would know how to properly create a temporary classloader that can be used during bytcode modification (though perhaps no JPA providers
actually use this, and we should eliminate this method?)
PersistenceUnitInfo.getJtaDataSource()/getNonJTADatasource() – seems a provider could look this up?? But it is not quite that simple. JPA has some bootstrapping issues around this… creation of EntityManagorFactory instances must be done very early so that
the JPA provider can register class transformers, however, that generally must be done so early that the JNDI names spaces haven’t been fully determined, especially for java:comp. To accommodate this, container vendor must use “deferral” tricks to provide
usable datasources at a later time; I don’t expect that a JPA Implementation will be able to handle this. Perhaps when using CDI @Inject, the specification could just indicate that java:comp datasource references cannot be used?
For the Servlet container, java:comp is not very relevant anyway (in corresponds bassically to the entire application there), so that brings us again back to the realm of EARs and EJB, both which are pretty much "deprecated" in modern Jakarta
EE (or MicroProfile) CDI based code.
And that on its turn brings us back to the earlier statement of us having a ton of practically deprecated things in Jakarta EE that complicate other things massively (Interceptors and Concurrency face some of these issues too).
Properties Map : Here are things a container/vendor may include :
- BeanManager : perhaps this is an easy one for modern EE APIs to provide
- ValidatorFactory : how would the Jakarta Persistence provide obtain the one provided by the container?
InitialContext.doLookup("java:comp/ValidatorFactory")?
The Jakarta Specification has different rules for when running in Java SE vs Jakarta EE. This is optional, so there may be container vendor specific configuration options on when
to make this available; how would a JPA implementation know that?
Just think of Jakarta Faces using Jakarta Validation as well, and Jakarta Faces implementations have no issues with dealing with the container vendor specific configuration options.
- TransactionManager : perhaps an old API vs new API thing, but in the past each vendor had different ways of obtaining this.
Well, there simply should not be different ways to obtain that. EclipseLink for instance already tries all known vendor specific ways to obtain the TransactionManager.
- Other container/vendor specific properties. Container/Vendors may include various properties to control the default behavior when using their product… do they just lose this
level of control? For example, open-liberty configuration provides a way to configure enabling trace, and when that is specified, the container will pass through properties to the JPA provider to control that trace, so it is enabled appropriately and ends
up in the same trace logs as the rest of the product. How could this be achieved if the container is not the one creating the EntityManagerFactory?
Make that configuration available to the Jakarta Persistence implementation? The container also doesn't create, say, the FacesContext in Jakarta Faces, or the SecurityContext in Jakarta Security (just to name some objects). If those need
specific configuration, the container makes sure that config is available and passed on. We have a couple of implementation options like that in both Mojarra (Faces) and WaSP (Pages). It doesn't mean the container should be the one that creates all Faces and
Pages artefacts. That's the responsibility of Mojarra resp. WaSP.
|