• Nenhum resultado encontrado

UNIVERSIDADE FEDERAL DE PERNAMBUCO GRADUAÇÃO EM SISTEMAS DE INFORMAÇÃO CENTRO DE INFORMÁTICA 2016.1

N/A
N/A
Protected

Academic year: 2021

Share "UNIVERSIDADE FEDERAL DE PERNAMBUCO GRADUAÇÃO EM SISTEMAS DE INFORMAÇÃO CENTRO DE INFORMÁTICA 2016.1"

Copied!
56
0
0

Texto

(1)

UNIVERSIDADE FEDERAL DE PERNAMBUCO

GRADUAÇÃO EM SISTEMAS DE INFORMAÇÃO

CENTRO DE INFORMÁTICA

2016.1

HIVE.CLOUD NFE: SOFTWARE PARA EMISSÃO DE NOTA

FISCAL ELETRÔNICA

TRABALHO DE GRADUAÇÃO

Aluno

SEBASTIÃO ALVINO DE LIMA FILHO (salf2@cin.ufpe.br)

Orientadora

CARLA TACIANA LIMA LOURENÇO SILVA SCHUENEMANN (ctlls@cin.ufpe.br)

Recife 2016

(2)

RESUMO

A Hive.log é uma empresa brasileira de software, situada em Recife – PE, especializada no desenvolvimento de soluções na área de logística de transporte. Sua plataforma integrada Hive.cloud é composta de diversos produtos, que oferecem aos proprietários de transportadoras de cargas a possibilidade de gerenciar suas operações de transporte, bem como de armazenar e emitir as documentações fiscais requeridas pela Receita Federal para o adequado funcionamento dessas operações.

Um dos documentos fiscais exigidos na logística de transporte é a Nota Fiscal

Eletrônica, ou simplesmente NF-e, que armazena informações fiscais referentes às

mercadorias transportadas. Apesar de não ser um documento comumente emitido pelas transportadoras, mas, sim, por seus clientes, em situações específicas faz-se necessário que a transportadora emita uma NF-e.

Esse trabalho de graduação descreve o processo de desenvolvimento da solução

Hive.cloud NFe, das principais tecnologias utilizadas nesse processo de

desenvolvimento, bem como dos conceitos associados à Engenharia de Software utilizados na manufatura dessa solução, com a finalidade de atender a uma demanda da empresa Hive.log e de seus respectivos clientes.

(3)

AGRADECIMENTOS

A conclusão desse Trabalho de Graduação me exigiu muita luta, muito esforço, e sem medo de soar como um clichê, muito suor e muitas lágrimas. Porém, nada disso teria sido possível sem a participação e a ajuda de muitas pessoas, que foram de fundamental importância para mim ao longo de todo esse processo. Como está escrito: “Deem a cada um o que lhe é devido: a quem respeito, respeito; a quem honra, honra” (Romanos 13:7). A cada um deles, o meu mais profundo agradecimento.

À minha esposa, Manoela, por ter lutado, como pôde, além de suas próprias forças, para me ajudar a concluir essa graduação.

Aos meus pais, Sebastião e Marineusa, por todo amor, carinho, companheirismo e dedicação que me dispensaram desde o meu primeiro dia de vida e ao longo de toda a minha formação.

A Antonio, meu irmão, amigo, companheiro e conselheiro de todas as horas, sempre dividindo comigo um pouco de sua muita sabedoria.

A Vicente e Suzy, meus terapeutas, que me ajudaram a aprender a conviver com meus medos, e de como eu poderia enfrenta-los e vencê-los. Sem eles, a realização desse trabalho jamais teria acontecido.

A Daniel, meu chefe, a Fernando, meu líder de equipe, e a cada um dos meus amigos de trabalho da Hive.log. A convivência e o aprendizado que tive com cada um de vocês foi o que permitiu que o Hive.cloud NFe fosse concebido.

À Carla, minha orientadora, por toda a compreensão e apoio que me deu ao longo da elaboração desse trabalho.

A cada um dos professores e colaboradores do CIn, que fizeram parte da minha formação e graduação nesse centro de excelência.

A cada um dos meus amigos e familiares, que mesmo distantes, compartilharam comigo a sua torcida e as suas orações, para que essa graduação fosse concluída.

E por último, mas, de modo algum menos importante, eu deixo aqui o meu eterno agradecimento ao meu Deus e Pai. O Pai do meu Senhor e Salvador Jesus Cristo, razão da minha vida e da minha existência. Sem o auxílio do Seu Santo Espírito, eu jamais teria conseguido atravessar o período mais difícil e sofrido da minha vida, e no meio dele, encontrar paz e sossego.

Pude experimentar nesses últimos meses, de modo inquestionável, a verdade contida nessas palavras: “Porque eu, o SENHOR, teu Deus, te tomo pela tua mão direita e te digo: Não temas, que eu te ajudo. Não temas, porque eu sou contigo; não te assombres porque eu sou o teu Deus; eu te fortaleço, e te ajudo, e te sustento com a minha destra fiel.” (Isaías 41:13, 10).

Ao fim dessa jornada, eu finalmente posso dizer, como Jó: “Bem sei que tudo podes, e nenhum dos teus planos pode ser frustrado. Eu te conhecia só de ouvir, mas agora os meus olhos te veem.” (Jó 42:2, 5).

(4)

Índice

1 Introdução ... 6

1.1 A Plataforma Hive.cloud... 6

1.2 A Nota Fiscal Eletrônica (NF-e)... 7

1.3 O Hive.cloud NFe ... 9

2 Principais tecnologias utilizadas ... 10

2.1 Google Web Toolkit (GWT) ... 10

2.2 RequestFactory ... 12 2.2.1 Entity ... 13 2.2.2 Entity Proxies ... 14 2.2.3 Value Proxies ... 15 2.2.4 Interface RequestFactory ... 16 2.2.5 Tipos transportáveis ... 18 2.2.6 Implementações no servidor ... 18

2.2.7 Uso de Locator e ServiceLocator ... 19

2.3 Java Persistence API (JPA) ... 21

2.3.1 Mapeamento Objeto Relacional (ORM) ... 21

2.3.2 Java Persistence API e Frameworks ORM ... 22

2.3.3 JPA 2.0 ... 22

2.3.4 Entidades ... 23

2.3.5 Multiplicidade no Relacionamento de Entidades ... 23

2.3.6 Relacionamentos Bidirecionais ... 24

2.3.7 Relacionamentos Unidirecionais ... 24

2.3.8 Consultas e Direção do Relacionamento ... 24

2.3.9 Remoção em Cascata e Relacionamentos ... 25

2.3.10 Gerenciando Entidades ... 25

2.3.11 Unidades de Persistência ... 27

2.4 Spring Framework ... 27

2.5 Apache Maven ... 30

3 Cenários de Uso da Aplicação ... 32

3.1 Cadastro e Seleção de Ambiente ... 32

3.2 Configuração do Certificado Digital ... 35

(5)

3.3.1 Telas de Listagem ... 40 3.3.2 Telas de Exibição ... 43 3.3.3 Telas de Edição ... 43 3.4 Criação da NF-e ... 44 3.5 Emissão da NF-e ... 46 3.6 Exportação do XML da NF-e ... 51 3.7 Impressão do DANFE ... 52 4 Conclusão ... 55 Referências Bibliográficas ... 56

(6)

6

1 INTRODUÇÃO

1.1 A Plataforma Hive.cloud

A Hive.cloud é uma suíte de softwares e serviços voltados para a gestão logística de transporte. Atualmente, a suíte é composta dos seguintes produtos:

 Hive.cloud CTe: Software para emissão de Conhecimento de Transporte Eletrônico

 Hive.cloud MDFe: Software para emissão de Manifesto Eletrônico  Hive.cloud AR: Registro de ocorrências via celular

 Hive.cloud TMS: Software completo para gestão operacional de transportadoras

 Hive.cloud RPA: Software para emissão de Recibo de Pagamento a Autônomo

 Hive.cloud B2I: Software para intercâmbio eletrônico (EDI) e extração de dados analíticos

 Hive.cloud LIVE: Software para gestão e acompanhamento de operações em tempo real

 Hive.cloud WMS: Software para Gestão Operacional de Armazéns  Hive.cloud EDU: Educação e certificação em Logística

 Hive.cloud CONSULT: Assessoria em implantação e consultoria em Logística

Os softwares que compõem a suíte possuem planos de contratação variados, que atendem as necessidades desde uma pequena transportadora até às de uma grande corporação. Esses softwares podem ser adquiridos de modo individual ou em conjunto, atendendo às necessidades específicas de cada cliente. O intercâmbio de informações entre os serviços também é possível, visto que eles estão preparados para funcionarem de maneira integrada.

A plataforma baseia-se no conceito de Software as a Service (SaaS), de modo que, para fazer uso das aplicações, os clientes da empresa só precisam estar conectados à internet e de um navegador web. Fazendo uso das soluções em cloud computing oferecidas pela Amazon, os servidores de armazenamento de dados e de execução das aplicações ficam todos situados na nuvem, reduzindo os custos operacionais da empresa significativamente, o que também se traduz em valores de contratação convidativos para os seus clientes.

(7)

7

Figura 1: A suíte Hive.cloud

1.2 A Nota Fiscal Eletrônica (NF-e)

De maneira simplificada, a empresa emissora de NF-e gerará um arquivo eletrônico, no formato XML, contendo as informações fiscais da operação comercial, o qual deverá ser assinado digitalmente, de maneira a garantir a integridade dos dados e a autoria do emissor. Este arquivo eletrônico, que corresponderá à Nota Fiscal Eletrônica (NF-e), será então transmitido pela Internet para a Secretaria da Fazenda de jurisdição do contribuinte, que fará uma pré-validação do arquivo e devolverá um protocolo de recebimento (Autorização de Uso), sem o qual não poderá haver o trânsito da mercadoria. A NF-e também será transmitida para a Receita Federal, que será repositório nacional de todas as NF-e emitidas (Ambiente Nacional) e, no caso de operação interestadual, para a Secretaria de Fazenda de destino da operação, e Suframa, no caso de mercadorias destinadas às áreas incentivadas. As Secretarias de Fazenda e a RFB (Ambiente Nacional), disponibilizarão consulta, através da Internet, para o destinatário e outros legítimos interessados, que detenham a chave de acesso do documento eletrônico.

(8)

8

Tabela 1: Visão resumida do XML de uma NF-e autorizada

<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> <NFe xmlns="http://www.portalfiscal.inf.br/nfe"> <infNFe versao="3.10" Id="NFe33150500776574001390550050031990431205801931"> <ide></ide> <emit></emit> <dest></dest>

<det nItem="1"></det> <det nItem="2"></det> <total></total> <transp></transp> <infAdic></infAdic> </infNFe> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> </Signature> </NFe> <protNFe versao="3.10"> <infProt> <tpAmb>1</tpAmb> <verAplic>SVRS201504271011</verAplic> <chNFe>33150500776574001390550050031990431205801931</chNFe> <dhRecbto>2015-05-08T19:45:03-03:00</dhRecbto> <nProt>333150062851333</nProt>

<digVal>/XvPI7Pk4P2mw7huUmBKOfM34KY=</digVal> <cStat>100</cStat>

<xMotivo>Autorizado o uso da NF-e</xMotivo> </infProt>

</protNFe> </nfeProc>

Para acompanhar o trânsito da mercadoria será impressa uma representação gráfica simplificada da Nota Fiscal Eletrônica, intitulado DANFE (Documento Auxiliar da Nota Fiscal Eletrônica), em papel comum, em única via, que conterá impressa, em destaque, a chave de acesso para consulta da NF-e na Internet e um código de barras bidimensional que facilitará a captura e a confirmação de informações da NF-e pelas unidades fiscais.

O DANFE não é uma nota fiscal, nem substitui uma nota fiscal, servindo apenas como instrumento auxiliar para consulta da e, pois contém a chave de acesso da NF-e, que permite ao detentor desse documento confirmar a efetiva existência da NF-e através do Ambiente Nacional (RFB) ou site da SEFAZ na Internet.

O contribuinte destinatário, não emissor de NF-e, poderá escriturar os dados contidos no DANFE para a escrituração da NF-e, sendo que sua validade ficará vinculada à efetiva existência da NF-e nos arquivos das administrações tributárias envolvidas no processo, comprovada através da emissão da Autorização de Uso. O contribuinte emitente da NF-e, realizará a escrituração a partir das NF-e emitidas e recebidas.

A SEFAZ do estado de São Paulo atualmente disponibiliza para download um software emissor gratuito de NF-e. Porém, devido ao crescente uso de soluções mais robustas e personalizadas às necessidades dos emissores, esse software da SEFAZ será descontinuado em 1/1/2017, não sendo mais possível a realização do seu download. Desse

(9)

9 modo, os emissores de NF-e que ainda fazem uso dessa solução gratuita, precisarão recorrer ao uso de outros softwares desenvolvidos especificamente para esse fim.

1.3 O Hive.cloud NFe

Foi visando atender à essa demanda futura que o autor desse trabalho deu início ao desenvolvimento do software Hive.cloud NFe. A ideia do sistema surgiu inicialmente como uma proposta para a execução e escrita do presente trabalho. Porém, ao ser apresentada à diretoria da empresa, a ideia veio a se enquadrar também com uma necessidade real da empresa, que apesar de não ter a resolução dessa necessidade como uma prioridade imediata, propôs ao autor que realizasse o desenvolvimento da solução, o que atenderia às necessidades de ambos, tanto do autor, como da empresa na qual ele trabalha.

O Hive.cloud NFe será capaz de gerar, editar, armazenar e emitir notas fiscais eletrônicas, por meio da conexão web aos servidores da SEFAZ, atendendo a todos os requisitos técnicos exigidos pela mesma.

A interface com o usuário apresentará telas de listagem, exibição e edição das informações concernentes às NF-es, desenvolvidas de modo a tornar cada processo o mais intuitivo possível para o usuário.

O software se diferencia, desse modo, do emissor gratuito da SEFAZ, que além de não apresentar as facilidades de uso no momento da emissão da NF-e, exige do usuário a instalação de um programa em sua máquina local, e também deixa à carga do emissor armazenar e gerenciar os arquivos eletrônicos gerados no momento da emissão, o que obriga o usuário a se preocupar com a manutenção e preservação desses arquivos.

Por meio do Hive.cloud NFe, os clientes da Hive.log terão essas deficiências suplantadas, por meio de um sistema ágil, robusto, de fácil manuseio, que não necessita de nenhuma instalação adicional e que livra o emissor da preocupação com o armazenamento e gerenciamento das suas NF-es.

(10)

10

2 PRINCIPAIS TECNOLOGIAS UTILIZADAS

2.1 Google Web Toolkit (GWT)

Na construção da interface gráfica do usuário (GUI), os mais recentes sistemas desenvolvidos pela Hive.log utilizam o Google Web Toolkit, ou GWT.

Figura 2: Estrutura básica de um projeto GWT

O GWT é um kit de desenvolvimento open source, completamente gratuito, utilizado na construção de aplicações web. Seu objetivo é permitir o desenvolvimento dessas aplicações, sem que seja necessário ao desenvolvedor ser um especialista nas peculiaridades dos navegadores a serem utilizados, em XMLHttpRequest, ou em linguagem JavaScript. O GWT é utilizado por muitos dos principais produtos do Google, incluindo o AdWords, AdSense, Wallet, Blogger, dentre outros.

O Software Development Kit (SDK) do GWT fornece um conjunto de Widgets e APIs, que permitem ao desenvolvedor escrever aplicações AJAX utilizando a linguagem de programação Java e, em seguida, compilar o código fonte para um JavaScript altamente otimizado, que pode ser executado em qualquer navegador, incluindo os navegadores móveis para Android e iPhone. Além disso, o desenvolvedor não está limitado aos widgets preestabelecidos, podendo desenvolver por conta própria novos widgets customizados às suas necessidades. Tudo aquilo que pode ser feito por meio da

(11)

11 codificação do Data Object Model (DOM) do navegador e por JavaScript, pode ser feito em GWT, incluindo interagir com outros códigos JavaScript.

O GWT permite a depuração (debug) das aplicações tanto no ambiente de desenvolvimento (IDE), como acontece com aplicações desktop, quanto no navegador utilizado, como acontece na codificação JavaScript. Isso é possível por meio do seu development plugin, que se encarrega de estabelecer o vínculo entre o bytecode Java no depurador e o JavaScript do navegador. Com isso, o desenvolvedor pode visualizar de imediato se as modificações realizadas em seu código surtiram efeito, e ao mesmo tempo, inspecionar variáveis, definir pontos de interrupção (breakpoints), e utilizar todas as outras ferramentas de depuração disponíveis em Java.

Tabela 2: Exemplo de arquivo XML de configuração de um projeto GWT

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

<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN"

"http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd"> <module rename-to='nfe'> <inherits name="com.google.gwt.user.User" /> <inherits name="com.google.gwt.i18n.I18N" /> <inherits name="com.google.gwt.resources.Resources" /> <inherits name="com.google.web.bindery.requestfactory.RequestFactory" /> <inherits name="com.hivelog.gwttheme2.Gwttheme2" /> <stylesheet src="theme.css" />

<extend-property name="locale" values="pt_BR" /> <set-property-fallback name="locale" value="pt_BR" /> <set-property name="user.agent" value="safari" /> <set-property name="locale" value="pt_BR" /> <source path="client" />

<source path="shared" /> <entry-point

class="com.hivelog.nfe.gui.nfe.gwt.client.NfeEntryPoint" /> </module>

A configuração do projeto GWT é feita por meio de um arquivo XML (Figura 4), onde é possível:

 Adicionar dependências a outros projetos GWT;

 Especificar os arquivos CSS utilizados na composição de estilo da aplicação;

 Definir as linguagens em que a aplicação poderá ser executada (internacionalização);

 Modificar configurações de compilação (como definir que o projeto seja compilado para um único tipo de navegador);

 Especificar os pacotes específicos dos arquivos fonte do projeto GWT;  Definir a localização do entry point da aplicação.

Diferente das aplicações Java para desktop, uma aplicação GWT não é iniciada a partir de uma classe contendo o método main. Em lugar disso, é configurada (como visto na Tabela 2) uma classe para ser o entry point da aplicação. Essa classe deve implementar

(12)

12 uma interface GWT chamada EntryPoint, contendo um método chamado onModuleLoad. O código implementado nesse método dará início à execução da aplicação.

Tabela 3: Exemplo de implementação de um EntryPoint public class NfeEntryPoint implements EntryPoint {

NfeAppController app;

StandardDispatchAsync dispatch; @Override

public void onModuleLoad() {

dispatch = new StandardDispatchAsync();

EventBus eventBus = EventBusProvider.initialize(); NfeRequestTransportInterceptor interceptor = new NfeRequestTransportInterceptor();

NfeRequestFactory requestFactory = NfeRequestFactoryProvider .initialize(eventBus, interceptor);

NfeAppSession.initialize(eventBus);

TenantRequestFactory tenantRequestFactory =

TenantRequestFactoryProvider.initialize(eventBus, interceptor); app = new NfeAppController(requestFactory,

tenantRequestFactory, dispatch, eventBus);

dispatch.execute(new Action(), new AsyncCallback<Result>() { @Override

public void onSuccess(Result result) {

NfeAppSession.getInstance().setPrincipal( result.getPrincipal()); NfeAppSession.getInstance().setServerTimeZone( result.getGmt()); NfeAppSession.getInstance().setServerOffset( result.getOffset()); NfeAppSession.getInstance().setTenantId( result.getTenantId()); app.go(RootLayoutPanel.get()); } @Override

public void onFailure(Throwable arg0) { app.go(RootLayoutPanel.get()); } }); } }

2.2 RequestFactory

A comunicação cliente-servidor de uma aplicação GWT, assim como em qualquer aplicação web, pode ser feita por meio de servlets. No geral, nas aplicações desenvolvidas na Hive.log, só se torna necessária a implementação de um servlet específico quando a transação envolve trânsito de arquivos, como numa operação de importação ou exportação de um arquivo XML, ou numa operação de impressão, por exemplo.

Para transações com o servidor que envolvam apenas o transporte de tipos básicos Java, como em serviços orientados a dados, responsáveis pelas operações CRUD da

(13)

13 aplicação, as aplicações da empresa fazem uso de uma API própria disponibilizada pelo SDK do GWT chamada RequestFactory.

A API RequestFactory é uma alternativa para a criação de serviços orientados a dados. RequestFactory e suas interfaces relacionadas (RequestContext e EntityProxy) facilitam a construção de aplicações orientadas a dados (CRUD), tendo sido projetada para ser usada em conjunto com uma camada ORM (Object Relacional Mapping) no lado servidor, como por exemplo a JPA (Java Persistence API).

RequestFactory facilita a implementação de uma camada de acesso a dados tanto no lado cliente como no lado servidor. Ela permite que o lado servidor seja estruturado numa forma centrada nos dados, e provê um nível maior de abstração do que o GWT-RPC (uma vez que este último é orientado a serviços, e não orientado a dados). No lado cliente, RequestFactory gerencia os objetos que tenham sido modificados, enviando apenas as diferenças para o servidor, o que resulta em payloads de rede muito leves. Além disso, RequestFactory provê uma sólida fundação para batching automático e cache de solicitações.

A codificação em RequestFactory envolve a manipulação dos seguintes componentes:  Entity  Entity Proxies  Value Proxies  Interface RequestFactory  Tipos transportáveis  Implementações no servidor  Uso de Locator e ServiceLocator

2.2.1 Entity

Uma entidade é uma classe do domínio da aplicação que pode ser persistida, por exemplo, em um banco de dados relacional. Em frameworks de persistência como o JPA, entidades são anotadas com @Entity. A seguir é exibido, como exemplo, parte da definição de uma entidade que faz uso dessa e de outras anotações do JPA.

Tabela 4: Exemplo de implementação de uma classe Entity @Entity

public class Cliente { @Id

@Column(length = 36) private String id; @Version

private Integer version; @Embedded

private DadosPessoais dadosPessoais; @OneToOne(cascade = CascadeType.PERSIST) private Envolvido envolvido;

(14)

14

public Cliente() {

dadosPessoais = new DadosPessoais(); }

@PrePersist

public void generateId() {

id = UUID.randomUUID().toString(); }

public String getId() { return id;

}

public Integer getVersion() { return version;

}

public DadosPessoais getDadosPessoais() { return dadosPessoais;

}

public Envolvido getEnvolvido() { return envolvido;

} // ... }

2.2.2 Entity Proxies

Um entity proxy é uma representação do lado cliente de uma entidade, também conhecida como DTO (Data Transfer Object). Deve estender a interface EntityProxy, indicando que um objeto pode ser gerenciado por uma RequestFactory. A RequestFactory popula automaticamente as propriedades entre as entidades no lado servidor e o proxy correspondente no lado cliente, simplificando o uso do pattern DTO. Além disso, a interface EntityProxy possibilita que a RequestFactory avalie e envie apenas as mudanças (deltas) para o servidor. Abaixo, está o EntityProxy correspondente à classe de domínio Cliente que acabamos de mostrar.

Tabela 5: Exemplo de interface que estende a interface EntityProxy @ProxyFor(value = Cliente.class, locator = ClienteLocator.class)

public interface ClienteProxy extends EntityProxy { String getId();

Integer getVersion();

DadosPessoaisProxy getDadosPessoais(); EnvolvidoProxy getEnvolvido();

void setEnvolvido(EnvolvidoProxy envolvido);

void setDadosPessoais(DadosPessoaisProxy dadosPessoais); }

(15)

15 Além de estender a interface EntityProxy, é necessário também utilizar a anotação @ProxyFor para referenciar a entidade do lado servidor que está sendo representada. Não é necessário representar todas as propriedades e métodos da entidade do lado servidor no EntityProxy, apenas os getters e setters das propriedades que precisem ser acessadas no lado cliente. É possível perceber que os métodos getDadosPessoais() e getEnvolvido() retornam uma associação a uma interface proxy. As associações no código cliente também devem ser implementadas como subinterfaces de ValueProxy e EntityProxy, respectivamente. RequestFactory automaticamente converte os proxies para as entidades correspondentes no lado servidor.

2.2.3 Value Proxies

Um value proxy pode ser utilizado para representar uma classe de qualquer tipo. Diferente de um EntityProxy, um ValueProxy não precisa possuir um ID e uma versão. Um ValueProxy é comumente utilizado para representar tipos de objetos incorporados em entidades. No exemplo citado anteriormente, a entidade Cliente (Tabela 4) representa DadosPessoais como um tipo incorporado, por meio da anotação @Embedded. Da mesma forma, a classe DadosPessoais deve ser anotada com @Embeddable. Desse modo, DadosPessoais será persistido como um objeto serializado dentro da entidade Cliente.

Tabela 6: Exemplo de implementação de uma classe Embeddable @Embeddable

public class DadosPessoais {

@NotNullAttribute(attributeName = "RAZÃO SOCIAL / NOME", message = ValidationMessages.ATTRIBUTE_NOT_NULL)

@SizeAttribute(attributeName = "RAZÃO SOCIAL / NOME", maxSize = 60, message = ValidationMessages.SIZE_PATTERN, minSize = 1)

@Column(length = 60) private String nome; @Embedded

private Endereco endereco;

@SizeAttribute(attributeName = "TELEFONE", maxSize = 13, message = ValidationMessages.SIZE_PATTERN, minSize = 7, checkVazio = false)

@Column(length = 13) private String telefone; public DadosPessoais() {

endereco = new Endereco(); }

public String getNome() { return nome;

}

public Endereco getEndereco() { return endereco;

(16)

16

public String getTelefone() { return telefone;

} // ... }

No cliente, DadosPessoais é representado por meio de uma interface que estende a interface ValueProxy. Um ValueProxy pode ser usado para passar qualquer tipo de bean de e para o servidor por meio da RequestFactory.

Tabela 7: Exemplo de interface que estende a interface ValueProxy @ProxyFor(DadosPessoais.class)

public interface DadosPessoaisProxy extends ValueProxy { String getNome();

EnderecoProxy getEndereco(); String getTelefone();

void setNome(String nome);

void setEndereco(EnderecoProxy endereco); void setTelefone(String telefone);

}

2.2.4 Interface RequestFactory

Similar ao GWT-RPC, é necessário definir uma interface entre o código cliente e o código servidor. A interface RequestFactory da aplicação consiste em métodos que retornam stubs de serviços.

Tabela 8: Exemplo de interface RequestFactory public interface NfeRequestFactory extends RequestFactory {

ClienteRequest clienteRequest(); EnvolvidoRequest envolvidoRequest(); }

Tabela 9: Exemplo de um stub de serviço usando a classe Cliente @Service(value = Cliente.class, locator = ServiceLocatorImp.class) public interface ClienteRequest extends RequestContext {

Request<ClienteProxy> persistOrMerge(ClienteProxy Cliente); Request<Void> remove(ClienteProxy Cliente);

Request<Void> removeById(String id); Request<ClienteProxy> findById(String id);

(17)

17

Request<ClienteProxy> findAndEdit(String id); Request<Void> removeByIdList(List<String> ids); Request<Void> remove(Set<ClienteProxy> clientes); }

Os stubs de serviço devem estender RequestContext, e usar a anotação @Service para indicar a classe correspondente da implementação do serviço no servidor. Ao invés dos métodos do stub de serviço retornarem diretamente as entidades, eles retornam objetos que são subclasses de com.google.gwt.requestfactory.shared.Request. Esses objetos são parametrizados genericamente com o tipo de retorno do método do serviço. Este será justamente o tipo do objeto esperado como argumento pela chamada onSuccess do Receiver. Métodos que não retornam valor devem retornar Request<Void>. Requests podem ser parametrizados com os seguintes tipos:

 Tipos-Valor: BigDecimal, BigInteger, Boolean, Byte, Enum, Character, Date, Double, Float, Integer, Long, Short, String, Void

 Entidades: quaisquer subinterfaces de EntityProxy

 Coleções: List<T> ou Set<T>, onde T é um tipo-valor ou uma subinterface de EntityProxy.

Os tipos primitivos Java não são suportados, devendo-se usar os wrappers correspondentes.

Os métodos nesta interface são invocados de forma assíncrona, pela chamada Request.fire(), de forma similar à passagem dos objetos AsyncCallback nos serviços GWT-RPC.

Tabela 10: Exemplo de chamada do método Request.fire() nfeRequestFactory.clienteRequest().findById(id).fire(new

Receiver<ClienteProxy>() { @Override

public void onSuccess(ClienteProxy cliente) { ...

} });

Da mesma forma que as chamadas GWT-RPC passam um AsyncCallback que implementa os métodos onSuccess e onFailure, Request.fire() recebe um Receiver como argumento, que deve implementar o método Request.onSuccess(). Receiver é uma classe abstrata que já oferece uma implementação padrão para onFailure(), que simplesmente dispara uma RuntimeException. Para alterar a implementação padrão, pode-se estender Receiver e sobrescrever o método onFailure(). Receive possui também um método onViolation(), que retorna as violações de regras de validação (JSR 303) no servidor.

RequestFactory suporta validação com JSR 303. Isto torna possível manter as regras de validação no lado servidor e notificar o cliente quando uma entidade não puder ser persistida devido a erros de validação. Para isso, basta que uma implementação da JSR-303 esteja disponível no servidor, e que as entidades a serem validadas possuam

(18)

18 anotações de validação, como as anotações @NotNullAttribute e @SizeAttribute exibidas no exemplo da classe DadosPessoais (Tabela 6). Antes de invocar o método do serviço no servidor, RequestFactory chamará a framework de validação e enviará as ConstraintViolations do servidor para o cliente, o qual chamará o método onViolation() no objeto Receiver usado no Request.

2.2.5 Tipos transportáveis

RequestFactory restringe os tipos que podem ser usados como propriedades de proxy e parâmetros dos métodos de serviço. Coletivamente, estes tipos são referidos como tipos transportáveis. Cada tipo transportável do lado do cliente é mapeado para um tipo de domínio do lado do servidor. As regras de mapeamento são exibidas na Tabela 11.

Tabela 11: Mapeamento dos tipos transportáveis

Tipo no cliente Tipo no servidor

Tipo primitivo (p. ex. int) Tipo primitivo

Wrapper do tipo primitivo (p. ex. Integer) Wrapper do tipo primitivo Tipo valor: Enum, BigInteger, BigDecimal, Date Tipo valor

@ProxyFor(Foo.class) FooProxy extends EntityProxy Uma entidade Foo @ProxyFor(Bar.class) BarProxy extends ValueProxy Um objeto Bar Set ou List de tipos transportáveis Set ou List

Map de tipos transportáveis Map

2.2.6 Implementações no servidor

Os serviços podem ser implementados no servidor de duas maneiras: como métodos estáticos em um tipo que representa uma entidade ou como métodos de instância em uma classe de serviço acompanhada por um ServiceLocator.

Em ambos os casos, os métodos definidos em uma interface de serviço são implementados na classe chamada na anotação @Service ou @ServiceName. O serviço do lado servidor deve implementar cada método definido na respectiva interface RequestContext do lado cliente, mesmo que ele não implemente formalmente essa interface. Ao contrário do GWT-RPC, essa implementação da RequestContext não se torna necessária pelo fato dos argumentos no lado cliente retornarem tipos para os proxies das entidades, enquanto as implementações do lado servidor retornam os próprios objetos de domínio dessas entidades.

Tabela 12: Exemplo de interface de serviço no lado servidor public interface ClienteController {

Cliente persistOrMerge(Cliente cliente); void remove(Cliente cliente);

(19)

19

void removeById(String id); Cliente findById(String id); Cliente findAndEdit(String id);

void removeByIdList(List<String> ids); void remove(Set<Cliente> clientes); }

O nome do método e a lista de argumentos são os mesmos tanto no cliente quanto no servidor, segundo as seguintes regras de mapeamento:

 Métodos que no lado cliente retornam Request<T>, retornam apenas T no lado servidor. Por exemplo, se um método retorna Request<String> no cliente, a implementação do servidor retorna String.

 O lado servidor retorna as entidades de domínio enquanto no lado cliente são retornados EntityProxies. Se o lado cliente retorna Request<List<ClienteProxy>>, a implementação no lado servidor retornará List<Cliente>

 Métodos que retornam um objeto Request na interface cliente devem ser implementados como métodos estáticos na implementação no servidor como no exemplo Employee.findAllEmployees().Métodos que retornam um objeto Request na interface cliente são implementados como métodos estáticos na classe de serviço. Alternativamente, eles podem ser implementados como métodos de instância de um objeto de serviço retornado por um ServiceLocator.

2.2.7 Uso de Locator e ServiceLocator

Quando não se deseja implementar código de persistência na própria entidade, RequestFactory permite que a implementação dos métodos localizadores dessa entidade seja feita por meio de uma classe localizadora que estende a classe abstrata Locator.

Tabela 13: Exemplo de implementação de uma classe Locator public class ClienteLocator extends Locator<Cliente, String> {

private ApplicationContext context; private Dao dao;

public EmpresaLocator() { super();

HttpServletRequest request = RequestFactoryServlet .getThreadLocalRequest();

ServletContext servletContext = request.getSession() .getServletContext();

context = WebApplicationContextUtils

.getWebApplicationContext(servletContext); dao = context.getBean(Dao.class);

(20)

20

@Override

public Cliente create(Class<? extends Cliente> clazz) { return new Cliente();

}

@Override

public Cliente find(Class<? extends Cliente> clazz, String id) { return dao.findById(clazz, id);

}

@Override

public Class<Cliente> getDomainType() { return Cliente.class;

}

@Override

public String getId(Cliente cliente) { return cliente.getId();

}

@Override

public Class<String> getIdType() { return String.class;

}

@Override

public Object getVersion(Cliente cliente) { return cliente.getVersion();

}

public ApplicationContext getContext() { return context;

} }

A associação com a entidade é feita por meio da anotação @ProxyFor, como pode ser visto no início da Tabela 5.

Uma vez que muitos frameworks de persistência oferecem métodos find/get/query genéricos, também é possível criar uma classe Locator genérica e especificá-la na anotação @ProxyFor para cada tipo de entidade. Para isso, todas as entidades podem estender uma classe base que fornece getId () e getVersion (). Alternativamente, o Locator genérico pode usar reflexão para chamar getId () e getVersion () quando necessário.

Muitos frameworks de persistência também permitem a utilização de uma classe DAO (Data Access Object) genérica, onde o DAO de cada entidade estende o DAO genérico e sobrescreve os seus métodos, conforme necessário. Um dos benefícios da RequestFactory é que é possível expor classes DAO diretamente como serviços. No entanto, a herança dos métodos de serviço de uma classe base não funciona se os serviços são implementados como métodos estáticos em uma classe de entidade. Nesses casos, utiliza-se um ServiceLocator para dizer à RequestFactory como obter uma instância de um serviço. Ao usar um ServiceLocator, RequestFactory irá invocar métodos que retornam um tipo Request como métodos de instância, ao invés de métodos estáticos.

(21)

21 Para fazer uso de um ServiceLocator, basta simplesmente implementar a interface ServiceLocator.

Tabela 14: Exemplo de implementação de um ServiceLocator public class ServiceLocatorImp implements ServiceLocator {

public Object getInstance(Class<?> clazz) {

HttpServletRequest request = RequestFactoryServlet .getThreadLocalRequest();

ServletContext servletContext = request.getSession() .getServletContext();

ApplicationContext context = WebApplicationContextUtils .getWebApplicationContext(servletContext); return context.getBean(clazz);

} }

Em seguida, basta anotar a interface de serviço com o nome da classe de serviço e do ServiceLocator, como pode ser visto no início da Tabela 9. Como RequestFactory armazena em cache instâncias ServiceLocator e de serviços, é necessário se certificar de que ambos são thread-safe.

2.3 Java Persistence API (JPA)

2.3.1 Mapeamento Objeto Relacional (ORM)

Com a popularização do Java em ambientes corporativos, logo se percebeu que grande parte do tempo do desenvolvedor era gasto na codificação de queries SQL e no respectivo código JDBC responsável por trabalhar com elas.

Além de um problema de produtividade, algumas outras preocupações surgiram. A linguagem SQL, que apesar de ter um padrão ANSI, apresenta diferenças significativas dependendo do fabricante, o que traz dificuldades no momento em que se torna necessário trocar um tipo de banco de dados por outro.

Uma outra dificuldade é a mudança do paradigma. A programação orientada a objetos difere muito do esquema entidade relacional, e desse modo, é preciso encontrar uma forma de se trabalhar das duas maneiras para se fazer um único sistema. Na representação das informações num banco de dados, utilizam-se tabelas e colunas. As tabelas geralmente possuem chave primária (primary key ou PK) e podem ser relacionadas por meio da criação de chaves estrangeiras (foreign keys ou FK) em outras tabelas.

Quando se trabalha com uma aplicação Java, segue-se o paradigma orientado a objetos, onde as informações são representadas por meio de classes e atributos. Além disso, é possível fazer uso de herança, composição para relacionar atributos, polimorfismo, enumerações, entre outros. Essa lacuna entre esses dois paradigmas gera bastante trabalho: a todo momento deve-se transformar objetos em registros e registros em objetos.

(22)

22

2.3.2 Java Persistence API e Frameworks ORM

Ferramentas para auxiliar nesta tarefa tornaram-se populares entre os desenvolvedores Java e são conhecidas como ferramentas de mapeamento objeto-relacional (object relational mapping ou ORM). O Hibernate é uma ferramenta ORM open source e é a líder de mercado, sendo a inspiração para a especificação Java Persistence API (JPA). O Hibernate nasceu sem a JPA, mas, hoje em dia é comum acessar o Hibernate pela especificação JPA. Como toda especificação, ela deve possuir implementações. Entre as implementações mais comuns, podemos citar: Hibernate da JBoss, EclipseLink da Eclipse Foundation e o OpenJPA da Apache. Apesar do Hibernate ter originado a JPA, o EclipseLink é a implementação referencial.

O Hibernate abstrai o código SQL, toda a camada JDBC e o SQL será gerado em tempo de execução. Mais que isso, ele vai gerar o SQL que serve para um determinado banco de dados, já que cada banco fala um "dialeto" diferente dessa linguagem. Assim, há também a possibilidade de se trocar o tipo do banco de dados sem ter de se alterar o código Java, já que isso fica de responsabilidade da ferramenta.

Ao fazer uso da JPA, abstrai-se mais ainda, pois, pode-se desenvolver sem o conhecimento dos detalhes sobre o Hibernate, e até mesmo trocar o Hibernate por uma outra implementação como a OpenJPA.

2.3.3 JPA 2.0

No momento em que a primeira versão do JPA foi iniciada, outros modelos de persistência ORM já haviam evoluído. Mesmo assim, muitas características foram adicionadas nesta versão e outras foram deixadas para a versão seguinte.

A versão JPA 2.0 incluiu um grande número de características que não estavam na primeira versão, especialmente as mais requisitadas pelos usuários, entre elas a capacidade adicional de mapeamento, expansões para a Java Persistence Query Language (JPQL), a API Criteria para criação de consultas dinâmicas, entre outras características.

Entre as principais inclusões na JPA, destacam-se:

 POJOS Persistentes: Talvez o aspecto mais importante da JPA seja o fato de que os objetos são POJOs (Plain Old Java Object ou Velho e Simples Objeto Java), significando que os objetos possuem designs simples, que não dependem da herança de interfaces ou classes de frameworks externos. Qualquer objeto com um construtor default pode ser feito persistente sem nenhuma alteração numa linha de código. Mapeamento Objeto-Relacional com JPA é inteiramente dirigido a metadados. Isto pode ser feito através de anotações no código ou através de um XML definido externamente.  Consultas em Objetos: As consultas podem ser realizadas através da Java

Persistence Query Language (JPQL), uma linguagem de consulta que é derivada do EJB QL e transformada depois para SQL. As consultas usam um esquema abstraído que é baseado no modelo de entidade como oposto às colunas na qual a entidade é armazenada.

 Configurações simples: Existe um grande número de características de persistência que a especificação oferece. Todas são configuráveis através de anotações, XML ou uma combinação das duas. Anotações são simples

(23)

23 de usar, convenientes para escrever e fácil de ler. Além disso, JPA oferece diversos valores defaults, portanto, para já sair usando JPA é simples, bastando algumas anotações.

 Integração e Teste: Atualmente, as aplicações normalmente rodam num servidor de aplicação, sendo um padrão do mercado atual. Testes em servidores de aplicação são um grande desafio e normalmente impraticáveis. Efetuar teste de unidade e teste caixa branca em servidores de aplicação não é uma tarefa tão trivial. Porém, isto é resolvido com uma API que trabalha fora do servidor de aplicação. Isto permite que a JPA possa ser utilizada sem a existência de um servidor de aplicação. Dessa forma, testes unitários podem ser executados mais facilmente.

2.3.4 Entidades

Uma entidade é um objeto do domínio de persistência. Tipicamente, uma entidade representa uma tabela em um banco de dados relacional, e cada instância da entidade corresponde a uma linha na tabela. O artefato primário de programação de uma entidade é a classe da entidade, embora essas entidades possam usar classes auxiliares.

O estado de persistência de uma entidade é representado através de campos ou propriedades persistentes. Estes campos ou propriedades usam anotações de mapeamento objeto relacional para mapear as entidades e os seus relacionamentos aos dados relacionais na camada subjacente de armazenamento de dados.

2.3.5 Multiplicidade no Relacionamento de Entidades

Existem quatro tipos de multiplicidades: um-para-um, um-para-muitos, muitos-para-um e muitos-para-muitos.

 Um-para-um: Cada instância da entidade está relacionada a uma única instância de uma outra entidade. Por exemplo, para modelar um armazém físico no qual cada posição no depósito contém um único container, Posicao e Container teriam um relacionamento para-um. Relações um-para-um usam a anotação javax.persistence.OneToOne na propriedade ou campo persistente correspondente.

 Um-para-muitos: Uma instância de entidade pode estar relacionada a várias instâncias de outras entidades. Uma nota fiscal, por exemplo, pode ter vários produtos. Numa aplicação de emissão de notas fiscais, NotaFiscal teria um relacionamento um-para-muitos com Produto. Relações um-para-muitos usam a anotação javax.persistence.OneToMany na propriedade ou campo persistente correspondente.

 Muitos-para-um: Várias instâncias de uma entidade podem estar relacionadas a uma única instância de outra entidade. Essa multiplicidade é o oposto de um relacionamento um-para-muitos. No exemplo mencionado anteriormente, a partir da perspectiva de Produto, a relação com a NotaFiscal é muitos-para-um. Relacionamentos muitos-para-um

(24)

24 usam a anotação javax.persistence.ManyToOne na propriedade ou campo persistente correspondente.

 Muitos-para-muitos: Várias instâncias de uma entidade podem estar relacionadas a múltiplas instâncias de uma outra. Por exemplo, numa faculdade, cada disciplina tem muitos alunos, e cada aluno pode cursar várias disciplinas. Portanto, em uma aplicação de matrículas, Disciplina e Aluno teriam uma relação muitos. Relações muitos-para-muitos usam a anotação javax.persistence.ManyToMany na propriedade ou campo persistente correspondente.

2.3.6 Relacionamentos Bidirecionais

Em um relacionamento bidirecional, cada entidade tem um campo ou propriedade relacional que se refere à outra entidade. Através desse campo ou propriedade relacional, o código de uma classe de entidade pode acessar seu objeto relacionado. Se uma entidade possui um campo relacionado, então, pode-se dizer que a entidade conhece o objeto relacionado. Por exemplo, se a NotaFiscal conhece as instâncias de Produto que ela possui, e cada instância de Produto sabe a qual NotaFiscal ela pertence, então eles possuem um relacionamento bidirecional.

Relacionamentos bidirecionais devem seguir as seguintes regras:

 O lado inverso de uma relação bidirecional deve referir-se a seu lado proprietário usando o elemento mappedBy das anotações @OneToOne, @OneToMany, ou @ManyToMany. O elemento mappedBy designa a propriedade ou campo na entidade que é o proprietário do relacionamento.  O lado muitos de relacionamentos bidirecionais muitos-para-um não deve definir o elemento mappedBy. O lado muitos é sempre o lado proprietário do relacionamento.

 Para relacionamentos bidirecionais um-para-um, o lado proprietário corresponde ao lado que contém a chave estrangeira correspondente.  Para relacionamentos bidirecionais muitos-para-muitos, ambos os lados

podem ser o lado proprietário.

2.3.7 Relacionamentos Unidirecionais

Num relacionamento unidirecional, somente uma entidade tem um campo ou propriedade relacional que se refere à outra. Por exemplo, Departamento teria um campo relacional que identifica Projeto, mas, Projeto não teria um campo ou propriedade relacional para Departamento. Em outras palavras, Departamento sabe sobre o Projeto, mas Projeto não sabe qual instância de Departamento se refere a ele.

2.3.8 Consultas e Direção do Relacionamento

Consultas em Java Persistence Query Language (JPQL) muitas vezes permitem navegar através dos relacionamentos. A direção de um relacionamento determina se uma consulta pode navegar de uma entidade para outra. Por exemplo, uma consulta pode navegar de Departamento para Projeto, mas não pode navegar na direção oposta. Já entre

(25)

25 Disciplina e Aluno, uma consulta pode navegar em ambas as direções, porque essas duas entidades possuem um relacionamento bidirecional.

2.3.9 Remoção em Cascata e Relacionamentos

Entidades que utilizam relacionamentos muitas vezes têm dependências sobre a existência da outra entidade no relacionamento. Por exemplo, um Projeto é parte de um Departamento e, se o Departamento for excluído, em seguida, o Projeto também deve ser excluído. Isso é chamado de relacionamento de remoção em cascata.

Relacionamentos de remoção em cascata são determinados por meio do uso do elemento de especificação cascade=CascadeType.REMOVE em relacionamentos do tipo @OneToOne e @OneToMany.

Tabela 15: Exemplo de configuração de remoção em cascata @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "departamento") public Set<Projeto> getProjetos() {

return projetos; }

2.3.10 Gerenciando Entidades

As entidades são gerenciadas pelo gerenciador de entidade. O gerenciador de entidade é representado por instâncias de javax.persistence.EntityManager. Cada instância de EntityManager está associada a um contexto de persistência.

Um contexto de persistência é um conjunto de instâncias de entidade gerenciadas que existem em um repositório de dados particular. Esse contexto define o âmbito em que cada uma das instâncias das entidades é criada, persistida, e removida.

A interface EntityManager define os métodos que são usados para interagir com o contexto de persistência. Essa API cria e remove instâncias de entidades persistentes, encontra entidades por meio de suas chaves primárias, e permite que consultas sejam executadas nas entidades.

Com um gerenciador de entidade controlado por contêiner, o contexto de persistência de uma instância de EntityManager é propagado automaticamente pelo contêiner para todos os componentes de aplicativos que usam a instância EntityManager dentro de uma única transação Java Transaction Architecture (JTA).

Transações JTA geralmente envolvem chamadas entre componentes da aplicação. Para completar uma transação JTA, esses componentes geralmente precisam de acesso a um único contexto de persistência. Isso ocorre quando um EntityManager é injetado nos componentes da aplicação por meio da anotação javax.persistence.PersistenceContext. O contexto de persistência é propagado automaticamente com a atual transação JTA, e as referências de EntityManager que são mapeadas para a mesma unidade de persistência fornecem acesso ao contexto de persistência dentro dessa transação. Ao propagar automaticamente o contexto de persistência, os componentes da aplicação não precisam passar uns para os outros as referências às instâncias de EntityManager, a fim de fazer alterações em uma única transação. O contêiner Java EE gerencia o ciclo de vida dos gerenciadores de entidades controlados por contêiner.

(26)

26 Para se obter uma instância de EntityManager, deve-se injetar o gerenciador de entidades no componente da aplicação:

Tabela 16: Trecho da implementação de um DAO usando JPA EntityManager

public class JpaDaoImp implements Dao, HibernateDao { @PersistenceContext

private EntityManager em; @Override

public <T> T persist(T obj) { em.persist(obj);

em.flush(); return obj; }

@Override

public <T> T merge(T obj) { em.merge(obj);

em.flush(); return obj; }

@Override

public void remove(Object obj) { em.remove(em.merge(obj)); em.flush();

}

@Override

public <T> T findById(Class<T> clazz, Object id) { return em.find(clazz, id);

}

@Override

public <T, G extends QueryReturn<T>> G find(Class<T> clazz, Query query, G queryReturn) {

TypedQuery<T> typedQuery = em.createQuery(query.getSelectquery(), clazz);

for (Entry<String, Object> param : query.getMap().entrySet()) { typedQuery.setParameter(param.getKey(), param.getValue()); } if (query.getFirstResult() != 0) { typedQuery.setFirstResult(query.getFirstResult()); } if (query.getMaxResults() != 0) { typedQuery.setMaxResults(query.getMaxResults()); } queryReturn.setFindReturn(typedQuery.getResultList()); return queryReturn; } // ... }

(27)

27

2.3.11 Unidades de Persistência

Uma unidade de persistência define um conjunto de todas as classes de entidades que são gerenciadas por instâncias de EntityManager em uma aplicação. Este conjunto de classes de entidades representa os dados contidos dentro de um único repositório de dados.

Unidades de persistência são definidas pelo arquivo de configuração persistence.xml. O arquivo JAR ou diretório cujo META-INF contém persistence.xml é chamado de raiz da unidade de persistência. Essa raiz determina o escopo dessa unidade. Cada unidade de persistência deve ser identificada com um nome que é exclusivo para o seu escopo.

Unidades de persistência podem ser encapsuladas como parte de um arquivo WAR ou EJB JAR, ou pode ser encapsulada como um arquivo JAR que pode ser incluído em um arquivo WAR ou EAR.

Tabela 17: Exemplo de arquivo persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">

<persistence-unit name="nfe" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>com.hivelog.nfe.domain.Empresa</class>

<class>com.hivelog.nfe.domain.Envolvido</class> <class>com.hivelog.nfe.domain.NfeTransaction</class> <class>com.hivelog.nfe.domain.NfeFile</class>

<class>com.hivelog.nfe.domain.Nfe</class>

<class>com.hivelog.nfe.domain.NfeAttributes</class> <class>com.hivelog.nfe.domain.NfeAppProperties</class> <class>com.hivelog.nfe.domain.AutorizacaoXml</class> <class>com.hivelog.nfe.domain.NfeAppUserProperty</class> <exclude-unlisted-classes /> <properties> <property name="hibernate.dialect" value="com.hivelog.utils.hibernate.HiveMySQL5InnoDbDialect" /> <property name="hibernate.connection.provider_class" value="com.hivelog.tenant.persistence.hibernate4.MultitenantConnectionProvi der" /> <property name="hibernate.tenant_identifier_resolver" value="com.hivelog.infra.persistence.hibernate.ThreadLocalCurrentTenantIden tifierResolver" />

<property name="hibernate.show_sql" value="false" /> </properties>

</persistence-unit> </persistence>

2.4 Spring Framework

O Spring é um framework open source, desenvolvido para a linguagem de programação Java, criado por Rod Johnson e descrito em seu livro "Expert One-on-One: JEE Design and Development". Trata-se de um framework não intrusivo, baseado nos padrões de projeto inversão de controle (IoC) e injeção de dependência.

(28)

28 No Spring, o container se encarrega de instanciar classes de uma aplicação Java e definir as dependências entre elas, o que pode ser feito por meio de um arquivo de configuração em formato XML, através de inferências do framework, o que é chamado de auto-wiring, ou ainda pelo uso de anotações nas classes, métodos e propriedades. Dessa forma, o Spring permite o baixo acoplamento entre classes de uma aplicação orientada a objetos.

Tabela 18: Exemplo de arquivo applicationContext.xml do Spring

<?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:aop="http://www.springframework.org/schema/aop" xmlns:ws="http://jax-ws.dev.java.net/spring/core" xmlns:wss="http://jax-ws.dev.java.net/spring/servlet" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://jax-ws.dev.java.net/spring/core http://jax-ws.java.net/spring/core.xsd http://jax-ws.dev.java.net/spring/servlet http://jax-ws.java.net/spring/servlet.xsd">

<!-- Ativar anotações nos beans registrados em applicationContext -->

<context:annotation-config />

<!-- Ativar suporte às anotações @AspectJ -->

<aop:aspectj-autoproxy />

<bean class="com.hivelog.infra2.controller.ExceptionHandlerAspect" />

<!-- Configuração do EntityManagerFactory -->

<bean id="nfe.entityManagerFactory"

class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="nfe" />

</bean>

<!-- Configuração do JpaTransactionManager -->

<bean id="nfe.transactionManager"

class="org.springframework.orm.jpa.JpaTransactionManager">

<property name="entityManagerFactory" ref="nfe.entityManagerFactory"

/> </bean>

<!-- Criar transações usando anotações do Spring para Hibernate -->

<tx:annotation-driven transaction-manager="nfe.transactionManager" />

<!-- Configura o container Spring para agir como um container JPA e injetar um EntityManager da EntityManagerFactory --> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBean PostProcessor" /> <!-- Configuração do JpaDaoImp --> <bean id="nfe.dao" class="com.hivelog.infra2.persistence.jpa.JpaDaoImp" /> </beans>

(29)

29 O Spring possui uma arquitetura baseada em interfaces e POJOs (Plain Old Java Objects), oferecendo aos POJOs características como mecanismos de segurança e controle de transações. Também facilita a realização de testes unitários e surge como uma alternativa à complexidade existente no uso de EJBs. Com Spring, pode-se ter um alto desempenho da aplicação.

Tabela 19: Exemplo do uso das anotações do Spring na confecção de uma classe de testes unitários

@RunWith(SpringJUnit4ClassRunner.class) @TransactionConfiguration(transactionManager = "nfe.transactionManager", defaultRollback = true) @ContextConfiguration(locations = { "classpath*:**/applicationContext-nfe*.xml" }) @Transactional

public class EmitenteTest {

private static final String TENANT_ID = "ca7dde21-e791-44f9-ad3e-50f04b339a4f";

private static final String EMITENTE_ID = "c60b59d3-e93d-42fd-b948-e3cf4b27a8a7";

@Autowired

private ApplicationContext applicationContext; @Resource(name = "nfe.dao")

private Dao dao; @BeforeClass

public static void setUpClass() throws Exception { DependencyList dependency = DBMappingUtils .getDependency(DBNfeMapping.DP_EMITENTE);

DBUnitUtils.deleteInsert(MultitenancyUtils.getDefaultDataSource(), dependency);

} @Before

public void setUp() throws Exception {

TenantSessionContext.instance.registerSession(new MapSessionWrapper());

TenantSessionContext.instance.registerContext(new MapSessionWrapper());

MultitenancyUtils.configMultitenancy(TENANT_ID, "0"); ApplicationContextRegistry.setContext(applicationContext); }

@Test

public void testUpdate() {

Emitente emitente = dao.findById(Emitente.class, EMITENTE_ID); emitente.getDadosPessoais().getEndereco().setBairro("Dois Unidos"); dao.persistOrMerge(emitente);

emitente = dao.findById(Emitente.class, EMITENTE_ID);

assertEquals(bairro, emitente.getDadosPessoais().getEndereco()

.getBairro()); }

(30)

30 Esse framework oferece diversos módulos que podem ser utilizados de acordo com as necessidades do projeto, como módulos voltados para desenvolvimento Web, persistência, acesso remoto e programação orientada a aspectos.

Nas aplicações da Hive.log em que se faz uso do framework, ele é utilizado com a finalidade de:

 Oferecer controle de acesso e de segurança à base de dados por meio da definição de papéis (roles), configuráveis tanto para ambiente de desenvolvimento quanto para ambiente de produção.

 Controlar as transações realizadas entre os controladores e as entidades do banco de dados, livrando o desenvolvedor da preocupação de gerenciar conexões ao banco e de definir operações de rollback.

 Definir o tipo de framework ORM e o tipo de banco de dados a ser utilizado na aplicação. Em nossas aplicações, utilizam-se o Hibernate e o MySQL, respectivamente. A integração com o framework ORM e a subsequente conexão com a base de dados é realizada por meio da API JPA, citada anteriormente.

 Instanciar, usando o padrão singleton, as classes que controlam todos os tipos de transações da aplicação, evitando, dessa forma, o uso desnecessário de recursos do sistema.

 Configurar, de maneira simplificada, as classes de testes unitários.

2.5 Apache Maven

Apache Maven, ou simplesmente Maven, é uma ferramenta de automação de compilação utilizada primariamente em projetos Java. O projeto Maven é hospedado pela Apache Software Foundation.

O Maven utiliza um arquivo XML (POM ou Project Object Model) para descrever o projeto de software a ser construído, suas dependências sobre módulos e componentes externos, a ordem de compilação, diretórios e plug-ins necessários. Ele vem com objetivos pré-definidos para realizar certas tarefas bem definidas, como compilação de código e seu empacotamento.

O Maven descarrega bibliotecas Java e seus plugins dinamicamente de um ou mais repositórios, como o Maven 2 Central Repository, e armazena-os em uma área de cache local. Este cache local de artefatos descarregados pode também ser atualizado com artefatos criados por projetos locais. Repositórios públicos podem também ser atualizados.

O Maven é construído utilizando uma arquitetura baseada em plugin, que permite que ele faça uso de qualquer aplicação controlável através da entrada padrão. Teoricamente, isto permitiria qualquer um escrever plugins para fazer interface com ferramentas de construção (compiladores, ferramentas de teste de unidade, etc.) para qualquer outra linguagem.

(31)

31 A estrutura de diretórios de um projeto Maven padrão possui as seguintes entradas de diretório:

Tabela 20: Estrutura padrão de diretórios de um projeto Maven

Nome do diretório Propósito

home Contém o pom.xml e todos os subdiretórios.

src/main/java Contém o código-fonte Java entregável para o projeto. src/main/resources Contém os recursos entregáveis para o projeto, tais

como arquivos de propriedades.

src/test/java Contém as classes de teste (casos de teste JUnit ou TestNG, por exemplo) para o projeto.

src/test/resources Contém os recursos necessários para teste.

Com a utilização do Maven, o usuário fornece apenas a configuração para o projeto, enquanto os plugins configuráveis fazem o trabalho real de compilação do projeto, limpando diretórios de destino, executando testes de unidade, gerando documentação de API e etc.

Tabela 21: Exemplo mínimo de um arquivo de configuração 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>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <version>0.0.1-SNAPSHOT</version> <properties>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>

<dependencies> <dependency>

<groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.14</version> </dependency> </dependencies> <build> <plugins> <plugin>

<groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project>

(32)

32

3 CENÁRIOS DE USO DA APLICAÇÃO

3.1 Cadastro e Seleção de Ambiente

No momento em que o usuário efetua o login na aplicação, ele precisa selecionar o ambiente em que a aplicação será executada. A Sefaz determina que seus documentos fiscais eletrônicos podem ser emitidos em dois tipos de ambiente:

 Ambiente de Produção: os documentos fiscais emitidos nesse tipo de ambiente possuem validade fiscal, sendo portanto, documentos oficialmente aceitos em operações comerciais.

 Ambiente de Homologação: esse tipo de ambiente é basicamente um ambiente de teste, onde os documentos fiscais emitidos não possuem validade fiscal. Esse é o tipo de ambiente utilizado no processo de desenvolvimento de aplicações de emissão de documentos fiscais eletrônicos.

Ao se cadastrar pela primeira vez na aplicação, o usuário precisa inserir os dados da empresa emitente, para que sejam criados os dois tipos de ambiente para esse emissor.

(33)

33 Para dar prosseguimento à criação dos ambientes o usuário deve então clicar no botão Criar Ambiente.

Figura 4: Tela de Boas-Vindas

Na tela de boas-vindas, o usuário, então, seleciona o botão Avançar.

(34)

34 Na tela Dados do Emitente, o usuário deve inserir os dados da pessoa jurídica que será o emissor das NF-es, identificando o Código de Regime Tributário (CRT) do qual ela faz parte. Após a inserção desses valores, o usuário deve, então, clicar em Concluir.

O sistema fará uma validação dos valores inseridos. Caso haja algum valor inválido, será exibida uma mensagem de alerta, e o usuário permanece na tela Dados do Emitente para efetuar as devidas correções.

Estando todos os valores válidos, os ambientes serão criados, o usuário retorna para a tela de Seleção de Ambiente, onde estarão presentes na lista um ambiente de Produção e outro de Homologação.

Figura 6: Tela de Seleção de Ambiente com os dois tipos de ambiente

O usuário seleciona o ambiente desejado, sendo direcionado para a Tela Principal da aplicação.

(35)

35

Figura 7: Tela Principal sem Certificado Digital configurado

3.2 Configuração do Certificado Digital

Todos os documentos fiscais eletrônicos aceitos pela Sefaz precisam ser assinados digitalmente como garantia de integridade das informações contidas no arquivo XML. Desse modo, para que uma empresa possa emitir NF-es, ela precisa possuir um certificado digital habilitado para esse tipo de emissão.

Nossos sistemas dão suporte a três tipos de configuração de Certificado Digital:  Certificado A1: consiste de um arquivo protegido por senha, com

validade anual, e de custo mais acessível. O usuário deverá informar a senha do certificado e realizar o seu upload para a aplicação para que ele possa emitir as NF-es.

 Certificado A3: é um certificado de tipo físico, que pode ser lido na máquina do emitente por meio de um leitor de cartões ou de um dispositivo USB. Possui validade de três anos e possui um custo de maior valor.  Certificado CS: como muitos de nossos clientes emitem mais de um tipo

de documento, em mais de um tipo de produto, nós oferecemos o

Certification Service, onde um certificado previamente configurado em

uma das nossas aplicações, pode ser compartilhado com outra de nossas aplicações por meio de um token alfanumérico.

Por questões de viabilidade, será exibido abaixo apenas o processo de configuração desse último tipo.

Na Tela Principal (Figura 7), o usuário dá início ao processo de configuração clicando no botão Configurar Certificado, inserido no painel Dados Certificado. É

Referências

Documentos relacionados

Embora Para futuros devem analisar uma amostra maior, bem como cada variável do estresse pode afetar o estresse geral e assim ter uma escala maior para

1. As candidaturas são analisadas pela Comissão Permanente do Conselho Geral ou por uma comissão especialmente designada para o efeito por aquele órgão sendo qualquer uma destas

del estado de conciencia se distingue de otro; que tiene su propia cualidad positiva que no consiste en ninguna otra cosa, y que es por sí mismo todo lo

- Se o estagiário, ou alguém com contacto direto, tiver sintomas sugestivos de infeção respiratória (febre, tosse, expetoração e/ou falta de ar) NÃO DEVE frequentar

Uma segunda característica reside no facto de mais de 1/3 dos seus docentes leccionar em duas ou mais instituições de ensino superior, por exemplo para colmatar carências existentes

The convex sets separation is very important in convex programming, a very powerful mathematical tool for, see [ ], operations research, management

Podemos realçar algumas justificativas para a aplicabilidade do empreendedorismo à gestão escolar, tais como: as exigências das esferas públicas, bem como de toda a

INCLUSÃO SOCIAL E DESEMPENHO DOS ALUNOS COTISTAS NO ENSINO SUPERIOR NA UNIVERSIDADE FEDERAL DE VIÇOSA.. Belo