O objetivo desse post é oferecer dicas de como trabalhar com web-services usando as bibliotecas XStream e HttpClient 4.x, que já abordamos em um post anterior, e além disso verificar a data corrente online. As vezes pode ser necessário verificar de tempos em tempos se a data de uma aplicação cliente é exatamente a mesma de uma aplicação servidora. Não é algo tão corriqueiro, entretanto tem uma importância razoável visto que uma bateria de BIOS ruim ou um usuário mal intencionado ou por erro podem alterar a data da máquina. Dentre as várias soluções para verificar essa data a mais lógica é verificar essa data online. Verificar a data na aplicação servidora não é muito interessante pois o cliente pode, ocasionalmente, perder a comunicação com a aplicação servidora. Diante disso a saída é consumir algum web-service que disponibilize essas informações. Como era de se esperar não encontrei um no Brasil (mesmo que existisse provavelmente seria pago como é o caso do CEP). Dos vários web-services internacionais o mais interessante, par esse propósito, é o disponibilizado pelo Earth Tools.org. Ele oferece uma série de informações sobre clima e outras coisas e claro também sobre data.
Partindo para o desenvolvimento a primeira coisa que precisamos é definir as dependências no nosso POM. As dependências mais importantes de nosso projeto são as do HttpClient e a XStream. As primeiras são necessárias para podermos nos comunicar com o web-service já a segunda converte XML em objetos Java.
<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"> <!-- VERIFIQUE O POM COMPLETO NO GITHUB https://github.com/leandrocgsi/DateSynchronizer --> <dependencies> <!-- DEPENDÊNCIA DA XSTREAM RESPONSÁVEL POR CONVERTER XML EM OBJETOS --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.3</version> </dependency> <!-- DEPENDÊNCIA DA JERSEY --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.8</version> </dependency> <!-- DEPENDÊNCIA DO ASM --> <dependency> <artifactId>asm</artifactId> <groupId>asm</groupId> <type>jar</type> <version>3.1</version> </dependency> <!-- DEPENDÊNCIA DO HTTP CLIENT --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.0.3</version> </dependency> <!-- DEPENDÊNCIA DO HTTP MIME --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.0.3</version> </dependency> <!-- DEPENDÊNCIA DO HTTP CORE --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.0.1</version> </dependency> <!-- DEPENDÊNCIA DA JMONKEYENGINE--> <dependency> <groupId>com.projectdarkstar.ext.com.jmonkeyengine</groupId> <artifactId>jme-xml</artifactId> <version>2.0-S1</version> <type>jar</type> </dependency> </dependencies> </project>
Agora partindo para as classes Java precisamos acessar a seguinte URL http://www.earthtools.org/timezone/-18.5134/-46.512809 que recebe como parâmetro em sua parte final dois números correspondentes a longitude e latitude de onde estamos acessando. Se acessarmos essa URL via browser veremos um XML similar ao da imagem abaixo.
Podemos identificar, no XML, a necessidade de criarmos dois beans responsáveis por armazenar as informações do XML. O primeiro deles assinalado com o numero 1 (timezone) dará origem ao bean Timezone, que além de uma série de atributos simples possui um atributo composto por outro objeto (location) que por sua vez dará origem ao bean Location. Na criação do bean ao adicionarmos a anotação @XStreamAlias indicamos que aquele objeto representa um nó do arquivo XML. Fora isso nossas classes não possuem nada demais apenas geters, setters, serialização e construtor.
package br.com.semeru.datesynchronizer.beans; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.io.Serializable; // Anotação que indica para a XStream que timezone // é um nó de um arquivo XML ou seja ele é um objeto @XStreamAlias("timezone") public class Timezone implements Serializable{ //Atributo para serialização do bean private static final long serialVersionUID = 1L; //Atributo do XML private String version; /*Essa anotação indica que o atributo XML abaixo é um atributo um pouco mais complexo e representa um objeto dentro de timezone*/ @XStreamAlias("location") private Location location; //Outro atributo do XML private String offset; private String suffix; private String localtime; private String isotime; private String utctime; private String dst; // Construtor, getters e setters omitidos }
Observe que o bean Timezone se relaciona de 1 para 1 com Location.
package br.com.semeru.datesynchronizer.beans; import com.thoughtworks.xstream.annotations.XStreamAlias; import java.io.Serializable; /* Anotação que indica para a XStream que location é um nó de um arquivo XML ou seja ele é um objeto */ @XStreamAlias("location") public class Location implements Serializable{ private static final long serialVersionUID = 1L; private String latitude; private String longitude; // Construtor, getters e setters omitidos }
Feito isto é só nos acessarmos a URL e converter o XML em objetos. Inicialmente definimos a URL e um main que invoca um outro método (readXMLURL) que por sua vez se conecta à URL e recupera um inputStream que por sua vez é passado como parâmetro na invocação do método parserXMLToObject que recupera o XML do inputStream e converte-o em objeto retornando um objeto do tipo Timezone que agora podemos usar na aplicação.
package br.com.semeru.datesynchronizer; import br.com.semeru.datesynchronizer.beans.Timezone; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import java.io.IOException; import java.io.InputStream; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; public class RecoveryDateWitchURL { //Determino a URL de onde será recuperada a informação do webservice private static String url = "http://www.earthtools.org/timezone/-18.5134/-46.512809"; //Método main public static void main(String[] args) throws IOException, ClassNotFoundException { //Invoco o método passando como parâmetro a URL readXMLURL(url); } // Método responsável por recuperar um inputstream a // partir de uma URL e converter o resultado em objeto private static void readXMLURL(String url) throws IOException { //Crio uma instancia de cliente HTTP HttpClient client = new DefaultHttpClient(); //Crio uma instancia de HTTPGet passando a URL como parâmetro HttpGet method = new HttpGet(url); //Atribuo à HTTP response o resutado da execução do método get HttpResponse httpResponse = client.execute(method); //Declaro uma variável que recebe o código de status da requisição HTTP int statusCode = httpResponse.getStatusLine().getStatusCode(); //Verifico se o código do status é igual a SC_OK (200) if (statusCode == HttpStatus.SC_OK) { //Se for significa que a requisição foi bem sucedida e então //crio uma instancia de InputStream pegando o conteúdo da response InputStream inputStream = httpResponse.getEntity().getContent(); //Invoco o método parserXMLToObject passando o inputStream como parâmetro parserXMLToObject(inputStream); } } //Método que efetivmente converte o input stream em XML e depois em objeto private static Timezone parserXMLToObject(InputStream inputStream) { //Crio uma instancia de XStream que recebe via //construtor uma instancia de DomDriver XStream xStream = new XStream(new DomDriver()); //Processa as anotações da classe Timezone xStream.processAnnotations(Timezone.class); //Crio uma instancia de Timezone que recebe um cast para Timezone //do inputstream convertido para XML e depois para Objetc Timezone timezone = (Timezone) xStream.fromXML(inputStream); //Imprimo algumas informações de timezone para testar System.out.println("O TimeZone É: " + timezone.getLocaltime() + " - " + timezone.getUtctime() + "\n" + "e as Cordenadas são: " + timezone.getLocation().getLatitude() + " de Latitude Sul" + timezone.getLocation().getLongitude() + " de Longitude Oeste. :->"); //Retorno um objeto do tipo Timezone que poderá //ser usado em outras partes da aplicação. return timezone; } }
Posteriormente pretendo fazer mais posts abordando outros aspectos de web-services. Lembrando sempre que se você ficou alguma dúvida relacionada ao conteúdo desse post sinta-se a vontade para comentar, criticar e/ou contribuir com o seu comentário. Além disso você pode acessar todo o código fonte desse projeto através do GitHub.