The @DataSourceDefinition provides the url property, but it will be ignored. If the the url is set to jdbc:postgres://database:5432/demo, a connection to localhost:5432 will be established. The same settings work great by setting them as serverName, portNumber and databaseName directly.
A small demo project to illustrate this behaviour can be found at https://github.com/ThomasPr/DataSourceDefinition
The properties serverName, portNumber and databaseName are set individually. A connection to postgres at database:5432 will be established successfully.
@DataSourceDefinition(
name = "java:global/jdbc/DemoDataSource",
className = "org.postgresql.ds.PGSimpleDataSource",
serverName = "database", // set the property
portNumber = 5432, // set the property
databaseName = "demo", // set the property
user = "demo",
password = "demo")
The same settings from the working example will be used again, but this time, only the url property will be set. The result is a connection attempt to localhost:5432 instead of database:5432
@DataSourceDefinition(
name = "java:global/jdbc/DemoDataSource",
className = "org.postgresql.ds.PGSimpleDataSource",
url = "jdbc:postgresql://database:5432/demo", // only use url, but no serverName, portNumber or databaseName
user = "demo",
password = "demo")
The same url-setting is used like in the failing example. But the serverName, portNumber and databaseName are set to empty values. Very strange: This time a connection to database:5432 will be established successfully. The only difference to the failing example are the mentioned three empty values.
@DataSourceDefinition(
name = "java:global/jdbc/DemoDataSource",
className = "org.postgresql.ds.PGSimpleDataSource",
url = "jdbc:postgresql://database:5432/demo", // use the url to configure connection properties
user = "demo",
password = "demo",
serverName = "", // set it to an empty value
portNumber = -1, // set it to an empty value
databaseName = "") // set it to an empty value
During startup of Payara, the following Exception will occur in the failing case:
microservice_1 | [2019-12-13T14:29:00.071+0000] [] [SEVERE] [] [org.eclipse.persistence.session./file:/tmp/payaramicro-rt7729847129244438567tmp/applications/ROOT/WEB-INF/classes/_demo.ejb] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1576247340071] [levelValue: 1000] [[
microservice_1 |
microservice_1 | Local Exception Stack:
microservice_1 | Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.payara-p2): org.eclipse.persistence.exceptions.DatabaseException
microservice_1 | Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: Connection could not be allocated because: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
microservice_1 | Error Code: 0
microservice_1 | at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:318)
microservice_1 | at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:150)
microservice_1 | at org.eclipse.persistence.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:172)
microservice_1 | at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.setOrDetectDatasource(DatabaseSessionImpl.java:233)
microservice_1 | at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:815)
...
Hi Thomas,
Thanks for the detailed reproducer, but when I run it, the deployment succeeds.
microservice_1 | [2019-12-16T12:38:11.706+0000] [] [CONFIG] [] [org.eclipse.persistence.session./file:/tmp/payaramicro-rt9091557307888333170tmp/applications/ROOT/WEB-INF/classes/_demo.connection] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1576499891706] [levelValue: 700] [[
microservice_1 | Connected: jdbc:postgresql://database:5432/demo?prepareThreshold=5&preparedStatementCacheQueries=256&preparedStatementCacheSizeMiB=5&databaseMetadataCacheFields=65536&databaseMetadataCacheFieldsMiB=5&defaultRowFetchSize=0&binaryTransfer=true&readOnly=false&binaryTransferEnable=&binaryTransferDisable=&unknownLength=2147483647&logUnclosedConnections=false&logServerErrorDetail=true&disableColumnSanitiser=false&tcpKeepAlive=false&loginTimeout=0&connectTimeout=10&socketTimeout=0&cancelSignalTimeout=10&receiveBufferSize=-1&sendBufferSize=-1&ApplicationName=PostgreSQL+JDBC+Driver&jaasLogin=true&useSpnego=false&gsslib=auto&sspiServiceClass=POSTGRES&allowEncodingChanges=false&targetServerType=any&loadBalanceHosts=false&hostRecheckSeconds=10&preferQueryMode=extended&autosave=never&cleanupSavepoints=false&reWriteBatchedInserts=false&hideUnprivilegedObjects=false&escapeSyntaxCallMode=select&readOnlyMode=transaction
microservice_1 | User: demo
microservice_1 | Database: PostgreSQL Version: 12.1
microservice_1 | Driver: PostgreSQL JDBC Driver Version: 42.2.9]]
(I did a checkout of your git repo and did mvn clean package and docker-compose up --build.
Also, if you check the code responsible for handling the annotation, the URL is considered when there are non defaults values for serverName, databaseName and portNumber defined. (line 397)
Regards
Rudy
Hi Rudy,
thanks very much for your swift reply!
I still can reproduce the issue with the very same command. Unfortunately, the issue seems to be unreliable, sometimes I have to execute the docker-compose down && mvn clean package && docker compose up --build command up to 5 times to get the exception.
However, I will try to reproduce this issue on a different environment to make absolutely sure, it's not a fault on my side.
Best,
Thomas
Hi,
i think i could pinpoint the error. The issue seems to be in the class com.sun.enterprise.deployment.DataSourceDefinitionDescriptor. There the property "serverName" is initialized with a default value "localhost".
`
public class DataSourceDefinitionDescriptor extends ResourceDescriptor {
private String name ;
private String description;
private String className ;
private int portNumber = -1;
private String databaseName ;
private String serverName = "localhost";
`
If only the url is specified then the descriptor contains the url and the serverName.
Later on when the datasource is constructed, the attributes are set via reflections, depending on the order of the calls either the url is set first or the servername is set first. This results in the works / dont work result of the bug. (see com.sun.gjc.common.DataSourceObjectBuilder#constructDataSourceObject)
In my opinion the serverName should not be initialized with localhost as default value.
Best,
Michael
@rdebusscher Michael found probably a bug in Payara which causes this issue. Can you have a look again?
Hi @ThomasPr
I have verified the mentioned method and I see that com.sun.gjc.common.DataSourceObjectBuilder#constructDataSourceObject uses the original @DataSourceDefinition values and not the cleaned up values created by org.glassfish.jdbcruntime.deployment.annotation.handlers.DataSourceDefinitionHandler#createDescriptor.
I created the internal issue CUSTCOM-173 to fix this. You can use the workaround of setting the values to empty values to work around in the meantime.
Regards
Rudy
The same issue happens to me on the datasource I defined in the web.xml. After a couple of restarts it actually works.
I have the same problem but only in Payara Full.
The Payara Micro works with the url parameter. I am using 5.201.
So is the bug implementation specific?
Most helpful comment
Hi @ThomasPr
I have verified the mentioned method and I see that
com.sun.gjc.common.DataSourceObjectBuilder#constructDataSourceObjectuses the original @DataSourceDefinition values and not the cleaned up values created byorg.glassfish.jdbcruntime.deployment.annotation.handlers.DataSourceDefinitionHandler#createDescriptor.I created the internal issue
CUSTCOM-173to fix this. You can use the workaround of setting the values to empty values to work around in the meantime.Regards
Rudy