D
ra
ft
Introdução à JEE - Java Enterprise Edition – SI – Univás
Introdução à JEE - Java Enterprise Edition
Roberto Ribeiro Rocha
1
Objetivos
• Apresentar as características da arquitetura JEE;
• Criar uma aplicação mínima utilizando o Eclipse e JBoss.
2
Motivação
Entender alguns componentes básicos e recursos disponíveis no JEE.
3
Introdução
Muitas aplicações standalone / PC based foram criadas para revolver os mais variados
tipos de problemas. Esses programas ainda possuem certas características:
• uma conexão com banco;
• uma ou poucasthreads;
• execução e interfaces locais;
• outras . . . , sugestões???
Porém não havia (ou há?) a preocupação com desempenho, uso de memória e recursos, como uso em disco, volume trafegado em rede, bem como tempo de resposta ao usuário, etc . . . . Basicamente as aplicações possuem uma arquitetura externa do tipo:
Application⇔ Database
Depois surgiu a arquitetura Cliente/Servidor:
req/resp
Client ⇔ Server
Porém o ambienteclient/server requer algumas responsabilidades extras do desenvolvedor em relação a um ambientestandalone:
1. implementar a comunicação pela rede entre o cliente e servidor;
2. implementar o código de segurança para assegurar a confidencialidade dos dados;
4. implementar a capacidade depolling;
5. outros . . .
6. Implementar a lógica de negócio que o cliente pediu.
Os itens de 1 a 5 são requisitos necessários a todas as aplicaçõesclient/server.
4
A Especificação JEE
Em 1999 a Sun identificou esses requisitos em comum, e lançou uma especificação JSR (Java Specification Requests) para desenvolvimento de servidores JEE.
A ideia é escrever somente o código com as regras de negócio, utilizando os serviços de infraestrutura que já estão prontos. Além disso, o mesmo código pode ser executado em diferentes servidores JEE, sem a necessidade de alterações.
Os principais serviços disponíveis em um servidor JEE são:
• JNDI:Java Naming and Directory Interface;
• EJB:Enterprise Java Beans;
• Servlets, JSP e JSF;
• JMS:Java Message Service;
• JTA:Java Transaction API;
• JAX-WS:Java API for XML Web Services;
• JMX:Java Management Extensions;
• etc. . .
Para executar uma aplicação JEE é necessário utilizar um servidor de aplicação que implemente a especificação JEE. Alguns fornecedores que implementaram a especificação são:
• SUN (GlassFish);
• BEA Systems (Web Logic);
• IBM (WebSphere);
• Apache (Tomcat) * (somente JSP e Servlets);
• JBoss (Jboss);
• e outros. . .
5
Component
×
Container
Component é uma peça pequena de software que implementa uma lógica de negócio ou
Introdução à JEE - Java Enterprise Edition – SI – Univás
• independência entre os componentes;
• maior disponibilidade do componente;
• maior escalabilidade;
• maior sustentabilidade;
• facilitade de manutenção, etc. . . .
Exemplo: ao invés de ter somente 1 dinossauro grande e forte, utiliza-se muitas formigui-nhas para fazer o trabalho... :)
Container é um software que provê a facilidade de se plugar components, fornecendo
vários serviços para os componentes utilizarem, como:
• acesso à rede;
• escalabilidade (cluster);
• alta disponibilidade;
• alta performance;
• pooling (objetos, connection, etc);
• eficientemultithreading;
• security;
• etc.
Na especificação Java, existem quatro tipos decontainers:
• Applet Container: executa osapplets (pouco utilizado atualmente);
• Servlet Container ou Web Container: Servlets, JSP, JSF;
• Application Container: Servlets, EJB, JNDI, etc.;
• Client Container: possui alguns recursos para comunicar com oapplication container.
Exemplo de container: fish and aquarium.
OApplication Container usa e disponibiliza uma grande variedade de “Design Patterns”.
6
Arquitetura MVC
×
aplicação JEE
Uma aplicação JEE pode se encaixar na arquitetura MVC conforme a Figura 1.
7
Aplicações JEE
• são escritos em Java;
Figura 1: Arquitetura de uma aplicação JEE
• podem ser implantados em qualquer servidor que implementa JEE, chamados deAplication Server’s;
• utilizam um serviço de localização de objetos: JNDI:Java Naming Directory Interface:
– é uma API que provê serviço de localização de objetos, serviços, recursos, etc, através
de um nome que os identifiquem;
– é independente de qualquer implementação de serviço de diretório, suportando: DNS, WINS, Active Directory, LDAP, RMI, etc;
– o JNDI possui uma forma robusta de associar um nome a um objeto;
– ele é um serviço disponível dentro do Application Server.
A publicação e localização de um objeto é ilustrada na Figura 2.
Figura 2: Publicação e localização de objetos.
8
EJB:
Enterprise Java Bean
• são objetos (componentes) distribuídos;
• oferecem serviços de negócios distribuídos e implementáveis;
• são reutilizáveis em diferentesApplication Servers;
• podem utilizar todos os serviços providos peloApplication Server;
Introdução à JEE - Java Enterprise Edition – SI – Univás
– EJB Session Bean: objetos de acesso a um serviço.
∗ Stateless: não armazenam informações (estado) entre as chamadas.
∗ Stateful: mantém as informações (estado) entre as chamadas.
– EJB Entity Bean: objetos de acesso à dados (JPA);
– MDB (Message Driven Bean): objetos de mensageiria.
• podem ser acessado de 2 formas:
– localmente: pode somente ser acessado na mesma JVM. É definido através da ano-tação @Local;
– remotamente: pode ser acessado de outra JVM. É definido através da anotação @Remote.
Iteração básica entre os componentes estudados até aqui:
cliente (browser) −→ servlet −→ EJB Session −→ EJB Entity −→ Banco de dados
Uma característica importante é que os EJB’s podem ser objetos distribuídos em vários servidores JEE, permitindo assim: Clustering,Load Balance,Failover, etc.
9
Estrutura de uma
Enterprise Application
Uma aplicação corporativa é composta por vários módulos. Cada módulo é responsável por uma parte da aplicação, e corresponde a um projeto no eclipse. Os tipos de projetos mais comuns são:
• projeto EJB: contém as classes de EJB, contendo lógica de negócio, de acesso a dados e classes utilitárias;
• projeto WEB: contém todos os elementos web necessários;
• projeto EAR (Enterprise Archive): contém todos os módulos necessários para uma apli-cação, podendo ser arquivosjar’s ewar’s. Ele pode conter vários “projetos” WEB e EJB;
• projeto App Client: além de suas classes específicas (Console, Swing, etc), contém classes clientes para acesso aos EJB’s dentro do container.
As anotações mais utilizadas são:
• @Local
• @Remore
• @LocalBinding
• @RemoteBinding
• @EJB
• @Stateful
• @LocalBinding(jndiBinding=“NomeDoBean”)
Exemplo 1 – Chamando um EJB Session Stateful utilizando JNDI.
Observação: para esta atividade, é necessário instalar opluginJBoss Tools no Eclipse (ver
link: http://tools.jboss.org/downloads/jbosstools/luna/4.2.0.Final.html#zips).
Para demonstrar o uso dos EJB’s Session Stateful, será desenvolvido uma pequena
apli-cação de calculadora. As funções disponíveis são: contabilizar o valor e obter o total da soma. Para isto, será seguido os seguintes passos:
1. Configurar o servidor JBoss dentro do Eclipse;
2. Criar os projetos:
• CalculadoraEJB (EJB Project)
• CalculadoraEAR (Enterprise Application Project). Ao criar este projeto, adicione o projeto CalculadoraEJB como módulo.
Os itens de 3 a 6 devem ser feitos dentro do projeto CalculadoraEJB;
3. Definir a interface EJB de sessão com seus respectivos os métodos:
package br.edu.univas.si6.lb6.calculadora.interfaces;
public interface CalculadoraInterface {
public void contabilizar(int valor);
public int getTotal(); }
4. Implementar a classe de sessão com os métodos definidos anteriormente:
package br.edu.univas.si6.lb6.calculadora;
import javax.ejb.Remote;
import javax.ejb.Stateful;
import br.edu.univas.si6.lb6.calculadora.interfaces.CalculadoraInterface;
@Stateful
@Remote(CalculadoraInterface.class)
public class CalculadoraBean implements CalculadoraInterface {
private int total;
@Override
public void contabilizar(int valor) { total += valor;
}
@Override
public int getTotal() {
return total; }
ás 7
5. Criar uma classeCalculadoraExceptionque estende deRunTimeExceptionpara ser uti-lizada no próximo passo. Gerar os construtores da super classe;
6. Criar o código para localização do objeto que implementa o serviço de calculadora, utili-zando JNDI:
package br.edu.univas.si6.lb6.calculadora;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import br.edu.univas.si6.lb6.calculadora.interfaces.CalculadoraInterface;
public class CalculadoraServiceLocator {
private static final String appName = "CalculadoraEAR";
private static final String moduleName = "CalculadoraEJB";
private static final String distinctName = "";
private static final String beanName = CalculadoraBean.class.getSimpleName();
private static final String viewClassName = CalculadoraInterface.class.getName();
/** Busca o EJB Session de Calculadora atraves de seu nome. */ public static CalculadoraInterface getCalculadoraBean()
throws CalculadoraException {
try {
String jndiName = "ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName + "?stateful";
System.out.println("Looking for EJB via JNDI with name: " + jndiName); InitialContext context = new InitialContext();
return (CalculadoraInterface) context.lookup(jndiName); } catch (NamingException e) {
// TODO: nao eh para acontecer
e.printStackTrace();
throw new CalculadoraException(e); }
} }
7. Criar o projetoCalculadoraClient (Application Client Project).
8. Configurar oJava Build Pathdo projetoCalculadoraClient para referenciar o projeto CalculadoraEJB, utilizando a opção: Properties -> Java Build Path -> Projects e adicionar o projetoCalculadoraEJB;
9. Criar a classeCalculadoraClientMain:
package br.edu.univas.lab6.calc.client;
import br.edu.univas.si6.lb6.calculadora.CalculadoraServiceLocator;
import br.edu.univas.si6.lb6.calculadora.interfaces.CalculadoraInterface;
public class CalculadoraClientMain {
// codigo cliente que acessa o session bean para contabilizar e buscar o resultado. public static void main(String[] args) {
CalculadoraInterface calc = CalculadoraServiceLocator.getCalculadoraBean();
if (calc != null) { calc.contabilizar(4); calc.contabilizar(7); calc.contabilizar(5);
int resultado = calc.getTotal();
} else {
System.out.println("Erro obtendo EJB."); } }
}
10. Incluir o jarJBOSS_HOME/bin/client/jboss-client.jar noclasspathdo projetoCalculadoraClient.
11. Entrar na pastaJBOSS_HOME/bin/ e executar oscriptadd-user.bat(Windows) ouadd-user.sh (Linux) no prompt, para criar um usuário aluno(usado pelo cliente do EJB), como mos-trado no seguinte trecho:
roberto@rocha:/opt/jboss-as-7.1/bin$ ./add-user.sh
What type of user do you wish to add?
a) Management User (mgmt-users.properties)
b) Application User (application-users.properties) (a): b
Enter the details of the new user to add.
Realm (ApplicationRealm) :
Username : aluno Password : aluno123
Re-enter Password : aluno123
What roles do you want this user to belong to?
(Please enter a comma separated list, or leave blank for none) : alunorole About to add user 'aluno' for realm 'ApplicationRealm'
Is this correct yes/no? yes Added user 'aluno' to file
'/opt/jboss-as-7.1/standalone/configuration/application-users.properties'
Added user 'aluno' to file '/opt/jboss-as-7.1/domain/configuration/application-users.properties'
Added user 'aluno' with roles alunorole to file
'/opt/jboss-as-7.1/standalone/configuration/application-roles.properties'
Added user 'aluno' with roles alunorole to file
'/opt/jboss-as-7.1/domain/configuration/application-roles.properties'
12. No projeto CalcClient, para a aplicação cliente acessar o EJB, deve existir o arquivo jndi.properties na pastaappClientModule com o seguinte conteúdo:
java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory java.naming.factory.url.pkgs=org.jboss.ejb.client.naming
java.naming.provider.url=remote://localhost:4447
java.naming.security.principal=aluno java.naming.security.credentials=aluno123 jboss.naming.client.ejb.context=true
13. Ainda no projeto CalcClient, para a aplicação cliente acessar o EJB, também deve exis-tir o arquivo jboss-ejb-client.propertiesna pasta appClientModulecom o seguinte conteúdo:
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost remote.connection.default.port=4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=aluno remote.connection.default.password=aluno123
14. Criar um servidor JBoss, publicar o projeto CalculadoraEARe iniciar o JBoss;
Introdução à JEE - Java Enterprise Edition – SI – Univás
Exemplo 2 – Acessando o banco de dados com um EJB Entity Bean
Este exemplo demonstra a facilidade de acesso ao banco de dados utilizando um Entity Bean, que utiliza a especificação JPA. A partir do exemplo anterior, criar um novo EJBSession Bean Statelessseguindo os passos para extender a funcionalidade de calculadora para salvar os
valores no banco e recuperar o total. Neste exemplo será criado um novosession bean stateless:
1. Executar oscript abaixo no banco de dados
CREATE TABLEoperando( idinteger NOT NULL, valorinteger NOT NULL,
CONSTRAINToperando_pkPRIMARY KEY(id) );
CREATESEQUENCE seq_operando START1;
2. Criar a classe Entity Bean que fará o mapeamento ao banco (utilizando anotações da
especificação JPA):
package br.edu.univas.si6.lb6.calculadora.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Operando {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="operando_gen")
@SequenceGenerator(name="operando_gen", sequenceName="seq_operando", allocationSize=1)
private Long id;
private Integer valor;
//implementar os sets e gets
}
3. Configurar o arquivoCalculadoraEJB/META-INF/persistence.xml, utilizado pelo JPA:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="persistence_context_calculadora"
transaction-type="JTA">
<jta-data-source>java:jboss/datasources/CalculadoraDS</jta-data-source> <properties>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> </properties>
</persistence-unit> </persistence>
4. Criar o arquivo CalculadoraEAR/Univas_calculadora-ds.xml e configurar as proprie-dades de datasource (conexão com o banco de dados), com o seguinte conteúdo:
<datasources>
<datasource jndi-name="java:jboss/datasources/CalculadoraDS"
pool-name="CalculadoraDS" enabled="true" use-java-context="true" jta="true"> <connection-url>jdbc:postgresql://localhost:5432/aluno
<driver-class>org.postgresql.Driver</driver-class> <driver>postgresql-9.3-1100.jdbc4.jar</driver> <security>
<user-name>aluno</user-name> <password>aluno</password> </security>
</datasource> </datasources>
5. Corrigir a URL, usuário e senha para conexão com o banco.
6. Copiar o arquivoCalculadoraEAR/Univas_calculadora-ds.xml para o diretório $JBOSS/standalone/deployments
7. Criar um novoSession Bean Stateless para fazer o acesso ao banco de dados utilizando a Entity Bean criada no passo 1. Não esqueça de organizar osimports:
package br.edu.univas.si6.lb6.calculadora.bean;
@Stateless
@Remote(CalculadoraInterface.class)
public class CalculadoraPersistenteBean implements CalculadoraInterface {
@PersistenceContext(unitName = "persistence_context_calculadora") EntityManager em;
@Override
public void contabilizar(int valor) { Operando op = new Operando(); op.setValor(valor);
em.persist(op); //a transacao eh gerenciada pelo container
}
@Override
public int getTotal() {
Query q = em.createQuery("select sum(o.valor) from Operando o");
return ((Number)q.getSingleResult()).intValue(); }
}
8. Na classe CalculadoraServiceLocator, criar o seguinte método, que retorna uma refe-rência para o session criado:
private static final String beanPersistenteName = CalculadoraPersistenteBean.class. getSimpleName();
public static CalculadoraInterface getCalculadoraPersistenteBean() throws
CalculadoraException {
try {
String jndiName = "ejb:" + appName + "/" + moduleName + "/" + beanPersistenteName +
"!" + viewClassName;
System.out.println("Looking for EJB via JNDI with name: " + jndiName); InitialContext context = new InitialContext();
return (CalculadoraInterface) context.lookup(jndiName); } catch (NamingException e) {
// TODO: nao eh para acontecer
e.printStackTrace();
throw new CalculadoraException(e); }
publicás 11
9. No projetoCalculadoraClient, criar a classeCalculadoraClientPersistenteMainpara fazer a chamada ao EJB criado no passo 7, com o seguinte código dentro do main:
// código cliente que acessa o session bean stateless para contabilizar e buscar o resultado.
public static void main(String[] args) {
CalculadoraInterface calc = CalculadoraServiceLocator.getCalculadoraPersistenteBean();
if (calc != null) { calc.contabilizar(4); calc.contabilizar(7); calc.contabilizar(5);
int resultado = calc.getTotal();
System.out.println("Resultado: " + resultado); } else {
System.out.println("Erro obtendo EJB."); }
}
10. Copiar o jar do PostgreSQL para o diretório$JBOSS/standalone/deployments.
11. Iniciar o JBoss;
12. Executar omainda classeCalculadoraClientPersistenteMainvárias vezes, e para cada uma, fazer consultas na tabela operandoapós cada execução e verificar os resultados.
Exercício 1 – Estender o Exemplo 2 para conter as seguintes funcionalidades:
1. Criar um método na interfaceCalculadoraInterfacepara zerar o valor da contabilização dos valores, com a seguinte assinatura:
public void inicializar()
Este método na classeCalculadoraBancoBeandeve remover os registros da tabelaOperador.
2. Fazer os ajustes necessários nas classesCalculadoraBean,CalculadoraBancoBeaneCalculadoraDelegate
3. Fazer a classeCalculadoraClientBancoMain chamar o método que zera o valor da con-tabilização.
4. Fazer consultas na tabela após cada execução e verificar os resultados;
Exercício 2 – Integrando o EJB com uma página JSF.
Os EJB’s criados até aqui também podem ser utilizados por servlets, ou qualquer outro
recurso Java Web.
Criar um projeto CalculadoraWEB, duas páginas JSF, uma para inserir o valor a ser contabilizado e outra para mostrar o resultado. OManaged Bean(que encapsula oservlet) deve
ser ocontroller que gerencia a navegação e faz as respectivas chamadas ao EJB, através da classe CalculadoraDelegate, vista a seguir.
import br.edu.univas.si6.lb6.calculadora.CalculadoraServiceLocator;
import br.edu.univas.si6.lb6.calculadora.interfaces.CalculadoraInterface;
public class CalculadoraDelegate implements CalculadoraInterface {
CalculadoraInterface bean = CalculadoraServiceLocator.getCalculadoraBean();
@Override
public void inicializarCalculo() { bean.inicializarCalculo(); }
@Override
public void contabilizar(int valor) { bean.contabilizar(valor);
}
@Override
public int getTotal() {
return bean.getTotal(); }
}
Por último implementar uma opção de escolha na tela do usuário, para ele escolher o fazer a chamada no session bean stateless ou no stateful. Para isso é necessário alterar as telas, o servlet e criar um novo delegate, chamado CalculadoraPersistenteDelegate.
10
Bibliografia
http://java.sun.com/javaee/5/docs/tutorial/doc/ http://www.roseindia.net/ejb/
https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide
https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+server+ instance
https://docs.jboss.org/author/display/AS71/add-user+utility
https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+ using+JNDI
http://community.jboss.org/wiki/DataSourceConfigurationInAS7