Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 322585 - JPA2: Refactor Metamodel usage via EMF before the first EM deploy that would result in an uninitialized metamodel
Summary: JPA2: Refactor Metamodel usage via EMF before the first EM deploy that would ...
Status: RESOLVED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 7
: P2 enhancement (vote)
Target Milestone: ---   Edit
Assignee: Michael OBrien CLA
QA Contact:
URL: http://wiki.eclipse.org/EclipseLink/D...
Whiteboard:
Keywords:
: 303684 (view as bug list)
Depends on: 266912 282518 324194 324213
Blocks: 322184 324974 297748 297928 303063 303684 315041 320273 322166 332290
  Show dependency tree
 
Reported: 2010-08-12 16:38 EDT by Michael OBrien CLA
Modified: 2022-06-09 10:15 EDT (History)
3 users (show)

See Also:
michael.f.obrien: documentation+


Attachments
Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to eclipselink.login-at-emf==true (4.90 KB, patch)
2010-08-17 17:10 EDT, Michael OBrien CLA
no flags Details | Diff
Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to login = True (see new property name) (7.16 KB, patch)
2010-08-27 07:27 EDT, Michael OBrien CLA
no flags Details | Diff
Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to login = True (see new property name) - with login for auto-db detection for bug# 324213 (10.13 KB, patch)
2010-09-02 12:02 EDT, Michael OBrien CLA
no flags Details | Diff
Option 7 (in use): Do a getServerSession that does a deploy/login that calls initializeDescriptors only for early emf.getMetamodel() users - em.getMetamodel() users do not login (3.28 KB, patch)
2010-09-03 09:09 EDT, Michael OBrien CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Michael OBrien CLA 2010-08-12 16:38:53 EDT
>Issue: if an emf.getMetamodel() call is done before at least 1 EM deploy - the metamodel is invalid
- why? the predeploy does not initialize entity descriptor - we need to fully deploy at least 1 entityManager first.

We will refactor Metamodel usage via EMF before the first EM deploy that would result in an uninitialized metamodel.

>This bug will fix several issues where uninitialized descriptors would cause issues between a predeploy and deploy including
bug # 297748, bug # 297928, bug # 303063, bug # 322166, bug # 322184
Customer bug # 315041 (duplicated to bug # 303063)
>the following is via the EM not the EMF in Spring (so may not be related)
http://jira.springframework.org/browse/SPR-6826
Comment 2 Michael OBrien CLA 2010-08-16 11:30:59 EDT
*** Bug 303684 has been marked as a duplicate of this bug. ***
Comment 3 Michael OBrien CLA 2010-08-17 17:10:06 EDT
Created attachment 176849 [details]
Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to eclipselink.login-at-emf==true 

Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to eclipselink.login-at-emf==true 
>see DI 106 - alt #3
http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#Alt_106-3:_Force_full_real_deploy
>The only issue with alt #3 is that even though the descriptor.javaClass is set
- the initialization state is incomplete
Comment 4 Michael OBrien CLA 2010-08-17 22:07:08 EDT
>testing results
After trying 2 locations of a getServerSession() call in order to do a login before an official deploy() on createEntityManager - I came across code that already exists for JPA validation that will do a login for us and effect a deploy just after the predeploy finishes on the EMF. 
>Performance Results 106-3
The following show that that the time taken to update the session, do DDL generation and intialize the metamodel and canonical metamodel has shifted to the EMF creation from the EM creation. In essence an emf.createEntityManager() now takes just a couple microseconds instead of seconds. 
Doing all the following in the predeploy 
  updateServerSession 
  session.login 
  generateDDL 
  metamodel initalization 
  canonical metamodel initialization 
takes in SE 
 with change 
  predeploy() = 2.6 sec 
   [EL Finest]: 2010-08-17 18:01:12.002--ServerSession(27196165)--Thread(Thread[main,5,main])--Begin predeploying Persistence Unit dao.create.tables.derby; session default-session; state Initial; factoryCount 0 
   [EL Finest]: 2010-08-17 18:01:14.67--ServerSession(27196165)--Thread(Thread[main,5,main])--End deploying Persistence Unit dao.create.tables.derby; session default-session; state Deployed; factoryCount 1 
  deploy() = 0.09 sec 
   [EL Finest]: 2010-08-17 18:01:14.67--ServerSession(27196165)--Thread(Thread[main,5,main])--End deploying Persistence Unit dao.create.tables.derby; session default-session; state Deployed; factoryCount 1 
   [EL Finer]: 2010-08-17 18:01:14.763--ServerSession(27196165)--Thread(Thread[main,5,main])--client acquired 
 
 without change 
  predeploy() = 0.75 sec 
   [EL Finest]: 2010-08-17 17:58:29.169--ServerSession(2279771)--Thread(Thread[main,5,main])--Begin predeploying Persistence Unit dao.create.tables.derby; session default-session; state Initial; factoryCount 0 
   [EL Finest]: 2010-08-17 17:58:29.934--ServerSession(2279771)--Thread(Thread[main,5,main])--End predeploying Persistence Unit dao.create.tables.derby; session default-session; state Predeployed; factoryCount 1 
  deploy() = 1.87 sec 
   [EL Finest]: 2010-08-17 17:58:29.934--ServerSession(2279771)--Thread(Thread[main,5,main])--Begin deploying Persistence Unit dao.create.tables.derby; session default-session; state Predeployed; factoryCount 1 
   [EL Finer]: 2010-08-17 17:58:31.806--ServerSession(2279771)--Thread(Thread[main,5,main])--client acquired 

On emf.createEntityManager() we just skip deploy/login in getServerSession(), login in createEntityManagerImpl as well as deploy/login in getServerSession() in the EntityManagerImpl constructor 
because the emf.createEntityManager() does virtually nothing after this change 

EE Server testing on WebLogic 10.3.3.0 via standard @PersitenceContext injection on a SSB @EJB injected on a servlet client is OK 

Notice that a predeploy also does a deploy now - previously the deploy was only done when the client persisted or read from the persistence unit (via injection) 

Daemon Thread [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] (Suspended (breakpoint at line 314 in EntityManagerSetupImpl))	
	EntityManagerSetupImpl.deploy(ClassLoader, Map) line: 314	
	EntityManagerFactoryImpl.getServerSession() line: 157	
	PersistenceProvider.createContainerEntityManagerFactory(PersistenceUnitInfo, Map) line: 243	
	PersistenceUnitInfoImpl.createEntityManagerFactory(boolean) line: 352	
	PersistenceUnitInfoImpl.createEntityManagerFactory() line: 332	
	PersistenceUnitInfoImpl.<init>(PersistenceUnitBean, PersistenceUnitConfigurationBean, GenericClassLoader, String, URL, URL) line: 134	
	ModulePersistenceUnitRegistry(AbstractPersistenceUnitRegistry).storeDescriptors(Map, Map) line: 336	
	ModulePersistenceUnitRegistry(AbstractPersistenceUnitRegistry).loadPersistenceDescriptor(VirtualJarFile, boolean, File) line: 250	
	ModulePersistenceUnitRegistry.<init>(GenericClassLoader, ApplicationContextInternal, Module, boolean) line: 69	
	EJBModule.setupPersistenceUnitRegistry() line: 221	
	EJBModule$1.execute() line: 322	
	PersistenceUnitRegistryInitializer.setupPersistenceUnitRegistries() line: 62	
	WebAppModule.prepare() line: 398	
	ScopedModuleDriver.prepare() line: 176	
	ModuleListenerInvoker.prepare() line: 199	
	DeploymentCallbackFlow$1.next(Object) line: 507	
	StateMachineDriver.nextState(StateChange, Object[]) line: 41	
	DeploymentCallbackFlow.prepare(Module[]) line: 149	
	DeploymentCallbackFlow.prepare() line: 45	
	BaseDeployment$1.next(Object) line: 1221	
	StateMachineDriver.nextState(StateChange, Object[]) line: 41	
	EarDeployment(BaseDeployment).prepare(DeploymentContext) line: 367	
	EarDeployment.prepare(DeploymentContext) line: 58	
	DeploymentStateChecker.prepare(DeploymentContext) line: 154	
	AppContainerInvoker.prepare(DeploymentContext) line: 60	
	RedeployOperation.createAndPrepareContainer() line: 98	
	RedeployOperation.doPrepare() line: 122	
	RedeployOperation(AbstractOperation).prepare() line: 217	
	DeploymentManager.handleDeploymentPrepare(Deployment, DeploymentManager$DeploymentRequestInfo) line: 747	
	DeploymentManager.prepareDeploymentList(ArrayList, DeploymentContext) line: 1216	
	DeploymentManager.handlePrepare(DeploymentContext) line: 250	
	DeploymentServiceDispatcher.prepare(DeploymentContext) line: 159	
	DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentContext) line: 171	
	DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer, DeploymentContext) line: 13	
	DeploymentReceiverCallbackDeliverer$1.run() line: 46	
	SelfTuningWorkManagerImpl$WorkAdapterImpl.run() line: 528	
	ExecuteThread.execute(Runnable) line: 201	
	ExecuteThread.run() line: 173
Comment 5 Michael OBrien CLA 2010-08-18 08:27:56 EDT
>Fix Summary/Workaround
Essentially this fix just makes validation default to true unless disabled
- validation is off by default
- login during emf predeploy is now on by default
>workaround is to enable validation in persistence.xml
The following property is named as though the persistence unit is "only" used for validation.  
In fact it validates the persistence unit by doing a deploy just after the predeploy - without waiting for client code to login - after that it behaves normally.
This solves our issue where we may get a NPE on an unitialized descriptor's javaClass (was null) set on a Metamodel ManagedType

     <property name="eclipselink.validation-only" value="True"/>
Comment 6 Michael OBrien CLA 2010-08-18 09:45:15 EDT
>Regression testing
- looking through the log we need to verify that bug # 290342 "Injected EMF fails to deploy if already deployed through createEMF" - is not affected by moving the first deploy from emf.createEM
Comment 7 Michael OBrien CLA 2010-08-18 09:57:22 EDT
>Some history - the validation code that we build on here was put in a couple days after the initial source drop 
in Sept 2007 under SVN rev# 282 - and has proved very usefull
Comment 8 Michael OBrien CLA 2010-08-25 11:03:56 EDT
>We need to agree on a good name for the property that forces validation on
Names for the persistence.xml property LOGIN_AT_EMF_PROPERTY that essentially turns of validation by default. 
Here are some possible names
>eclipselink.login-at-emf - maybe
eclipselink.force-deploy-at-predeploy 
eclipselink.force-login-at-predeploy 
eclipselink.fully-process-emf-before-login 
eclipselink.enable-login-at-emf-predeploy 
eclipselink.enable-full-login-at-emf 
eclipselink.enable-deploy-during-predeploy 
eclipselink.enable-deploy-during-emf-predeploy 
eclipselink.enable-login-during-emf-predeploy 
eclipselink.enable-validation-by-default 
>eclipselink.enable-default-login-at-predeploy - recommended 

>Issue: this new property will essentially deprecate the validation flag unless we make validation=false also disable the new forced login flag
Comment 9 Michael OBrien CLA 2010-08-27 07:27:52 EDT
Created attachment 177607 [details]
Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to login = True (see new property name)
Comment 10 Michael OBrien CLA 2010-08-27 07:45:35 EDT
>EE Server regression testing
I have been running and debugging with validation on (deploy as part of predeploy) on WebLogic 10.3.3.0 for the past 5 days while testing various JTA EE applications for bug # 323403 and bug # 323148 with no discernable change in behaviour from a separate predeploy and login
We should have no issues enabling this property to True after I test on JBoss and Glassfish.
Comment 11 Doug Clarke CLA 2010-08-27 09:51:06 EDT
Running in WLS 10.3.3 I noticed that when I set 

<property name="eclipselink.validation-only" value="True"/>

I received an error message at bootstrap time if my project was configured to use native sequencing. It appeared to login and validate my metamodel without processing the auto db-platform discovery. I had to set my DB platform to avoid this situation.
Comment 12 Michael OBrien CLA 2010-08-27 18:56:27 EDT
>Doug, Good one, we will have to add/document and possibly warn about this issue - I have only used JPA sequencing so far.
Comment 13 Michael OBrien CLA 2010-09-01 09:50:47 EDT
>Reproduction - I get the following Exception in the SE JPA tests when I enable validation

Exception Description: SCIENTIST_SEQ: platform DatabasePlatform does not support NativeSequence.
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:411)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:156)
	at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:170)
	at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:67)
	at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)

>I also get the same validation exception if an SE JPA project disables the target-database but does not reference VendorNameToPlatformMapping.properties 
which is in eclipselink.jar or in core/resource - see bug # 324194 for the .classpath fix
[EL Finest]: 2010-09-01 08:42:10.633--ServerSession(23583040)--Thread(Thread[main,5,main])--property=eclipselink.validation-only; value=False
[EL Warning]: 2010-09-01 08:42:10.844--Thread(Thread[main,5,main])--Can not load resource [org/eclipse/persistence/internal/helper/VendorNameToPlatformMapping.properties] that loads mapping from vendor name to database platform. Autodetection of database platform will not work.
[EL Fine]: 2010-09-01 08:42:10.844--Thread(Thread[main,5,main])--Detected Vendor platform: null
[EL Info]: 2010-09-01 08:42:10.844--Thread(Thread[main,5,main])--Not able to detect platform for vendor name [Apache Derby]. Defaulting to [org.eclipse.persistence.platform.database.DatabasePlatform]. The database dialect used may not match with the database you are using. Please explicitly provide a platform using property eclipselink.platform.class.name.
[EL Config]: 2010-09-01 08:42:10.854--ServerSession(23583040)--Connection(21479899)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
	platform=>DatabasePlatform

Exception [EclipseLink-7144] (Eclipse Persistence Services - 2.2.0.qualifier): org.eclipse.persistence.exceptions.ValidationException
Exception Description: EL_CELL_SEQ: platform DatabasePlatform does not support NativeSequence.
	at org.eclipse.persistence.exceptions.ValidationException.platformDoesNotSupportSequence(ValidationException.java:1959)
..
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:228)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:383)
Comment 14 Michael OBrien CLA 2010-09-01 11:27:18 EDT
>bug # 324213 entered to switch the order of initialize descriptors and DB auto detection
JPA: validation-only=True breaks EntityManager deploy because initializeDescriptors() is called before loginAndDetectDatasource() in login() causing a default to the generic DatabasePlatform superclass
Comment 15 Michael OBrien CLA 2010-09-02 12:02:36 EDT
Created attachment 178057 [details]
Option 3 - preliminary patch : option to login/deploy on EMF creation (post predeploy) will default to login = True (see new property name) - with login for auto-db detection for bug# 324213
Comment 16 Michael OBrien CLA 2010-09-03 09:09:46 EDT
Created attachment 178140 [details]
Option 7 (in use): Do a getServerSession that does a deploy/login that calls initializeDescriptors only for early emf.getMetamodel() users - em.getMetamodel() users do not login

>Better solution: do a login only for emf.getMetamodel() instead of for everyone in predeploy().
I don't know what is wrong with me.  After a review by Gordon, Andrei and Peter, gordon suggested to move the login into the getMetamodel() call.
This is a better solution, so instead of logging in everyone on the predeploy, we only login early users of emf.getMetamodel() and emf.getCriteriaBuilder() via a emf.getServerSession().
Comment 17 Michael OBrien CLA 2010-09-03 09:27:24 EDT
>As Andrei says: I also need to verify that the correct classLoader is used for descriptors.
We set the JavaClass in the deploy in the call to getServerSession so we should be using the realClassLoader.
Later we switch classLoaders blindly anyway only for MappedSuperclasses.
Thread [main] (Suspended)	
	RelationalDescriptor(ClassDescriptor).convertClassNamesToClasses(ClassLoader) line: 1218	
	MappedSuperclassTypeImpl<X>.create(MetamodelImpl, RelationalDescriptor) line: 90	
	ManagedTypeImpl<X>.create(MetamodelImpl, RelationalDescriptor) line: 443	
	MetamodelImpl.initialize() line: 364	
	MetamodelImpl.<init>(DatabaseSession) line: 109	
	MetamodelImpl.<init>(EntityManagerSetupImpl) line: 128	
	EntityManagerSetupImpl.getMetamodel() line: 2011	
	EntityManagerSetupImpl.deploy(ClassLoader, Map) line: 408	
	EntityManagerFactoryImpl.getServerSession() line: 164	
	EntityManagerFactoryImpl.getMetamodel() line: 510	
	DDLGenerationClient.initialize(String) line: 136	
	DDLGenerationClient.doQuery() line: 443	
	DDLGenerationClient.main(String[]) line: 434	

An isAssignable error would occur if the classLoader was wrong.
Comment 18 Michael OBrien CLA 2010-09-03 15:16:25 EDT
>See the fix for bug # 322585 in SVN rev# 8141 for 2.2 and 8142 for 2.1.2
https://fisheye2.atlassian.com/changelog/eclipselink/?cs=8141
We now do a preemptive DB login via getServerSession to force initializeDescriptors so that MappedSuperclass javaClass is set on the descriptor when a client does an emf.getMetamodel() or emf.getCriteriaBuilder() before at least one EntityManager is created or logged in.
If a NullPointerException occurs on early post-predeploy but pre-deploy access to the Metamodel via an EntityManagerFactory.getMetamodel() or emf.getCriteriaBuilder() call before an initial login to the DB - then reopen this bug.
NPE in ManagedTypeImpl.getTypeClassFromAttributeOrMethodLevelAccessor
NPE in MetamodelImpl.initialize
Comment 19 Craig Ringer CLA 2012-07-30 04:11:31 EDT
The property landed up being called "eclipselink.deploy-on-startup" , for anyone searching for it later.
Comment 20 Eclipse Webmaster CLA 2022-06-09 10:09:03 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink
Comment 21 Eclipse Webmaster CLA 2022-06-09 10:15:21 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink