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

PostgreSQL Driver not loaded from WAR or Uber JAR #1584

Closed
pedrovieirasilva opened this issue May 9, 2017 · 15 comments
Closed

PostgreSQL Driver not loaded from WAR or Uber JAR #1584

pedrovieirasilva opened this issue May 9, 2017 · 15 comments
Assignees

Comments

@pedrovieirasilva
Copy link

Description


When including PostgreSQL driver as a dependency and starting Payara Micro with a WAR or from a Uber JAR , the driver fails to load.

Expected Outcome

I currently have a maven project generating a WAR that has a declared dependency on PostgresSQL

<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.0.0</version>
</dependency>

When I build it it puts the driver jar inside tha WAR's WEB-INF/lib directory. So when the application is started it should have the driver in the classpath and load it correctly.

Current Outcome

However when I start my application with the command:

java -jar payara-micro-4.1.1.171.1.jar --deploy payara-microservice-0.0.1-SNAPSHOT.war

I always get the exception:

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.qualifier): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: The driver could not be loaded: org.postgresql.Driver
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.getDatabaseSession(EntityManagerFactoryDelegate.java:183)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getDatabaseSession(EntityManagerFactoryImpl.java:528)
        at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactoryImpl(PersistenceProvider.java:385)
        at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:313)
        at org.glassfish.persistence.jpa.PersistenceUnitLoader.loadPU(PersistenceUnitLoader.java:207)
        at org.glassfish.persistence.jpa.PersistenceUnitLoader.<init>(PersistenceUnitLoader.java:114)
        at org.glassfish.persistence.jpa.JPADeployer$1.visitPUD(JPADeployer.java:223)
        at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510)
        at org.glassfish.persistence.jpa.JPADeployer.createEMFs(JPADeployer.java:230)
        at org.glassfish.persistence.jpa.JPADeployer.prepare(JPADeployer.java:168)
        at com.sun.enterprise.v3.server.ApplicationLifecycle.prepareModule(ApplicationLifecycle.java:926)
        at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:435)
        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(Unknown Source)
        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(Unknown Source)
        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 com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:149)
        at fish.payara.micro.impl.PayaraMicroImpl.deployAll(PayaraMicroImpl.java:1411)
        at fish.payara.micro.impl.PayaraMicroImpl.bootStrap(PayaraMicroImpl.java:1005)
        at fish.payara.micro.impl.PayaraMicroImpl.main(PayaraMicroImpl.java:201)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at fish.payara.micro.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at fish.payara.micro.boot.loader.Launcher.launch(Launcher.java:107)
        at fish.payara.micro.boot.loader.Launcher.launch(Launcher.java:70)
        at fish.payara.micro.boot.PayaraMicroLauncher.main(PayaraMicroLauncher.java:72)
        at fish.payara.micro.PayaraMicro.main(PayaraMicro.java:358)
Caused by: java.sql.SQLException: Error in allocating a connection. Cause: The driver could not be loaded: org.postgresql.Driver
        at com.sun.gjc.spi.base.AbstractDataSource.getConnection(AbstractDataSource.java:121)
        at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:135)
        ... 48 more
Caused by: javax.resource.spi.ResourceAllocationException: Error in allocating a connection. Cause: The driver could not be loaded: org.postgresql.Driver
        at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:319)
        at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:196)
        at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:171)
        at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:166)
        at com.sun.gjc.spi.base.AbstractDataSource.getConnection(AbstractDataSource.java:114)
        ... 49 more
Caused by: com.sun.appserv.connectors.internal.api.PoolingException: The driver could not be loaded: org.postgresql.Driver
        at com.sun.enterprise.resource.pool.datastructure.RWLockDataStructure.addResource(RWLockDataStructure.java:103)
        at com.sun.enterprise.resource.pool.ConnectionPool.addResource(ConnectionPool.java:282)
        at com.sun.enterprise.resource.pool.ConnectionPool.createResourceAndAddToPool(ConnectionPool.java:1512)
        at com.sun.enterprise.resource.pool.ConnectionPool.createResources(ConnectionPool.java:944)
        at com.sun.enterprise.resource.pool.ConnectionPool.initPool(ConnectionPool.java:230)
        at com.sun.enterprise.resource.pool.ConnectionPool.internalGetResource(ConnectionPool.java:511)
        at com.sun.enterprise.resource.pool.ConnectionPool.getResource(ConnectionPool.java:381)
        at com.sun.enterprise.resource.pool.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:244)
        at com.sun.enterprise.resource.pool.PoolManagerImpl.getResource(PoolManagerImpl.java:170)
        at com.sun.enterprise.connectors.ConnectionManagerImpl.getResource(ConnectionManagerImpl.java:360)
        at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:307)
        ... 53 more
Caused by: com.sun.appserv.connectors.internal.api.PoolingException: The driver could not be loaded: org.postgresql.Driver
        at com.sun.enterprise.resource.pool.ConnectionPool.createSingleResource(ConnectionPool.java:924)
        at com.sun.enterprise.resource.pool.ConnectionPool.createResource(ConnectionPool.java:1189)
        at com.sun.enterprise.resource.pool.datastructure.RWLockDataStructure.addResource(RWLockDataStructure.java:98)
        ... 63 more
Caused by: com.sun.appserv.connectors.internal.api.PoolingException: The driver could not be loaded: org.postgresql.Driver
        at com.sun.enterprise.resource.allocator.LocalTxConnectorAllocator.createResource(LocalTxConnectorAllocator.java:110)
        at com.sun.enterprise.resource.pool.ConnectionPool.createSingleResource(ConnectionPool.java:907)
        ... 65 more
Caused by: javax.resource.ResourceException: The driver could not be loaded: org.postgresql.Driver
        at com.sun.gjc.spi.DMManagedConnectionFactory.createManagedConnection(DMManagedConnectionFactory.java:117)
        at com.sun.enterprise.resource.allocator.LocalTxConnectorAllocator.createResource(LocalTxConnectorAllocator.java:87)
        ... 66 more
]]

Even if I produce an Uber JarI get the same error.

I have verified that the PostgreSQL jar is being placed inside the War's WEB-INF\lib directory.

The only way I have managed to startup the application successfully is if I create a root dir with the driver jar inside the lib folder:

└───payara
    └───lib
            postgresql-42.0.0.jar

and start the application with following command:

java -jar payara-micro-4.1.1.171.1.jar --rootdir payara --deploy ../workspace/payara-microservice/target/payara-microservice-0.0.1-SNAPSHOT.war

Steps to reproduce (Only for bug reports)

Declare a dependency on PostgreSQL driver for an application to be run with payara micro.
Define the data source in the web.xml
Make sure you inject the persistence unit onto an EJB or similar so that a connection is made to the database
Build the app and verifiy that the drive is placed inside the WEB-INF/lib directory
Try to run the appilication as a WAR or as an Uber JAR.

Environment

  • Payara Version: 4.1.1.171.1
  • Edition: Micro
  • JDK Version: 8 u131- Oracle
  • Operating System: Windows
@MattGill98
Copy link
Contributor

Hi Pedro!

I attempted to recreate your issue by downloading the Payara Examples project here. Here's a link to my changes. This project then loaded the postgresql driver correctly. Is there any way you could make a small project to recreate the issue?

Alternatively, does the same project fail for other Payara Micro versions or database providers?

@mikecroft mikecroft added 1:Wait PR: TESTS REQUIRED PR Requires Tests to be merged labels May 22, 2017
@gilbertoca
Copy link

I've tested this on Wildfly and Tomee 7. Definitely is a issue with payara connection pool. @MattGill98 your example uses an Application DataSource not an Application Server DataSource [1] [2]. The application server code (our war) should use the org.postgresql.Driver as data source class name. Hence the issue create by @pedrovieirasilva

cc/ @smillidge @OndrejM

[1] https://jdbc.postgresql.org/documentation/head/datasource.html
[2] https://jdbc.postgresql.org/documentation/publicapi/org/postgresql/ds/PGPoolingDataSource.html

@smillidge
Copy link
Contributor

We still need a test case those links don't really help us.

@gilbertoca
Copy link

gilbertoca commented Dec 6, 2017

Just put org.postgresql.Driver in the example you will see.
Quoting one of the links:

This class is provided as a convenience, but the JDBC Driver is really not supposed to handle the connection pooling algorithm. Instead, the server or middleware product is supposed to handle the mechanics of connection pooling, and use the PostgreSQL implementation of ConnectionPoolDataSource to provide the connections to pool.

@MattGill98
Copy link
Contributor

Hi @gilbertoca,

I've found the error you're referring to and I believe it is an issue. I've made internal issue PAYARA-2328 to look into this.

@MattGill98 MattGill98 added 0:Triaged and removed 1:Wait PR: TESTS REQUIRED PR Requires Tests to be merged labels Dec 7, 2017
@gilbertoca
Copy link

gilbertoca commented Dec 7, 2017

Thanks @MattGill98! I hope we can use the payara-micro in our project.

@smillidge
Copy link
Contributor

smillidge commented Dec 7, 2017

I don't believe this is a bug org.postgresql.Driver does not implement

 DataSource, XADataSource or ConnectionPoolDataSource

the javaee schema definition explicitly states that classname should be an implementation of one of those interfaces. @MattGill98 original example used org.postgresql.ds.PGSimpleDataSource which works.

Postgres documentation recommends org.postgresql.ds.PGConnectionPoolDataSource is used.

@gilbertoca
Copy link

Maybe I misunderstood this

In an application server environment, the application server configuration will typically refer to the PostgreSQL™ ConnectionPoolDataSource implementation, while the application component code will typically acquire a DataSource implementation provided by the application server (not by PostgreSQL™).

And this one as well

For an environment without an application server, PostgreSQL™ provides two implementations of DataSource which an application can use directly. One implementation performs connection pooling, while the other simply provides access to database connections through the DataSource interface without any pooling. Again, these implementations should not be used in an application server environment unless the application server does not support the ConnectionPoolDataSource interface.

Even better

In general it is not recommended to use the PostgreSQL™ provided connection pool. Check your application server or check out the excellent jakarta commons DBCP project.

Even their tomcat example follow their own docs.

@smillidge don't get me wrong! I don't want to start a discussion (I can not express myself in English very well, I try my best not offend anyone)
I've tried both setups and no one works in my project.

@smillidge
Copy link
Contributor

I agree with below

In an application server environment, the application server configuration will typically refer to the PostgreSQL™ ConnectionPoolDataSource implementation, while the application component code will typically acquire a DataSource implementation provided by the application server (not by PostgreSQL™).

The implementation of ConnectionPoolDataSource you should use is org.postgresql.ds.PGConnectionPoolDataSource this is not a connection pool it is a datasource designed to work with application servers.

The Tomcat example is not the definition of a JavaEE datasource used within a war file. It is an example of how to create a datasource in Tomcat using Tomcat proprietary Resource syntax and the parameter required is the Driver.

Are you saying that using org.postgresql.ds.PGConnectionPoolDataSource in your web.xml the datasource definition does not work?

@gilbertoca
Copy link

No, I was using org.postgresql.ds.PGSimpleDataSource .

We used org.postgresql.Driver (tested with Tomee 7 and Wildfly 10), Payara doesn't work (inclusive the old known issue #907 occurs ).
After, I've tried with org.postgresql.ds.PGSimpleDataSource as @MattGill98 suggested and it loads the driver but don't do the connection.
Lastly I followed your suggestion org.postgresql.ds.PGConnectionPoolDataSource and works as you said.

Wildfly :

Caused by: java.lang.ClassCastException: org.postgresql.ds.PGConnectionPoolDataSource cannot be cast to javax.sql.DataSource
        at org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.getDataSource(LocalManagedConnectionFactory.java:635)
        ... 7 more

Tomee:

[ERROR] Unable to deploy collapsed ear in war StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/gace]
org.apache.openejb.OpenEJBException: Creating application failed: /home/gilberto.andrade/tmp/gace/target/gace: java.lang.ClassCastException: Cannot cast org.postgresql.ds.PGConnectionPoolDataSource to javax.sql.DataSource: Cannot cast org.postgresql.ds.PGConnectionPoolDataSource to javax.sql.DataSource
        at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:1050)

@smillidge
Copy link
Contributor

smillidge commented Dec 8, 2017

Are you deploying your datasource using a web.xml defined datasource in both Tomcat and WildFly? Please provide the web.xml snippet.

@gilbertoca
Copy link

gilbertoca commented Dec 14, 2017

Finally I've had time to dig into this! But before, wasted two day trying to deploy in the Wildfly - without success. We use eclipselink extension and Wildfly makes it practically impossible to deploy to.
So @smillidge , it is a misunderstanding on my part - not only me I think [1][2].
I've tested the three options with payara-micro

org.postgresql.ds.PGConnectionPoolDataSource
org.postgresql.ds.PGSimpleDataSource
org.postgresql.xa.PGXADataSource

using the data-source defined in web.xml:

gilberto.andrade@BEM-INF007:gace (master * u=) $ tail -n 20 target/gace/WEB-INF/web.xml 
        <mime-type>image/svg+xml</mime-type>
    </mime-mapping>        
    <data-source>
        <name>java:app/gace/gaceDS</name>
        <class-name>org.postgresql.xa.PGXADataSource</class-name>
        <url>jdbc:postgresql://srv-postgres:5444/teste</url>
        <user>gace_user</user>
        <password>gace_user</password>
        <transactional>true</transactional>
        <isolation-level>TRANSACTION_READ_COMMITTED</isolation-level>
        <initial-pool-size>2</initial-pool-size>
        <max-pool-size>10</max-pool-size>
        <min-pool-size>5</min-pool-size>
        <max-statements>0</max-statements>
    </data-source>
</web-app>

The web-app uses that setup in java code with @resource(name = "java:app/gace/gaceDS") and in persisten.xml <jta-data-source>java:app/gace/gaceDS</jta-data-source>.
All three options works!!

Now, I will report the issue to TomEE project - it only works with org.postgresql.Driver.

[1] https://stackoverflow.com/q/12826191/269514
[2] https://stackoverflow.com/q/6506859/269514
[3] https://stackoverflow.com/q/2279913/269514

@smillidge
Copy link
Contributor

Good to know it works. Are you happy to close the issue?

@gilbertoca
Copy link

gilbertoca commented Dec 15, 2017

I have not objection! @pedrovieirasilva do you have (any objection)?
Thank you!

@gilbertoca
Copy link

@smillidge @mikecroft can you help me with post/discussion[1] ? I could not explain/show that TomEE is not working like the java EE 7 expect.

[1] http://tomee-openejb.979440.n4.nabble.com/web-xml-data-source-definition-td4683131.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants