persistence@glassfish.java.net

strange side effect of recent change to Persistence.java while using TopLink Essentials

From: Sahoo <Sahoo_at_Sun.COM>
Date: Wed, 25 Jul 2007 16:18:12 +0530

Because of recent change to Persistence.java, where the code has been
added to gracefully recover in case a PersistenceProvider.createEMF()
throws exception, I am observing a very strange side effect while using
TopLink Essentials. The code that was earlier failing with exception /
predeploy for PersistenceUnit [em1] failed.
Internal Exception: Exception [TOPLINK-30007] (Oracle TopLink Essentials
- 2.0 (Build SNAPSHOT (07/17/2007))):
oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while loading class:
example.UserCredential to check whether it implements @Entity,
@Embeddable, or @MappedSuperclass./
now succeeds.

There are three things contributing to this:
1) TopLink Essentials installs two providers, whose functionalities are
identical, but names are different (I think it has to do with backward
compatibility).
2) There is a bug in JavaSECMPInitializer.TempEntityLoader (discussed in
forum [1] recently).
3) TopLink Essentials is not using this TempEntityLoader during so
called redeployment (see code below).

This is the sequence of events:
1. The bootstrap code in Persistence.java tries the first TopLink provider.
2. A new EntityManagerSetupImpl is created and registered with the
global map of name -> EntittyManagerSetupImpl.
3. EntityManagerSetupImpl.predeploy() throws the aforementioned
exception. It is set to STATE_PREDEPLOY_FAILED state and the exception
is thrown to bootstrap class, which records it.
4. Bootstrap code tries the second TopLink provider.
5. Now TopLink gets hold of the previous EntityManagerSetupImpl, and
proceeds with the deployment. This time, predeploy() succeeds because it
uses the real ThreadContextClassLoader as the TempClassLoader as shown
below:
File EntityManagerFactoryProvider.java:
            if(emSetupImpl.shouldRedeploy()) {
                SEPersistenceUnitInfo persistenceInfo =
(SEPersistenceUnitInfo)emSetupImpl.getPersistenceUnitInfo();
                
persistenceInfo.setClassLoader(JavaSECMPInitializer.getMainLoader());
                
*persistenceInfo.setNewTempClassLoader(JavaSECMPInitializer.getMainLoader());*
            }

I don't think fixing the TempEntityLoader alone is sufficient. Is
TopLink correct in calling predeploy() twice, that too with different
temporary class loaders? What are its side effects in a production
system? Secondly, why is TopLink not matching the provider name in its
createEMF() implementation?

Thanks,
Sahoo

[1] http://forums.java.net/jive/thread.jspa?messageID=227934