There are many stuff in the internet how to work with RESTful Client API. These are basics. But even though the subject seems to be trivial, there are hurdles, especially for beginners. In this post I will try to summurize my know-how how I did this in real projects. I usually use Jersey (reference implementation for building RESTful services). See e.g.
my other post. In this post, I will call a real remote service from JSF beans. Let's write a session scoped bean
RestClient.
package com.cc.metadata.jsf.controller.common;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
/**
* This class encapsulates some basic REST client API.
*/
@ManagedBean
@SessionScoped
public class RestClient implements Serializable {
private transient Client client;
public String SERVICE_BASE_URI;
@PostConstruct
protected void initialize() {
FacesContext fc = FacesContext.getCurrentInstance();
SERVICE_BASE_URI = fc.getExternalContext().getInitParameter("metadata.serviceBaseURI");
client = Client.create();
}
public WebResource getWebResource(String relativeUrl) {
if (client == null) {
initialize();
}
return client.resource(SERVICE_BASE_URI + relativeUrl);
}
public ClientResponse clientGetResponse(String relativeUrl) {
WebResource webResource = client.resource(SERVICE_BASE_URI + relativeUrl);
return webResource.accept("application/json").get(ClientResponse.class);
}
}
In this class we got the service base URI which is specified (configured) in the
web.xml.
<context-param>
<param-name>metadata.serviceBaseURI</param-name>
<param-value>http://somehost/metadata/</param-value>
</context-param>
Furthermore, we wrote two methods to receive remote resources. We intend to receive resources in JSON format and convert them to Java objects. The next bean demonstrates how to do this task for GET requests. The bean
HistoryBean converts received JSON to a
Document object by using
GsonConverter. The last two classes will not be shown here (they don't matter).
Document is a simple POJO and
GsonConverter is a singleton instance which wraps
Gson.
package com.cc.metadata.jsf.controller.history;
import com.cc.metadata.jsf.controller.common.RestClient;
import com.cc.metadata.jsf.util.GsonConverter;
import com.cc.metadata.model.Document;
import com.sun.jersey.api.client.ClientResponse;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
/**
* Bean getting history of the last extracted documents.
*/
@ManagedBean
@ViewScoped
public class HistoryBean implements Serializable {
@ManagedProperty(value = "#{restClient}")
private RestClient restClient;
private List<Document> documents;
private String jsonHistory;
public List<Document> getDocuments() {
if (documents != null) {
return documents;
}
ClientResponse response = restClient.clientGetResponse("history");
if (response.getStatus() != 200) {
throw new RuntimeException("Failed service call: HTTP error code : " + response.getStatus());
}
// get history as JSON
jsonHistory = response.getEntity(String.class);
// convert to Java array / list of Document instances
Document[] docs = GsonConverter.getGson().fromJson(jsonHistory, Document[].class);
documents = Arrays.asList(docs);
return documents;
}
// getter / setter
...
}
The next bean demonstrates how to communicate with the remote service via POST. We intent to send the content of uploaded file. I use the
PrimeFaces' FileUpload component, so that the content can be extracted as
InputStream from the listener's parameter
FileUploadEvent. This is not important here, you can also use any other web frameworks to get the file content (also as byte array). More important is to see how to deal with RESTful Client classes
FormDataMultiPart and
FormDataBodyPart.
package com.cc.metadata.jsf.controller.extract;
import com.cc.metadata.jsf.controller.common.RestClient;
import com.cc.metadata.jsf.util.GsonConverter;
import com.cc.metadata.model.Document;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;
import org.primefaces.event.FileUploadEvent;
import java.io.IOException;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.ws.rs.core.MediaType;
/**
* Bean for extracting document properties (metadata).
*/
@ManagedBean
@ViewScoped
public class ExtractBean implements Serializable {
@ManagedProperty(value = "#{restClient}")
private RestClient restClient;
private String path;
public void handleFileUpload(FileUploadEvent event) throws IOException {
String fileName = event.getFile().getFileName();
FormDataMultiPart fdmp = new FormDataMultiPart();
FormDataBodyPart fdbp = new FormDataBodyPart(FormDataContentDisposition.name("file").fileName(fileName).build(),
event.getFile().getInputstream(), MediaType.APPLICATION_OCTET_STREAM_TYPE);
fdmp.bodyPart(fdbp);
WebResource resource = restClient.getWebResource("extract");
ClientResponse response = resource.accept("application/json").type(MediaType.MULTIPART_FORM_DATA).post(
ClientResponse.class, fdmp);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed service call: HTTP error code : " + response.getStatus());
}
// get extracted document as JSON
String jsonExtract = response.getEntity(String.class);
// convert to Document instance
Document doc = GsonConverter.getGson().fromJson(jsonExtract, Document.class);
...
}
// getter / setter
...
}
Last but not least, I would like to demonstrate how to send a GET request with any query string (URL parameters). The next method asks the remote service by URL which looks as
http://somehost/metadata/extract?file=<some file path>
public void extractFile() {
WebResource resource = restClient.getWebResource("extract");
ClientResponse response = resource.queryParam("file", path).accept("application/json").get(
ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed service call: HTTP error code : " + response.getStatus());
}
// get extracted document as JSON
String jsonExtract = response.getEntity(String.class);
// convert to Document instance
Document doc = GsonConverter.getGson().fromJson(jsonExtract, Document.class);
...
}