I want to create a modular(plugin-like) application that uses JPA as its persistence abstraction, and this application should be extensible by third parties.
The catch is that I want this application and its plugins to be easily portable to other databases/JPA providers, so the third party vendors can't know anything about the used JPA provider(or databases connections), they can only extend the persistence layer by defining new entities to be stored in the main app persistence unit(this would allow one to switch databases without having to reconfigure every module to point to the new db).
Can I do something like that with JPA? I can do it easily with .NET's nHibernate(and probably with Hibernate) but I prefer to program against JPA since I'm in a Java EE environment.
Funnily, I have made exactly this using OSGi, Equinox and EclipseLink, but it's not trivial. Essentially, a custom bundle takes all persistence.xml files from all resolved bundles, merges them into a single persistence.xml that is used to initialize the EclipseLink Persistence Provider. Additionally, there are some custom hooks that allow me to specify f.e. connection options separately for development and deployment.
Drawbacks: say bye-bye to container-managed persistence, but it's still possible to join transactions. Also, some tools react violently to cross-bundle entity references. Also, if you add a new bundle with new entities, you will need to have set up the database with the proper tables, references, indexes & constraints beforehand.
Advantages: Drop in new bundle, see it work at once, dynamically, without restarting the container.
I am also researching how to do JPA in a modular way (in the Netbeans module system or in an OSGI container).
One thing you should be aware of is that if you need to build a central, big EntityManagerFactory (by the central persistence module) than you may have some issues if your application is big:
If the persistence module needs to react to module startup/shutdown events, it needs to rebuild the central EntityManagerFactory when a module is added or removed. If the application is big (lots of classes), rebuilding the EntityManagerFactory is slow and costly.
The application needs not storing references to the EntityManagerFactory because if a module is added/removed the old one becomes stale. The application should work with very short-lived EntityManager and always get the EntityManagerFactory.
It may be more flexible to build EntityManagerFactories for every JPA-using module, but that may need more memory and may take up more computing power until all of the EntityManagerFactories are created for every module (although EntityManager factories may be created on-demand by your central JPA service).
Dynamic-JPA (http://www.dynamicjava.org/projects/dynamic-jpa) may help if you work in an OSGI container.
Related
I have a module with a persistence.xml for several classes. I have an application which uses that module, but wants to augment that EntityManagerFactory with a couple of other classes that are specific to this application and don't belong in the module.
If I create a persistence.xml in the application that overrides the persistence unit it does not work reliably (it does work when run from IntelliJ's debugger, but does not work when invoked using a maven appassemble package) because it seems the rules governing which of the persistence.xml files in the various jars takes effect are beyond my understanding, and probably difficult to control.
If I create a second persistence unit to contain only the new tables, then I will need multiple EntityManagerFactory-s to retrieve the various object types in JPA. I do not currently need to execute queries that join objects from the library module with objects specific to the application module, but I am reasonably certain it would be impossible if the objects were in different persistence units.
Even worse, using multiple persistence units appears to make derby angry because the second persistence unit fails when it finds that the database is already opened (by the first persistence unit; why derby can't share in the same JVM I don't know, and there may be workarounds I do not know).
What are the dangers if you have persistence units that overlap? ( both units have objects mapped to the same table in the same database )
What are the proper guidelines for dealing with persistence units from multiple .jars ?
Using standard JPA functionality, there is no means to supply additional entity classes in runtime.
The approach I recommend is to remove persistence.xml from your modules and create orm files, which contain the same entities as original persistence.xml files.
Then create single persistence unit in the application and include orm files from all required modules.
This is what has always worked for me an it seems the only reasonable approach with current JPA version.
This way, you end up with single persistence unit, and still having modular and extensible sets of entities.
I have a Java web application using Spring, Hibernate and Wicket connecting to a MySQL database that I'd like to refactor and separate into several applications. I started by using Maven's multi-module system but in reality each of the applications would have its own release cycle, so I've ditched that effort now and I'm looking at creating individual projects for each of them. They will all continue to connect to the same database so I was going to move the model classes into a project of their own which can be used as a dependency.
I have a few questions regarding this setup:
Is moving the model classes to their own project a typical solution to the multiple apps/single database problem, or is there another way?
Is there a nice way of ensuring all the applications are using the same version of the model dependency?
Should I also include any base daos and services in this core project that each application could use or extend, or should I just include my GenericHibernateDao and let each application create its own daos and services? Obviously I will want to avoid changing this project as much as possible as it will require a new release of all the applications depending on it.
Is there any Hibernate related config I would need to change, such as connection pooling? Does it matter if each app has its own pool or should they share one? I'm not using caching at the moment, but I understand if I wanted to I would need a distributed cache?
How would I share application config such as db params, email host, sms gateway etc. between applications? Is there any way of defining them once somewhere to ensure they are all pointed at the same db?
Are there any other gotchas I may encounter further down the road with this setup, either with Maven or during deployment? Any tips or best practises I should follow?
These have been usual scenario with me, what I have usually done is..
- DAOs, Conn. Pool Management, Fail over related code can be managed by writing separate module [jar]
- You can then use this module in components as you have mentioned.
With this you will have separate connection pool for each of your component.
While working on a modular system architecture for an enterprise application I run into some problems with database initialization. We have a core library that provides base entities and base configuration. On top of this core several modules are build. They are pluggable and can have their own entities and configuration. Some characteristics:
Configuration, like system properties, resourcebundles, etc, are all stored in the database.
JPA is used to make the system database independent.
System runs on Java SE
Every module can bring its own tables, but they can also require to populate the core property table, or the core resourcebundle table. So somehow we need some mechanisme to run a DDL and DML initialization for the database. Some options:
Create simple sql scripts. Disadvantage is that they must be database independent and perhaps this is not the most developer friendly. Unless we can generate them with some DB diff tool?
Use Java classes to initialize via JPQL?
Store configuration in files? This avoids a lot (but not all) of configuration DML.
Use some tool like liquibase?
What would be the best practice for this (or a similar) problem?
Use a database for store all configuration data is the best option. Many products, such as WebSphere Portal or Liferay use a database to store the configuration data for each portlet or even for theme. Don't forget to include those that are used as part of an SOA and Business Rules.
Therefore, the use of SQL scripts is also the best choice. However, if you require very specific features of SQL, you may need to create several versions of same script for each database management system.
I am currently in an project that has the same idea of modules that add functionality to a core system.
Generally we are using maven and multiple src folders as well as maven profiles and different builds to be able to generate a deployable with different modules. (we do not have the necessity to push out single modules and install them later on - this might be different in your project. We just build different versions with different modules.)
Anyway, for the DB we are using liquibase. Firstly to manage the DB and the changes done to it. But also (and this might be helpful to you) to include/generate another SQL script that adds tables for the modules.
Each module has its own changeset-file that includes everything that is necessary for that module (also in different versions as the modules evolve through time). These can then be applied or not.
So, I think liquibase could also be useful in your case (even though it's main purpose is to manage DB changes).
I know there are quite a few questions on my topics already, but I haven't really been completely satisfied with any of the answers. It's also difficult to find decent information on the web, so I'm starting a new question.
Basically, I'm struggling with how to best use JPA in a Spring application for a scenario that must comply to the following requirements:
Using Spring Transaction management
Using multiple Persistence Units (with Spring Data Repository support)
Using multiple DataSources (I want to be able to switch the DataSource for a PersistenceUnit dynamically at runtime)
Combining parts of the application (that include JPA entities) in separate modules to use them in different projects
Consider the following UseCase
Application A allows the User to read and write DB data from different DataSources, D1, D2, Dn. I only need a single PersistenceUnit P1 to define the needed entities
Module M contains two entities AuthUser and AuthRole that are used to store user and permission information. I'd like to use it modularly in different projects. Basically, I need to be able to define the PersistenceUnit P2 that only contains the two entities and a DataSource Da as the users are stored in ONE database, independent from the other DataSources D1, D2, ... the application accesses.
Application A includes Module M and defines which DataSource it should use
The issues i ran into:
I would like to use #PersistenceContext and #Transactional in Module M, without having to specify explicit persistenceUnits or transactionManagers everywhere. Ideally, Spring would use the PersistenceContext / EntityManager of a running Transaction. This way, I would specify the desired PersistenceUnit in a transactional method of Application A and Module M would inherit the transaction and PersistenceContext. I couldn't find a solution of how to do this. I was thinking of providing a custom PersistenceAnnotationBeanPostProcessor, but I couldn't find any resources on the web on this subject.
To use multiple DataSources with the same PersistenceUnit, I looked into AbstractRoutingDatatSource. This should work, even though I'm suspisous on how it will cooperate with the Transactional annotation. Any experience on using it and on how to prevent changing DataSources in the middle of a transaction?
I hope I could make my point clear. I didn't want to include too much code as in a first instance, I'm interested more in the conceptual answer than the technical one. To boil it down to one (large) sentence:
What's the best practice in Spring / JPA to build modular, transactional applications using multiple PersistenceUnits and DataSources without having to specify hard coded persistence information (like persistenceUnit names) in the source code (especially of the modules)?
I am in the process of troubleshooting a recent translation of EJB code to native Hibernate code (painful process, since EJB spoiled me so much with its convenience).
One thing I find troublesome is that Hibernate keeps its entity declarations in a hbm.xml file and then the configurations in separate files. While this isn't necessarily a big issue, the Netbeans wizard doesn't really let the developer to just click a button, detect, all the entities on the fly, and update the configuration file.
With persistence.xml, however, I can do that easily by just adding the classes and forget about it. Another good thing is that persistence.xml stores pretty much everything needed for the ORM aside from the class-specific annotations (which I am keeping).
With that said, is there any way for me to have Hibernate to (1) stay off EE and (2) use persistence.xml to get the connection, mapping, etc?
Also, a related question - CriteriaQuery is apparently a Java EE thing. One thing I really like about using EJB is that there are strong compile-time contraints. For instance, I can put ClassName_.myAttribute directly as a parameter in a CriteriaQuery, whereas if I use the Hibernate native "Criteria" object, I have to use "my_attribute" instead, which is not subjected to compile time integrity checks (Note: ClassName_.myAttribute maps to "my_attribute" on the table).
So is there anyway to keep that compile-time integrity?
Thanks.
Hibernate EntityManager can be used outside of a Java EE container. See http://docs.jboss.org/hibernate/core/4.0/hem/en-US/html_single/#architecture-javase.
Moreover, even with the Hibernate native API, since you're using annotations, you don't need any hbm.xml file. Just a central Hibernate config file listing the entities and some Hibernate properties.