Masoud Kalali's Blog

My thoughts on software engineering and beyond…

By

How REST interface covers for the absence of JMX/AMX administration and management interface in GlassFish 3.1

For sometime I wanted to write this entry and explain what happened to GlassFish JMX/AMX management and administration interface but being busy with other stuff prevented me from doing so. This article here can be an upgrade to my other article about GlassFish 3.0 JMX administration interface which I wrote while ago. Long story short, in GlassFish 3.1 the AMX/JMX is no longer available and instead we can use the REST interface to change the server settings and perform all administration/management and monitoring activities we need. There are fair number of articles and blog entries all over the web about the RESTful interface which I included them at the end of this blog. Firs of all the rest interface is available trough the administration console application meaning that we can access the interface using a URL similar to: http://localhost:4848/management/domain/ The administration console and the rest interface  are running on a separate virtual server and therefore a separate HTTP Listener and if required transport configuration. What I will explain here will be the following items:

  • How to use Apache HttpClient to perform administration tasks using GlassFish REST interface
  • How to find the request parameters for different commands.
  • GlassFish administration, authentication and transport security

How to use Apache HttpClient to interact with GlassFish administration and management application

Now back to the RESTful interface, this is a HTTP based interaction channel with the GlassFish administration infrastructure which basically allows us to do almost anything possible to do using asadmin trhough HTTP in a RESTful manner. We can use basically any programming language capable to writing on a socket to interact with the RESTFul interface. Here we will use Apache HTTPClient to take care of sending the commands to GlassFish RESTFul console. When using GlassFish REST management we can use any of the POST/GET and DELETE methods to perform the following tasks:

  • POST: create and partially update a resource
  • GET: get information like details of a connection pool
  • DELETE: to delete a resource

Following sample code shows how to use the  to perform some basic operations including updating a resource, getting some resources list, creating a resource and finally deleting it.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.logging.Logger;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;

/**
 *
 * @author Masoud Kalali
 */
public class AdminGlassFish {

    //change the ports to your own settng
    private static final String ADMINISTRATION_URL = "http://localhost:4848/management";
    private static final String MONITORING_URL = "http://localhost:4848/monitoring";
    private static final String CONTENT_TYPE_JSON = "application/json";
    private static final String CONTENT_TYPE_XML = "application/xml";
    private static final String ACCEPT_ALL = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    private static final Logger LOG = Logger.getLogger(AdminGlassFish.class.getName());

    public static void main(String args[]) throws IOException, HttpException, URISyntaxException {

        //just chaning the indent level for the JSON and XML output to make them readable, for humans...
        String prettyFormatRestInterfaceOutput = "{"indentLevel":2}";
        String response = postInformation("/domain/configs/config/server-config/_set-rest-admin-config", prettyFormatRestInterfaceOutput);
        LOG.info(response);
        //getting list of all JDBC resources
        String jdbcResources = getInformation("/domain/resources/list-jdbc-resources");
        LOG.info(jdbcResources);

//        creating  a JDBC resource on top of the default pool
        String createJDBCResource = "{"id":"jdbc/Made-By-Rest","poolName":"DerbyPool"}";
        String resourceCreationResponse = postInformation("/domain/resources/jdbc-resource", createJDBCResource);
        LOG.info(resourceCreationResponse);

//        deleting a JDBC resource
        String deletionReponse = deleteResource("/domain/resources/jdbc-resource/jdbc%2FMade-By-Rest");
        LOG.info(deletionReponse);

    }

    //using HTTP get
    public static String getInformation(String resourcePath) throws IOException, AuthenticationException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet httpG = new HttpGet(ADMINISTRATION_URL + resourcePath);
        httpG.setHeader("Accept", CONTENT_TYPE_XML);
        HttpResponse response = httpClient.execute(httpG);
        HttpEntity entity = response.getEntity();
        InputStream instream = entity.getContent();
        return isToString(instream);
    }

    //using HTTP post for creating and partially updating resources
    public static String postInformation(String resourcePath, String content) throws IOException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(ADMINISTRATION_URL + resourcePath);
        StringEntity entity = new StringEntity(content);

        //setting the content type
        entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_JSON));
        httpPost.addHeader("Accept",ACCEPT_ALL);
        httpPost.setEntity(entity);
        HttpResponse response = httpClient.execute(httpPost);

        return response.toString();
    }

    //using HTTP delete to delete a resource
    public static String deleteResource(String resourcePath) throws IOException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpDelete httpDelete = new HttpDelete(ADMINISTRATION_URL + resourcePath);
        httpDelete.addHeader("Accept",
                ACCEPT_ALL);
        HttpResponse response = httpClient.execute(httpDelete);
        return response.toString();

    }

//converting the get output stream to something printable
    private static String isToString(InputStream in) throws IOException {
        StringBuilder sb = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(in), 1024);
        for (String line = br.readLine(); line != null; line = br.readLine()) {
            sb.append(line);
        }
        in.close();
        return sb.toString();
    }
}

You may ask how could one know what are the required attributes names, there are several ways to do it:

  • Look at the reference documents…
  • View the source code of the html page representing that kind of resource, for example for the JDBC resource it is like http://localhost:4848/management/domain/resources/jdbc-resource which if you open it in the browser you will see an html page and viewing its source will give you the names of different attributes. I think the label for the attributes is also the same as the attributes themselves.

  • Submit the above page and monitor the request using your browser plugin, for example in case of chrome and for the JDBC resource it is like the following picture

GlassFish administration, authentication and transport security

By default when we install GlassFish or we create a domain the domain administration console is not protected by authentication nor it is protected by HTTPS so whatever we send to the application server from through this channel will be readable by someone sniffing around. Therefore you may need to enable authentication using the following command:

You may ask now that we enabled the authenticaiton for the admin console, how we can use it by our sample code, the answer is quite simple,  Just set the credentials for the request object and you are done. Something like:

UsernamePasswordCredentials cred = new UsernamePasswordCredentials("admin", "admin");
httpget.addHeader(new BasicScheme().authenticate(cred, httpget));

Make sure that you are using correct username and passwords as well as correct request object. In this case the request object is httpGet

Now about the HTTPs to have have encryption during the transport we need to enable the SSL for the admin HTTP listener. following steps show how to use the RESTFul interface through a browser to enable HTTPS for the admin console. When using the browser, GlassFish admin console shows basic HML forms for different resources.

  1. Open the http://localhost:4848/management/domain/configs/config/server-config/network-config/protocols/protocol/admin-listener in the browser
  2. Select true for security-enabled option element
  3. Click Update to save the settings.
  4. Restart server using http://localhost:4848/management/domain/restart

The above steps have the same effect as

This will enable the SSL layer for the admin-listener but it will use the default, self singed certificate. Here I explained how to install a GoDaddy digital certificate into GlassFish application server to be sure that none can listen during the transport of command parameters and on the other hand the certificate is valid instead of being self signed. And here I explained how one can use the EJBCA to setup and use an small inter-corporate certificate authority with GlassFish, though the manual is a little old but it will give you enough understanding to use the newer version of EJBCA.

If you are asking about how our small sample application can work with this dummy self signed certificate of GlassFish you need to wait till next time that I will explain how to bypass the invalid certificate installed on our test server.

In the next part of this series I will cover more details on the monitoring part as well as discussing  how to bypass the self signed Digital certificate during the development…

11 Responses to How REST interface covers for the absence of JMX/AMX administration and management interface in GlassFish 3.1

  1. cbe317 says:

    Is it possible to deploy a WAR or an EAR using the REST interface?

  2. admin says:

    Yes, it is possible to deploy war and ear files. Take a look at the following link to see how. http://blogs.steeplesoft.com/2011/02/deploying-applications-to-glassfish-using-curl/

  3. Bas van Gils says:

    I was quite surprised when I read your article about removed JMX/AMX support in GlassFish 3.1.
    We use it for monitoring our production servers and currently we are migrating from GlassFish 3.0.1 to 3.1.1.

    So I fired up VisualVM and connected it to our test-server with 3.1.1 and there I do see AMX MBeans!

    So I don’t understand… can you enlighten me?

  4. Amit says:

    Nice post. Thanks for sharing the code. It made it easy to create the connection pool.

    How can I retrieve the javax.sql.DataSource instance after it is created by the above way?

    • Masoud Kalali says:

      I am not sure if I understand the question completely but you can use @Resource(name=”jdbc/datasource_Name”) to inject it into a Java EE component and use it if it is what you meant. You can retrieve the newly created data source using a resource uri like …/domain/resources/jdbc-resource/jdbc_res_id

  5. Amit says:

    Thanks for the reply.

    I need to create a jdbc connection pool programmatically since the pool configuration is dynamic. Hence in an actual environment, the web application deployed in glassfish will create a jdbc connection pool.

    I was able to create the pool by having a look at the code in this post. Now how can I retrieve an instance of javax.sql.DataSource so that the web application can then further use it to create database connections.

    The two suggestions you provided doesn’t suit the above requirements
    1. @Resource(name=”jdbc/datasource_Name”) because the pool creation is dynamic.
    2. How can construct an instance of javax.sql.DataSource class from the xml response retrieved by using the resource url “domain/resources/jdbc-resource/jdbc_res_id”

    Any more suggestions?

  6. Amit says:

    Thanks for the reply.
    To complete my jdbc connection pool configuration, I would have to add properties detailing the server name, user, port number etc. Any suggestions on how should the json string look like for adding properties during connection pool creation?

    I will follow up on the JNDI lookup too. Thanks.

  7. Hi Masoud, nice blog. FYI – starting with GF 3.1.2 you also need to add “X-Requested-By” header to every state changing request (i.e. for HTTP POST and DELETE) as the admin REST ifc started using the CsrfProtectionFilter from Jersey – see http://blog.alutam.com/2011/09/14/jersey-and-cross-site-request-forgery-csrf/
    Maybe you could update this blog entry with that information.
    Btw, if you used Jersey Client API instead of Apache HTTP client, adding the client CsrfProtectionFilter on the client side would be the way to go. Thanks!

  8. Hatem says:

    please i have a have a problem i want to change Maxpoolsize of the DerbyPool i used your code whitch is

    String query = “amx:j2eeType=X-JDBCConnectionPoolConfig,name=DerbyPool”;

    ObjectName queryName = new ObjectName(query);

    Set s = mbsc.queryNames(queryName, null);

    derbyPool = (ObjectName) s.iterator().next();

    mbsc.setAttribute(derbyPool, new Attribute(“MaxPoolSize”, new Integer(64)));

    but it doesn’t work because the problem is in the line

    derbyPool = (ObjectName) s.iterator().next();

    s is null
    and thank’s for your help Mr Masoud Kalali :)

Leave a Reply

Your email address will not be published. Required fields are marked *


− 7 = zero

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">