rest Posts

Creating a Rest API Call with WorkItemHandler on Red Hat Process Automation Manager

Usually we are using tasks for showing steps of process on top of Red Hat Process Automation Manager (RHPAM). But most of the time we need a customized task involved, thats where WorkItemHandler comes in handy.
For this demo, im trying to create a simple WorkItemHandler to create a custom task on top of RHPAM which is getting some response from a third party api provider.

So here is pretty much the raw concept,

As usual, for beginning we need to create a pom xml file, and it is important to put “scope” variable as provided.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>AnimeWorkItemHandler</artifactId>
    <version>1.0.4</version>
    <description>a simple rest api to be used within RHPAM</description>
    <packaging>jar</packaging>


    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <distributionManagement>
        <repository>
            <id>repo-custom</id>
            <url>http://nexus:8081/repository/pam/</url>
        </repository>
        <snapshotRepository>
            <id>repo-custom</id>
            <url>http://nexus:8081/repository/pam/</url>
        </snapshotRepository>
    </distributionManagement>

    <dependencies>
        <dependency>
            <groupId>org.jbpm</groupId>
            <artifactId>jbpm-flow</artifactId>
            <version>7.38.0.Final</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>1.9.9</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.9</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-xc</artifactId>
            <version>1.9.9</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
</project>

and simple java class to do a simple REST Api call,

package com.edw;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;

import org.codehaus.jackson.map.ObjectMapper;
import org.drools.core.process.instance.WorkItemHandler;
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemManager;

public class AnimeWorkItemHandler implements WorkItemHandler {
    public void abortWorkItem(WorkItem wi, WorkItemManager wim) {
        wim.abortWorkItem(wi.getId());
    }

    // will try fire to https://jikan.moe/ api
    public void executeWorkItem(WorkItem wi, WorkItemManager wim) {
        String name = (String) wi.getParameter("name");

        String nameResponse = "";
        String imageUrl = "";

        try {
            // api endpoint = https://api.jikan.moe/v3/search/character?q=???&limit=1
            URL url = new URL(String.format("https://api.jikan.moe/v3/search/character?q=%s&limit=1", name));

            URLConnection urlConnection = url.openConnection();
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                            urlConnection.getInputStream()));
            String inputLine;
            StringBuffer stringBuffer = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                stringBuffer.append(inputLine);
            }

            ObjectMapper objectMapper = new ObjectMapper();
            HashMap jsonResult = objectMapper.readValue(stringBuffer.toString(), HashMap.class);
            List<HashMap> results = (List<HashMap>) jsonResult.get("results");

            nameResponse = (String) results.get(0).get("name");
            imageUrl = (String) results.get(0).get("image_url");

            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        HashMap result = new HashMap();
        result.put("nameResponse", nameResponse);
        result.put("imageUrl", imageUrl);
        wim.completeWorkItem(wi.getId(), result);
    }
}

Once created, we need to build it by using an mvn command

mvn clean package

After jar has been build, next step is to upload that jar thru your Business Central,

If uploading success, we can see the uploaded jar file within our Nexus

Next is lets go to RHPAM dashboard, and create a work item definition

And put this values, make sure that the content of “parameters” and “result” is the same as on your java class, which in my case is “name”, “nameResponse” and “imageUrl”.

[
  [
    "name" : "AnimeWorkItemHandler", 
    "parameters" : [ 
        "name" : new StringDataType() 
    ], 
    "results" : [ 
        "nameResponse" : new StringDataType(),
        "imageUrl" : new StringDataType() 
    ], 
    "displayName" : "AnimeWorkItemHandler", 
    "icon" : "" 
  ]
]

The next step, and pehaps the most important is, include our newly created jar file into RHPAM project. We can do so by going thru “Settings” tab, and create a new Work Item Handlers,

And import the library and dependency needed

The last is adding our new WorkItemHandler to our existing workflow,

So as you can see, it’s not that difficult to create a custom task on RHPAM. And for the full code for this project can be accessed on my github page,

https://github.com/edwin/anime-work-item-handler

Beginning REST Using JBoss RESTEasy

On today’s demo im trying to use RESTEasy to handle multiple REST requests. According to Wikipedia, REST (Representational state transfer) is a style of software architecture for distributed hypermedia systems such as the World Wide Web. While RESTEasy is a JBoss project that provides various frameworks to help you build RESTful Web Services and RESTful Java applications. It is a fully certified and portable implementation of the JAX-RS specification. JAX-RS is a new JCP specification that provides a Java API for RESTful Web Services over the HTTP protocol.

On this project, im trying to create 2 different services. 1 service to get all objects, while another one for fetching a single objects. I create 2 different responses type for each service, JSON and XML. Okay, so lets try with 2 simple javabeans.

package com.edw.bean;

import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {

    private String name;
    private String address;
    private int age;

    @XmlElement(name="book")
    @XmlElementWrapper(name = "books")
    private List<Book> books;

    public Student() {
    }

    public Student(String name, String address, int age, List<Book> books) {
        this.name = name;
        this.address = address;
        this.age = age;
        this.books = books;
    }

	// other setter getter

    @Override
    public String toString() {
        return "Student{" + "name=" + name + ", address=" + address + ", age=" + age + ", books=" + books + '}';
    }
}
package com.edw.bean;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Book {

    private String title;
    private double price;

    public Book() {
    }

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

	// other setter getter

    @Override
    public String toString() {
        return "Book{" + "title=" + title + ", price=" + price + '}';
    }
}

Now, you need to create a java class to handle all REST services,

package com.edw.rest;

import com.edw.bean.Book;
import com.edw.bean.Student;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/service/student")
public class StudentRest {

    @GET
    @Path("/json")
    @Produces(MediaType.APPLICATION_JSON)
    // path would be http://localhost:8080/YourProject/service/student/json
    public List<Student> getStudentsJSON() {
        return getStudents();
    }

    @GET
    @Path("/xml")
    @Produces(MediaType.APPLICATION_XML)
    // path would be http://localhost:8080/YourProject/service/student/xml
    public List<Student> getStudentsXML() {
        return getStudents();
    }

    @GET
    @Path("/json/{name}")
    @Produces(MediaType.APPLICATION_JSON)
    // path would be http://localhost:8080/YourProject/service/student/json/insertyournamehere
    public Student getStudentJSON(@PathParam("name") String name) {
        return new Student(name, name + " Address", 10, getBooks());
    }

    @GET
    @Path("/xml/{name}")
    @Produces(MediaType.APPLICATION_XML)
    // path would be http://localhost:8080/YourProject/service/student/xml/insertyournamehere
    public Student getStudentXML(@PathParam("name") String name) {
        return new Student(name, name + " Address", 10, getBooks());
    }

    private List<Book> getBooks() {
        List<Book> books = new ArrayList<Book>();
        books.add(new Book("Harry Potter", 100d));
        books.add(new Book("Lord of the Ring", 120d));
        books.add(new Book("Chicken Soup", 20d));
        books.add(new Book("Doraemon", 190d));
        books.add(new Book("Laskar Pelangi", 200d));
        return books;
    }

    private List<Student> getStudents() {
        List<Student> students = new ArrayList<Student>();
        students.add(new Student("Edwin", "Jakarta", 25, getBooks()));
        students.add(new Student("Kamplenk", "Ciledug", 29, getBooks()));
        students.add(new Student("Tebek", "Pamulang", 38, getBooks()));
        students.add(new Student("Syamsu", "Bandung", 60, getBooks()));
        return students;
    }
}

And dont forget to register your service class

package com.edw.config;

import com.edw.rest.StudentRest;
import java.util.Set;
import java.util.HashSet;
import javax.ws.rs.core.Application;

public class ApplicationConfig extends Application {

    private Set<Object> singletons = new HashSet<Object>();
    private Set<Class<?>> empty = new HashSet<Class<?>>();

    public ApplicationConfig() {
        singletons.add(new StudentRest());
    }

    @Override
    public Set<Class<?>> getClasses() {
        return empty;
    }

    @Override
    public Set<Object> getSingletons() {
        return singletons;
    }
}

And last, register all in your web.xml file

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.edw.config.ApplicationConfig</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Here are some screenshots,

Have fun with RESTEasy 😉