Then Jesus said, "Come to me, all of you
who are weary and carry heavy burdens,
       and I will give you REST."
                                  Matthew 11:28
JavaO
                                     ne LA
                                   2012 TAM




   Approaching Pure
     REST in Java:
HATEOAS and HTTP Tuning
        Eder Ignatowicz
      Senior Architect, Dextra
Software Craftsman @ Dextra
               (Arquitetura, NoSQL, Devops, QA)

                     Doutorando na Unicamp
           (Polyglot Persistence em Cidades Digitais)

                 Professor na Faccamp e Unisal

                   Editor líder no InfoQ Brasil

@ederign
Galera Ponta Firme e que Manda bem



                        Dextra
Projetos Desafiadores




                                                             Qualidade de Vida
                        Ambiente de Melhoria Contínua
WE’R
                                 E
                        Galera Ponta Firme e que Manda bem



                        Dextra
Projetos Desafiadores




                        HIRIN
                                                             Qualidade de Vida
                              G!!!
                        Ambiente de Melhoria Contínua
O mundo, antes de REST
http://geekswithblogs.net/images/geekswithblogs_net/ugandadotnet/eai-spaghetti.jpg
TEMPOS DIFÍCEIS...

      MUITOS “PADRÕES”
             RMI, Corba, DCOM
   MUITOS FORNECEDORES
   Sun, Microsoft, OASIS, OMG
        MUITAS LÁGRIMAS
Não existia interoperabilidade
           Reinvenção da roda
              Vendor “lock-in”
SOAP WEB SERVICES
http://geekswithblogs.net/images/geekswithblogs_net/ugandadotnet/eai-spaghetti.jpg
http://geekswithblogs.net/images/geekswithblogs_net/ugandadotnet/eai-spaghetti.jpg
Então surgiu o REST!!!
REST
Roy Fielding Dissertation   REpresentational State Transfer




                            ESTILO DE ARQUITETURA DE SOFTWARE PARA SISTEMAS
                            DISTRIBUÍDOS HYPERMEDIA SEMELHANTES A WORLD
                            WIDE WEB
PRINCÍPIOS E RESTRIÇÕES REST

                                    CLIENTE-SERVIDOR
                                 SERVIDOR STATELESS
                                               CACHE
                                 INTERFACE UNIFORME
                             IDENTIFICAÇÃO DE RECURSOS
MANIPULAÇÃO DESTES RECURSOS ATRAVÉS DE REPRESENTAÇÕES
                          MENSAGENS AUTO-DESCRITIVAS
         HYPERMEDIA COMO ENGINE DO ESTADO DA APLICAÇÃO
                          ARQUITETURA EM CAMADAS
                              CÓDIGO SOB DEMANDA
                                           (OPCIONAL)
HTTP tunning
CACHE

    HATEOAS
GET           Buscar recursos, cache

POST            Criar um novo recurso

 PUT     Atualizar (todo o) recurso existente

DELETE          Remover um recurso

PATCH      Atualizar (parte de) um recurso
NÃO RESTful
 VERBO        URI (Substantivo)      Ação
  POST       /bookmarks/create       Criar
   GET      /bookmarks/show/1     Visualizar
  POST     /bookmarks/update/1     Alterar
GET/POST   /bookmarks/delete/1     Apagar
                 RESTful
 VERBO       URI (Substantivo)       Ação
  POST         /bookmarks/           Criar
   GET        /bookmarks/1        Visualizar
  PUT         /bookmarks/1         Alterar
 DELETE       /bookmarks/1         Apagar
TOLERÂNCIA A FALHAS
NOSSOS
        SONHOS
               NA INTE
SEGURANÇA SISTE       GRAÇÃO
                MAS          DE
  ESCALABILIDADE
                      BAIXO ACOPLAMENTO
Mas extremamente
mal compreendida...
“
“O que precisa ser feito para que entendam que
   no estilo arquitetural REST o hypertext é um
                   pré-requisito?
  Em outras palavras, se a engine do estado da
 aplicação (e consequentemente sua API) não é
 guiada por hypertext, então sua aplicação não
pode ser RESTful e nem ter uma API REST. PONTO.
  Existe por ai algum manual que necessite ser
                   consertado?”
                                Roy Thomas Fielding
HYPERMEDIA
Richardson’s Maturity Model
                                   REST Sagrado
   Nível 3: Controles Hypermedia

      Nível 2: Verbos HTTP
      Nível1: Recursos

Nível 0: O pântano do POX
Nível 0: O pântano do POX
            Uma URI, um método HTTP
              XML-RPC / SOAP / POX
           HTTP usado como transporte

POST /agendamentoService HTTP/1.1
[headers...]

<appointmentRequest>
  <slot doctor = "rcmito" start = "1400" end = "1450"/>
  <patient id = "ederi"/>
</appointmentRequest>
Nível 1: Recursos
 Cada recurso tem uma única URI
          URI tunneling
Um único verbo HTTP (POST ou GET)
   HTTP usado como transporte

POST /slots/1234 HTTP/1.1
[headers...]

<appointmentRequest>
	 <patient id = "ederi" />
</appointmentRequest>
Level 2: HTTP Verbs
      Muitas URIs, utilizando corretamente
                 os verbos HTTP
      Uso correto dos códigos de resposta
      Expõe estado e não comportamento
                       CRUD
GET /doctors/rcmito/slots?date=20121010?status=open
HTTP/1.1
[headers...]
HTTP/1.1 200 OK

<openSlotList>
	 <slot id = “1234” start=”1400” end=”1450”       />
    <slot id = “1234” start=”1600” end=”1650”/>
</openSlotList>
Níveis 0,1 e 2
não são RESTful
    (e nem REST)
Nível 3: Controles Hypermedia

   Hypermedia As The Engine of Application State
                   (HATEOAS)

             Recursos auto descritivos

Clientes só precisam saber a URI root (home page) de
         uma API e os media types utilizados

               O resto é HTTP e links
“   O nome Representational State Transfer foi
escolhido com a intenção de criar uma imagem de
 como uma aplicação Web bem desenvolvida se
comporta: uma rede de páginas web (máquina de
 estados), onde o usuário navega selecionando
  links (transições de estados), resultando na
 próxima página (próximo estado da aplicação).
                               Roy Thomas Fielding
ESTADO                                           ESTADO
                            http://uri
                                           Transição
         Transição
                             ESTADO

                                         Transição
                Transição
ESTADO                                           ESTADO
HTTP/1.1 201 Created
Location: http://jogano10.com/slots/1234/appointment
[various headers]

<appointment>
  <slot id = "1234" doctor = "rcmito" start = "1400"
end = "1450"/>
  <patient id = "ederi"/>
  <link rel = "/linkrels/appointment/cancel"
        uri = "/slots/1234/appointment"/>
  <link rel = "/linkrels/appointment/addTest"
        uri = "/slots/1234/appointment/tests"/>
  <link rel = "self"
        uri = "/slots/1234/appointment"/>
  <link rel = "/linkrels/appointment/updateContactInfo"
        uri = "/patients/ederi/contactInfo"/>
</appointment>
Isto é
RESTFUL
As três grandes
invenções da nossa
   história são:
HYPERLINK !!!
JAX-RS API
JAX-RS API
                                            Recursos

         @Path("/cartao/{cardId}")
         public class Cartao {
                                                       Injeção dos
         	 @GET
         	 @Path("/saldo")
                                                       parâmetros
         	 @Produces("text/plain")
         	 public Saldo saldo(@PathParam("cardId") String card) {
         	 	 return getSaldo(card);
         	 }
         ...
         }


HTTP Method
  Binding                    Serialização
                             automática
JAX-RS API
  SUPORTE A HATEOAS
Hypermedia
                 Suporte a HATEOAS

// Server API
Response res = Response.ok(order)
    .link("http://.../orders/1/ship", "ship")
    .build();

// Client API
Response order = client.target(…)
    .request("application/xml").get();

if (order.getLink(“ship”) != null) {
    Response shippedOrder = client
        .target(order.getLink("ship"))
        .request("application/xml").post(null);
 }
REST sem HATEOAS
    não é REST
Não devem existir
verbos na sua URI
Mas, eu preciso mais do
   que a semântica
    GET/POST/PUT
     DELETE/PATCH  "But my model is different!".
                   You are not a special or
                   unique snowflake.
                   - should I build another
                   protocol? - should I add a new
                   HTTP method?
                   - answer 1: tough shit. you're
                   wrong, it can be modeled with
                   the uniform interface, it's
                   sufficiently general.
Concorrência?
                If you do two PUTs at once,
                one wins. The solution
                depends on what you need.
                For a lot of applications, "last
                update wins" is a fine strategy.
                If not, Etags are the solution.
Transações... ?!?
             I want to debit one guy's
             account at the same time, and
             only if, I can credit another
             guy's account. I could do two
             PUTs in a row, but that's
             begging for inconsistencies to
             creep into the system.
             answer 1: YAGNI. Answer 2:
             what you probably want is a
             new resource to encapsulate
Não existe a necessidade
     de API nem de
versionamento de APIs!!!
                    - So Iʼll wrap up where we
                    started. Youʼll find that the closer
                    you move to REST, the less of a
                    distinct API youʼll have at all.
                    The “regular” application and its
                    API will become one.
                    - The rub, and itʼs a big rub, is
                    not a technical one but a social
                    one. Building on a API requires
                    trust of stability, and “traditional”
                    websites donʼt provide for
Escalabilidade HTTP + JAX-RS
      http://2.bp.blogspot.com/-JmDsZ1ESAWg/TyiHY8MMdzI/AAAAAAAAEDs/lFZxR0z5fGk/s1600/escalada1.jpg
HTTP


                                            Caching
                                                      Reverse   Web Server
                              Translation              Proxy
                                 Proxy

Local Cache   “The Proxies”
HTTP
    allowed (or not)
         expiration
intermediary caches
                     Caching features
    allowed (or not)
          validation
    storable(or not)
HTTP                   Quando “cachear”?

                            Expires header
                            Expires: Sun, 04 Aug 2012 16:00 GMT



         Cache-control header
      Cache-Control: no-cache
Cache-Control: public, max-age=3000



                                             Validation Header
                          Last-Modified: Mon, 29 Jun 2012 02:28:12 GMT
                                   ETag: "3e86-410-3596fbbc"
JAX-RS e Cache Control
@Path("/doutores")
public class DoutoresService {
	 @Path("/{id}")
	 @GET
	 @Produces("application/xml")
	 public Response getDoutores(@PathParam("id") int id) {
	 	 List<Doutor> doutores = //getDoutores
	 	 CacheControl cc = new CacheControl();
	 	 cc.setMaxAge(3000);
	 	 return Response.ok(doutores).cacheControl(cc).build();
	 }
}
JAX-RS e Gets Condicionais
Last-Modified: Mon, 29 Jun 2012 02:28:12 GMT
         ETag: "3e86-410-3596fbbc"




           O cache está valido?
           304 “Not Modified”

              Não está?
       200 “OK” + recurso válido
@Path("/doutores")
public class DoutoresService {
	 @Path("/{id}")
	 @GET
	 @Produces("application/xml")
	 public Response getDoutores(@PathParam("id") int id,
	 	 	 @Context Request request) {
	 	 EntityTag tag = // get tag mais atualizada
	 	 ResponseBuilder builder = null;

	   	   builder = request.evaluatePreconditions(tag);
	   	   if (builder != null){
	   	   	 return builder.cacheControl(cc).build();
	   	   }
	   	   Object doutores = // getDoutores	
	   	   return Response.ok(doutores).cacheControl(cc).build();
	   }
}
JAX-RS e Cache-Control
@Path("/doutores")

         O mesmo princípio se aplica
public class DoutoresService {
	 @Path("/{id}")
	 @GET

              para PUTs e POSTs
	 @Produces("application/xml")
	 public Response getDoutores(@PathParam("id") int id) {


                condicionais
	 	 List<Doutor> doutores = //getDoutores
	 	 CacheControl cc = new CacheControl();
	 	 cc.setMaxAge(3000);

	 }
}
           (updates concorrentes)
	 	 return Response.ok(doutores).cacheControl(cc).build();
JSR 339: JAX-RS 2.0
Public Review Ballot 24/11/2012

          Adopt a JSR
Client API
	   @Before
	   public void setUp() throws Exception {
	   	   // start the server
	   	   server = Main.startServer();
	   	   // create the client
	   	   Client c = ClientFactory.newClient();
	   	   target = c.target(Main.BASE_URI);
	   }

	   @After
	   public void tearDown() throws Exception {
	   	   server.stop();
	   }

	   @Test
	   public void testExtratoSemHATEOAS() {
	   	   String responseMsg = target.path("cartao/1/saldo").request()
	   	   	    	   .get(String.class);
	   	   assertEquals(value, responseMsg);
	   }
Interceptors/Handlers
      Pontos de extensão: Logging, Compression, Security, etc.

@Provider
class LoggingFilter
    implements RequestFilter, ResponseFilter {

    @Override
    public FilterAction preFilter(FilterContext ctx)
      throws IOException {
        logRequest(ctx.getRequest());
        return FilterAction.NEXT;
    }
    @Override
    public FilterAction postFilter(FilterContext ctx)
      throws IOException {
        logResponse(ctx.getResponse());
        return FilterAction.NEXT;
    }
Async

                       Suporte na API Client

// Acesso URI
Target target = client.target("http://.../atm/balance")…

// Chamada async e callback
Future<?> handle = target.request().async().get(
    new InvocationCallback<String>() {
        public void complete(String balance) { … }
        public void failed(InvocationException e) { … }
      });
Java <3
@ederign

Rest Java One

  • 1.
    Then Jesus said,"Come to me, all of you who are weary and carry heavy burdens, and I will give you REST." Matthew 11:28
  • 2.
    JavaO ne LA 2012 TAM Approaching Pure REST in Java: HATEOAS and HTTP Tuning Eder Ignatowicz Senior Architect, Dextra
  • 3.
    Software Craftsman @Dextra (Arquitetura, NoSQL, Devops, QA) Doutorando na Unicamp (Polyglot Persistence em Cidades Digitais) Professor na Faccamp e Unisal Editor líder no InfoQ Brasil @ederign
  • 4.
    Galera Ponta Firmee que Manda bem Dextra Projetos Desafiadores Qualidade de Vida Ambiente de Melhoria Contínua
  • 5.
    WE’R E Galera Ponta Firme e que Manda bem Dextra Projetos Desafiadores HIRIN Qualidade de Vida G!!! Ambiente de Melhoria Contínua
  • 6.
  • 7.
  • 8.
    TEMPOS DIFÍCEIS... MUITOS “PADRÕES” RMI, Corba, DCOM MUITOS FORNECEDORES Sun, Microsoft, OASIS, OMG MUITAS LÁGRIMAS Não existia interoperabilidade Reinvenção da roda Vendor “lock-in”
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
    REST Roy Fielding Dissertation REpresentational State Transfer ESTILO DE ARQUITETURA DE SOFTWARE PARA SISTEMAS DISTRIBUÍDOS HYPERMEDIA SEMELHANTES A WORLD WIDE WEB
  • 14.
    PRINCÍPIOS E RESTRIÇÕESREST CLIENTE-SERVIDOR SERVIDOR STATELESS CACHE INTERFACE UNIFORME IDENTIFICAÇÃO DE RECURSOS MANIPULAÇÃO DESTES RECURSOS ATRAVÉS DE REPRESENTAÇÕES MENSAGENS AUTO-DESCRITIVAS HYPERMEDIA COMO ENGINE DO ESTADO DA APLICAÇÃO ARQUITETURA EM CAMADAS CÓDIGO SOB DEMANDA (OPCIONAL)
  • 15.
  • 16.
    GET Buscar recursos, cache POST Criar um novo recurso PUT Atualizar (todo o) recurso existente DELETE Remover um recurso PATCH Atualizar (parte de) um recurso
  • 17.
    NÃO RESTful VERBO URI (Substantivo) Ação POST /bookmarks/create Criar GET /bookmarks/show/1 Visualizar POST /bookmarks/update/1 Alterar GET/POST /bookmarks/delete/1 Apagar RESTful VERBO URI (Substantivo) Ação POST /bookmarks/ Criar GET /bookmarks/1 Visualizar PUT /bookmarks/1 Alterar DELETE /bookmarks/1 Apagar
  • 18.
    TOLERÂNCIA A FALHAS NOSSOS SONHOS NA INTE SEGURANÇA SISTE GRAÇÃO MAS DE ESCALABILIDADE BAIXO ACOPLAMENTO
  • 19.
  • 20.
    “ “O que precisaser feito para que entendam que no estilo arquitetural REST o hypertext é um pré-requisito? Em outras palavras, se a engine do estado da aplicação (e consequentemente sua API) não é guiada por hypertext, então sua aplicação não pode ser RESTful e nem ter uma API REST. PONTO. Existe por ai algum manual que necessite ser consertado?” Roy Thomas Fielding
  • 21.
  • 22.
    Richardson’s Maturity Model REST Sagrado Nível 3: Controles Hypermedia Nível 2: Verbos HTTP Nível1: Recursos Nível 0: O pântano do POX
  • 23.
    Nível 0: Opântano do POX Uma URI, um método HTTP XML-RPC / SOAP / POX HTTP usado como transporte POST /agendamentoService HTTP/1.1 [headers...] <appointmentRequest> <slot doctor = "rcmito" start = "1400" end = "1450"/> <patient id = "ederi"/> </appointmentRequest>
  • 24.
    Nível 1: Recursos Cada recurso tem uma única URI URI tunneling Um único verbo HTTP (POST ou GET) HTTP usado como transporte POST /slots/1234 HTTP/1.1 [headers...] <appointmentRequest> <patient id = "ederi" /> </appointmentRequest>
  • 25.
    Level 2: HTTPVerbs Muitas URIs, utilizando corretamente os verbos HTTP Uso correto dos códigos de resposta Expõe estado e não comportamento CRUD GET /doctors/rcmito/slots?date=20121010?status=open HTTP/1.1 [headers...] HTTP/1.1 200 OK <openSlotList> <slot id = “1234” start=”1400” end=”1450” /> <slot id = “1234” start=”1600” end=”1650”/> </openSlotList>
  • 26.
    Níveis 0,1 e2 não são RESTful (e nem REST)
  • 27.
    Nível 3: ControlesHypermedia Hypermedia As The Engine of Application State (HATEOAS) Recursos auto descritivos Clientes só precisam saber a URI root (home page) de uma API e os media types utilizados O resto é HTTP e links
  • 28.
    O nome Representational State Transfer foi escolhido com a intenção de criar uma imagem de como uma aplicação Web bem desenvolvida se comporta: uma rede de páginas web (máquina de estados), onde o usuário navega selecionando links (transições de estados), resultando na próxima página (próximo estado da aplicação). Roy Thomas Fielding
  • 29.
    ESTADO ESTADO http://uri Transição Transição ESTADO Transição Transição ESTADO ESTADO
  • 30.
    HTTP/1.1 201 Created Location:http://jogano10.com/slots/1234/appointment [various headers] <appointment> <slot id = "1234" doctor = "rcmito" start = "1400" end = "1450"/> <patient id = "ederi"/> <link rel = "/linkrels/appointment/cancel" uri = "/slots/1234/appointment"/> <link rel = "/linkrels/appointment/addTest" uri = "/slots/1234/appointment/tests"/> <link rel = "self" uri = "/slots/1234/appointment"/> <link rel = "/linkrels/appointment/updateContactInfo" uri = "/patients/ederi/contactInfo"/> </appointment>
  • 31.
  • 32.
    As três grandes invençõesda nossa história são:
  • 35.
  • 36.
  • 37.
    JAX-RS API Recursos @Path("/cartao/{cardId}") public class Cartao { Injeção dos @GET @Path("/saldo") parâmetros @Produces("text/plain") public Saldo saldo(@PathParam("cardId") String card) { return getSaldo(card); } ... } HTTP Method Binding Serialização automática
  • 38.
    JAX-RS API SUPORTE A HATEOAS
  • 39.
    Hypermedia Suporte a HATEOAS // Server API Response res = Response.ok(order) .link("http://.../orders/1/ship", "ship") .build(); // Client API Response order = client.target(…) .request("application/xml").get(); if (order.getLink(“ship”) != null) { Response shippedOrder = client .target(order.getLink("ship")) .request("application/xml").post(null); }
  • 41.
    REST sem HATEOAS não é REST
  • 42.
  • 43.
    Mas, eu precisomais do que a semântica GET/POST/PUT DELETE/PATCH "But my model is different!". You are not a special or unique snowflake. - should I build another protocol? - should I add a new HTTP method? - answer 1: tough shit. you're wrong, it can be modeled with the uniform interface, it's sufficiently general.
  • 44.
    Concorrência? If you do two PUTs at once, one wins. The solution depends on what you need. For a lot of applications, "last update wins" is a fine strategy. If not, Etags are the solution.
  • 45.
    Transações... ?!? I want to debit one guy's account at the same time, and only if, I can credit another guy's account. I could do two PUTs in a row, but that's begging for inconsistencies to creep into the system. answer 1: YAGNI. Answer 2: what you probably want is a new resource to encapsulate
  • 47.
    Não existe anecessidade de API nem de versionamento de APIs!!! - So Iʼll wrap up where we started. Youʼll find that the closer you move to REST, the less of a distinct API youʼll have at all. The “regular” application and its API will become one. - The rub, and itʼs a big rub, is not a technical one but a social one. Building on a API requires trust of stability, and “traditional” websites donʼt provide for
  • 48.
    Escalabilidade HTTP +JAX-RS http://2.bp.blogspot.com/-JmDsZ1ESAWg/TyiHY8MMdzI/AAAAAAAAEDs/lFZxR0z5fGk/s1600/escalada1.jpg
  • 49.
    HTTP Caching Reverse Web Server Translation Proxy Proxy Local Cache “The Proxies”
  • 50.
    HTTP allowed (or not) expiration intermediary caches Caching features allowed (or not) validation storable(or not)
  • 51.
    HTTP Quando “cachear”? Expires header Expires: Sun, 04 Aug 2012 16:00 GMT Cache-control header Cache-Control: no-cache Cache-Control: public, max-age=3000 Validation Header Last-Modified: Mon, 29 Jun 2012 02:28:12 GMT ETag: "3e86-410-3596fbbc"
  • 52.
    JAX-RS e CacheControl @Path("/doutores") public class DoutoresService { @Path("/{id}") @GET @Produces("application/xml") public Response getDoutores(@PathParam("id") int id) { List<Doutor> doutores = //getDoutores CacheControl cc = new CacheControl(); cc.setMaxAge(3000); return Response.ok(doutores).cacheControl(cc).build(); } }
  • 53.
    JAX-RS e GetsCondicionais Last-Modified: Mon, 29 Jun 2012 02:28:12 GMT ETag: "3e86-410-3596fbbc" O cache está valido? 304 “Not Modified” Não está? 200 “OK” + recurso válido
  • 54.
    @Path("/doutores") public class DoutoresService{ @Path("/{id}") @GET @Produces("application/xml") public Response getDoutores(@PathParam("id") int id, @Context Request request) { EntityTag tag = // get tag mais atualizada ResponseBuilder builder = null; builder = request.evaluatePreconditions(tag); if (builder != null){ return builder.cacheControl(cc).build(); } Object doutores = // getDoutores return Response.ok(doutores).cacheControl(cc).build(); } }
  • 55.
    JAX-RS e Cache-Control @Path("/doutores") O mesmo princípio se aplica public class DoutoresService { @Path("/{id}") @GET para PUTs e POSTs @Produces("application/xml") public Response getDoutores(@PathParam("id") int id) { condicionais List<Doutor> doutores = //getDoutores CacheControl cc = new CacheControl(); cc.setMaxAge(3000); } } (updates concorrentes) return Response.ok(doutores).cacheControl(cc).build();
  • 56.
    JSR 339: JAX-RS2.0 Public Review Ballot 24/11/2012 Adopt a JSR
  • 57.
    Client API @Before public void setUp() throws Exception { // start the server server = Main.startServer(); // create the client Client c = ClientFactory.newClient(); target = c.target(Main.BASE_URI); } @After public void tearDown() throws Exception { server.stop(); } @Test public void testExtratoSemHATEOAS() { String responseMsg = target.path("cartao/1/saldo").request() .get(String.class); assertEquals(value, responseMsg); }
  • 58.
    Interceptors/Handlers Pontos de extensão: Logging, Compression, Security, etc. @Provider class LoggingFilter implements RequestFilter, ResponseFilter { @Override public FilterAction preFilter(FilterContext ctx) throws IOException { logRequest(ctx.getRequest()); return FilterAction.NEXT; } @Override public FilterAction postFilter(FilterContext ctx) throws IOException { logResponse(ctx.getResponse()); return FilterAction.NEXT; }
  • 59.
    Async Suporte na API Client // Acesso URI Target target = client.target("http://.../atm/balance")… // Chamada async e callback Future<?> handle = target.request().async().get( new InvocationCallback<String>() { public void complete(String balance) { … } public void failed(InvocationException e) { … } });
  • 60.
  • 62.