Rethinking ClassLoading architecture 
-------------------------------------

                 Key: OPENJPA-2057
                 URL: https://issues.apache.org/jira/browse/OPENJPA-2057
             Project: OpenJPA
          Issue Type: Improvement
          Components: kernel
            Reporter: Pinaki Poddar


This issue proposes an overhaul of the classloading architecture.

Background:
------------------
OpenJPA runtime needs to load classes and resources at various time points in 
its life cycle and employs various classloading strategies at different parts 
of its code base. 
These are few broad categories of classes/resources OpenJPA needs to load
1. Resources: user-specified resources such as persistence.xml or orm.xml
2. Persistent Domain classes
3. Native Plug-ins: Implementation of interfaces e.g. UpdateManager that are 
supplied by OpenJPA and packaged in its own distribution
4. User Plug-ins: Implementation of interfaces e.g. MappingStrategy or 
ValueHandlers that the user has supplied via configuration and packaged in 
deployed units
5. Temporary classloader for java agent or weaving code loading domain classes 
to enhance them prior to their use

To load these different artifacts by their name, OpenJPA at different places 
employ available classloaders such as 
   i) the current thread's context class loader 
   ii) the clasloader that loaded OpenJPA native classes/interfaces 
  iii) the classloader that loaded a deployed application which can vary based 
on the container (Spring, OSGi, JEE) environment
  iv) system classloader   

The problem is the decision about which classloader is appropriate in a given 
context is quite scattered. This weakness appears in numerous places where a 
method is supplied with a ClassLoader and if the supplied loader is null, the 
method chooses a classloader (often the context classloader) or a class has its 
own classforname() method that tries a series of classloaders etc. 

This is a perennial problem and manifested in several reported bugs whose 
resolutions often introduced further localized logic to account for the point 
defects, thereby  accentuating the same trends that I believe is the root cause 
of the problem itself. 

Proposed solution/design:
-------------------------------------
Unify classloading decision in a singular abstraction. 
Allow that abstraction to cope with classloading regimes of different 
containers (Spring, OSGi, JEE etc). 

The natural candidate for unifying classloading is existing Configuration 
object. This object is a per persistence unit singleton and available 
throughout the runtime. 
However, certain class/resource loading must take place even before a 
Configuration instance is instantiated. For example, to locate and load the 
persistence.xml itself. 
Also note that the persistence.xml or orm.xml may contain fully-qualified names 
of persistent domain classes or  plug-in names (both native and custom/user 
variety) and they can occur either by their  fully-qualified class name or 
registered alias. The specialized parsers often has to load the class given 
their parsed string names or aliases. 

The bootstrap sequence of OpenJPA runtime is to construct a specific 
ConfigurationProvider and a series of specialized parsers to parse meta-data of 
various sorts (annotations, mapping xml, persistence.xml). These 
ConfigurationProviders are responsibilities of ProductDerivation -- the core 
mechanics that contributes their individual aspects to build up a 
Configuration. 

Given this existing well-designed bootstrap strategy, here is a proposal
  1. Let each ProductDerivation make their decision on how they will load 
whatever they need to load using whatever classloader they may need. For 
example, a OSGi ProductDerivation will use a bundle classloader to load its 
relevant resources. This phase occurs *before* a persistence unit (i.e. 
EntityManagerFactory) is constructed.
  2. Once the ProductDerivations have finished their loading using their own 
ConfigurationProvider, they transfer the accumulated information to a 
Configuration instance which essentially becomes the holder of entire runtime 
information for an EntityManagerFactory. During this transfer phase, let the 
ProductDerivations set the classloader as well into the Configuration instance.
  3. Once the Configuration instance has the classloader, this classloader is 
used throughout the codebase.

But what kind of classloader is used by the Configuration that will suit 
complex needs of class/resource loading? 
OpenJPA already has a powerful abstraction called MultiClassLoader which can 
employ an ordered series of (possibly unrelated) classloaders. So that 
MultiClassLoader is the correct classloader for Configuration instance. The 
ProductDerivation or ConfigurationProvider can add/remove their contributions. 

I understand that a change of this nature could be destabilizing in short-term. 
Also the change is difficult to validate across various container environments. 
I hope the community users will help by suggesting and testing such an overhaul 
to streamline OpenJPA classloading for long-term sustainability and 
maintenance. 
   
  



--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to