Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PersistenceUnit not updated across multiple deployments /CUSTCOM-65 #1606

Closed
ctabin opened this issue May 18, 2017 · 6 comments
Closed

PersistenceUnit not updated across multiple deployments /CUSTCOM-65 #1606

ctabin opened this issue May 18, 2017 · 6 comments
Assignees
Labels
Status: Accepted Confirmed defect or accepted improvement to implement, issue has been escalated to Platform Dev Type: Bug Label issue as a bug defect

Comments

@ctabin
Copy link
Contributor

ctabin commented May 18, 2017

Description


In an embedded payara server, the second time it is deployed, the PersistenceUnit that is used seems to come from the previous deployment.

Warning: I speak about PersistenceUnit to say it is related with the lookup of the JNDI specified in the persistence.xml. I don't know if it is effecitvely linked to the PersistenceUnit, it seems likely to be related to the JDBC connection pool handling.

Edit: I attached a small project to reproduce the case.

Context

Like in #1596, we want to use the payara server (or GlassFish embedded) for testing our application. Since there are complex workflows, this involves to start/stop GlassFish multiple times with different configurations (domain.xml).

In order to have a full fresh environment for each deployment, we create a new domain.xml which point to different folders. The problem is that we make H2 point to a different database file:

<jdbc-connection-pool datasource-classname="org.h2.jdbcx.JdbcDataSource" name="h2_${POOL_NAME}" wrap-jdbc-objects="false" is-connection-validation-required="true" connection-validation-method="auto-commit" res-type="javax.sql.DataSource">
    <property name="URL" value="jdbc:h2:${DATABASE_FILE};MODE=MySQL"></property>
    <property name="driverClass" value="org.h2.Driver"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="h2_${POOL_NAME}" jndi-name="jdbc/database"></jdbc-resource>

As you can see, before each startup, we replace ${POOL_NAME} with a random string in order to ensure the pool is different and ${DATABASE_FILE} with the path to the new file that will host the database. However, since the EAR is already packaged, we cannot change the JNDI name (jdbc/database).

Here is the content of the persistence.xmlfile:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="OurProject-ejbPU" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>jdbc/database</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <shared-cache-mode>NONE</shared-cache-mode>
    <validation-mode>NONE</validation-mode>
    <properties>
      <property name="hibernate.jdbc.batch_size" value="35" />
      <property name="hibernate.order_updates" value="true" />
      <property name="hibernate.order_inserts" value="true" />
    </properties>
  </persistence-unit>
</persistence>

Code snippet

Here is the code we use to start/stop Payara:

File domainFile = ...; //updated domain.xml, with replaced variables (pool-name=h2_random_3871)
GlassFishProperties gfprops = new GlassFishProperties();
gfprops.setConfigFileURI(domainFile.toURI().toString());

ClassLoader contentCL = new URLClassLoader(new URL[]{});
BootstrapProperties bsprops = new BootstrapProperties();
GlassFishRuntime runtime = GlassFishRuntime.bootstrap(bsprops, contentCL);
GlassFish glassfish = runtime.newGlassFish(gfprops);
glassfish.start();

String depName = glassfish.getDeployer().deploy(earFile); //first time => fine !

//Do nothing and stop directly the server
//At this point, the access to the database works fine

glassfish.getDeployer().undeploy(depName);
glassfish.stop();
glassfish.dispose();
runtime.shutdown();

Now, we change the domain.xml to make it point to other files, as described above and we restart the server:

File domainFile = ...; //updated domain.xml, with replaced variables (pool-name=h2_random_1645)
GlassFishProperties gfprops = new GlassFishProperties();
gfprops.setConfigFileURI(domainFile.toURI().toString());

ClassLoader contentCL = new URLClassLoader(new URL[]{});
BootstrapProperties bsprops = new BootstrapProperties();
GlassFishRuntime runtime = GlassFishRuntime.bootstrap(bsprops, contentCL);
GlassFish glassfish = runtime.newGlassFish(gfprops);
glassfish.start();

String depName = glassfish.getDeployer().deploy(earFile); //second time => CRASH !

In the console, we have the following stacktrace:

Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.qualifier): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: No pool by name [ h2_random_3871 ] found
Error Code: 0
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:316)
        at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:147)
        at org.eclipse.persistence.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:162)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.setOrDetectDatasource(DatabaseSessionImpl.java:207)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:760)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:265)
        at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:731)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:205)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:305)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:337)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:303)
        at org.glassfish.persistence.jpa.JPADeployer$2.visitPUD(JPADeployer.java:451)
        at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510)
        at org.glassfish.persistence.jpa.JPADeployer.iterateInitializedPUsAtApplicationPrepare(JPADeployer.java:492)
        at org.glassfish.persistence.jpa.JPADeployer.event(JPADeployer.java:395)
        at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:131)
        at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:488)
        at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:220)
        at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:487)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:360)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:360)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
        at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722)
        at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:134)
        at ch.saierp.sainet.testing.server.SAINetServer.start(SAINetServer.java:398)
        at ch.saierp.sainet.testing.server.deploy.DeploymentTest.testMultipleDeploymentsInDifferentFolders(DeploymentTest.java:33)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.apache.maven.surefire.junitcore.JUnitCore.run(JUnitCore.java:55)
        at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.createRequestAndRun(JUnitCoreWrapper.java:137)
        at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.executeEager(JUnitCoreWrapper.java:107)
        at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:83)
        at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:75)
        at org.apache.maven.surefire.junitcore.JUnitCoreProvider.invoke(JUnitCoreProvider.java:157)
        at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:386)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:323)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:143)
Caused by: java.sql.SQLException: No pool by name [ h2_random_3871 ] found
        at com.sun.enterprise.connectors.service.ConnectorConnectionPoolAdminServiceImpl.getConnection(ConnectorConnectionPoolAdminServiceImpl.java:1566)
        at com.sun.enterprise.connectors.ConnectorRuntime.getConnection(ConnectorRuntime.java:639)
        at org.glassfish.jdbcruntime.service.JdbcDataSource.getConnection(JdbcDataSource.java:88)
        at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:135)
        ... 68 more
Caused by: java.lang.RuntimeException: No pool by name [ h2_random_3871 ] found
        at com.sun.enterprise.connectors.ConnectorRuntime.getConnectionPoolConfig(ConnectorRuntime.java:1156)
        at com.sun.enterprise.connectors.service.ConnectorService.checkAndLoadPool(ConnectorService.java:321)
        at com.sun.enterprise.connectors.service.ConnectorConnectionPoolAdminServiceImpl.getUnpooledConnection(ConnectorConnectionPoolAdminServiceImpl.java:553)
        at com.sun.enterprise.connectors.service.ConnectorConnectionPoolAdminServiceImpl.getConnection(ConnectorConnectionPoolAdminServiceImpl.java:1550)
        ... 71 more

As you can see, the server is still searching the pool-name h2_random_3871 instead of h2_random_1645, indicating that the previous PersistenceUnit seems to be still loaded.

What I tried

We made the tests with Hibernate 5.2.10.Final and the default EclipseLink to ensure this is not a bug in the underlying JPA library.

Please also notice that we always pass an empty ClassLoader to the GlassfishRuntime, thinking that all our code would run in a sandbox, but it seems that this ClassLoader has absolutely no effect.

BootstrapProperties bsprops = new BootstrapProperties();
ClassLoader contentCL = new URLClassLoader(new URL[]{}); //empty ClassLoader with no parent
GlassFishRuntime runtime = GlassFishRuntime.bootstrap(bsprops, contentCL);

We tried different configurations of the ClassLoader (non, with parent, with delegation), but it seems to be completely ignored. But this might be due to the fact that we are running the instances with JUnit4 ?
Since the EJB project (packaged in the EAR) is a dependence of our testing project, this might be some ClassLoader issue (but since we are giving an empty ClassLoader to the GlassFishRuntime, I don't see what else we could do) ?

More logs

Output during closing of the first run:

May 18, 2017 3:23:02 PM org.eclipse.persistence.session./file:/tmp/gfembed7895636191108038854tmp/applications/ejb-timer-service-app/WEB-INF/classes/___EJB__Timer__App.connection
INFO: /file:/tmp/gfembed7895636191108038854tmp/applications/ejb-timer-service-app/WEB-INF/classes/___EJB__Timer__App logout successful
JdbcRuntimeExtension,  getAllSystemRAResourcesAndPools = [GlassFishConfigBean.org.glassfish.jdbc.config.JdbcResource, GlassFishConfigBean.org.glassfish.jdbc.config.JdbcConnectionPool, GlassFishConfigBean.org.glassfish.jdbc.config.JdbcConnectionPool, GlassFishConfigBean.org.glassfish.jdbc.config.JdbcResource]

Output after the second start:

May 18, 2017 3:23:09 PM com.sun.enterprise.web.WebContainer createHttpListener
INFO: Created HTTP listener http-listener-1 on host/port 0.0.0.0:8080
May 18, 2017 3:23:09 PM com.sun.enterprise.web.WebContainer createHttpListener
INFO: Created HTTP listener http-listener-2 on host/port 0.0.0.0:8181
May 18, 2017 3:23:09 PM com.sun.enterprise.web.WebContainer createHttpListener
INFO: Created HTTP listener admin-listener on host/port 0.0.0.0:4848
May 18, 2017 3:23:09 PM com.sun.enterprise.web.WebContainer createHosts
INFO: Created virtual server server
May 18, 2017 3:23:09 PM com.sun.enterprise.web.WebContainer createHosts
INFO: Created virtual server __asadmin
May 18, 2017 3:23:09 PM org.apache.catalina.realm.JAASRealm setContainer
INFO: Setting JAAS app name glassfish-web
May 18, 2017 3:23:09 PM com.sun.enterprise.web.WebContainer loadSystemDefaultWebModules
INFO: Virtual server server loaded default web module 
May 18, 2017 3:23:09 PM org.eclipse.persistence.session./file:/tmp/gfembed8818596850491646972tmp/applications/SNV4SRV/SNV4SRV-ejb_jar/_SNV4SRV-ejbPU.ejb
SEVERE: 
Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.qualifier): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: No pool by name [ h2_random_3871 ] found
Error Code: 0
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:316)
        at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:147)
        at org.eclipse.persistence.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:162)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.setOrDetectDatasource(DatabaseSessionImpl.java:207)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:760)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:265)
        at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:731)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:205)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:305)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:337)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:303)
        at org.glassfish.persistence.jpa.JPADeployer$2.visitPUD(JPADeployer.java:451)
        at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510)
        at org.glassfish.persistence.jpa.JPADeployer.iterateInitializedPUsAtApplicationPrepare(JPADeployer.java:492)
        at org.glassfish.persistence.jpa.JPADeployer.event(JPADeployer.java:395)
...

Maven

<dependency>
  <groupId>fish.payara.extras</groupId>
  <artifactId>payara-embedded-all</artifactId>
  <version>4.1.1.171.1</version>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>1.4.195</version>
</dependency>

Environment

  • Payara Version: 4.1.1.171.1
  • Edition: payara-embedded-all
  • JDK Version: Oracle JDK 1.8
  • Operating System: Linux Debian
  • Database: H2
@ctabin
Copy link
Contributor Author

ctabin commented May 20, 2017

Hello,

I recreated the case in this very small project, where I just changed the pool name. You can run it by just launching mvn clean package.

The test case is in the folder run in the class ch.astorm.payaraissue1606.CrashTest. The code is straightforward:

//first run => all is fine !
FacadeBeanRemote facade1 = createServer("myDatabase.db", "pool");
String fullName1 = facade1.getUserFullName(USERNAME_TEST);
assertEquals(FULLNAME_TEST, fullName1);
closeServer();

/* 
 * If you change either 'myDatabase.db' or 'pool' to any other name than
 * the line above, you'll get an error.
 * - If the database file is changed, then a SQL exception will be inside the EJB because
 *   it points to the old 'myDatabase.db' specified in the first run.
 * - If the pool name is changed, then the deployment will fail because it is 
 *   unable to find the corresponding JDBC connection pool.
 */
FacadeBeanRemote facade2 = createServer("myDatabase.db", "pool");
String fullName2 = facade2.getUserFullName(USERNAME_TEST);
assertEquals(FULLNAME_TEST, fullName2);
closeServer();

Let me know if I'm doing something wrong :-)

Best regards,
Cédric

@MattGill98
Copy link
Contributor

Hi Cédric,

Thank you for your test project, it helped greatly in reproducing your issue. You're not doing anything wrong as far as I can see! This bug seems to be from a very similar issue to #1596, as the embedded instance doesn't seem to be responding very well to a second configuration. I'll make an addendum to internal issue PAYARA-1651. In the meantime, if you're running multiple tests against a Payara Embedded instance for your code, might I suggest running Arquillian tests? Alternatively, it might be easier to add the specific JDBC resources to the Payara Embedded rather than create an entirely new instance.

Hope this helps,
Matt

@MattGill98 MattGill98 added Status: Accepted Confirmed defect or accepted improvement to implement, issue has been escalated to Platform Dev and removed 1:Investigating labels May 22, 2017
@MattGill98 MattGill98 self-assigned this May 22, 2017
@ctabin
Copy link
Contributor Author

ctabin commented May 23, 2017

Hello Matt,

Thanks for your reply. I'll have a look on Arquillian as you suggest :-)

I think I've found another another bug related to the JaaS authentication, still appearing after a second restart (JaaS authenticates the user as ANONYMOUS, even when mapped to the correct database). Do you mind if I open another issue ?

Best,
Cédric

@MattGill98
Copy link
Contributor

Hi Cédric,

If you think it is an unrelated bug then of course. Otherwise just let me know of any information to add to the internal issue!

Thanks,
Matt

@rdebusscher
Copy link

Tracked now by CUSTCOM-65

@OndroMih OndroMih changed the title PersistenceUnit not updated across multiple deployments PersistenceUnit not updated across multiple deployments /CUSTCOM-65 Feb 4, 2020
@OndroMih OndroMih added Type: Bug Label issue as a bug defect and removed c:PossibleBug labels Mar 3, 2020
@AlanRoth
Copy link

Hi, due to how long ago this issue was raised we have decided to close the issue immediately, and not consider the implementation of the fix/improvement that was requested. Please understand that this decision was taken into consideration with the resources that we have available at the moment. In case of having reported a bug, if the issue is still pressing to you, feel free to verify if it’s applicable in the current release of Payara Community edition, and proceed to raise a new issue with details of the test reproducer. Many thanks for your understanding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Accepted Confirmed defect or accepted improvement to implement, issue has been escalated to Platform Dev Type: Bug Label issue as a bug defect
Projects
None yet
Development

No branches or pull requests

5 participants