Skip to content

Instantly share code, notes, and snippets.

@xurror
Last active August 30, 2020 14:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xurror/9fc6a93e2234dcd546b9d92ba44be28e to your computer and use it in GitHub Desktop.
Save xurror/9fc6a93e2234dcd546b9d92ba44be28e to your computer and use it in GitHub Desktop.
3 months interning at Apache Fineract experience working with open source.

Google Summer of Code 2020 Project Report

Project title: Migrate Fineract ORM from OpenJPA to EclipseLink

Organisation: Apache Software Foundation

Student: Yemdjih Kaze Nasser

Mentors: Courage Angeh, Sanyam Goel

Introduction

EclipseLink is a free and Open-source persistence framework like hibernate or OpenJPA. During this summer I worked on migrating the Fineract ORM from OpenJPA to EclipseLink. OpenJPA has been the persistence provider used in the community for the past years but is now reaching an end of life with less and less community involvement.

Background

Fineract started out with hibernate as persistence provider and migrated to OpenJPA when the project was moved to the Apache Software foundation due to a licensing problem.

OpenJPA came in with little to no performance dropout and has been used in the community for over 5 years but lately community involvement in OpenJPA has largely reduced which is the main reason for the migration.

EclipseLink as the reference implementation for JPA comes in with a lot of performance optimisations and is more standard compliance. EclipseLink has over the years accumulated a lot of features making it reliable and stable and trade-offs between it and hibernate are very minimal.

Project Implementation

I started off this project by cleaning up the codebase of OpenJPA and it's dependencies and then setting up EclipseLink persistence configurations and dependencies. Some of the few things that were changed/removed or are new are:

  1. Persistence configuration: The very first thing to do for this project was to handle the persistence configuration. Setting eclipselink as JPA provider in persistence.xml and adding necessary parameters. This required a lot of googling, and searching and trial and errors. I was able to pull off a working configuration. Below is a preview:

     <persistence-unit name="EclipseLink-PU" transaction-type="RESOURCE_LOCAL">
     <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
     <exclude-unlisted-classes>false</exclude-unlisted-classes>
     <shared-cache-mode>NONE</shared-cache-mode>
     <properties>
         <property name="eclipselink.weaving" value="static" />
         <!-- <property name="eclipselink.logging.file" value="C:\myout\"/> -->
         <!-- Performance Profiling https://www.eclipse.org/eclipselink/documentation/2.5/solutions/performance002.htm#CHDIAFJI -->
         <!-- <property name="eclipselink.profiler" value="PerformanceProfiler"/> -->
         <property name="eclipselink.weaving.eager" value="true" />
         <property name="eclipselink.logging.level" value="FINE" />
         <property name="eclipselink.allow-zero-id" value="true" />
         <property name="eclipselink.target-database" value="MySQL" />
         <property name="eclipselink.jdbc.batch-writing" value="JDBC" />
         <property name="eclipselink.cache.shared.default" value="false" />
         <property name="eclipselink.jdbc.batch-writing.size" value="1000" />
         <property name="eclipselink.persistence-context.flush-mode" value="auto" />
         <property name="eclipselink.ddl-generation.index-foreign-keys" value="true" />
         <!-- <property name="eclipselink.weaving.changetracking" value="false"/> -->
    
         <!-- Schema Generation
         <property name="eclipselink.ddl-generation" value="create-tables"/>
         <property name="eclipselink.ddl-generation.output-mode" value="sql-script"/>
         <property name="eclipselink.application-location" value="/dir> -->
     </properties>
     </persistence-unit>
    

Entity manager factory bean:

<bean id="entityManagerFactory"
	class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
	depends-on="tenantDatabaseUpgradeService">
	<property name="dataSource" ref="routingDataSource" />
	<property name="persistenceUnitName" value="EclipseLink-PU" />
	<property name="jpaDialect">
	    <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
	</property>
	<property name="jpaVendorAdapter">
	    <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
		<property name="showSql" value="true" />
	    </bean>
	</property>
    </bean>
  1. MySQLDB Dictionary Support: With OpenJPA there was no native support for MySQL DB, so we had to setup DB dictionary. EclipseLink comes natively with support for MySQL and other DBs.

  2. Enhancement / Weaving: Just like OpenJPA, EclipseLink does not support out of the box runtime enhancement on tomcat server. For this, there a couple of options which were tried but we settled for a static or compile time weaving. We able to achieve this through a gradle task which handle this manually. Here is a peek of the task:

    configurations {
        weaver.extendsFrom implementation
        integrationTestCompile.extendsFrom testImplementation 
        integrationTestRuntime.extendsFrom testRuntime
    }
    task weave(type: JavaExec, dependsOn: [ compileJava, processResources ]) {
        main = 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
        classpath configurations.weaver args '-persistenceinfo'
        args processResources.destinationDir.absolutePath
        args '-classpath'
        args configurations.compile.incoming.files.asPath
        args '-loglevel'
        args 'INFO' // logging level at "FINE" shows alot of output to console. 
        args sourceSets.main.java.outputDir.absolutePath
        args sourceSets.main.java.outputDir.absolutePath
        inputs.files fileTree(processResources.destinationDir).matching({pattern -> pattern.include('**/META-INF/persistence.xml')})
    }
    classes.dependsOn weave
    
  3. Entity Persistence: Unlike OpenJPA, EclipseLink has a bit of trouble persisting entities especially in a cases of OneToMany or ManyToOne or self referencing entities as most often transactions are not committed until the very end of the transaction. To overcome this, "saveAndFlush" was used in some parts of the code instead of "save" as saveAndFlush committed changes immediately.

  4. Default Constructors: Unlike OpenJPA, EclispeLink is not tolerant to the absence of a default no-arg constructor in entity classes. OpenJPA enhancement handled that but EclipseLink does not have a thing for that. This should be watch for when creating a new entity.

  5. Common negligence errors: EclipseLink with it's high compliance with standards tends to non-tolerant of some mistakes which sometimes escape our attention, like duplicate column names, wrong SQL syntax in case of JPQL queries. We picked up some of these during the migration.

  6. Adopting GenerationType.TABLE: In the course of this work, the generation and assigning of IDs was not very efficient as there were cases of cascade persistence where foreign key IDs were not properly assigned. Using GenerationType.TABLE as the ID generation strategy for the certain entities helped improve on ID assignment.

With the above changes, I was able to get most of the integration tests available passing proving the migration was effective.

Summary

EclipseLink just like OpenJPA or hibernate provides an interface for JPA that eases the transactions between a DBMS and a java application. Fineract has journeyed through hibernate, OpenJPA and now EclipseLink. The most noticeable changes are at the level of the use of saveAndFlush instead of the standard save operation. Overall, the migrations have had little to no performance drop. These providers also have different entity enhancement methods, EclipseLink enhancement was trickier to handle and implement.

Conclusions

The EclipseLink integration was not very smooth, some of the default setup that were existing till now failed at the level of persisting data to a database. So far most aspects of the migration, that is writing and reading data from the database were successfully implemented. The migration needs to go through further tests to ensure the reliability of the migration and also make sure it doesn't fails in production.

References / Useful Links

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