back to all blogsSee all blog posts

Testing database connections in Open Liberty apps with REST APIs

image of author
Nathan Mittlestat on Sep 13, 2019
Post available in languages:

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.

Try it now