Leaving JPA in an OSGi based world
Since a while, I have decided to leave JPA and use QueryDSL instead. JPA2 was great to go with, but after a while the life-cycles of Entity objects took more than they gave. It was only the Criteria API in JPA that we liked.
With OSGi it is much easier to develop reusable modules and with the help of type-safe SQL queries (like JPA Criteria API and QueryDSL) this re-usability can be extended onto the persistence level.
Check the Localization example. With Localization you can have an independent table in a separate modul. Based on the table you can have the same features as the ResourceBundle does in Java. However, it is also possible to create Util function that can return a SubQuery with the logic (based on the function COALESCE). You can embed the Localization logic into the selection part of query without knowing about the difficulty of the subquery. On the end, you will be able to query only a range of an ordered resultSet from a database where the ordering is done based on the localized column.
Question: How can we create the DDL scripts and when should we run them?
I have checked many projects and it seems that Liquibase is the tool what I need.
Liquibase in short: I can create an mostly database independent XML. The XML can contain schema definition but also uprade scripts (in case the current db uses an older version). Liquibase can run on existing database, validate it, or give advices what SQL should be applied on a production database by the DB Admin.
In case I have a module like Localization, it seems obvious to take the liquibase changelog XML into the META-INF folder of the bundle. What should pick it up and when?
I have a DS component in the bundle that registers the Localization service. Somehow the database should be validated/populated by Liquibase before my service is registered. I can do the database check when the DataSource reference is available in the component.
I have the following options, but I do not like any of them:
- I generate the SQL scripts at development time for every supported database systems and put the native SQL scripts into the bundle, too. In that case I could give the SQL scripts to the DB Admins. However, this solution is not really good as Liquibase can handle version upgrades as well. In this case it is not really possible to do anything at runtime (even validate).
- Hardcode the databae initiatization part of the component into the activate method by calling Liquibase code. What should be done than? Trying to update the database and if it is not necessary, saving the native SQL script somewhere to the file system or simply log it out with LogService?
- Implementing a solution that can fit into the DS component registration based on service properties transparently. I am not sure it is even possible. What if my solution starts later than DS?
- Creating Service Hooks… I will not do that for sure 🙂
This is a difficult question. I think at least the schema validation should be done during the Component activation when the DataSource is ready. Without writing Liquibase based code into the Activate function, I do not see if it is possible at all.