sábado, 14 de janeiro de 2012

The GateIn Management/Navigation API

Consuming popular APIs is very interesting and cool. You can in a few minutes seek in the web some how-to, or a sample application and create yours. After create a lot of these kind of applications I got myself bored and no motivation to keep posting. For example, a Twitter app will be only another twitter app and there's a lot of API needing clients or needing to be explored.

So I started to look new APIs to explore. One of these not well recognized, but very well designed in REST terms is GateIn Management API. GateIn is the JBoss Java Portal an it is a great tool with a big community behind it.



The GateIn 3.2 API is not hard to understand and you can learn more about it in this great documentation. Basically we have the base resource called... Resource. The Resource contains all the possible operations and their children. You can navigate by the children and find more operations. You will notice that the more notable feature of this API is the presence of HATEOAS. The API also serve data in XML and JSON formats. You can test the API, but you will need to have the GateIn running somewhere to access. Here is a sample of the response body when you access the base URL in my local installation(I'm using EPP, the enterprise product from Red Hat based in GateIn, so the context may change for pure GateIn installation):

GET on http://192.168.56.101:8080/rest/private/managed-components/
{"description": "Available operations and children (sub-resources).","children": [{"name": "mop","description": "MOP (Model Object for Portal) Managed Resource, responsible for handling management operations on navigation, pages, and sites.","link": {"rel": "child","href": "http://192.168.56.101:8080/rest/private/managed-components/mop"}}],"operations": [{"operation-name": "read-resource","operation-description": "Lists information about a managed resource, including available operations and children (sub-resources).","link": {"rel": "self","href": "http://192.168.56.101:8080/rest/private/managed-components"}}]}

I made a very simple command line app to consume this API and learn more about it. It was used RESTEasy Client API. It is important to say that this API requires authentication since it exposes information of all GateIn groups.

package org.gateinmanager.test.model;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

import javax.ws.rs.core.MediaType;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.gateinmanager.model.Child;
import org.gateinmanager.model.Link;
import org.gateinmanager.model.Operation;
import org.gateinmanager.model.Resource;
import org.jboss.resteasy.client.ClientExecutor;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientRequestFactory;
import org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor;

/**
 * 
 * It will just test the request is being parsed to domain objects...
 * 
 * @author jesuino
 * 
 */
@SuppressWarnings("deprecation")
public class TestModel {
    private static final String USERNAME = "root";
    private static final String PASSWORD = "gtn";

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {

        ClientRequestFactory factory = createFactory(USERNAME, PASSWORD);
        Scanner sc = new Scanner(System.in);
        String in;

        Resource resource = null;
        System.out.println("\t\t*****GateIn Management API*****\n\n");

        System.out
                .println(">> Enter the HOST to start navigating or press"
                        + " Q to quit (the base URL is "
                        + "http://192.168.56.101:8080/rest/private/managed-components)\n");
        while (!(in = sc.next()).startsWith("Q")) {
            // Entered a URL, just load Resource and print it
            if (in.startsWith("http://")) {
                ClientRequest cr = factory.createRequest(in);
                cr.accept(MediaType.APPLICATION_XML);
                try {
                    System.out.println("Loading...");
                    resource = (Resource) cr.get().getEntity(Resource.class);
                    System.out.println("Resource loaded!");
                } catch (Exception e) {
                    System.out
                            .println("\n\n>>>  Something went wrong when loading your URL...\n");
                    e.printStackTrace();
                }
            } else {
                System.out
                        .println("\nPlease enter a valid URL or press Q to quit...");
            }
            if (resource != null)
                printResource(resource);
            System.out.println("\n>> Enter URL or Q to quit: ");
        }

    }

    public static ClientRequestFactory createFactory(String username,
            String password) throws URISyntaxException {
        // Setting Credentials though an HttpExecutor
        Credentials credentials = new UsernamePasswordCredentials(username,
                password);
        HttpClient httpClient = new HttpClient();
        httpClient.getState().setCredentials(AuthScope.ANY, credentials);
        httpClient.getParams().setAuthenticationPreemptive(true);
        ClientExecutor clientExecutor = new ApacheHttpClientExecutor(httpClient);

        // creating the factory
        return new ClientRequestFactory(clientExecutor, new URI(""));
    }

    public static void printResource(Resource resource) {
        System.out.println("**\t" + resource.getDescription() + "\t**\n");
        System.out.println("Possible Operations:");
        List<Operation> operations = resource.getOperations();
        if (operations != null) {
            for (Operation operation : operations) {
                Link link = operation.getOperationLink();
                System.out.println("\t* " + operation.getOperationName() + ": "
                        + operation.getOperationDescription() + "\n\t   rel: "
                        + link.getRel() + ". Located at " + link.getHref());
            }
        }

        Set<Child> children = resource.getChildren();
        if (children != null) {
            System.out.println("\nChildren:");
            for (Child child : children) {
                Link link = child.getLink();
                System.out.println("\t* " + child.getName() + ": "
                        + child.getDescription() + "\n\t   rel: "
                        + link.getRel() + ". Located at " + link.getHref());
            }
        }

    }
}



The authentication part of this code is the most boring. We need to set it in the Executor, which who will make the authentication behind RESTEasy calls. We use RESTEasy factory to create requests based on the URI supplied by the user of the application. From the response, we retrieve the body as object using the model objects from GateIn REST API source code. Here is the application running:


*****GateIn Management API*****

>> Enter the HOST to start navigating or press Q to quit (the base URL is http://192.168.56.101:8080/rest/private/managed-components)
http://192.168.56.101:8080/rest/private/managed-components
Loading...
Resource loaded!
** Available operations and children (sub-resources). **
Possible Operations:
* read-resource: Lists information about a managed resource, including available operations and children (sub-resources).
  rel: self. Located at http://192.168.56.101:8080/rest/private/managed-components
Children:
* mop: MOP (Model Object for Portal) Managed Resource, responsible for handling management operations on navigation, pages, and sites.
  rel: child. Located at http://192.168.56.101:8080/rest/private/managed-components/mop
>> Enter URL or Q to quit:
http://192.168.56.101:8080/rest/private/managed-components/mop
Loading...
Resource loaded!
** Available site types. **
Possible Operations:
* read-resource: Lists available site types for a portal
  rel: self. Located at http://192.168.56.101:8080/rest/private/managed-components/mop
* export-resource: Exports any resources with an export operation handler registered.  This operation is recursive until an operation handler is found.
  rel: content. Located at http://192.168.56.101:8080/rest/private/managed-components/mop.zip
* import-resource: Imports mop data from an exported zip file.
  rel: operation. Located at http://192.168.56.101:8080/rest/private/managed-components/mop
Children:
* portalsites: Management resource responsible for handling management operations on a specific site type for a portal.
  rel: child. Located at http://192.168.56.101:8080/rest/private/managed-components/mop/portalsites
* usersites: Management resource responsible for handling management operations on a specific site type for a portal.
  rel: child. Located at http://192.168.56.101:8080/rest/private/managed-components/mop/usersites
* groupsites: Management resource responsible for handling management operations on a specific site type for a portal.
  rel: child. Located at http://192.168.56.101:8080/rest/private/managed-components/mop/groupsites
>> Enter URL or Q to quit:
Q

I have a critic to this REST API that is the use of the ".xml" in some URIs , but the API design is good for the portal management for its composite architecture (Everything is a resource and has children). I hope post something more graphical in next weeks :-D

Um comentário:

  1. Thanks for the sample of code.

    It is interesting and helpfull.

    I'll use it to build my site with GateIn :

    http://www.presta-expert.com/pexpalctnr/pcr

    Antoine

    ResponderExcluir