Thursday, May 10, 2018

Relatórios Utilizando Bean Datasource (parte 2)

Utilizando o JasperStudio

Como dissemos na parte 1 deste artigo, o JasperStudio é uma ferrementa visual que agiliza a criação de relatórios, de outra forma, teríamos que criar o arquivo jrxml na mão. Caso não tenha o JasperStudio instalado, você pode baixá-lo aqui.

Abra o JasperStudio. Clique com o botão direito do mouse em MyReports/New/Jasper Report:


Escolha Blank A4. Depois Next. Dê o nome do relatório de relatorioFuncionarios e clique em Finish:



Após criar o relatório, você terá a seguinte tela:


O painel Pallete à direita representa os componentes que você pode arrastar e colocar no relatório (textos estáticos, linhas, imagens, campos de texto, imagens, subrelatórios, etc.).

No painel Outline a esquerda, você tem os Fields, cujos nomes devem coincidir com os atributos da classe RelatorioFuncionariosBean.java, portanto, é através dos elementos Field que o JasperReport saberá quais métodos ele deve chamar na classe java para preencher os campos dinâmicos do relatório. Ainda no painel Outiline, temos o item Parameters que representa parâmetros dinâmicos que acrescentamos no relatório em tempo de execução utilizando java.util.Map (nome do parâmetro/valor do parâmetro).

Clique com o botão direito no item Parameters e escolha a opção Create Parameter. No painel Properties à direita aparece as propriedades do parâmetro que você criou, cujo nome padrão é Parameter1. Dê o nome a esse parâmetro de FuncionariosDataSource e em class coloque net.sf.jasperreports.engine.data.JRBeanCollectionDataSource.


Da mesma forma, crie outro parâmetro chamado LOGOMARCA e defina o tipo da classe para java.io.InputStream.

Repare que o relatório é divido em bandas, cujos nomes são auto-explicativos, com exceção da banda Detail 1 que pode ser usada para campos cujo tipo estende java.util.Collection.

Se o seu data source tem campos que extendem a interface java.util.Colleciton, então você pode exibí-los no seu relatório utilizando os elementos Subreport, Table ou List do painel Palette. No nosso caso utilizarema a Table para exibir os funcionários.

Adiconado Table no Relatório

No painel Outline clique com o botão direito do mouse em cada banda e delete-a. Com exceção de Detal1 e Title. Ele vai ficar como segue:


No painel Palette ache o elemento Table e adicione-o na banda Detail1. No assitente Dataset que vai aparecer escolha a opção Create Table using a new dataset e Next:


Em seguida escolha a opção Create an empty dataset e dê o nome para o seu dataset de TabelaFuncionarios e Next:


Na janela Connection, marque a opção Use JRDataSource expression.


Clique no botão assitente, localizado à direita, para abrir o ExpressionEditor. No painel esquerdo selecione parameters e no painel do meio ache o parametro que você criou FuncionariosDatasource, dê duplo clique nele e Finish. Depois Finish de novo na janela connection.


O elelemento Tabela aparece no seu relatório. Precisamos de uma tablea com apenas duas colunas, nome e cpf do funcionário, não será necessário cabeçalhos nem rodapé. Para editar seu formato, dê uma duplo clique na tabela. Vamos deixá-la com duas colunas e uma linha, excluindo as demais.



Repare que a tabela também possui bandas, assim como o relatório principal. Mas só vamos precisar da banda detail e column header. Clique com o botão direito nas demais e delete-as. Crie mais uma coluna na tabela. No painel Palette localize o elemento lable static e adicione um em cada coluna.


No painel Outline, clique com o botão direito do mouse no item fields e adicione um campo nome e outro cpf, ambos do tipo String. Após criá-los, arraste-os na repsectiva linha da tabela.


Clique no botão main report e volte para a perspectiva do relatório inteiro. Assim como você criou os campos cpf e nome do funcionario, crie mais dois campos para representar o nome e o cnpj da empresa e arraste-os para a banda title do relatório, associe também os respectivos static labels para esses campos. Arraste tabem um componente Image para representar a logomarca da empresa.


Agora, nas propeidades do componente Image, em Expression, coloque o parâmetro LOGOMARCA, como $P{LOGOMARCA}.


Pronto. Salve e compile o relatório. O JasperStudio vai gerar o arquivo relatorioFuncionarios.jasper na pasta do seu projeto na aba Project Explorer à esquerda. Copie esse arquivo e cole-o no pacote relatorios do seu projeto no eclipse.

Execute o projeto e gere o relatório:


Veja também este exemplo completo no youtube.

Thursday, April 26, 2018

Relatórios Utilizando Bean Datasource (parte 1)

JasperReports é uma biblioteca open-source de classes Java cuja finalidade é ajudar desenvolvedores com a tarefa de criar e adicionar rotinas de geração de relatório nas aplicações. Enquanto que o JasperStudio é uma aplicação que provê recursos visuais de alto nível drag and drop para agilizar a criação de relatórios utilizando o JasperReports.

As fontes de dados de um relatório podem ser as mais diversas, um arquivo xml, banco de dados, uma planilha, arquivos json. A mais comum em aplicações comerciais talvez seja as tabelas de um banco de dados relacional. Neste exemplo criamos um relatório que utiliza como fonte da dados os campos de um POJO (Plain Old Java Object) que adere às especificações JavaBeans (link) carregado na memória.

No nosso exemplo teremos um objeto Empresa que possui um conjunto de funcionários. Instanciamos a Empresa bem como seus funcionário e exibimos sob a forma de um relatório.

Utilizando a IDE Eclipse crie um novo projeto Maven. Vá em File/New/Other... na janela que abrir escolha Maven Project:


Clique em Next. Na próxima janela marque Create a simple project:


Clique em Next. Dê o nome ao seu projeto de ReportBeanDataSourceExample conforme a imagem abaixo e clique em finish:


No projeto, crie o pacote entidades e em seguida as classes Empresa e Funcionario.
package entidades;

import java.util.HashSet;
import java.util.Set;

public class Empresa {

 private String nome;
 private String cnpj;
 private Set<Funcionario> funcionarios = new HashSet<>();
 
 public Empresa(String nome, String cnpj) {

  super();
  this.nome = nome;
  this.cnpj = cnpj;
 }

 //getters e setters omitidos...
E a classe Funcionario:
package entidades;

public class Funcionario {

 private String nome;
 private String cpf;
 
 public Funcionario(String nome, String cpf) {

  super();
  this.nome = nome;
  this.cpf = cpf;
 }

 //getters e setters omitidos...
Tanto Empresa como Funcionario fazem parte do nosso modelo de negócios. Porém não serão essas classes efetivamente nossa fonte de dados, POJO. A nossa fonte de dados será um composition dessas duas classes e vamos definir nela apenas os métodos getters que queremos que seja exibido no relatório. Neste caso queremos um relatório que exiba o nome e o cnpj da empresa logo no começo, e nas próximas linhas liste os funcionário apresentando o nome e o cpf de cada um em duas colunas.

Uma vez definidos os requisitos, vamos criar nosso Bean Datasource. Vamos chamar essa classe de RelatorioFuncionariosBean:
package relatorios.bean;

import java.util.Set;
import entidades.Empresa;
import entidades.Funcionario;

public class RelatorioFuncionariosBean {

 private Empresa empresa;

 public RelatorioFuncionariosBean(Empresa empresa) {
  
  if(empresa == null)
   throw new NullPointerException("Empresa não pode ser null.");

  this.empresa = empresa;
 }
 
 public String getNomeEmpresa() {

  return empresa.getNome();
 }
 
 public String getCnpjEmpresa() {

  return empresa.getCnpj();
 }
 
 public Set<Funcionario> getFuncionarios() {

  return empresa.getFuncionarios();
 } 
}
As classes da biblioteca JasperReports descobre os valores dos campos invocando os métodos getters em cada classe, para isso é importante que suas classes sigam o padrão JavaBeans.

Adicionando no Projeto a Biblioteca JasperReport

Para exibir com sucesso nosso relatório, precisamos adiconar as bibliotecas JasperReports e a JasperFonts. Abra seu arquivo pom.xml e adicione as coordenadas das biblioteca conforme segue. Adicione também uma propriedade para que o Maven compile seu código de acordo com a versão 8 do Java:
pom.xml
<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>ReportBeanDataSourceExample</groupId>
  <artifactId>ReportBeanDataSourceExample</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
 <maven.compiler.source>1.8</maven.compiler.source>
 <maven.compiler.target>1.8</maven.compiler.target>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
   <dependency>
  <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports-fonts</artifactId>
    <version>6.0.0</version>
   </dependency>
   <dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>6.5.0</version>
   </dependency>
  </dependencies>
</project>
Agora utilize as teclas de atalho ALT + F5 para que o Maven atualize seu projeto e importe as bibliotecas que você especificou no arquivo pom.xml.

Quando você trabalha com a biblioteca JasperReports, o primeiro passo é criar um arquivo template .xml contendo todos os elementos do relatório. Quando terminar de construir essa template, o relatório deve ser compilado para um arquivo .jasper, é esse arquivo que a aplicação java, por meio das classes da biblioteca JasperReports, utliza para construir o relatório preenchendo os campos com a fonte de dados. As classes da biblioteca Jasper ficam se ramificam a partir do pacote net.sf.jasperreports.

Crie um pacote main no seu projeto. Dentro dele, a classe Main.java. Crie também um pacote chamado imagem e cole nele alguma imagem qualquer para representar a logomarca da empresa.

Main.java
package main;

import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import entidades.Empresa;
import entidades.Funcionario;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRAbstractBeanDataSource;
import net.sf.jasperreports.engine.data.JRBeanArrayDataSource;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JasperViewer;
import relatorios.bean.RelatorioFuncionariosBean;

public class Main {

 public static void main(String[] args) throws Exception {  
  
  //fonte de dados
  Empresa empresa = selectEmpresa();

  //Data Object
  RelatorioFuncionariosBean dadosDoRelatorio = new RelatorioFuncionariosBean(empresa);

  //obtem o arquivo compilado do relatório 
  InputStream arquivoJasper = Main.class.getResourceAsStream("/relatorios/relatorioFuncionarios.jasper");
  
  //JRAbstractBeanDataSource representa a fonte dados do relatório, passamos o objeto 'dadosDoRelatorio' no construtor
  JRAbstractBeanDataSource dataSource = new JRBeanArrayDataSource(new RelatorioFuncionariosBean[] {dadosDoRelatorio});
  
  JRAbstractBeanDataSource funcionarios = new JRBeanCollectionDataSource(empresa.getFuncionarios());
  
  //qualquer parâmetro dinâmico do relatório, a logomarca da empresa por exemplo...
  Map<String, Object> parametrosRelatorio = new HashMap<>();
  parametrosRelatorio.put("LOGOMARCA", Main.class.getResourceAsStream("/imagem/acme.jpg"));
  parametrosRelatorio.put("FuncionariosDataSource", funcionarios);
  
  //JasperPrint representa o arquivo do relatório, fillReport() carrega o relatório a partir do InputStream 
  JasperPrint jasperPrint = JasperFillManager.fillReport(arquivoJasper, parametrosRelatorio, dataSource);
  
  //JasperViwer extende javax.swing.JFrame para exibir o relatório
  JasperViewer jasperViewer  = new JasperViewer(jasperPrint);
  jasperViewer.setVisible(true);
 }

 private static Empresa selectEmpresa() {
  
  Empresa empresa = new Empresa("ACME Corporation S/A", "12345678999-78");
  List<Funcionario> funcionarios = Arrays.asList(new Funcionario("Danilo Levi", "22222222222"),
          new Funcionario("Yasmim Marlene", "33333333333"),
          new Funcionario("Francisca Lucia", "33333333333"),
          new Funcionario("Livia Sabrina", "44444444444"),
          new Funcionario("Rafael Lago", "55555555555"),
          new Funcionario("Heitor Augusto", "66666666666"),
          new Funcionario("Caleb Luis", "77777777777"),
          new Funcionario("Luiza Costa", "88888888888"));
  empresa.setFuncionarios(new HashSet<>(funcionarios));  
  return empresa;
 }
}
A aplicação está pronta. Agora precisamos desenhar o relatório, compila-lo e colar o arquivo relatorioFuncionarios.jasper no pacote relatorios. Faremos isso com o JasperStudio na Parte 2 deste artigo.

Monday, March 26, 2018

Obtendo sua OCA (Oracle Certified Associate Java SE 8) em 60 dias

OCA (Oracle Certified Associate Java SE Programmer I) é a primeira certificação Oracle  que programadores Java podem tirar, o código do exame para a versão 8 do Java é 1ZO-808 (todos os exames da Oracle têm um código).

Felizmente minha primeira experiência na tentativa de obter uma certificação oficial de peso foi positiva. Conforme a imagem abaixo obtida em certview.oracle.com, passei no exame 1ZO-808.  A seguir compartilho todo processo de estudo, agendamento e realização do exame.


Estudando para o Exame

Pagar um curso em uma escola especializada em certificações Java ou estudar por conta própria? Hoje com a internet das coisas bombando, você tem recursos abundantes para se virar sozinho em qualquer área, ninguém mais detem o monopólio de qualquer conhecimento. Optei por estudar em casa, é prático e barato. A menos que você não tenha disciplina para planejar e seguir sua própria rotina de estudos, acredito que pagar um curso seria um desperdício de dinheiro (economize essa grana para pagar o exame!) e de tempo, se for um curso presencial.

Do primeiro dia de estudo até o dia do exame se passaram 60 dias (já estar trabalhando com Java pode diminuir o tempo que você leva para estudar todos os tópicos cobrados pelo exame). O material que utilizei foi o excelente livro OCA Study Guide de Jeanne Boyarsky e‎ Scott Selikoff que cobre 100% do conteúdo da prova. O site da editora Sybex também tem um excelente material de apoio, incluindo 3 exames simulados e respostas comentadas (muito importante). Esse material online de apoio é disponível somente para quem comprou o livro.


Não cometa o erro de pensar que, por ter muita experiência na área, você teria condições de passar estudando pouco ou nada! O exame tem como objetivo testar seu conhecimento sobre tudo o que é possível fazer com Java, dentro dos tópicos cobrados, e apresenta cenários um tanto bizarros, os quais você dificilmente encontraria no mundo real! Por exemplo, você jamais precisaria declarar imports para classes que estão no mesmo pacote. Mas o que aconteceria com um código que contivesse tal redundância? Erro de compilação ou apenas um advertência do compilador? Confesso que nunca parei para pensar nisso!

Ou, você seria capaz de dizer se o código abaixo compila? Se compila, qual exception é encaminhada para quem chamou o método m1()? Se não compila, onde está o erro?
public void m1(){

        try {
            throw new Exception("1");
        }
        catch (Exception e) {
            throw new NumberFormatException("2");
        }
        finally{
            throw new ArrayIndexOutOfBoundsException("3");
        }
}
Esteja preparado. O exame 1ZO-808 é repleto de código astucioso, não identado e várias forçações de barra malucas para testar o seu domínio sobre o objetivo em questão. Um tipo de questão com a qual você deve ficar especialmente atento são aquelas que apresentam código muito complicado de se analisar, quase sempre com loops aninhados, esse tipo de código geralmente possui algum erro de compilação e a intenção é fazer você perder tempo tentando descobrir qual é o resultado final. Na dúvida, marque a opção O código não compila. Felizmente, com um bom material de estudo você fica por dentro de 90% dessas artimanhas. O livro de Boyarsky e‎ Selikoff tem essse incrível mérito.

Estudei de uma a duas horas por dia, seis dias por semana, na última semana puxei um pouco mais. Dessa forma consegui com folga concluir um capítulo por semana junto com os respectivos exercícios. Recomendo utilizar uma caneta marca-texto para os trechos que você considerar mais importantes e procure sempre reler, senão todo capítulo, pelo menos esses trechos marcados (isso é importantíssimo). Na última semana fiz os exames simulados que o site da Sybex disponibiliza e refiz alguns exercícios dos outros capítulos.


Não se limite apenas a ler, marcar e resolver os exercícios. É fundamental que você implemente vários exemplos e alguns excercícios, principalmente aqueles que você errou e não entendeu. Ao programar, evite utilizar IDEs, elas são boas para produtividade, mas péssimas para estudar. Utilize o editor mais rudimentar que você puder encontrar. No meu caso utilizei o editor VI do Linux, para usuários Windows, recomendo o bloco de notas.

Agendando o Exame

Quando você tiver concluido todos os tópicos de estudo e realizado umas duas centenas de exercícios, é chegada a hora de agendar o exame!

O agendamento é feito em pearsonvue.com/oracle. O processo é semelhante a compar algo pela internet com cartão de crédito. Em vários passos, primeiro você seleciona o nome/código do exame que quer fazer, no caso 1ZO-808. Depois o site exibe os centros de aplicação do exame mais próximos da sua localidade. Escolha o que mais lhe convier, se houver uma unidade do Senac na sua cidade, é bem provável que o exame seja realizado lá, como foi no meu caso.

Após escolher a unidade de aplicação do exame, você deve selecionar uma data e hora disponível para agendamento, a opção mais imediata que encontrei era dentro de 3 dias; a mais longa, para dalí 2 meses. Como já havia praticamente terminado de estudar todos os tópicos, agendei o exame para dalí quatro dias. Você também deve escolher em qual língua quer fazer o exame, as opções disponíveis são espanhol e inglês.

No último passo você informa os dados de seu cartão de crédito e confirma. O valor do exame 1ZO-808 era de U$ 150 até a data de publicação deste artigo (meio caro para quem ganha em R$!). Imprima o comprovante de agendamento.


Realizando o Exame

Caso você não conheça o centro de aplicação do exame para onde foi agendada sua prova, recomendo que você dê uma passada por lá na véspera para se familiarizar com o local, pergunte em que sala são realizados os exames de certificação e quem é o responsável. No caso do SENAC, é provável que o exame seja realizado em algum canto da biblioteca adaptado para essa finalidade, semelhante a uma cabine onde trabalham profissionais do telemarketing. No meu caso foi assim.

No dia do exame não fique refém de imprevistos e chegue com antecedência. Não queira saber o que acontece caso você se atrase! Ao chegar no local da prova, você deve deixar todos os seus pertences em algum ármario guarda-volumes. Caso não lhe seja fornecido nenhum material de rascunho, certifique-se de pedir um, você irá precisar! Note que material de rascunho não significa necessariamente papel e caneta. A bibliotecária me forneceu um quadro plastificado e uma espécie de caneta hidrográfica péssima para escrever naquele material, mas quebrou o galho. Antes de começar o exame, certifique-se de que a caneta realmente funcione!

O software da prova é excelente e intuitivo. No canto superior direito tem um cronômetro que marca quanto tempo você ainda tem de prova, porém não se distraia e evite ficar olhando o tempo todo momento. Há também um recurso de marcar a questão atual e passar para a próxima. Depois você pode visualizar todas as questões marcadas e voltar nelas. Esse rescurso é valioso. Não desperdice tempo demais tentando resolver questões muito complicadas, marque-as e vá para próxima.

Ao começar a prova, tive uma supresa boa e outra ruim. A ruim foi que o nível das questões era mais difícil do que eu esperava, algumas exercícios tinham enunciados grandes de 4 parágrafos com várias linhas cada um, mais o código para ser analizado. Não vi nada parecido nos exercicios e nas provas simuladas da editora Sybex, nem em nenhum outro lugar. Felizmente o tempo para fazer o exame foi maior do que eu esperava, tinha em mente de que seriam 90 minutos, mas quando o ví o cronômetro do em contagem regressiva a partir de 2 horas e 30 minutos, o alívio foi grande! Esse tempo extra compensou o nível maior de dificuldade e foi suficiente para responder todas as questões e ainda revisar as que tinha marcado.

No software do exame há uma opção que você clica quando acabar. Após confirmar que você realmente deseja encerrar, o exame é finalizado e as questões são submetidas. O resultado  será disponibilizado em até 30 minutos em certview.oracle.com. Após cerca de 48 horas, na sua conta em certview será ativada uma série de recursos como seu histórico de exames, tópicos em que você errou, e, caso você tenha passado, uma espécie de diploma, entre outras ferramentas que autenticam sua certificação.


O score mínimo para passar no exame 1ZO-808 é de 65%. O meu foi de 70%. Na sua conta em certview.oracle.com você saberá qual foi seu score e em quais tópicos você errou.

Apêndice

Os profissionais da área de TI passam boa parte da carreira estudando. Otimizar esse tempo de estudo, aprendendo mais rápido e memorizando muito mais coisas pode fazer uma diferença enorme na sua evolução profissional. Alguns alimentos comprovadamente turbinam suas funções cerebrais e melhoram o seu desempenho, tais como gorduras naturais (oleo de coco, TCM, ômega 3, azeite extra virgem, manteiga natural, gordura da carne vermelha), ovos (muitos), 2 litros de água (da boa) por dia. Tão importante quanto fazer uso dos bons alimentos, é não consumir aqueles que atrasam a sua vida e diminuem seu desempenho cognitivo, tais como óleos hidrogenados, gluten, açucar, refrigerantes e industrializados em geral.

referências sobre as dicas alimentares:
canal Dr. Lair Ribeiro no YouTube
canal Dr. Uronal Zancan no YouTube
canal Dr. Dayan Seabra no YouTube

Friday, January 5, 2018

SOAP Web Services in WildFly

Web services are client and server applications that communicate with each other through the HyperText Transfer Protocol (HTTP). As the name implies, web services represent something accessible on the web that gives you a service. The application that gives a service is called the provider and the one that uses a service is called consumer.

The main advantage of web services is that they provide a standard means of interoperating between software applications running on a variety of platforms and frameworks, i.e., the underlying implementation can be done in any language (Java, PHP, C#, C++, ...). A consumer and a service provider will still be able to exchange data in a loosely coupled way using XML documents.

SOAP (Simple Object Access Protocol) web services are said to be loosely coupled because the client doesn't have to know its implementation details. The communication between them happens by means of XML messages that rely on the SOAP specification which refers to the WSDL (Web Services Description Languages).  The Web Service Description Language is the de facto standard to provide a description of a web service contract exposed to clients. If you want to use (consume) some SOAP based web services you must follow the rules described in its XML, the WSDL document, that describes a web service in terms of the operations that it provides, and the data types that each operation requires as input and can return in the form of results.

Creating a SOAP Web Service in WildFly 10 to validate a CPF

 Open Eclipse IDE and create a New Maven Project. Give it the name SOAP_WS_ValidateCPF, select packaging as .war and Finish:




In the pom.xml add the dependency for JavaEE 8 API. It should be like this:
<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>SOAP_WS_ValidateCPF</groupId>
  <artifactId>SOAP_WS_ValidateCPF</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <properties>
 <failOnMissingWebXml>false</failOnMissingWebXml>
 <maven.compiler.source>1.8</maven.compiler.source>
 <maven.compiler.target>1.8</maven.compiler.target>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
 <dependency>
  <groupId>javax</groupId>
  <artifactId>javaee-api</artifactId>
  <version>8.0</version>
 </dependency>
  </dependencies>
</project>

Although it's not mandatory, we will create an interface to represent our web service contract. It will have a method that receives a Pessoa as an argument and checks if its CPF field is valid by setting a flag in the field cpfValido, then returns that person to the consumer:
public interface ConsultaCPF {

 public Pessoa consultarCPF( Pessoa pessoa);
}
And the interface implementation ConsultCPFImpl. We turn that class into a web service just by adding the mandatory @WebService annotation, all others annotations are optional.
@WebService(targetNamespace="http://www.company.com/", serviceName="ConsultaCPFService")
public class ConsultaCPFImpl implements ConsultaCPF {

 @Override
 @WebMethod
 @WebResult(name = "pessoa")
 public Pessoa consultarCPF( @WebParam(name = "pessoa") Pessoa pessoa) {
  
  //business rules...
  if(pessoa.getCpf() != null && pessoa.getCpf().length() == 11 ){
   
   String cpf = pessoa.getCpf();
   char ultimoDigito = cpf.charAt(cpf.length()-1);
   int n = new Integer(ultimoDigito);
   boolean par = n % 2 == 0;
   pessoa.setCpfValido(par);   
  }
  else
   pessoa.setCpfValido(false);
  
  return pessoa;
 }
}
The hypothetical validation rule just checks if the field is not null and has 11 characters, then validates if the last character is even. The meaning of the other annotations and its parameters are:
  • @WebService(targetNameSpace="xyz"): declare the namespaces for WSDL elements generated by the web service
  • @WebService(serviceName="name"): the name specified is used to generate the name attribute in the service element in the WSDL interface
  • @WebMethod(): indicates that you want to expose this public method as web service
  • @WebParam(): indicates the parameter name that should be exhibited in the WSDL
  • @WebResult(): similar to @WebParam, it specifies the method param name in the WSDL
Of course, we need the entity Pessoa. As stated before, everything exchanged between the consumer and the web service take place as XML file, that means things like java POJOs should be marshaled/unmarshaled to/from an XML format as it is sent/received by consumer and provider. JAXB API does that behind the scenes, all we need to do is annotate the classes and its fields that will be exchanged like following:

@XmlRootElement(name = "pessoa")
@XmlAccessorType(XmlAccessType.FIELD)
public class Pessoa {
 
 @XmlAttribute(name = "nome")
 private String nome;

 @XmlAttribute(required = true)
 private String cpf;

 @XmlAttribute(name = "nascimento")
 private Date nascimento;

 @XmlAttribute(name = "cpfValido")
 private boolean cpfValido;
//getters & setters...

That's all we need. Now right click on your project, go to properties, then project facets at the right panel, click the runtime tab in the right panel and choose wild fly:


Now right click on your project, choose run as, run on  server... (you might need to clean and build your project or restart wildfly). Check WildFly log and look for this part confirming your web service is already published:

As a compliant JavaEE container, WildFly recognizes, by the @WebService annotation, that your project has web services and automatically creates and publishes the WSDL document. Open WildFly admin console (generally at port 9990), click Runtime tab and navigates through Standalone Server, Subsystems, Web Services and click in view:


Click on WSDL Url to see the generated WSDL XML document exposed representing your web service:



Invoking the Web Service

Since our web service is up and running, it is time to consume it. Make sure to not shutdown wildfly, otherwise the web service won't be accessible anymore.

Create a simple new Java project named SOAP_WS_ValidateCPF_Consumer. Create a class named Main with the main method. At this point, the new project doesn't know nothing about the ConsultaCPFService web service. Java has the utility wsimport under <JAVA_HOME>/bin folder to create the needed artifacts that allow some project to consume a specified web service.

Open your terminal command and go to the source folder of SOAP_WS_ValidateCPF_Consumer project (in my case /home/rafael/workspace/SOAP_WS_ValidateCPF_Consumer/src/) and execute the wsimport utility passing the WSDL Url as a parameter like the picture (you might need root privileges if you are in a Linux environment):


/usr/lib/jvm/jdk1.8.0_144/bin/wsimport -keep -verbose http://localhost:8080/SOAP_WS_ValidateCPF-0.0.1-SNAPSHOT/ConsultaCPFService?wsdl

The wsimport utility imports all needed artifacts to invoke the web service. Refresh your project on eclipse and see that new packages were created in accord with WSDL contract at the URL passes as a parameter:



Now the Main class looks like:

package main;

import com.company.ConsultaCPF;
import com.company.ConsultaCPFService;
import com.ecommerce.ws.consulta_cpf.Pessoa;

public class Main {
 
 //we can get a reference to web service by calling the method getConsultaCPFImplPort()
 ConsultaCPF consultaCPF = new ConsultaCPFService().getConsultaCPFImplPort();
 
 public static void main(String[] args) {
  
  new Main();    
 }
 
 public Main(){
  
  System.out.println(consultaCPF);
  Pessoa pessoa = new Pessoa();
  pessoa.setCpf("55555555551");
  System.out.println(consultaCPF.consultarCPF(pessoa).isCpfValido());
 }
}

Run the project. It will return true or false depending on the last digit of CPF field. This small standalone class has shown how it is possible to use SOAP-based services from the client-side perspective.

Now, shutdown wildfly and try to run the Main again. An exception is thrown because the service is not accessible anymore:
Exception in thread "main" javax.xml.ws.WebServiceException: Failed to access the WSDL at: http://localhost:8080/SOAP_WS_ValidateCPF-0.0.1-SNAPSHOT/ConsultaCPFService?wsdl. It failed with: 
 Connection refused (Connection refused).
 at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:250)
 at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:231)
 at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:194)
 at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:163)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:348)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:306)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:215)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:196)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:192)
 at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:104)
 at javax.xml.ws.Service.<init>(Service.java:77)
 at com.company.ConsultaCPFService.<init>(ConsultaCPFService.java:42)
 at main.Main.<init>(Main.java:10)
 at main.Main.main(Main.java:14)

References:
GONCALVES, Antonio . Beginning Java EE 7 (Expert Voice in Java). 1. ed. New York: Apress, 2013. 608 p.
ĆMIL , Michal; MATLOKA, Michal ; MARCHIONI, Francesco . Java EE 7 Development with WildFly. 2. ed. Birmingham: Packt Publishing Ltd., 2013
JENDROCK, Eric et al. Java Platform, Enterprise Edition: The Java EE Tutorial Release 7. 1. ed. [S.l.]: Oracle, 2014. 980 p.

Thursday, November 16, 2017

Adicionando Opções de Resolução de Tela no Linux

O camando xrandr é um utilitário de configuração do X Window, framework básico para construção de diversos padrões de interfaces gráficas no estilo desktop. O xrandr permite a (re)configuração do X Window dinamicamente, isto é, sem necessidade de reiniciar o servidor. Você também pode obter informações técnicas sobre o monitor e o ambiente gráfico em geral tais como resolução, refresh rate, etc.

Execute camando xandr sem parâmetros e veja todos os outputs (geralmente monitores) conectados ao sistema e alguns detalhes técnicos de cada, como as resoluções:
~ $ xrandr
Screen 0: minimum 8 x 8, current 1680 x 1050, maximum 32767 x 32767
VGA1 connected 1680x1050+0+0 (normal left inverted right x axis y axis) 477mm x 268mm
   1680x1050     59.95*+  
   1280x1024     75.02    60.02  
   1152x864      75.00  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   640x480       75.00    59.94  
   720x400       70.08  
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
A saída do comando mostra um VGA1 conectado e a resolução marcada com * e + indicam a que está sendo usada no momento e a preferencial, respectivamente.
Com essas informações, você pode definir uma opção de resolução diferente para o monitor (desde que ela esteja disponível). Por exemplo você pode adicionar a resolução 1920x1080 com o seguinte comando:
~ $ cvt 1920 1080
# 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz
Modeline "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync

Repare em todo trecho que vem após modeline. Copie-o e cole como parâmetro para o comando xrandr:
$ xrandr --newmode "1920x1080_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -hsync +vsync

Em seguida, execute novamente:
~ $ xrandr --addmode VGA1 "1920x1080_60.00"

A partir deste ponto a nova resolução 1920x1080 já estará disponível em suas configurações de monitor. Caso seu desktop seja um XFCE, por exemplo, você poderá encontrar a nova opção em settings/display a partir do menu inicial, como a janela abaixo:



Wednesday, November 1, 2017

DataSource no servidor WildFly utilizando JPA, JSF, Maven e Eclipse: parte 2

Criando uma aplicação Java para acessar o DataSource

Dando sequência à parte 1 deste artigo onde configuramos o datasource no servidor WildFly 10, agora criamos a aplicação.
Abra o Eclipse e crie um Novo Projeto Maven (File/New/Other.../Maven Project). Marque a opção Create a Simple Project e Next:


Informe as propriedades do projeto e na combobox Packaging escolha war. Finish:


Vá em propriedades do projeto. No painel esquerdo selecione Project Facets. No painel direito marque as opções CDI, JPA e Java Server Faces. Mais à direita, na aba Runtimes marque WildFly. Clique em Apply e OK:



No arquivo pom.xml adicionamos as dependências do JPA (hibernate):
<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>TestDataSource</groupId>
 <artifactId>TestDataSource</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <dependencies>
  <dependency>
   <groupId>org.jboss.logging</groupId>
   <artifactId>jboss-logging</artifactId>
   <version>3.3.1.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>3.6</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>6.0.2.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>5.2.10.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>5.2.10.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>com.lowagie</groupId>
   <artifactId>itext</artifactId>
   <version>2.1.7</version>
   <scope>compile</scope>
  </dependency>
 </dependencies>
</project>

Na pasta META-INF o eclipse já cria para nós o arquivo persistence.xml dentro do qual informamos alguns parâmetros do JPA, como o nome do data source no servidor, instruímos a gerar tabelas no banco de dados a partir das classes do projeto e mostrar os scripts SQL por exemplo.

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.1"
 xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

 <persistence-unit name="TestDataSource">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <jta-data-source>java:jboss/datasources/empresaDB_DS_mysql</jta-data-source>

  <properties>
   <property name="javax.persistence.schema-generation.database.action"
    value="none" />
   <property name="hibernate.format_sql" value="true" />
   <property name="hibernate.show_sql" value="true" />
   <property name="hibernate.hbm2ddl.auto" value="update" />
  </properties>
 </persistence-unit>
</persistence>


Entidade Funcionario

Agora que o projeto já está configurado, crie  pacote chamado entidades e nele a classe Funcionario como segue. A anotação @Entity informa ao JPA que essa classe será uma tabela no banco de dados:
@Entity
public class Funcionario implements Serializable{

 @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id; //chave primaria da tabela 
 
 private String nome;

 private Integer idade;

 private Date nascimento;

 private Double salario;
 
 //getters, setters omitidos para clareza
}

Até o momento a estrutura do nosso projeto está como na imagem:



Página JSF e Managed Bean

Crie um pacote chamado controle e nele a classe chamada FuncionarioMB e FuncionarioService, onde esta é responsável por intermediar as ações com o banco de dados (salvar, editar, excluir, etc) e aquela gerencia os eventos na interface gráfica com o usuário, neste caso a página web:

FuncionarioMB (gerencia os eventos na web page):
import java.util.List;
import javax.inject.Inject;
import javax.enterprise.inject.Model;
import javax.transaction.Transactional;
import entidade.Funcionario;

@Model
public class FuncionarioMB {

 @Inject
 private FuncionarioService funcionarioService; 
 
 private Funcionario funcionario = new Funcionario();
 private List<Funcionario> funcionarios;  
 
 //diz para o servidor wildFly abrir transação para persistir objeto no banco
 //o próprio servidor faz o commit após o método retornar
 @Transactional 
 public String salvar() {  
  funcionarioService.salvar(funcionario);
  return null;
 }
 
 public Funcionario getFuncionario() {

  return funcionario;
 }

 public void setFuncionario(Funcionario funcionario) {
  this.funcionario = funcionario;
 }

 public List<Funcionario> getFuncionarios() {
  
  //busca todos os registros na tabela e exibe
  if(funcionarios == null)
   funcionarios = funcionarioService.buscarTodos();
  
  return funcionarios;
 }
}

FuncionarioService (camada de serviço e acesso ao banco de dados):

package controle;

import java.util.List;
import javax.enterprise.inject.Model;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import entidade.Funcionario;

@Model
public class FuncionarioService {

 @PersistenceContext
 private EntityManager entityManager;
 
 public void salvar(Funcionario funcionario) {

  entityManager.persist(funcionario);  
 }
 
 public List<Funcionario> buscarTodos() {

  String query = "SELECT f FROM Funcionario f";
  return entityManager.createQuery(query).getResultList();
 }
}

Agora podemos criar a web page. No diretório src/main/webapp crie a pasta index.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html">

 <h:body>
 <h:form>
  <h:outputText value="Cadastro de Funcionário" />
  <h:panelGrid columns="2">
   <h:outputText value="Nome" />
   <h:inputText value="#{funcionarioMB.funcionario.nome}" />
   <h:outputText value="Idade" />
   <h:inputText value="#{funcionarioMB.funcionario.idade}" />       
   <h:outputText value="Salário" />
   <h:inputText value="#{funcionarioMB.funcionario.salario}" >
    <f:convertNumber pattern="#0.00" locale="pt"/>
   </h:inputText>
   <h:outputText value="Data Nascimento" />
   <h:inputText value="#{funcionarioMB.funcionario.nascimento}" >
    <f:convertDateTime pattern="dd/MM/yyyy" locale="pt" />
   </h:inputText>
   <h:commandButton action="#{funcionarioMB.salvar()}" value="Salvar" />
  </h:panelGrid>
  <p/>
  Lista
  <h:dataTable value="#{funcionarioMB.funcionarios}" var="funcionario" border="1">
   <h:column>
    <h:outputText value="#{funcionario.nome}" />
   </h:column>
   <h:column>
    <h:outputText value="#{funcionario.idade}" />
   </h:column>
   <h:column>
    <h:outputText value="#{funcionario.salario}" >
     <f:convertNumber pattern="#0.00" currencySymbol="$" locale="pt"/>
    </h:outputText>
   </h:column>
   <h:column>
    <h:outputText value="#{funcionario.nascimento}" >
     <f:convertDateTime pattern="dd/MM/yyyy" locale="pt" />
    </h:outputText>
   </h:column>
  </h:dataTable>
 </h:form>
 </h:body>
</html>
Todo input de texto em aplicações web são interpretados por padrão como texto puro, dessa forma utilizamos alguns converters padrão do JSF para a adpatar os tipos de dados que não são texto, como a idade, nascimento, e salário.
Pronto. A aplicação já está pronta para rodar. Clique com o botão direito na pasta raíz da aplicação, escolha Run as, em seguida Run on Server. A aplicação será acessada na porta default do servidor, geralmente a 8080:


Insira registros válidos (como nenhuma regra de validação foi implementada, se você inserir registros inválido, a aplicação vai lançar um erro) e salve. A tabela lista os funcionário cadastrados até o momento.
A estrutura final do projeto ficou como segue:

Wednesday, October 18, 2017

DataSource no servidor WildFly utilizando JPA, JSF, Maven e Eclipse: parte 1

Aplicações Java Enterprise acessam banco de dados utilizando a API JDBC. Nela os bancos de dados são acessados usando objetos do tipo DataSource, os quais possuem uma série de propriedades que identificam o banco de dados real como a URL do servidor, o nome do banco de dados, senha, etc.

Antes de acessar o banco de dados, a aplicação precisa criar uma conexão, e um objeto DataSource funciona como um factory de conexões entre o banco e a aplicação. Quando o DataSource é gerenciado pelo servidor de aplicações, geralmente a ele é associado um JNDI, que é um nome para o datasource. Assim quando a aplicação demanda uma conexão, ela utiliza o JNDI, o servidor instancia o(s) objeto(s) DataSource e disponibilizam a conexão.

Datasources em servidores Java EE geralmente implementam o poolingque são algoritmos de instanciação de DataSources totalmente transparentes à aplicação os quais otimizam a liberação, abertura e fechamento de conexões com o banco de dados.

DataSources para o banco de dados MySQL no servidor WildFly 10

Faça download da API JDBC do MySQL (mysql-connector-java-5.1.21.jar) e, caso necessário, baixe também o servidor WildFly 10 Java EE7 Full & Web Distribution . No MySQL, crie um banco de dados chamado EmpresaBD.

No WildFly, DataSources também são chamados de módulos. Assim, para acessar o MySQL do servidor precisamos instalar um novo módulo para ele. No diretório raiz do WildFly, há a pasta modules. A partir dela crie os diretórios /com/mysql/main/ da forma que segue:

WILDFLY_HOME/modules/com/mysql/main/

Dentro da pasta main cole o driver do MySQL que você acabou de baixar e crie um arquivo chamado module.xml, o qual conterá a definição do módulo cujo nome é com.mysql. 

A variável JBOSS_HOME aponta para pasta module e os arquivos e pastas criados lá dentro serão usados para carregar o datasource quando o servidor iniciar. O conteúdo do arquivo module.xml deve ser como segue:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.mysql"> 
    <resources>
        <resource-root path="mysql-connector-java-5.1.21.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>

Salve e feche o arquivo module.xml. A estrutura de diretórios que criamos então fica dessa forma:
  • WILDFLY_HOME/modules/com/mysql/main/mysql-connector-java-5.1.21.jar
  • WILDFLY_HOME/modules/com/mysql/main/module.xml

O módulo que permite acessar o MySQL do WildFly está instalado. Agora só precisamos criar o data source para o banco EmpresaDB. Para isso temos que editar o arquivo standalone.xml passando as coordenadas do banco (usuário, senha, etc.). Esse arquivo está localizado em:
  • WILDFLY_HOME/standalone/configuration/standalone.xml 
Abra esse arquivo, localize a tag <dataSources> e dentro dela cole o seguinte trecho (ajustando usuário e senha de acordo com suas configurações pessoais):
<datasource jta="true" jndi-name="java:jboss/datasources/empresaDB_DS_mysql"
 pool-name="empresaDB_DS_mysql" enabled="true">

 <connection-url>jdbc:mysql://localhost:3306/EmpresaDB</connection-url>
 <driver-class>com.mysql.jdbc.Driver</driver-class>
 <driver>mysql</driver>
 <security>
  <user-name>root</user-name>
  <password>P@ssword1</password>
 </security>

</datasource>

Ainda dentro da tag <dataSources> localize a tag <drivers> e dentro dela cole este trecho:
<driver name="mysql" module="com.mysql"/>
Repare que a tag driver aponta para o módulo que criamos. E o datasource que criamos aponta para a esta tag driver cujo nome é mysql.

Salve e feche o arquivo standalone.xml. Pronto. Inicie o servidor WildFly executando o arquivo standalone.sh (para Linux) ou standalone.bat (para Windows) localizado em WILDFLY_HOME/bin/

Acesse o console do servidor na porta 9990. Clique na aba Configurations, depois vá clicando em Subsystems, DataSources, Non-XA. Localize o datasource criado EmpresaDB_DS_mysql e teste a conexão. Conforme a imagem:



Repare que o nome que registramos, empresaDB_DS_mysql, é o que será usado na aplicação para que ela solicite ao servidor uma conexão com o banco de dados EmpresaDB.

Na parte 2 deste artigo criamos uma aplicação JavaEE que acessa o DataSource.

Referências:
ĆMIL , Michal; MATLOKA, Michal ; MARCHIONI, Francesco . Java EE 7 Development with WildFly. 2. ed. Birmingham: Packt Publishing Ltd., 2013