Testing database connections in Open Liberty apps with REST APIs
Looking for a simple way to test your database connections? You can now, in Open Liberty 19.0.0.9, validate your connections via REST endpoints that are automatically enabled by combining the Rest Connector 2.0 (restConnector-2.0
) feature with features supporting configuration validation. In addition to being simple, these REST endpoints exercise the same code paths as your applications, giving you confidence in your server configuration.
By itself, the Rest Connector 2.0 feature allows viewing of a server’s current configuration via the /ibm/api/config
endpoint. REST endpoints capable of validating specific resources become available under the /ibm/api/validation
parent endpoint, when the Rest Connector 2.0 feature is combined with features that implement configuration validation. Validation of JDBC, JCA, Cloudant, and JMS configuration elements are currently supported. Looking for more validation support? Start a thread on our Groups.io account and let us know.
Both the validation and config endpoints are generated using a combination of the config element name, and unique ID:
/ibm/api/config/{configElementName}/{uid}
/ibm/api/validation/{configElementName}/{uid}
OpenAPI documents on these endpoints become available when a MicroProfile OpenAPI feature is enabled.
A note on security: Access to these endpoints requires authentication with the Liberty server. The config endpoint requires a minimum of reader-role
access and the validation endpoint requires administrator-role
access. The examples we will be walking through use either quickStartSecurity
or basicRegistry
with the appSecurity-2.0
feature to setup secure access. However, any Liberty supported user registry will work.
Now, let’s take a look at how you can use this new REST API to validate your configuration.
Here is a sample server.xml
configuration that uses the Configuration Validator and JDBC features:
<server>
<featureManager>
<feature>appSecurity-2.0</feature>
<feature>restConnector-2.0</feature>
<feature>jdbc-4.2</feature>
</featureManager>
<keyStore id="defaultKeyStore" password="Liberty"/>
<quickStartSecurity userName="blogAdmin" userPassword="blogAdminPassword"/>
<library id="derby">
<file name="${server.config.dir}/derby/derby.jar"/>
</library>
<dataSource id="DefaultDataSource">
<jdbcDriver libraryRef="derby"/>
<!-- Example properties referencing an in-memory Derby Embedded database -->
<properties.derby.embedded databaseName="memory:defaultdb" createDatabase="create" user="dbuser" password="dbpass"/>
</dataSource>
...
</server>
Validating a data source
Let’s say we want to directly test a database connection that an application depends on. We can do this using a REST endpoint found under https://localhost:9443/ibm/api/validation/dataSource/{uid}
. For our case this endpoint is https://localhost:9443/ibm/api/validation/dataSource/DefaultDataSource.
When the data source is working properly, a success message is shown:
{
"uid": "DefaultDataSource",
"id": "DefaultDataSource",
"successful": true,
"info": {
"databaseProductName": "Apache Derby",
"databaseProductVersion": "10.11.1.1 - (1616546)",
"jdbcDriverName": "Apache Derby Embedded JDBC Driver",
"jdbcDriverVersion": "10.11.1.1 - (1616546)",
"schema": "DBUSER",
"user": "dbuser"
}
}
If there is a problem, details about the failure are displayed. For instance if the <jdbcDriver>
element references a <library>
that does not contain a valid DataSource
implementation, the following result is given:
{
"uid": "DefaultDataSource",
"id": "DefaultDataSource",
"failure": {
"class": "java.sql.SQLNonTransientException",
"stack": [
"com.ibm.ws.jdbc.internal.JDBCDriverService.classNotFound(JDBCDriverService.java:195)",
"com.ibm.ws.jdbc.internal.JDBCDriverService.create(JDBCDriverService.java:297)",
"com.ibm.ws.jdbc.internal.JDBCDriverService.createDefaultDataSource(JDBCDriverService.java:396)",
// stack trace cut short
"java.lang.Thread.run(Thread.java:785)"
],
"cause": {
"class": "java.lang.ClassNotFoundException",
"message": "org.apache.derby.jdbc.EmbeddedXADataSource40",
"stack": [
"com.ibm.ws.classloading.internal.AppClassLoader.findClassCommonLibraryClassLoaders(AppClassLoader.java:499)",
// stack trace cut short
"java.lang.Thread.run(Thread.java:785)"
]
}
}
}
Viewing data source configuration
To view all data source configurations, we start the server and visit the following endpoint https://localhost:9443/ibm/api/config/dataSource/. In this case there is only one data source to view, the DefaultDataSource
:
[
{
"configElementName": "dataSource",
"uid": "DefaultDataSource",
"id": "DefaultDataSource",
"beginTranForResultSetScrollingAPIs": true,
"beginTranForVendorAPIs": true,
"connectionSharing": "MatchOriginalRequest",
"enableConnectionCasting": false,
"jdbcDriverRef": [
{
"configElementName": "jdbcDriver",
"uid": "dataSource[DefaultDataSource]/jdbcDriver[default-0]",
"libraryRef": [
{
"configElementName": "library",
"uid": "derby",
"id": "derby",
"apiTypeVisibility": "spec,ibm-api,api,stable",
"fileRef": [
{
"configElementName": "file",
"uid": "library[derby]/file[default-0]",
"name": "/home/nmittles/git/liberty/open-liberty/dev/build.image/wlp/usr/servers/blog/derby/derby.jar"
}
]
}
]
}
],
"statementCacheSize": 10,
"syncQueryTimeoutWithTransactionTimeout": false,
"transactional": true,
"properties.derby.embedded": [
{
"createDatabase": "create",
"databaseName": "memory:defaultdb",
"password": "******",
"user": "dbuser"
}
],
"api": [
"/ibm/api/validation/dataSource/DefaultDataSource"
]
}
]
To view an individual data source, append the data source’s uid
as seen from viewing the configuration. In our case this is DefaultDataSource
, and results in a URL of:
https://localhost:9443/ibm/api/config/dataSource/DefaultDataSource
{
"configElementName": "dataSource",
"uid": "DefaultDataSource",
"id": "DefaultDataSource",
"beginTranForResultSetScrollingAPIs": true,
"beginTranForVendorAPIs": true,
"connectionSharing": "MatchOriginalRequest",
"enableConnectionCasting": false,
"jdbcDriverRef": [
{
"configElementName": "jdbcDriver",
"uid": "dataSource[DefaultDataSource]/jdbcDriver[default-0]",
"libraryRef": [
{
"configElementName": "library",
"uid": "derby",
"id": "derby",
"apiTypeVisibility": "spec,ibm-api,api,stable",
"fileRef": [
{
"configElementName": "file",
"uid": "library[derby]/file[default-0]",
"name": "/home/nmittles/git/liberty/open-liberty/dev/build.image/wlp/usr/servers/blog/derby/derby.jar"
}
]
}
]
}
],
"statementCacheSize": 10,
"syncQueryTimeoutWithTransactionTimeout": false,
"transactional": true,
"properties.derby.embedded": [
{
"createDatabase": "create",
"databaseName": "memory:defaultdb",
"password": "******",
"user": "dbuser"
}
],
"api": [
"/ibm/api/validation/dataSource/DefaultDataSource"
]
}
OpenAPI documents
To make accessing the validation and config REST endpoints easier, their API documentation can viewed as dynamically generated OpenAPI documents when any MicroProfile OpenApi feature is enabled (mpOpenApi-1.0
or higher):
/openapi/platform/config
/openapi/platform/validation
These OpenAPI documents can be retrieved in either YAML or JSON format by specifying the format
parameter on the URL, with the default being YAML. Here is a sample of the validation OpenAPI document viewed as YAML (https://localhost:9443/openapi/platform/validation):
openapi: 3.0.2
info:
title: Validation API
description: The Validation REST endpoint tests the basic configuration of resources
by attempting to perform a simple operation on them.
version: "1.0"
servers:
- url: https://127.0.0.1:9443/ibm/api
security:
- basicAuth: []
paths:
/validation/cloudantDatabase/:
get:
tags:
- Validation
summary: Validation of all Cloudant Database configurations
description: Retrieves the validation results for all cloudantDatabase configuration
elements. Validation involves establishing a connection to the database and
querying basic metadata information.
parameters:
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
responses:
200:
description: Validation results retrieved
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/validation.cloudantDatabase.result'
/validation/cloudantDatabase/{uid}:
get:
tags:
- Validation
summary: Validation of a Cloudant Database configuration
description: Retrieves the validation result for the specified cloudantDatabase
configuration element. Validation involves establishing a connection to the
database and querying basic metadata information.
parameters:
- name: uid
in: path
description: '**Unique identifier**. For a cloudantDatabase element configured
at top level, this is the value of the `id` attribute, if present. Otherwise,
it is a generated value, such as *cloudantDatabase[default-0]*.'
required: true
explode: false
schema:
type: string
example: MyCloudantDB
examples:
example-cloudantdb-id:
summary: Top-level cloudantDatabase element with id
description: In this case, the uid is the same as the id.
value: myConFactory
example-cloudantdb-no-id:
summary: Top-level cloudantDatabase element without id
description: A generated uid for top-level cloudantDatabase configuration
element which lack an id is computed based on the order of appearance
within server config, starting at 0.
value: cloudantDatabase[default-0]
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
responses:
200:
description: Validation result retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/validation.cloudantDatabase.result'
/validation/connectionFactory/:
get:
tags:
- Validation
summary: Validation of all Connection Factories
description: Retrieves the validation results for all connection factories (apart
from JMS, which uses different config elements). Validation involves establishing
a connection to the backend, querying basic metadata information, and performing
additional interface-specific operations. For JDBC connection factories, the
`java.sql.Connection.isValid` operation is invoked. For CCI connection factories,
the `javax.resource.cci.Connection.createInteraction` operation is invoked.
parameters:
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation results retrieved
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/validation.connectionFactory.result'
/validation/connectionFactory/{uid}:
get:
tags:
- Validation
summary: Validation of a Connection Factory
description: Retrieves the validation result for the specified connection factory.
Validation involves establishing a connection to the backend, querying basic
metadata information, and performing additional interface-specific operations.
For JDBC connection factories, the `java.sql.Connection.isValid` operation
is invoked. For CCI connection factories, the `javax.resource.cci.Connection.createInteraction`
operation is invoked.
parameters:
- name: uid
in: path
description: '**Unique identifier**. For a connection factory configured at
top level, this is the value of the `id` attribute, if present. Otherwise,
it is a generated value, such as *connectionFactory[default-0]*.'
required: true
explode: false
schema:
type: string
example: MyConFactory
examples:
example-cf-id:
summary: Top-level connection factory with id
description: In this case, the uid is the same as the id.
value: myConFactory
example-cf-no-id:
summary: Top-level connection factory without id
description: A generated uid for top-level connection factories which
lack an id is computed based on the order of appearance within server
config, starting at 0.
value: connectionFactory[default-0]
example-cf-app-def:
summary: App-defined connection factory
description: References a connection factory defined by @ConnectionFactoryDefinition
within the MyApp application, with a name of java:app/env/eis/cf1
value: application[MyApp]/connectionFactory[java:app/env/eis/cf1]
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation result retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/validation.connectionFactory.result'
/validation/dataSource/:
get:
tags:
- Validation
summary: Validation of all Data Sources
description: Retrieves the validation results for all data sources. Validation
involves establishing a connection to the database, querying basic metadata
information, and performing the `java.sql.Connection.isValid` operation.
parameters:
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation results retrieved
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/validation.dataSource.result'
/validation/dataSource/{uid}:
get:
tags:
- Validation
summary: Validation of a Data Source
description: Retrieves the validation result for the specified data source.
Validation involves establishing a connection to the database, querying basic
metadata information, and performing the `java.sql.Connection.isValid` operation.
parameters:
- name: uid
in: path
description: '**Unique identifier**. For a data source configured at top level,
this is the value of the `id` attribute, if present. Otherwise, it is a
generated value, such as *databaseStore[defaultDatabaseStore]/dataSource[default-0]*.'
required: true
explode: false
schema:
type: string
example: DefaultDataSource
examples:
example-ds-id:
summary: Top-level dataSource with id
description: The default data source is configured at top-level and has
an id of DefaultDataSource.
value: DefaultDataSource
example-ds-no-id:
summary: Top-level dataSource without id
description: A generated uid for top-level data sources which lack an
id is computed based on the order of appearance within server config,
starting at 0.
value: dataSource[default-0]
example-ds-nested:
summary: Nested dataSource without id
description: References the first dataSource (index 0) that is nested
under the databaseStore element with id of defaultDatabaseStore.
value: databaseStore[defaultDatabaseStore]/dataSource[default-0]
example-ds-nested-under-singleton:
summary: Nested dataSource (without id) under singleton
description: References the first dataSource (index 0) that is nested
under the transaction element. The transaction element is a singleton
and cannot have an id.
value: transaction/dataSource[default-0]
example-ds-app-def:
summary: App-defined data source
description: References a data source defined by @DataSourceDefinition
within the MyApp application, in the MyWebModule module, with a name
of java:module/env/jdbc/ds1
value: application[MyApp]/module[MyWebModule]/dataSource[java:module/env/jdbc/ds1]
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation result retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/validation.dataSource.result'
/validation/jmsConnectionFactory/:
get:
tags:
- Validation
summary: Validation of all basic JMS Connection Factories
description: Retrieves the validation results for all basic JMS connection factories
(apart from QueueConnectionFactory and TopicConnectionFactory, which uses
different config elements). Validation involves establishing a connection
to the backend, querying basic metadata information, and creating & closing
a session.
parameters:
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation results retrieved
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/validation.jms.result'
/validation/jmsConnectionFactory/{uid}:
get:
tags:
- Validation
summary: Validation of a basic JMS Connection Factory
description: Retrieves the validation result for the specified basic JMS connection
factory. Validation involves establishing a connection to the backend, querying
basic metadata information, and creating & closing a session.
parameters:
- name: uid
in: path
description: '**Unique identifier**. For a JMS connection factory configured
at top level, this is the value of the `id` attribute, if present. Otherwise,
it is a generated value, such as *jmsConnectionFactory[default-0]*.'
required: true
explode: false
schema:
type: string
example: DefaultJMSConnectionFactory
examples:
example-jmscf-id:
summary: Top-level JMS connection factory with id
description: In this case, the uid is the same as the id.
value: DefaultJMSConnectionFactory
example-jmscf-no-id:
summary: Top-level JMS connection factory without id
description: A generated uid for top-level JMS connection factories which
lack an id is computed based on the order of appearance within server
config, starting at 0.
value: jmsConnectionFactory[default-0]
example-jmscf-app-def:
summary: App-defined JMS connection factory
description: References a JMS connection factory defined by @JMSConnectionFactoryDefinition
within the MyApp application, with a name of java:app/env/jms/cf1
value: application[MyApp]/jmsConnectionFactory[java:app/env/jms/cf1]
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation result retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/validation.jms.result'
/validation/jmsQueueConnectionFactory/:
get:
tags:
- Validation
summary: Validation of all JMS Queue Connection Factories
description: Retrieves the validation results for all JMS queue connection factories.
Validation involves establishing a connection to the backend, querying basic
metadata information, and creating & closing a session.
parameters:
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation results retrieved
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/validation.jms.result'
/validation/jmsQueueConnectionFactory/{uid}:
get:
tags:
- Validation
summary: Validation of a JMS Queue Connection Factory
description: Retrieves the validation result for the specified JMS queue connection
factory. Validation involves establishing a connection to the backend, querying
basic metadata information, and creating & closing a session.
parameters:
- name: uid
in: path
description: '**Unique identifier**. For a JMS queue connection factory configured
at top level, this is the value of the `id` attribute, if present. Otherwise,
it is a generated value, such as *jmsQueueConnectionFactory[default-0]*.'
required: true
explode: false
schema:
type: string
example: MyQueueConFactory
examples:
example-qcf-id:
summary: Top-level JMS queue connection factory with id
description: In this case, the uid is the same as the id.
value: myQueueConFactory
example-qcf-no-id:
summary: Top-level JMS queue connection factory without id
description: A generated uid for top-level JMS queue connection factories
which lack an id is computed based on the order of appearance within
server config, starting at 0.
value: jmsQueueConnectionFactory[default-0]
example-qcf-app-def:
summary: App-defined JMS queue connection factory
description: References a JMS queue connection factory defined by @JMSConnectionFactoryDefinition
within the MyApp application, in the MyWebModule module, with a name
of java:module/env/jms/qcf1
value: application[MyApp]/module[MyWebModule]/jmsQueueConnectionFactory[java:module/env/jms/qcf1]
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation result retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/validation.jms.result'
/validation/jmsTopicConnectionFactory/:
get:
tags:
- Validation
summary: Validation of all JMS Topic Connection Factories
description: Retrieves the validation results for all JMS topic connection factories.
Validation involves establishing a connection to the backend, querying basic
metadata information, and creating & closing a session.
parameters:
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation results retrieved
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/validation.jms.result'
/validation/jmsTopicConnectionFactory/{uid}:
get:
tags:
- Validation
summary: Validation of a JMS Topic Connection Factory
description: Retrieves the validation result for the specified JMS topic connection
factory. Validation involves establishing a connection to the backend, querying
basic metadata information, and creating & closing a session.
parameters:
- name: uid
in: path
description: '**Unique identifier**. For a JMS topic connection factory configured
at top level, this is the value of the `id` attribute, if present. Otherwise,
it is a generated value, such as *jmsTopicConnectionFactory[default-0]*.'
required: true
explode: false
schema:
type: string
example: MyTopicConFactory
examples:
example-tcf-id:
summary: Top-level JMS topic connection factory with id
description: In this case, the uid is the same as the id.
value: myTopicConFactory
example-tcf-no-id:
summary: Top-level JMS topic connection factory without id
description: A generated uid for top-level JMS topic connection factories
which lack an id is computed based on the order of appearance within
server config, starting at 0.
value: jmsTopicConnectionFactory[default-0]
example-tcf-app-def:
summary: App-defined JMS topic connection factory
description: References a JMS topic connection factory defined by @JMSConnectionFactoryDefinition
within the MyApp application, in the MyWebModule module, with a name
of java:comp/env/jms/tcf1
value: application[MyApp]/module[MyWebModule]/jmsTopicConnectionFactory[java:copy/env/jms/tcf1]
- $ref: '#/components/parameters/X-Validation-User'
- $ref: '#/components/parameters/X-Validation-Password'
- $ref: '#/components/parameters/auth'
- $ref: '#/components/parameters/authAlias'
- $ref: '#/components/parameters/loginConfig'
- $ref: '#/components/parameters/X-Login-Config-Props'
- $ref: '#/components/parameters/headerParamsURLEncoded'
responses:
200:
description: Validation result retrieved
content:
application/json:
schema:
$ref: '#/components/schemas/validation.jms.result'
components:
schemas:
validation.cloudantDatabase.result:
required:
- uid
- successful
type: object
properties:
uid:
type: string
description: unique identifier
id:
type: string
description: id of cloudantDatabase
jndiName:
type: string
description: jndiName of cloudantDatabase
successful:
type: boolean
description: result of validation
info:
type: object
properties:
uri:
type: string
serverVersion:
type: string
vendorName:
type: string
vendorVersion:
type: string
vendorVariant:
type: string
failure:
$ref: '#/components/schemas/cause'
example:
uid: myCloudantDB
id: myCloudantDB
jndiName: cloudant/db1
successful: true
info:
uri: http://myhost.rchland.ibm.com:5984/exampledb1
serverVersion: 2.0.0
vendorName: IBM Cloudant
vendorVersion: 1.1.0
vendorVariant: local
validation.connectionFactory.result:
required:
- uid
- successful
type: object
properties:
uid:
type: string
description: unique identifier
id:
type: string
description: id of connectionFactory
jndiName:
type: string
description: jndiName of connectionFactory
successful:
type: boolean
description: result of validation
info:
anyOf:
- type: object
properties:
resourceAdapterName:
type: string
resourceAdapterVersion:
type: string
resourceAdapterVendor:
type: string
resourceAdapterDescription:
type: string
connectorSpecVersion:
type: string
eisProductName:
type: string
eisProductVersion:
type: string
user:
type: string
- $ref: '#/components/schemas/info'
failure:
$ref: '#/components/schemas/cause'
example:
uid: myConnectionFactory
id: myConnectionFactory
jndiName: eis/conFactory1
successful: false
info:
resourceAdapterName: LibConnect Adapter
resourceAdapterVersion: 104.153.185
resourceAdapterVendor: OpenLiberty
resourceAdapterDescription: This isn't a real resource adapter.
connectorSepcVersion: "1.7"
eisProductName: VeryFast Enterprise DB
eisProductVersion: 44.117.125
user: dbuser1
failure:
errorCode: ERR_NOT_AUTHORIZED
class: javax.resource.spi.SecurityException
message: User has insufficient privileges to access the backend data store.
stack:
- org.example.lca.ConnectionImpl.createInteraction(ConnectionImpl.java:146)
- com.ibm.ws.rest.handler.validator.jca.ConnectionFactoryValidator.validateCCIConnectionFactory(ConnectionFactoryValidator.java:304)
- com.ibm.ws.rest.handler.validator.jca.ConnectionFactoryValidator.validate(ConnectionFactoryValidator.java:169)
- com.ibm.ws.rest.handler.validator.internal.ValidatorRestHandler.handleSingleInstance(ValidatorRestHandler:231)
cause:
class: javax.security.auth.login.LoginException
message: unauthorized
stack:
- org.example.lca.AuthHelper.verifyPrivileges(AuthHelper.java:82)
- org.example.lca.ConnectionImpl.authenticate(EFConnection.java:223)
- org.example.lca.ConnectionImpl.deferredLogin(EFConnection.java:385)
validation.dataSource.result:
required:
- uid
- successful
type: object
properties:
uid:
type: string
description: unique identifier
id:
type: string
description: id of dataSource
jndiName:
type: string
description: jndiName of dataSource
successful:
type: boolean
description: result of validation
info:
$ref: '#/components/schemas/info'
failure:
$ref: '#/components/schemas/cause'
example:
uid: myDataSource
id: myDataSource
jndiName: jdbc/ds1
successful: false
info:
databaseProductName: VeryFast Enterprise DB
databaseProductVersion: 44.117.125
jdbcProductName: EvenFaster JDBC
jdbcProductVersion: 52.165.173
catalog: exampledb
schema: MYSCHEMA
user: dbuser1
failure:
sqlState: "08004"
errorCode: "9409"
class: java.sql.SQLInvalidAuthorizationSpecException
message: User has insufficient privileges to access database.
stack:
- org.example.efjdbc.EFConnection.isValid(EFConnection.java:253)
- com.ibm.ws.rest.handler.validator.jdbc.DataSourceValidator(DataSourceValidator.java:129)
- com.ibm.ws.rest.handler.validator.internal.ValidatorRestHandler.handleSingleInstance(ValidatorRestHandler:231)
cause:
class: javax.security.auth.login.LoginException
message: unauthorized
stack:
- org.example.efjdbc.AuthHelper.verifyPrivileges(AuthHelper.java:82)
- org.example.efjdbc.EFConnection.authenticate(EFConnection.java:223)
- org.example.efjdbc.EFConnection.deferredLogin(EFConnection.java:385)
validation.jms.result:
required:
- uid
- successful
type: object
properties:
uid:
type: string
description: unique identifier
id:
type: string
description: id of config element
jndiName:
type: string
description: jndiName of config element
successful:
type: boolean
description: result of validation
info:
type: object
properties:
jmsProviderName:
type: string
jmsProviderVersion:
type: string
jmsProviderSpecVersion:
type: string
clientID:
type: string
failure:
$ref: '#/components/schemas/cause'
example:
uid: myJMS1
id: myJMS1
jndiName: jms/cf1
successful: false
info:
jmsProviderName: OpenL Messaging Provider
jmsProviderVersion: 39.80.89
jmsProviderSpecVersion: "2.0"
clientID: MyClient
failure:
errorCode: ERR_UNAUTHORIZED
class: javax.jms.SecurityException
message: User lacks authority to send or receive messages.
stack:
- org.example.am.JMSConnectionImpl.createSession(JMSConnectionImpl.java:71)
- com.ibm.ws.rest.handler.validator.jms.JMSConnectionFactoryValidator.validate(JMSConnectionFactoryValidator.java:150)
- com.ibm.ws.rest.handler.validator.jca.ConnectionFactoryValidator.validate(ConnectionFactoryValidator.java:189)
- com.ibm.ws.rest.handler.validator.internal.ValidatorRestHandler.handleSingleInstance(ValidatorRestHandler:231)
cause:
class: javax.security.auth.login.LoginException
message: unauthorized
stack:
- org.example.lca.AuthHelper.verifyPrivileges(AuthHelper.java:82)
- org.example.lca.ConnectionImpl.authenticate(EFConnection.java:223)
- org.example.lca.ConnectionImpl.deferredLogin(EFConnection.java:385)
info:
type: object
properties:
databaseProductName:
type: string
databaseProductVersion:
type: string
jdbcDriverName:
type: string
jdbcDriverVersion:
type: string
catalog:
type: string
schema:
type: string
user:
type: string
cause:
type: object
properties:
sqlState:
type: string
errorCode:
type: string
class:
type: string
message:
type: string
stack:
type: array
items:
type: string
cause:
$ref: '#/components/schemas/cause'
parameters:
X-Validation-User:
name: X-Validation-User
in: header
description: '**User**. Supplies a user name when not using Container-managed
authentication. All non-ASCII characters and other characters not allowed
in a header must be URL encoded, in which case be sure to specify the *headerParamsURLEncoded*
parameter.'
required: false
explode: false
schema:
type: string
X-Validation-Password:
name: X-Validation-Password
in: header
description: '**Password**. Supplies a password when not using Container-managed
authentication. All non-ASCII characters and other characters not allowed
in a header must be URL encoded, in which case be sure to specify the *headerParamsURLEncoded*
parameter.'
required: false
explode: false
schema:
type: string
format: password
auth:
name: auth
in: query
description: '**Authentication**. Determines whether to use a resource reference
with Application-managed or Container-managed authentication, or no resource
reference.'
required: false
explode: false
schema:
type: string
enum:
- application
- container
authAlias:
name: authAlias
in: query
description: '**Authentication Alias**. Supplies the `id` of an `authData` to
use for Container-managed authentication.'
required: false
explode: false
schema:
type: string
loginConfig:
name: loginConfig
in: query
description: '**Custom Login**. Supplies the `name` of a `jaasLoginContextEntry`
to use for Container-managed authentication.'
required: false
explode: false
schema:
type: string
X-Login-Config-Props:
name: X-Login-Config-Props
in: header
description: '**Login Config Properties**. Supply login config properties as
name/value pairs. Each name/value pair is a list element, within which the
name and value are delimited by the first `=` character. For example, *prop1=value1*.
All non-ASCII characters and other characters not allowed in a header must
be URL encoded, in which case be sure to specify the *headerParamsURLEncoded*
parameter.'
required: false
explode: false
schema:
type: array
items:
type: string
headerParamsURLEncoded:
name: headerParamsURLEncoded
in: query
description: Enable this if you URL-encode values for header parameters, such
as X-Validation-User, X-Validation-Password, or X-Login-Config-Props. URL
encoding is necessary to supply values that include non-ASCII characters and
other characters that are not allowed in a header.
required: false
explode: false
schema:
type: boolean
securitySchemes:
basicAuth:
type: http
scheme: basic
Now lets view the config API description as JSON (https://localhost:9443/openapi/platform/config?format=json):
{
"openapi" : "3.0.2",
"info" : {
"title" : "Config API",
"description" : "The Config REST endpoint retrieves information about configured elements and lists available REST API for each.",
"version" : "1.0"
},
"servers" : [ {
"url" : "https://127.0.0.1:9443/ibm/api"
} ],
"security" : [ {
"basicAuth" : [ ]
} ],
"paths" : {
"/config/" : {
"get" : {
"tags" : [ "Config" ],
"summary" : "Shows configuration of all elements",
"description" : "Retrieves configuration detail for instances of all configuration element types.",
"parameters" : [ {
"$ref" : "#/components/parameters/queryParams"
} ],
"responses" : {
"200" : {
"description" : "Configuration info retrieved",
"content" : {
"application/json" : {
"schema" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/config.result"
}
}
}
}
}
}
}
},
"/config/{elementName}" : {
"get" : {
"tags" : [ "Config" ],
"summary" : "Shows configurations of the requested config element type",
"description" : "Retrieves configuration detail for instances of the requested type of configuration element.",
"parameters" : [ {
"name" : "elementName",
"in" : "path",
"description" : "**Configuration element name**. The type of configuration element, such as `dataSource` or `application`.",
"required" : true,
"explode" : false,
"schema" : {
"type" : "string",
"example" : "dataSource"
}
}, {
"$ref" : "#/components/parameters/queryParams"
} ],
"responses" : {
"200" : {
"description" : "Configuration info retrieved",
"content" : {
"application/json" : {
"schema" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/config.result"
}
}
}
}
}
}
}
},
"/config/{elementName}/{uid}" : {
"get" : {
"tags" : [ "Config" ],
"summary" : "Shows configuration of a single instance of the requested type",
"description" : "Retrieves configuration detail for a single configuration element, uniquely qualfied by its unique identifier.",
"parameters" : [ {
"name" : "elementName",
"in" : "path",
"description" : "**Configuration element name**. The type of configuration element, such as `dataSource` or `application`.",
"required" : true,
"explode" : false,
"schema" : {
"type" : "string",
"example" : "dataSource"
}
}, {
"name" : "uid",
"in" : "path",
"description" : "**Unique identifier**. For an element configured at top level, this is the value of the `id` attribute, if present. Otherwise, it is a generated value, such as *dataSource[default-0]*.",
"required" : true,
"explode" : false,
"schema" : {
"type" : "string",
"example" : "DefaultDataSource"
},
"examples" : {
"example-id" : {
"summary" : "Top-level element with id",
"description" : "The uid of a top-level config element is the value of its `id` attribute, if present.",
"value" : "DefaultDataSource"
},
"example-no-id" : {
"summary" : "Top-level element without id",
"description" : "The uid of a top-level config element without an `id` attribute is computed based on the order of appearance within server config, starting at 0.",
"value" : "jmsConnectionFactory[default-0]"
},
"example-nested" : {
"summary" : "Nested element without id",
"description" : "This example shows a generated uid for the first connectionManager (index 0, lacking an id) that is nested under a dataSource element with id of DefaultDataSource.",
"value" : "dataSource[DefaultDataSource]/connectionManager[default-0]"
},
"example-nested-under-singleton" : {
"summary" : "Nested element (without id) under singleton",
"description" : "This example shows a generated uid for the first dataSource (index 0, lacking an id) that is nested under the transaction element. The transaction element is a singleton and cannot have an id.",
"value" : "transaction/dataSource[default-0]"
},
"example-app-def" : {
"summary" : "App-defined resource",
"description" : "The uid for application-defined resources, such as @DataSourceDefinition and @JMSConnectionFactoryDefinition, is computed based on the configured name and qualified by its scope. This example is for a @DataSourceDefinition in the MyApp application, in the MyWebModule module, with a name of java:module/env/jdbc/ds1",
"value" : "application[MyApp]/module[MyWebModule]/dataSource[java:module/env/jdbc/ds1]"
}
}
} ],
"responses" : {
"200" : {
"description" : "Configuration info retrieved",
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/config.result"
}
}
}
}
}
}
}
},
"components" : {
"schemas" : {
"config.result" : {
"required" : [ "configElementName" ],
"type" : "object",
"properties" : {
"configElementName" : {
"type" : "string",
"description" : "config element name"
},
"uid" : {
"type" : "string",
"description" : "unique identifier"
},
"id" : {
"type" : "string",
"description" : "id of configuration element"
},
"jndiName" : {
"type" : "string",
"description" : "jndiName of configuration element"
},
"api" : {
"type" : "array",
"description" : "relative paths to available REST endpoints for this configuration element",
"items" : {
"type" : "string"
}
}
},
"example" : {
"configElementName" : "dataSource",
"uid" : "DefaultDataSource",
"id" : "DefaultDataSource",
"beginTranForResultSetScrollingAPIs" : true,
"beginTranForVendorAPIs" : true,
"connectionSharing" : "MatchOriginalRequest",
"containerAuthDataRef" : {
"configElementName" : "containerAuthData",
"uid" : "dataSource[DefaultDataSource]/containerAuthData[default-0]",
"password" : "******",
"user" : "derbyuser1"
},
"enableConnectionCasting" : false,
"jdbcDriverRef" : {
"configElementName" : "jdbcDriver",
"uid" : "dataSource[DefaultDataSource]/jdbcDriver[default-0]",
"libraryRef" : {
"configElementName" : "library",
"uid" : "Derby",
"id" : "Derby",
"apiTypeVisibility" : "spec,ibm-api,api,stable",
"fileRef" : [ {
"configElementName" : "file",
"uid" : "library[Derby]/file[default-0]",
"name" : "/Users/myself/drivers/derby/derby.jar"
} ]
}
},
"statementCacheSize" : "10,",
"syncQueryTimeoutWithTransactionTimeout" : "false,",
"transactional" : "true,",
"properties.derby.embedded" : {
"createDatabase" : "create",
"databaseName" : "memory:derbydb"
},
"api" : [ "/ibm/api/validation/dataSource/DefaultDataSource" ]
},
"additionalProperties" : {
"anyOf" : [ {
"type" : "boolean"
}, {
"type" : "number"
}, {
"type" : "string"
}, {
"$ref" : "#/components/schemas/config.result"
}, {
"type" : "object"
}, {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/config.result"
}
} ]
}
}
},
"parameters" : {
"queryParams" : {
"name" : "queryParams",
"in" : "query",
"description" : "**Query Parameters**. Supply additional query parameters in JSON as key/value pairs. For example, the following parameters could be specified for an application-defined data source: *{ \"application\": \"MyApp\", \"jndiName\": \"java:app/env/jdbc/MyDataSource\" }*",
"required" : false,
"explode" : false,
"schema" : {
"type" : "object",
"example" : { },
"additionalProperties" : {
"type" : "string"
}
}
}
},
"securitySchemes" : {
"basicAuth" : {
"type" : "http",
"scheme" : "basic"
}
}
}
}
Validating a JCA connection factory
Here is a sample server.xml
configuration that uses the Configuration Validator and JCA features:
<server>
<featureManager>
<feature>appSecurity-2.0</feature>
<feature>restConnector-2.0</feature>
<feature>jca-1.7</feature>
</featureManager>
<keyStore id="defaultKeyStore" password="Liberty"/>
<basicRegistry>
<user name="blogAdmin" password="blogAdminPwd" />
<user name="blogReader" password="blogReaderPwd" />
<user name="blogUser" password="blogUserPwd" />
</basicRegistry>
<administrator-role>
<user>blogAdmin</user>
</administrator-role>
<reader-role>
<user>blogReader</user>
</reader-role>
<authData id="auth2" user="containerAuthUser2" password="2containerAuthUser"/>
<connectionFactory id="cf1" jndiName="eis/cf1">
<containerAuthData user="containerAuthUser1" password="1containerAuthUser"/>
<properties.TestValidationAdapter.ConnectionFactory hostName="myhost.openliberty.io" portNumber="9876"/>
</connectionFactory>
...
</server>
The REST endpoints for validating a connection factory can be found at https://localhost:9443/ibm/api/validation/connectionFactory/{uid}. To test cf1
using container authentication we can use the following URL: https://localhost:9443/ibm/api/validation/connectionFactory/cf1?auth=container:
{
"uid": "cf1",
"id": "cf1",
"jndiName": "eis/cf1",
"successful": true,
"info": {
"resourceAdapterName": "TestValidationAdapter",
"resourceAdapterVersion": "28.45.53",
"resourceAdapterJCASupport": "1.7",
"resourceAdapterVendor": "OpenLiberty",
"resourceAdapterDescription": "This tiny resource adapter doesn't do much at all.",
"eisProductName": "TestValidationEIS",
"eisProductVersion": "33.56.65",
"user": "containerAuthUser1"
}
}
Validation of a connection factory supports both container and application authentication by the auth
parameter being included on the URL. Additionally, when using ?auth=application
, a user can be specified by including the X-Validation-User
and X-Validation-Password
headers. Finally, the authentication alias can be specified using the authAlias
parameter. For example, this could look like https://localhost:9443/ibm/api/validation/connectionFactory/cf1?auth=container&authAlias=auth2.
Viewing JCA Connection Factories
JCA connection factory configuration can be viewed similar to that of data sources. The endpoint to view all connection factories becomes https://localhost:9443/ibm/api/config/connectionFactory. Again, our simple example only has one config element:
[
{
"configElementName": "connectionFactory",
"uid": "cf1",
"id": "cf1",
"jndiName": "eis/cf1",
"containerAuthDataRef": [
{
"configElementName": "containerAuthData",
"uid": "connectionFactory[cf1]/containerAuthData[default-0]",
"password": "******",
"user": "containerAuthUser1"
}
],
"properties.TestValidationAdapter.ConnectionFactory": [
{
"hostName": "myhost.openliberty.io",
"password": "******",
"portNumber": 9876,
"userName": "DefaultUserName"
}
]
}
]
To view an individual connection factory append the uid
. In our case this will be https://localhost:9443/ibm/api/config/connectionFactory/cf1:
{
"configElementName": "connectionFactory",
"uid": "cf1",
"id": "cf1",
"jndiName": "eis/cf1",
"containerAuthDataRef": [
{
"configElementName": "containerAuthData",
"uid": "connectionFactory[cf1]/containerAuthData[default-0]",
"password": "******",
"user": "containerAuthUser1"
}
],
"properties.TestValidationAdapter.ConnectionFactory": [
{
"hostName": "myhost.openliberty.io",
"password": "******",
"portNumber": 9876,
"userName": "DefaultUserName"
}
]
}
Cloudant Database
Cloudant databases can be viewed and validated as well.
Let’s use the following server config snippets:
<server>
<featureManager>
<feature>appSecurity-2.0</feature>
<feature>cloudant-1.0</feature>
<feature>restConnector-2.0</feature>
</featureManager>
<keyStore id="defaultKeyStore" password="Liberty"/>
<basicRegistry>
<user name="blogAdmin" password="blogAdminPwd" />
<user name="blogReader" password="blogReaderPwd" />
<user name="blogUser" password="blogUserPwd" />
</basicRegistry>
<administrator-role>
<user>blogAdmin</user>
</administrator-role>
<reader-role>
<user>blogReader</user>
</reader-role>
<library id="CloudantLib">
<fileset dir="${server.config.dir}/cloudant"/>
</library>
<authData id="cloudantAuthData" user="${CLOUDANT_USER}" password="${CLOUDANT_PASS}"/>
<cloudant id="myCloudant" jndiName="cloudant/myCloudant" libraryRef="CloudantLib" url="http://localhost:5984">
<containerAuthData user="cloudantUser" password="cloudantPass"/>
</cloudant>
<cloudantDatabase id="myCloudantDB" jndiName="cloudant/myCloudantDB" cloudantRef="myCloudant" databaseName="testdb" create="true"/>
<keyStore id="defaultKeyStore" password="Liberty"/>
<quickStartSecurity userName="adminuser" userPassword="adminpwd"/>
</server>
The Cloudant config can be viewed at https://localhost:9443/ibm/api/config/cloudantDatabase, while the myCloudantDB
database can be tested using container authentication at
https://localhost:9443/ibm/api/validation/cloudantDatabase/myCloudantDB?auth=container. Similar to JCA connection factories, Cloudant validation supports auth
types of container
and application
. The authentication alias can be specified as a parameter as well. For example, https://localhost:9443/ibm/api/validation/cloudantDatabase/myCloudantDB?auth=Application&authAlias=cloudantAuthData can be used to test the myCloudantDB
database using Application
authentication with an authentication alias of cloudantAuthData
.
So there you have it. You can now test database connections and other resources supporting configuration validation using REST APIs. If you have any feedback, questions, or suggestions about further support that would be useful, let us know by posting to our Groups.io account.