Posts tagged ‘webservices’

Maven, Hibernate, Spring, CXF e MySql rodando no Jboss 7

Este post demonstra como usar de maneira prática o Hibernate com Spring publicando um Web Services utilizando com o Apache CXF, no Jboss 7 AS.

O primeiro passo é configurar o Maven, que irá auxiliar na automação do projeto. Acredito que é a parte mais complicada deste tutorial, já que encontrar todas as bibliotecas e dependências necessárias não é uma tarefa fácil. O pom.xml (arquivo de configuração do Maven) abaixo funciona perfeitamente para a configuração feita no nosso application-context.xml que você irá ver a seguir, você poderá fazer download da versão completa deste projeto no fim deste post.

...

	<dependencies>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate</artifactId>
			<version>3.2.1.ga</version>
			<exclusions>
				<exclusion>
					<groupId>asm</groupId>
					<artifactId>asm</artifactId>
				</exclusion>
				<exclusion>
					<groupId>asm</groupId>
					<artifactId>asm-attrs</artifactId>
				</exclusion>
				<exclusion>
					<groupId>cglib</groupId>
					<artifactId>cglib</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.8</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>2.1_3</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-annotations</artifactId>
			<version>3.2.0.ga</version>
		</dependency>
		<dependency>
			<groupId>javax.persistence</groupId>
			<artifactId>persistence-api</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
			<version>1.5.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.unitils</groupId>
			<artifactId>unitils</artifactId>
			<version>1.0</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>
	</dependencies>
...

Vamos começar a fazer nosso serviço que irá retornar informações sobre Clubes de Futebol. Vamos mapear o Bean referente a tabela TB_CLUBES.

package com.lucianosilva.lab.entity;

@Entity
@Table(name = "TB_CLUBES")
public class Clube implements BaseEntity<Long> {
	private static final long serialVersionUID = 5541457395540986982L;

	@Id
	@Column(name = "ID_CLUBE", nullable = false)
	private Long idClube;

	@Column(name = "NOME", nullable = true)
	private String nome;

	@Column(name = "NOME_POP", nullable = true)
	private String nomePopular;

	@Column(name = "FUNDACAO", nullable = true)
	private Date dataFundacao;

	/* (non-Javadoc)
	 * @see com.lucianosilva.lab.core.BaseEntity#getId()
	 */
	@Override
	public Long getId() {
		//
		return this.idClube;
	}

	/* (non-Javadoc)
	 * @see com.lucianosilva.lab.core.BaseEntity#setId(java.lang.Object)
	 */
	@Override
	public void setId(Long id) {
		//
		this.idClube = id;
	}

//... getters and setters
}

Agora podemos construir o acesso aos dados, que faz uso de Generic DAO ocultado neste post, não se preocupe é uma prática comum, no fim do post estão os arquivos para download.

Essa classe básicamente define o que vamos ter no serviço, duas operações de retorno filtrando pelo ID e Nome.

package com.lucianosilva.lab.dao;

public class ClubesDao extends HibernateGenericRepository<Clube, Long> {

	/* (non-Javadoc)
	 * @see com.lucianosilva.lab.repository.HibernateGenericRepository#findById(java.io.Serializable)
	 */
	@Override
	public Clube findById(Long id) {
		return super.findById(id);
	}

	public ClubesDao(){
		super(Clube.class);
	}

	/**
	 *
	 * @param name
	 * @return
	 */
	public List<Clube> findByName( String name ){
		return super.findByCriteria(Expression.like("nome", name, MatchMode.ANYWHERE));
	}
}

A definição deste serviço é tão simples quanto a construção do DAO acima, não foi feito o tratamento customizado das exceções já que o objetivo não é esse e, sim demonstrar a integração dos frameworks e como devem ser configurados, nada impede de você mesmo evoluir este código.

package com.lucianosilva.lab.webservices;

@WebService
public interface ClubeService {

	@WebMethod(operationName="ListAllClubes")
	@WebResult(name = "Clube")
	public List<Clube> listAll();

	@WebMethod(operationName="FindByClubeName")
	@WebResult(name = "Clube")
	public List<Clube> findByName(@WebParam(name = "clubeName") String name);

}

Implementação do serviço.

package com.lucianosilva.lab.webservices.impl;

import java.util.List;

import javax.jws.WebService;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.lucianosilva.lab.dao.ClubesDao;
import com.lucianosilva.lab.entity.Clube;
import com.lucianosilva.lab.webservices.ClubeService;

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
@WebService(endpointInterface="com.lucianosilva.lab.webservices.ClubeService")
public class ClubeServiceImpl implements ClubeService {

	private ClubesDao clubesDao; // configuracao no application-context

	public List<Clube> findByName(String name) {
		return clubesDao.findByName(name);
	}

	public List<Clube> listAll() {
		//
		return clubesDao.listAll();
	}

	/**
	 * @return the clubesDao
	 */
	public ClubesDao getClubesDao() {
		return clubesDao;
	}

	/**
	 * @param clubesDao the clubesDao to set
	 */
	public void setClubesDao(ClubesDao clubesDao) {
		this.clubesDao = clubesDao;
	}

}

Bem, até aqui nada de novo, pelo contrário tudo muito trivial. A configuração desta aplicação (application-context.xml) é o “pulo-do-gato”.

Adicionei comentários no bloco abaixo, para explicar cada parte da configuração.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:jaxrs="http://cxf.apache.org/jaxrs"
	xsi:schemaLocation="  

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

http://cxf.apache.org/core

http://cxf.apache.org/schemas/core.xsd

http://cxf.apache.org/jaxws

http://cxf.apache.org/schemas/jaxws.xsd

http://cxf.apache.org/jaxrs

http://cxf.apache.org/schemas/jaxrs.xsd"

	default-dependency-check="none" default-lazy-init="false">

	<!-- arquivo separado para a configuração dos EndPoints (WebServices) CXF veja mais abaixo -->
	<import resource="cxf-beans.xml" />

	<!-- Bean abstrato para evitar repetição de código -->
	<bean id="baseSessionFactory" abstract="true">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<!-- IoC - Implementação da interface ClubesDAO -->
	<bean id="clubesDao" class="com.lucianosilva.lab.dao.ClubesDao"
		parent="baseSessionFactory" />

        <!-- Configuração do DataSource para o Connection Pool - Este JNDI name está seguindo o padrão do JBoss -->
	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName">
			<value>java:/Laboratorio</value>
		</property>
	</bean>

	<!-- Configurações de uma Session Factories -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource">
			<ref local="dataSource" />
		</property>
		<property name="annotatedClasses">
			<list>
				<value>com.lucianosilva.lab.entity.Clube</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">
					org.hibernate.dialect.MySQLInnoDBDialect
				</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">false</prop>
			</props>
		</property>
	</bean>
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref local="sessionFactory" />
		</property>
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager" />
</beans>

Bem, lá no começo do application-context.xml fizemos o import da configuração do CXF, segue a descrição do arquivo cxf-beans.xml.

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

	<!-- Configurações do Apache CXF -->
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<!-- Configurações do endpoint WSDL -->
	<jaxws:endpoint id="clubeService" depends-on="clubeServiceImpl"
		implementor="#clubeServiceImpl" address="/ClubeService">
	</jaxws:endpoint>

	<!-- Bean que implementa o endpoint do nosso webservice -->
	<bean id="clubeServiceImpl" class="com.lucianosilva.lab.webservices.impl.ClubeServiceImpl">
		<property name="clubesDao" ref="clubesDao" />
	</bean>
</beans>

Compile, empacote e faça deploy no Jboss, agora vamos ver o serviço rodando no soapUI.

 

Por fim, você viu a configuração de um serviço simples, com acesso ao banco de dados utilizando DataSource, a qual considero importantíssimo como exemplo, já que NÍNGUEM utiliza a configuração do application-context informando os parâmetros do banco de dados (exceto para o uso do JUnit).

Você pode evoluir este código implementando o controle de erros com WebFault e também utilizando o Autowired no Spring, aumentando o controle da sua aplicação e diminuindo a configuração manual.

Download

 

PLSQL consuming Web Services

This is a simple sample, how to do to consuming Web Services from Oracle database using PL/SQL. This tutorial was tested in Oracle database versions 9i, 10g and 11g.

The Web Services used is avaliable in webservicex.net, see this link, there are more details.

declare
 soap_request  varchar2(30000);
 soap_respond  varchar2(30000);
 http_req      utl_http.req;
 http_resp     utl_http.resp;

 l_launch_url varchar2(240) := 'http://www.webservicex.net/geoipservice.asmx?WSDL';
 l_soap_action varchar2(240) := 'http://www.webservicex.net/GetGeoIP';
 l_ip varchar2(100) := '189.100.4.198'; // IP just for test

Now, second step you have to build the SOAP request it’s may be boring if you parameter list too long, so you can use the soapUI to test and prepared the string of requisition.

begin

soap_request :=
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webservicex.net/">
 <soapenv:Header/>
 <soapenv:Body>
 <web:GetGeoIP>
 <web:IPAddress>'|| l_ip || '</web:IPAddress>
 </web:GetGeoIP>
 </soapenv:Body>
</soapenv:Envelope>
';
 dbms_output.put_line(soap_request);
 HTTP_REQ:= UTL_HTTP.BEGIN_REQUEST(l_launch_url, -- web services url
 'POST',
 'HTTP/1.1');
 UTL_HTTP.SET_HEADER(HTTP_REQ,'Content-Type', 'text/xml'); -- since we are dealing with plain text in XML documents
 UTL_HTTP.SET_HEADER(HTTP_REQ,'Content-Length', length(soap_request));
 UTL_HTTP.SET_HEADER(HTTP_REQ,'SOAPAction' , l_soap_action); -- required to specify this is a SOAP communication
 UTL_HTTP.WRITE_TEXT(HTTP_REQ, SOAP_REQUEST);
 HTTP_RESP := UTL_HTTP.GET_RESPONSE(HTTP_REQ);
 UTL_HTTP.READ_TEXT(HTTP_RESP, SOAP_RESPOND);
 UTL_HTTP.END_RESPONSE(HTTP_RESP);

 dbms_output.put_line('-------------------------');
 dbms_output.put_line(soap_respond); -- here is the response
end;

Okay, that’s the cake recipe…

Enjoy it.

Annotations e XFire um jeito simples de criar Web Services

Eu já falei um pouco de Web Services por aqui, mas ainda tem muita coisa a ser discutida e experimentada sobre este assunto.

Existem diversas formas de distribuir serviços na internet e a o número de ferramentas para tornar isto cada vez mais fácil aumentam constantemente. Pesquisando sobre conceitos e maneiras práticas para desenvolvimento encontrei no Blog dos Desenvolvedores da Caelum um jeito simples para criação de Web Services utilizando a especificação JSR-181 e JSR-224, achei interessantíssimo e não perdi tempo em fazer os testes.

A especificação permite que você crie serviços utilizando apenas Annotations.

import javax.jws.WebMethod;
import javax.jws.WebService;
import tucano.bean.Pessoa;

@WebService
public class PessoaWS {
private Pessoa[] list = new Pessoa[5];

public PessoaWS() {
list[0] = new Pessoa("M", "Luciano", "Silva");
list[1] = new Pessoa("F", "Priscila", "Carmo");
list[2] = new Pessoa("F", "Maria", "Conceição");
list[3] = new Pessoa("F", "Lucia", "Felix");
list[4] = new Pessoa("M", "Cristino", "José");
}

@WebMethod
public Pessoa[] listAll(){
return list;
}
}

Perceba que este Web Service foi criado de maneira extremamente simples apenas para demonstração, porém, o método retorna um tipo de dado complexo, isto para sair da monotonia.

Ainda o que os caras da Caelum, vamos fazer a publicação/ativação do serviço utilizando o XFire projeto relacionado ao Apache CXF

<!-- // X-Fire //--->
<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFire Servlet</display-name>
<servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>services.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<!-- // //--->

Se você for seguir o site do projeto X-Fire, irá perceber que é sugerido a criação do arquivo no caminho META-INF/xfire/services.xml, isto não deu muito certo comigo, tentei diversas configurações e até percebi que é um bug em aberto para o projeto.

Para resolver o problema opite por colocar o arquivo de configuração services.xml na raíz do source [src/services.xml].

<beans xmlns="http://xfire.codehaus.org/config/1.0">
<service>
<name>PessoaService</name>
<namespace>http://xfire.codehaus.org/PessoaService</namespace>
<serviceClass>tucano.ws.PessoaWS</serviceClass>
</service>
</beans>

Básicamente a configuração se resume em um nome para o Serviço e a Classe que implementa-o. Após fazer deploy do projeto no seu container JEE você poderá acessar o serviço da seguinte maneira http://localhost/<CONTEXTO>/services/<SERVICE_NAME>?wsdl, então, http://localhost/Tucano/services/PessoaService?wsdl.

Você pode fazer o download dos fontes aqui.

É prático, fácil e rápido, vale ser estudado e em alguns casos sugerido como solução, mesmo assim eu estou cansado de ver configurações em arquivo XMLs fora do contexto, não sou muito adepto a esta solução, de qualquer maneira tá dado o recado. =)

Web Services com Apache Axis e Tipos Complexos – Part III

Criar WebServices já foi um trabalho árduo, mas há alguns anos isto deixou de ser um problema com a ajuda das IDEs. Então vou mostrar como utilizar os recursos do Eclipse que facilitam o desenvolvimento de serviços.

Você já sabe o que é um WebServices e também como é simples publicá-lo utilizando Axis, mas nem todos seus serviços irão trabalhar apenas com tipos de dados primitivos, provavelmente será necessário retornar uma lista de Pessoas, Enderecos, ou qualquer outro tipo de dado complexo.

Nosso cenário é um projeto cujo o objetivo é fornecer consultas de Países e seus respectivos Estados, acessados através de serviços, a definição de Beans, DAOs e qualquer outras classes serão ocultadas, porém, no final deste post você poderá baixar a versão completa do projeto.

Bem como já foi demonstrado aqui precisamos de uma classe para que seja a base do serviço, neste caso será a harpia.region.services.Region, veja:

package harpia.region.services;

/* imports ocultados */

public class Region {
private RegionDAO rdao = new RegionDAO();

/**
*
* @param Nome do Pais
* @return Todos os países encontrados
*/
public Pais[] find(String nmPais){
ArrayList<pais> list = rdao.getAllPais( nmPais );
Pais[] paises    = new Pais[list.size()];
list.toArray(paises);

return paises;
}
}

Criando o WSDL
Crie um novo objeto chamado Web Service (File > New > Others > Web Service). Após selecionar Web Service clique em Next.

Clique em Browse e selecione a classe responsável por implementar o serviço, ou seja, harpia.region.services.Region. Veja que o tipo deve ser Bottom up Java Web Service.

Na sequência serão exibidos os métodos disponibilizados pelo serviço, caso você não queira publicar basta desmarcar.

E por fim a caixa de dialogo informa que o servidor Apache está down é que será necessário fazer o startup para concluir a criação e publicação do WSDL, utilize esta mesma tela para iniciar o servidor e concluir o passo-a-passo.

Veja que um novo arquivo foi criado em projeto, agora existe o wsdl/Region.wsdl.

O WSDL (Web Service Description Language) nada mais é do que um Schema XML cujo está descrito o serviço de internet. Você poderá acessar este serviço em http://localhost/Harpia/wsdl/Region.wsdl ou também http://localhost/Harpia/services/Region?wsdl.

Criando o Client

Nosso serviço foi criado em Java 1.5, porem, neste momento poderiamos fazer uma solicitação a partir de qualquer linguagem que saiba interpretar o WSDL. Vamos continuar no Java por enquanto e fazer a chamada do nosso Web Service.
Já que a intensão é mostrar como a IDE facilita a criação de Web Services, aqui vai mais um wizard de como fazer o Web Service Client no eclipse.

Hey Client! Chamaí o serviço pow!

import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import harpia.region.bean.Pais;
import harpia.region.services.RegionServiceLocator;

public class HarpiaClient {

public static void main(String[] args) throws RemoteException, ServiceException {
// obter o nome do pais para pesquisa
String nome = JOptionPane.showInputDialog(null, "Qual é o pais?", "Unido");

RegionServiceLocator locator = new RegionServiceLocator(); // localizando ...
Pais[] paises = locator.getRegion().find(nome); // procurando ...
for (int i = 0; i < paises.length; i++) { // exibindo
Pais pais = paises[i];

System.out.println("["+i+"] " + pais.getNome() + " | ID: " + pais.getId_pais());
}
// Simples assim
}

}

E para aqueles que ainda dizem por aí que tudo isso aqui é conversa fiada, se é que existe algum maluco pra dizer isto, tomaí! PHP consumindo o Web Service feito em Java.

<?
$client = new SoapClient(null, array('location' => 'http://localhost/Harpia/services/Region?wsdl',
'uri' => 'http://localhost/Harpia/services/Region?wsdl',
'trace' => '1'));

$result = $client->find('ale');

if(  is_soap_fault($result) ){
echo "Ocorreu algum erro.<br/>";
}else{

print_r($result);
}

unset($client);
?>

Faça download dos fontes aqui.

That’s all.

Web Services com Apache Axis – Part II

Dando sequência a WebServices agora vou demonstrar um exemplo prático de como criar um serviço utilizando os recursos do framework Apache Axis.
A instalação do Axis funciona como qualquer outra API na plataforma JEE, portanto não será detalhado este procedimento.

A criação de webservices com Apache Axis é muito simples, veja a classe abaixo:

public class Calculo {
/**
*
* @param n1
* @param n2
* @return Resultado da Soma
*/
public double soma(double n1, double n2){
return (n1 + n2);
}
}

Após criar essa simples classe composta pelo método soma, cujo retorna um tipo primitivo, para que esta classe seja publicada como um serviço basta copiá-la para a aplicação do Axis ($TOMCAT_HOME\webapps\axis) em seguida renomeá-la para Calculo.jws. Acesse o serviço como http://localhost:8080/axis/Calculo.jws?wsdl, isto é tudo.

Simples assim, criar o Client que irá utilizar o serviço é tão simples quanto.

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

public class CalculoClient {

/**
* @param args
*/
public static void main(String[] args) throws Exception{
String url = "<a href="http://localhost/axis/Calculo.jws?wsdl">http://localhost/axis/Calculo.jws?wsdl</a>";
Service service = new Service();
Call call       = (Call) service.createCall();
call.setTargetEndpointAddress( url );
call.setOperationName("soma"); // método do webservices

Double[] param  = {15.0, 15.0}; // parâmetros
Double result   = (Double) call.invoke( param ); // chamada
System.out.println("Resultado : " + result );
}
}

Exemplos iguais a este devem existir centenas de milhares na internet, simples utilizando tipos primitivos, básico mesmo. Mas cansado de saber disto vou demonstrar um exemplo mais completo utilizando tipo de dados complexos!

Veja mais esses artigos excelentes:
http://www.javafree.org/content/view.jf?idContent=4
http://www.guj.com.br/java.tutorial.artigo.180.1.guj
http://www.guj.com.br/java.tutorial.artigo.132.1.guj