WebServices RESTful com JAX-RS / Jersey em instantes

JAX-RS (Java API for RESTful Web Services) ou JSR 311 é a especificação da linguagem Java para criar WebServices RESTful.

Existe varias implementações desta especificação tais como Jersey, Apache CXF, JBoss RESTEasy, Restlet…
Neste artigo vou utilizar Jersey a implementação da Sun/Oracle para esta especificação.
Com JAX-RS é possível criar WS através de Annotations de forma bastante simples e rápida, que podem ser distribuídos através de Web Containers como Tomcat, Jetty, JBoss etc…

Neste caso vou utilizar o framework Grizzly que permite criar um web container embedded excluindo assim a necessidade de um web container externo à aplicação. 
Comecemos pelo serviço que permite o calculo de fibonacci

package com.wordpress.magician.jaxrs.ws;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

/**
 * Calcula o resultado a sequencia de fibonacci
 * @author magician
 *
 */
@Path("/fib/{number}")
public class Fibonacci {

	/**
	 * Devolve uma resposta em plain text com o resultado do calculo.
	 * @param number numero a calcular
	 * @return resultado do calculo
	 */
	@GET
	@Produces("text/plain")
	public String fibText(@PathParam("number") int number){
		return String.format("%d",fibonacci(number));
	}

	/**
	 * Calcula a sequência de fibonacci de forma recursiva
	 * @param n numero actual do processo recursivo
	 * @return resultado actual do processo recursivo
	 */
	private long fibonacci(int n){
		if(n <= 1){
			return n;
		}else{
			return fibonacci(n-1) + fibonacci(n-2);
		}
	}
}

Fibonacci.java

Como se pode ver é muito simples, na header da classe utilizamos a annotation @Path que permite definir o caminho para o serviço. Neste caso o path será /fib/{number} onde o {number} é  utilizado como parâmetro para método fibText onde é associado através da annotation @PathParam.

A annotation @GET indica que o serviço deve ser acedido por HTTP GET e a annotation @Produces define o mime type do conteúdo gerado como resposta pelo WS. Em seguida temos o serviço Auth, este serviço recebe um username e uma password sob forma de String e caso o username seja igual à password ele devolve um long representando a session id que o utilizador deve usar. Caso o username seja diferente da password o serviço devolve -1 ou seja sem session id.


package com.wordpress.magician.jaxrs.ws;

import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

/**
 * Simula a autenticação de um user/pass
 * @author magician
 *
 */
@Path("/auth")
public class Auth {

	/**
	 * Devolve uma resposta em plain text com o resultado da autenticação.
	 * @param user String com o username
	 * @param pass String com a password
	 * @return String com a resposta plain text
	 */
	@POST
	@Produces("text/plain")
	public String authText(@FormParam("user") String user, @FormParam("pass") String pass){
		return String.format("%d", session(user, pass));
	}

	/**
	 * Devolve uma resposta em XML com o resultado da autenticação.
	 * @param String com o user username
	 * @param String com a pass password
	 * @return String com a resposta em XML
	 */
	@POST
	@Produces("text/xml")
	public String authXML(@FormParam("user") String user, @FormParam("pass") String pass){
		return String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><auth username=\"%s\">%d</auth>", user, session(user, pass));
	}

	/**
	 * Caso o user seja igual à pass a autenticação é feita
	 * com sucesso
	 * @param user String com o username
	 * @param pass String com a password
	 * @return -1 se a auth falha com long caso contrario
	 */
	private long session(String user, String pass){
		System.out.println(user);
		System.out.println(pass);
		if(user.equals(pass)){
			return System.nanoTime();
		}
		return -1;
	}
}

Auth.java

Este serviço tem duas coisas distintas do anterior, primeiro ele apenas deve ser acedido por HTTP POST e não por HTTP GET como era o caso anterior. Isto pode ser definido pela annotation @POST que é utilizada nas linhas 22 e 34, e utilizamos a annotation @FormParam para ir buscar os valores user e pass que devem vir no request POST.

A outra diferença está no tipo de conteúdo produzido pelo serviço neste serviço é gerado dois tipos de conteúdo Plain Text e XML. Desta forma quando o request vem limitado a resposta XML é o método authXML que é executado, caso o request aceite qualquer tipo de conteúdo ou plain text então é o método authText que é executado.

O terceiro serviço permite obter imagens através do seu nome, basicamente enviamos o nome da imagem no url e o WS envia como resposta o conteúdo do ficheiro da imagem.

package com.wordpress.magician.jaxrs.ws;

import java.io.File;

import javax.activation.MimetypesFileTypeMap;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;

/**
 * Procura a imagem pelo seu nome e devolve como resposta.
 * @author magician
 *
 */
@Path("/images/{image}")
public class GetFile {

	/**
	 * Devolve a imagem com o mime type do ficheiro ou 404 caso
	 * o ficheiro não seja encontrada.
	 * @param image nome da imagem a procurar
	 * @return imagem com o mime type da imagem fonte.
	 */
	@GET
	@Produces("image/*")
	public Response getImage(@PathParam("image") String image){

		String tmp = System.getProperty("java.io.tmpdir");
		File target = new File(tmp + image);
		System.out.println(target.getAbsolutePath());

		if(!target.exists()){
			throw new WebApplicationException(404);
		}
		String mt = new MimetypesFileTypeMap().getContentType(target);
		return Response.ok(target, mt).build();
	}

}

GetFile.java

A novidade neste serviço é a utilização da Classe Response, esta classe permite gerar uma resposta que deve ser devolvida pelo serviço. No serviço GetFile é gerada uma response OK e irá conter o conteúdo do ficheiro com o mime type desse mesmo ficheiro.
A classe Response permite retornar respostas de erro ou redirect com Response.status ou Response.temporaryRedirect.

Por fim temos o servidor que irá export por HTTP o WS com os serviços descritos acima, como referido foi utilizado o framework Grizzly.

package com.wordpress.magician.jaxrs;

import java.util.HashMap;
import java.util.Map;

import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;

/**
 * Servidor HTTP para o WebService utilizando o WebContainer
 * do framework Grizzly
 * @author magician
 *
 */
public class Server {

	public static void main(String[] args) throws Exception {
		Map<String, String> initParams = new HashMap<String, String>();

		initParams.put("com.sun.jersey.config.property.packages","com.wordpress.magician.jaxrs.ws");

		SelectorThread container = GrizzlyWebContainerFactory.create("http://0.0.0.0:8080/", initParams);

		try{
			container.initEndpoint();
			container.startEndpoint();
		}finally{
			if(container.isRunning()){
				container.stopEndpoint();
			}
		}
	}
}

Server.java

Como se pode ver a configuração é muito simples basta definir um URL (linha 22) e indicar o root package onde se encontram as implementações do serviços (linha 20). Por fim ao executar o nosso projecto
passamos a ter o serviço exposto no URI http://localhost:8080/
Acedendo ao URI http://localhost:8080/application.wadl recebemos a seguinte resposta

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<application xmlns="http://research.sun.com/wadl/2006/10"> 
    <doc xmlns:jersey="http://jersey.dev.java.net/" jersey:generatedBy="Jersey: 1.5 01/14/2011 12:36 PM"/> 
    <resources base="http://localhost:8080/"> 
        <resource path="/images/{image}"> 
            <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="template" name="image"/> 
            <method name="GET" id="getImage"> 
                <response> 
                    <representation mediaType="image/*"/> 
                </response> 
            </method> 
        </resource> 
        <resource path="/fib/{number}"> 
            <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int" style="template" name="number"/> 
            <method name="GET" id="fibText"> 
                <response> 
                    <representation mediaType="text/plain"/> 
                </response> 
            </method> 
        </resource> 
        <resource path="/auth"> 
            <method name="POST" id="authText"> 
                <request> 
                    <representation mediaType="application/x-www-form-urlencoded"> 
                        <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="query" name="user"/> 
                        <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="query" name="pass"/> 
                    </representation> 
                </request> 
                <response> 
                    <representation mediaType="text/plain"/> 
                </response> 
            </method> 
            <method name="POST" id="authXML"> 
                <request> 
                    <representation mediaType="application/x-www-form-urlencoded"> 
                        <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="query" name="user"/> 
                        <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="query" name="pass"/> 
                    </representation> 
                </request> 
                <response> 
                    <representation mediaType="text/xml"/> 
                </response> 
            </method> 
        </resource> 
    </resources> 
</application> 

Este XML é o utilizado para descrever o WS, tem um propósito semelhante ao WSDL dos WS SOAP mas neste caso para RESTful e bastante mais simples que o WSDL. Com ele é possível saber que serviços estão disponíveis, dado os paths, métodos de request, tipo de dados que devem ser passados ou que são devolvidos, etc…

Referencias:

http://en.wikipedia.org/wiki/JAX-RS

http://jersey.java.net/

http://grizzly.java.net/

http://www.suryasuravarapu.com/2009/02/rest-jersey-configuration-on-tomcat.html

Anúncios

2 thoughts on “WebServices RESTful com JAX-RS / Jersey em instantes

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão /  Alterar )

Google photo

Está a comentar usando a sua conta Google Terminar Sessão /  Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão /  Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão /  Alterar )

Connecting to %s