The OpenMRS Platform 3.0.0 is currently in active development. This next-generation release aims to modernize the backend by upgrading to Java 21, along with the latest versions of Spring and Hibernate. You can find more details through the following links.
As this will be a major release, we have the opportunity to introduce significant changes, including those that are not backward compatible. We invite you to share your suggestions, whether they are new features or improvements to existing systems, that you would like to see in Platform 3.0.0. We look forward to hearing your ideas.
It would be nice if we scrapped our custom authorization scheme and re-worked it in terms of Spring Security. In particular, being able to support Spring Security’s ACL’s may give us better solutions to certain issues.
It would be nice if we could switch the custom validation layer for Hibernate Validator
We should replace the current password scheme with something a little more “modern“. While there’s nothing particularly broken about our current scheme, but uses multiple iterations of hashing. In particular, we should support one of the schemes laid out here. We should also probably change the stored format to something similar to what Spring Security uses. Our current scheme doesn’t really record which hashing method is used, so upgrading password hashes is sort of a matter of taking the plaintext and trying them all until one matches. This scheme is unambiguous and allows for other properties to be encoded (e.g., the salt is part of the parameters for many password schemes; placing it here would allow us to more easily switch to using a unique salt per password rather than a unique salt per user).
A key facility added by the authentication module is the DelegatingAuthenticationScheme, which allows custom authentication schemes to be plugged in via runtime configuration. It would be nicer to adopt this mechanism rather than what we have now which allows only a single authentication scheme. (Using Spring Security might override this altogether, but I was thinking more about that as an authorization plugin rather than replacing authentication).
Some of our Exception classes have constructors that take message keys, but not all of them due, resulting in cases where exceptions return message keys rather than the actual message. This is technically a breaking change, but it would be better if all messages to APIException and descendants were handled as if they might be translatable keys.
These are roughly ordered from least easily implementable to most easily implementable.
This update will drop support for older Java versions and migrate our codebase to Java 21. It will also include updates to Spring and Hibernate that are not going to be backward compatible. These changes are the main reason for moving to the 3.x major version line. You can find more details in this discussion.
Yeah, I think the most important part here is that the libraries we depend on for Core have already made breaking changes in their supported versions of the Java ecosystem. E.g.,
Spring 6: JDK 17+, plus the move from Java EE → Jakarta EE, with all the packages renamed (so Tomcat 10+ as a minimum)
Hibernate 6: Java 11+, move to Jakarta Persistence (Hibernate 7 is Java 17 minimum, but that won’t be supported until Spring 7)
Basically, keeping up with our dependencies, even not on the bleeding edge but just the supported releases requires us to make breaking changes in the backend, so platform 3.x is kind of forced.
I would be interested in us making any changes we feel are appropriate to core to better support the goals laid out in this thread: Asynchronous message queuing, retries, and error handling . Basically I think this involves adding Event firing and listener registration to core such that these events are guaranteed delivery and transactional (listeners can choose to participate synchronously in the transaction or choose to run asynchronously outside of the transaction), and such that no module ever needs to implement a Hibernate Interceptor but can simply rely upon the core Event publishing API with 100% confidence.
While this can also be done in an improved event module, doing this in core allows us to decide to fire events at all sorts of interesting places throughout the core codebase that a module may be interested in plugging into, and allow us to get rid of AOP and other multiple Hibernate Interceptors altogether.
I would also be interested in improving the module loading lifecycle such that modules can have more fine-grained control over when certain functionality might be executed, whether in relation to core or in relation to other modules. A few specific examples:
My top-level distribution module depends on Initializer, but wants to invoke the Initializer API directly to have more control over when and how it loads the configuration, rather than have this happen during the Initializer activator’s started method. Currently this can only be controlled at the distribution level by setting certain runtime or system properties. It cannot be coded into the top-level module.
My implementation has a bunch of data that was created in an older version of OpenMRS and now fails validation rules. I want to write some migration scripts and deploy them in my module and have them execute before OpenMRS runs any liquibase changesets. Currently there is no way for a module to inject behavior into this phase of OpenMRS startup.