Skip to content

TRUNK-6469: Add support for automatic initialization of Envers audit tables (#5468) (#5831)#5834

Open
wikumChamith wants to merge 1 commit intoopenmrs:2.8.xfrom
wikumChamith:2.8.x-envers
Open

TRUNK-6469: Add support for automatic initialization of Envers audit tables (#5468) (#5831)#5834
wikumChamith wants to merge 1 commit intoopenmrs:2.8.xfrom
wikumChamith:2.8.x-envers

Conversation

@wikumChamith
Copy link
Member

@wikumChamith wikumChamith commented Feb 23, 2026

Description of what I changed

Cherry picked from: b276e07

Issue I worked on

see https://issues.openmrs.org/browse/TRUNK-

Checklist: I completed these to help reviewers :)

  • My IDE is configured to follow the code style of this project.

    No? Unsure? -> configure your IDE, format the code and add the changes with git add . && git commit --amend

  • I have added tests to cover my changes. (If you refactored
    existing code that was well tested you do not have to add tests)

    No? -> write tests and add them to this commit git add . && git commit --amend

  • I ran mvn clean package right before creating this pull request and
    added all formatting changes to my commit.

    No? -> execute above command

  • All new and existing tests passed.

    No? -> figure out why and add the fix to your commit. It is your responsibility to make sure your code works.

  • My pull request is based on the latest changes of the master branch.

    No? Unsure? -> execute command git pull --rebase upstream master

Copy link

@omeriinnocent omeriinnocent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of automatic Envers audit table initialization is solid:
Strengths
:
- Well-structured code with proper separation of concerns in EnversAuditTableInitializer
- Comprehensive test coverage (3 main scenarios: enable/disable/custom suffix)
- Follows OpenMRS standards (license headers, naming, logging with SLF4J)
- Good error handling with APIException wrapping
- Java 8 compatible (DatabaseUtil.java fix is good)
Minor Recommendations:
-In HibernateSessionFactoryBean.generateEnversAuditTables(), consider adding a null check for hibernateProperties before passing to EnversAuditTableInitializer.initialize() for defensive programming.
-Add javadoc to the test helper method buildSessionFactoryWithEnvers() for clarity.

@ibacher
Copy link
Member

ibacher commented Feb 24, 2026

@omeriinnocent Please don't add AI-generated review comments unless they add some kind of value. While it's fine to use AI to help you identify issues that you might want to raise with a PR author in a review, just copying and pasting the AI output is unhelpful.

import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.jspecify.annotations.NonNull;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer @Nonnull or at least the Spring version.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*/
@Override
public void setMappingResources(String... mappingResources) {
public void setMappingResources(String @NonNull ... mappingResources) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public void setMappingResources(String @NonNull ... mappingResources) {
public void setMappingResources(@Nonnull String ... mappingResources) {

Copy link
Member Author

@wikumChamith wikumChamith Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ibacher Since this method uses varargs, we need to annotate it as String @NonNull ..., which means the array itself cannot be null.

If we annotate it as @NonNull String ..., that means each String element cannot be null.

When I used @NonNull String ..., I got the warning:
Not annotated parameter overrides @NonNullApi parameter.

That’s why I annotated it as String @NonNull ... instead.

@wikumChamith wikumChamith force-pushed the 2.8.x-envers branch 2 times, most recently from 5b232de to 6effc2a Compare March 2, 2026 06:44
@wikumChamith
Copy link
Member Author

@ibacher, @dkayiwa is this ready to get merged :) ?

@wikumChamith wikumChamith requested a review from ibacher March 11, 2026 12:32
@sonarqubecloud
Copy link

private Integer conceptReferenceRangeId;

@Column(name = "criteria", length = 65535)
@Column(name = "criteria", length = 255)
Copy link
Contributor

@Binayak490-cyber Binayak490-cyber Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wikumChamith, as I was also working on the same issue around and they are #5933 and #5952 and was finding this PR only where the backfill changeset only makes sense if the audit tables already exist. So, I want to point out some points that the criteria column was silently reduced from 65535 to 255 with no Liquibase migration — any existing values longer than 255 chars would be truncated on update. Was this intentional? A migration changeset is needed here.


String lowerTableName = tableName.toLowerCase();

if (lowerTableName.contains("revision") || lowerTableName.equals("revinfo")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wikumChamith, Any table whose name happens to contain the word "revision" would be incorrectly pulled into the audit schema migration. This is too broad — should match only the exact Envers-generated revision table name based on the configured prefix/suffix.

Comment on lines +180 to +181
hasErrors.set(true);
log.warn("Schema migration encountered an issue: {}", throwable.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errors during audit table creation are only logged as warnings and execution continues. If a critical table fails to create, the system starts up silently broken — this should either throw or at minimum log at ERROR level so it doesn't go unnoticed in production.

String auditTablePrefix = hibernateProperties.getProperty("org.hibernate.envers.audit_table_prefix", "");
String auditTableSuffix = hibernateProperties.getProperty("org.hibernate.envers.audit_table_suffix", "_audit");

Map<String, Object> settings = new HashMap<>((Map) hibernateProperties);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unchecked raw type cast that will generate a compiler warning and could throw a ClassCastException at runtime if any property value is not a String. Should use explicit population instead.


@BeforeEach
void beforeEach() throws Exception {
this.dropAllDatabaseObjects();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling dropAllDatabaseObjects() in @beforeeach means if one test fails mid-run, the DB is left in a broken state for all subsequent tests. A more targeted teardown or transaction rollback would be safer.


@BeforeEach
void beforeEach() throws Exception {
this.dropAllDatabaseObjects();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling dropAllDatabaseObjects() in @beforeeach means if one test fails mid-run, the DB is left in a broken state for all subsequent tests. A more targeted teardown or transaction rollback would be safer.

public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
this.metadata = metadata;
generateEnversAuditTables(metadata, serviceRegistry);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing APIException from inside integrate() will crash the entire SessionFactory initialization with a generic error — giving no clear signal that Envers is the cause. Should log the failure clearly and consider making it non-fatal so startup can proceed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants