Novas APIs do Java EE 7

Propaganda
Novas APIs do
Java EE 7
E a batalha contra a complexidade
Helder da Rocha
[email protected]
Objetivos
Falar um pouco de complexidade do software e
apresentar três APIs do Java EE 7 que simplificam o
processo de desenvolvimento
Conteúdo
Breve reflexão sobre complexidade e entropia
JMS 2.0
APIs de Web Services (SOAP e REST)
O futuro?
2
"A complexidade do
software é uma
propriedade essencial, e não
acidental"
F. Brooks
Fonte: Grady Booch "Object Oriented Analysis and Design"
Ilusão da simplicidade
Fonte: Booch
6
Evolução das APIs
Uma API deve ser a mais simples possível
Contratos mais simples
Menos burocracia
Menos necessidade de documentação
Mas… problema inerente ao software: complexidade
Entropia sempre crescente
Sucesso depende do controle da complexidade
2.0
2.0
1.0
1.0
3.0
1.0
Java EE 7
Objetivo sempre presente na evolução das APIs:
Simplificar o uso!
Menor curva de aprendizado
Mais defaults, menos configuração
Menos, menos, menos
(até mesmo o JSF conseguiu ficar mais simples na Java EE 7 :-)
Java Message Service 1.0
jndi.lookup(queueFactory)
Queue
Connection
Factory
API para enviar e receber
mensagens usa classes e
métodos diferentes para
domínios Queue e Topic
createConnection()
Queue
Connection
createSession()
Queue
Sender
Queue
Session
create()
create()
createMessage()
Message
send()
receive()
Queue
jndi.lookup(queue)
Queue
Receiver
Java Message Service 1.1
jndi.lookup(factory)
Connection
Factory
API para enviar e receber
mensagens usa classes e
métodos iguais para
domínios Queue e Topic
createConnection()
Connection
createSession()
Message
Producer
Session
create()
create()
createMessage()
Message
send()
receive()
Destination
jndi.lookup(destination)
Message
Consumer
10
Java Message Service 2.0
@Inject factory
@Inject em vez de JNDI
Connection
Factory
Menos código para enviar
e receber mensagens
createJMSContext()
JMSProducer
JMSConsumer
JMSContext
create()
create()
createMessage()
Message
send()
Destination
@Inject destination
receive()
Java Message Service 2.0
Menos código!
Menos código!
@Inject factory
Connection
Factory
createJMSContext()
JMSContext
send()
receive()
Destination
@Inject destination
11
Envio de mensagens JMS 2.0
12
Antes (JMS 1.1)
public void sendJMS11(ConnectionFactory conFactory, Queue queue, String text) { try { Connection con = conFactory.createConnection(); try { Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(queue); TextMessage textMessage = session.createTextMessage(text); messageProducer.send(textMessage); } finally { connection.close(); } } catch (JMSException ex) { // handle exception } }
JMS 2.0
public void sendJMS2(ConnectionFactory conFactory, Queue queue, String text) { try (JMSContext context = conFactory.createContext();) { context.createProducer().send(queue, text); } catch (JMSRuntimeException ex) { // handle exception } }
Recebimento síncrono JMS 2.0
13
Antes (JMS 1.1)
public void recJMS11(ConnectionFactory conFactory, Queue queue, String text) { try { Connection con = conFactory.createConnection(); try { Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageConsumer messageConsumer = session.createConsumer(queue); con.start(); TextMessage textMessage = (TextMessage)messageConsumer.receive(); this.messageContents = textMessage.getText();
} finally { connection.close(); } } catch (JMSException ex) { // handle exception } }
JMS 2.0
public void recJMS2(ConnectionFactory conFactory, Queue queue, String text) { try (JMSContext context = conFactory.createContext();){ JMSConsumer consumer = context.createConsumer(queue); this.messageContents = consumer.receiveBody(String.class);
} catch (JMSRuntimeException ex) { // handle exception } }
14
Pré-história do SOAP, parte 1
No princípio, Web Service eram simples
de codificar em XML
POST /ISBNService.jsp HTTP/1.0
Content-type: text/xml
Content-length: 90
ISBNService.jsp
2
3
<chamada>
<funcao>
<nome>getPrice</nome>
<param>2877142566</param>
</funcao>
</chamada>
gera
requisição
19.50
HTTP/1.1 200 OK
Content-type: text/xml
Content-length: 77
ISBNClient
1
gera
resposta
2877142566
4
<resposta>
<funcao>
<param>19.50</param>
</funcao>
</resposta>
ISBNQuery
getPrice()
BD
Pré-história do SOAP parte 2
15
XML-RPC: padronização dos tags para operações,
parâmetros, tipos, etc.
Criado no grupo de discussões xml-dev em 1998
<methodCall>
<methodName>getPrice</methodName>
<params>
Requisição
<param>
<value><string>2877142566</string></value>
</param>
</param>
<methodResponse>
</methodCall>
<params>
<param>
<value><double>19.5</double></value>
</param>
Resposta
</param>
</methodResponse>
16
“Simples” requisição SOAP-RPC
Padronização oficial
Muito mais burocrática
POST /xmlrpc-bookstore/bookpoint/BookstoreIF HTTP/1.0
Content-Type: text/xml; charset="utf-8"
Content-Length: 585
SOAPAction: ""
Mensagem
<?xml version="1.0" encoding="UTF-8"?>
(envelope)
<env:Envelope
SOAP
xmlns:env="http://www.w3.org/2001/12/soap-envelope"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:enc="http://www.w3.org/2001/12/soap-encoding/"
env:encodingStyle="http://www.w3.org/2001/12/soap-encoding/">
<env:Body>
<ans1:getPrice xmlns:ans1="http://mybooks.org/wsdl">
<String_1 xsi:type="xsd:string">2877142566</String_1>
</ans1:getPrice>
</env:Body>
</env:Envelope>
Parâmetro (ISBN)
Payload
17
Resposta SOAP-RPC
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
SOAPAction: ""
Date: Thu, 08 Aug 2002 01:48:22 GMT
Server: Apache Coyote HTTP/1.1 Connector [1.0]
Connection: close
Mensagem
(envelope)
SOAP
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope
xmlns:env="http://www.w3.org/2001/12/soap-envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:enc="http://www.w3.org/2001/12/soap-encoding/"
xmlns:ns0="http://mybooks.org/types"
env:encodingStyle="http://www.w3.org/2001/12/soap-encoding/">
<env:Body>
<ans1:getPriceResponse xmlns:ans1="http://mybooks.org/wsdl">
<result xsi:type="xsd:decimal">19.50</result>
</ans1:getPriceResponse>
</env:Body>
</env:Envelope>
Resposta (Preço)
Payload
WSDL para descrever o serviço
<?xml version="1.0" encoding="UTF-­‐8"?> <definitions name="BookstoreService" targetNamespace="http://mybooks.org/wsdl" xmlns:tns="http://mybooks.org/wsdl" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> Compare com a <types>...</types> mensagem SOAP <message name="BookstoreIF_getPrice"> mostrada <part name="String_1" type="xsd:string"/> </message> anteriormente
<message name="BookstoreIF_getPriceResponse"> <part name="result" type="xsd:decimal"/> </message> <portType name="BookstoreIF"> <operation name="getPrice" parameterOrder="String_1"> <input message="tns:BookstoreIF_getPrice"/> <output message="tns:BookstoreIF_getPriceResponse"/> </operation> </portType> <binding ... > ...</binding> Informa onde está o serviço (endpoint)
<service ... > ... </service> </definitions> 19
Simplificação com JAX-WS
(escondendo a complexidade do XML)
WEB-INF
classes
web.xml
@WebService public class FilmeFacade { @PersistenceContext(unitName = "FilmesServiceSoap") EntityManager em; public List<Filme> getFilmes() { String jpql = "select filme from Filme filme"; Query query = em.createQuery(jpql); return (List<Filme>)query.getResultList(); } }
Deploy
FilmesServiceSoap.war
@Entity public class Filme implements Serializable { @Id private Long id; private String titulo; private String diretor; private Long ano; private long duracao; private String imdb; }
Endpoint:
http://servidor/FilmesServiceSoap/FilmeFacadeService
20
Cliente SOAP
public class FilmeClient { public static void main(String[] args) { FilmeFacadeService service = new FilmeFacadeService(); FilmeFacade proxy = service.getFilmeFacadePort(); listarFilmes(proxy.getFilmes()); } public static void listarFilmes(List<Filme> filmes) { for(Filme f : filmes) { System.out.println(f.getImdb()+": " + f.getTitulo() + "(" + f.getAno() + ")"); System.out.println(" " + f.getDiretor()); System.out.println(" " + f.getDuracao() + " minutos\n"); } } }
$ java –jar FilmeClient.jar Com geração automática do
código SOAP
Ainda assim muito complexo:
a complexidade migrou para
a configuração
tt0081505: The Shining(1980) Stanley Kubrick 144 minutos tt1937390: Nymphomaniac(2013) Lars von Trier 330 minutos tt0069293: Solyaris(1972) Andrei Tarkovsky 167 minutos tt1445520: Hearat Shulayim(2011) Joseph Cedar
Cliente em container
21
Mais simples. Menos configuração
@Named("filmesBean") CDI Managed Bean
public class FilmesManagedBean { @WebServiceRef(wsdlLocation=
"http://localhost:8080/FilmesServiceSoap/FilmeFacadeService?wsdl") private FilmeFacadeService service; private List<Filme> filmes; <h1>Lista de Filmes</h1> @PostConstruct <h:dataTable value="#{filmesBean.filmes}" var="filme”> public void init() { <h:column> FilmeFacade proxy = <f:facet name="header">IMDB</f:facet> <a href="http://www.imdb.com/title/#{filme.imdb}"> service.getFilmeFacadePort(); #{filme.imdb}</a> this.filmes = proxy.getFilmes(); </h:column> } <h:column> … <f:facet name="header">Título</f:facet> }
#{filme.titulo} </h:column> ... </h:dataTable>
JSF Facelets
RESTful Web Services
REST ~= Infraestrutura de um website
recursos (páginas), links, hierarquia
representações de dados e tipos (URIs, MIME)
vocabulário de operações do protocolo HTTP (GET, POST, …)
URIs ~= objetos
pais.estado.cidade ==
http://servidor/aplicacao/pais/estado/cidade/
Representações
XML, JSON, CSV, etc.
Métodos HTTP permitem operações CRUD
Create:
Retrieve:
Update:
Delete:
POST /pais/estado
(<estado>SP</estado>, no corpo)
GET /pais/estado/SP (Retrieve All com GET /pais/estado)
PUT /pais/estado/PB
DELETE /pais/estado/PB
22
JAX-RS
23
JAX-RS : API Java para RESTful WebServices
Componentes
Subclasse de Application: configuração
Root resource class: fachada de serviços
Resource method: associados a métodos HTTP (@GET, @POST, etc.)
Providers: produzem ou consomem representações de entidades
em outros formatos (ex: XML, JSON)
JAX-RS usa anotações para configurar os componentes
@ApplicationPath na subclasse de Application
@Path nos Root resource classes
@GET, @POST, etc e @Path nos Resource methods
@Produces, @Consumes nos Providers
@Context para injetar diversos tipos de contexto do ambiente Web
Path templates e @PathParam
24
@Path templates
@Path("/filmes/{imdb}") Aceita por exemplo: http://abc.com/war/app/filmes/tt0066921
Parâmetros @PathParam
@Path("/filmes/{imdb}") public class FilmesIMDBResource { @GET @Produces("text/xml")
public Filme getFilme(@PathParam("imdb") String codigoIMDB) { return entity.getFilmeByIMDBCode(codigoIMDB);
} } Diferentes representações de objetos
Classes
class Telefone {
int ddd;
int numero;
}
class Pessoa {
int numero;
String nome;
Telefone[] telefones = new Telefone[3];
}
Objetos
em Java
Pessoa pessoa = new Pessoa();
pessoa.numero = 145;
pessoa.nome = "Jeeves";
pessoa.telefone[0] = new Telefone();
pessoa.telefone[0].ddd = 11;
pessoa.telefone[0].numero = 34567890;
Representação em XML
<pessoa xmlns="http://pessoa" numero="145">
<nome>Jeeves</nome>
<telefone>
<ddd>11</ddd>
<numero>34567890</numero>
</telefone>
</pessoa>
application/xml
25
Representação em JSON
{
"@numero": 145,
"nome": "Jeeves",
[ "telefone": {
"ddd": 11, "numero": 34567890
}]
}
application/json
26
JAXB
Java API for XML Binding
Mapeia classes Java a XML Schema
Classes mapeadas a XML Schema (ferramentas xjc e schemagen)
Objetos mapeados a documentos XML (através da API javax.xml.bind e
operações de serialização em XML (marshalling e unmarshalling)
XML
Schema
xjc
Binding
Classes
Java
schemagen
Documentos
(instâncias
XML)
unmarshal()
Marshalling
marshal()
Objetos
(instâncias
Java)
JAXB: exemplo de classe anotada
27
@XmlSchema(namespace = "http://filmes.argonavis.com/") package com.argonavis.filmes.generated; @XmlRootElement public class Sala implements Serializable { private List<Assento> assentos; private String nome; private int lotacao; @XmlElementWrapper @XmlElement(name="assento") public List<Assento> getAssentos() { return assentos; } … }
Sem @XmlElementWrapper
<sala>
<assentos>…</assentos>
<assentos>…</assentos>
</sala> Com @XmlElementWrapper
<sala>
<assentos>
<assento>…</assento>
<assento>…</assento>
</assentos>
</sala>
JAXB Marshal / Unmarshal
28
Unmarshalling = XML àJava
JAXBContext jc = JAXBContext.newInstance( "com.argonavis.filmes.gen" ); Unmarshaller u = jc.createUnmarshaller(); Filme filme = (Filme)u.unmarshal( new File( "tt1937390.xml" ) ); Marshalling = Java àXML
JAXBContext jc = JAXBContext.newInstance( "com.argonavis.flmes.gen" );
Filme filme = ObjectFactory.createFilme();
filme.setAno(2014); // alterando objeto
Marshaller m = jc.createMarshaller(); m.marshal( filme, System.out );
29
JSON Binding!
Substituir o provedor JAXB default por EclipseLink MOXy:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Configuração de JAXBContext
Map properties = new HashMap();
props.put("eclipselink.media-type", "application/json");
JAXBContext ctx = JAXBContext.newInstance(new Class[] { Produto.class }, props);
JSON à
Java
UnMarshaller u = ctx.createUnMarshaller();
Produto produto= u.unmarshal(new StreamSource(“produto123.json”));
Java à
JSON
Marshaller m = ctx.createMarshaller();
m.marshal(produto, System.out);
Haverá suporte nativo
a JSON binding no
Java EE 8 (2016)
Cliente REST com java.net
30
Cliente HTTP!
URL url = new URL("http://localhost:8080/ctx/app/imdb/tt0066921"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/xml"); if (conn.getResponseCode() != 200) { throw new RuntimeException("Erro : " + conn.getResponseCode()); } BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); String linha = br.readLine(); System.out.println("Dados recebidos: " + linha); conn.disconnect(); JAXBContext jc = JAXBContext.newInstance(Filme.class); Unmarshaller u = jc.createUnmarshaller(); Filme filme = (Filme) u.unmarshal(new StringReader(linha)); System.out.println(filme.getIMDB()); …
31
Cliente Jersey*
Ainda mais simples
ClientConfig config = new DefaultClientConfig(); Client client = Client.create(config); URI baseURI = UriBuilder.fromUri("http://localhost:8080/ctx").build(); WebResource service = client.resource(baseURI); Filme filme = service.path("app")
.path("filme/imdb/tt0066921")
.accept(MediaType.APPLICATION_XML) .get(Filme.class); System.out.println(filme.getIMDB()); System.out.println(filme.getTitulo()); System.out.println(filme.getDiretor());
* Existem outras alternativas. Veja RESTEasy
32
Cliente mobile (iPhone)
REST é melhor alternativa para Web Services que fazem
integração como outras plataformas
1) Cliente REST escrito em Objective-C
rodando em iOS 7 gera requisição
GET http://192.168.1.25/festival/webapi/filme
2) Glassfish gera resposta HTTP
com lista de filmes em JSON
3) iPhone extrai dados e
preenche UITableView
Glassfish 4.0
O futuro
Java EE 8 promete uma vida menos complexa
API de segurança unificada
API de transações unificada
CDI com papel central em todas as aplicações
JSON binding nativo
Melhor integração com WebSockets
Mas, ...
A entropia continua a crescer... + linguagens + bugs +
problemas + ameaças + horizontes + iOT + ... a luta continua!
Fonte: http://tinyurl.com/7zlytsm
"the singularity is near!" Ray Kurzweil
[email protected]
Download