How to manage WildFly programmatically with DMR API

In this tutorial we will show how to use detyped management API to control your application server resources. The CLI tool that comes with the application server uses this interface, and user can develop custom clients that use it as well.

A detyped API works by making it possible to build up arbitrarily complex data structures using a small number of Java types. All of the parameter values and return values in the API are expressed using those few types. Ideally, most of the types are basic JDK types, like java.lang.String, java.lang.Integer, etc. In addition to the basic JDK types, WildFly’s detyped management API uses a small library called jboss-dmr.

The public API exposed by jboss-dmr is very simple: the primary class is org.jboss.dmr.ModelNode. A ModelNode is essentially just a wrapper around some value; the value is typically some basic JDK type. A ModelNode exposes a getType() method. This method returns a value of type org.jboss.dmr.ModelType, which is an enum of all the valid types of values.

In addition to jboss-dmr API the other module which is used to connect to the management API is jboss-as-controller-client. Both of these modules are included into the application server release 7.

Configuring the management API

First, include in your pom.xml  the following dependency:

<dependency>
   <groupId>org.jboss.as</groupId>
   <artifactId>jboss-as-controller-client</artifactId>
   <version>7.2.0.Final</version>
</dependency>

Then, include in your XML configuration the native interface element which has been deprecated in the default configuration:

<management-interfaces>
    <http-interface http-authentication-factory="management-http-authentication">
        <http-upgrade enabled="true" sasl-authentication-factory="management-sasl-authentication"/>
        <socket-binding http="management-http"/>
    </http-interface>

    <!-- Add the following native-interface -->
    <native-interface>
        <socket-binding native="management-native"/>
    </native-interface>

</management-interfaces>

That requires in turn the following socket-binding in your configuration:

<socket-binding name="management-native" interface="management" port="9999"/>

We are now ready to test our management API.

Coding a sample Class to manage WildFly programmatically

Here is a sample Servlet which performs a JNDI-lookup:

package com.sample;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.OperationBuilder;
import org.jboss.as.controller.client.helpers.ClientConstants;
import org.jboss.dmr.ModelNode;

@WebServlet("/jndi")
public class Test extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            PrintWriter out = response.getWriter();
            ModelNode op = new ModelNode();
            op.get("operation").set("jndi-view");

            ModelNode address = op.get("address");
            address.add("subsystem", "naming");

            op.get("recursive").set(true);
            op.get("operations").set(true);
            ModelControllerClient client = ModelControllerClient.Factory.create(
                    InetAddress.getByName("127.0.0.1"), 9999);

            ModelNode returnVal = client.execute(op);
            out.println(returnVal.get("result").toString());
            out.close();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
    }
}

}

In this example we have created a ModelNode with the following fields:

  • operation: the name of the operation to invoke. All operation requests must include this field and its value must be a String.
     
  • address: the address of the resource to invoke the operation against. This field’s must be of ModelType.LIST with each element in the list being a ModelType.PROPERTY. If this field is omitted the operation will target the root resource. Here we are targeting the jndi-view operation for the naming subsystem.

Running the Sample Servlet will display the JNDI tree of the application server:

wildfly modelclient

Source code for this example: https://github.com/fmarchioni/mastertheboss/tree/master/various/dmr

Here’s another sample which invokes the read-resource command on the available data sources:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {

            PrintWriter out = response.getWriter();
            List<ModelNode> dataSources = getDataSources();
            for (ModelNode dataSource : dataSources) {
                out.println("Datasource: " + dataSource.asString());
            }

            out.close();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static List<ModelNode> getDataSources() throws IOException {
        final ModelNode request = new ModelNode();
        request.get(ClientConstants.OP).set("read-resource");
        request.get("recursive").set(true);
        request.get(ClientConstants.OP_ADDR).add("subsystem", "datasources");
        ModelControllerClient client = null;
        try {
            client = ModelControllerClient.Factory.create(InetAddress.getByName("127.0.0.1"), 9999);
            final ModelNode response = client.execute(new OperationBuilder(request).build());

            return response.get(ClientConstants.RESULT).get("data-source").asList();
        } finally {
            safeClose(client);
        }
    }

    public static void safeClose(final Closeable closeable) {
        if (closeable != null) try {
            closeable.close();
        } catch (Exception e) {
            // no-op
        }
    }

Creating a Datasource programmatically

By using the Model API, you can also create resources. For example, here is how to create a Datasource programmatically:

public void createMySQLDatasource() throws Exception{
  ModelNode request = new ModelNode();
  request.get(ClientConstants.OP).set(ClientConstants.ADD);
  request.get(ClientConstants.OP_ADDR).add("subsystem","datasources");
  request.get(ClientConstants.OP_ADDR).add("data-source","java:/MySQLDS");
  request.get("jndi-name").set("java:/MySQLDS");
  request.get("connection-url").set("jdbc:mysql://localhost/test");
  request.get("driver-class").set("com.mysql.jdbc.Driver");
  request.get("driver-name").set("mysql-connector-java-5.1.29-bin.jar");
  request.get("user-name").set("username");
  request.get("password").set("password");
  request.get("pool-name").set("pool_NewDatasource");
  ModelControllerClient client = ModelControllerClient.Factory.create(InetAddress.getByName("127.0.0.1"), 9999);
  client.execute(new OperationBuilder(request).build());
}

In the above example we have created programmatically a Datasource bound into the “Java:/MySQLDS” JNDI binding, using the mysql-connector-java-5.1.29-bin.jar Driver.

Found the article helpful? if so please follow us on Socials