Community
Participate
Working Groups
>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
>This bug is designated design issue 106 for bug # 266912 on page http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/metamodel_api#DI_106:_20100810:_322585:Metamodel_initialization_via_EMF.getMetamodel.28.29_before_EM_deploy_results_in_an_invalid_Metamodel_because_of_UNINITIALIZED_descriptor.initializationStage
*** Bug 303684 has been marked as a duplicate of this bug. ***
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
>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
>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"/>
>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
>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
>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
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)
>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.
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.
>Doug, Good one, we will have to add/document and possibly warn about this issue - I have only used JPA sequencing so far.
>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)
>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
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
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().
>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.
>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
The property landed up being called "eclipselink.deploy-on-startup" , for anyone searching for it later.
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink