Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
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? 

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.

Kind regards,
Arjan Tijms




 

On Sat, 4 Nov 2023 at 17:54, Arjan Tijms <arjan.tijms@xxxxxxxxxxx> wrote:
Hi,
 


Hi,

On Fri, 3 Nov 2023 at 21:05, Tracy Burroughs <tkb@xxxxxxxxxx> wrote:

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.


What if the Bean<T>.create() method grabs the already created EntityManagerFactory from JNDI? (as per https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1#obtaining-an-entity-manager-in-the-jakarta-ee-environment)

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.

Kind regards,
Arjan Tijms

 

Back to the top