Jersey Guice AOP

1,077
-1

Published on

Poche chiacchiere e tanto codice per cercare rendere la nostra vita di
sviluppatori più divertente.
Parleremo di JAX-RS, le annotazioni, l'MVC che mette a disposizione e
l'integrazione di Jersey con Guice.
Useremo AOP per gestire log, transazioni e con l'aiuto di Infinispan
limiteremo le chamate concorrenti sul nostro cluster.

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,077
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
23
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Rel 1.1 Goals: POJO-based, HTTP-centric, Format Independence, Container Independence, Inclusion in Java EE. La release 2.0 si focalizza su HATEOAS e implementazioni client, ma anche su Validation, MVC, Async, Filters/Handlers, migliorie al Content Negotiation. Attualmente Early Draft Review 2.
  • @FormParam is slightly special because it extracts information from a request representation that is of the MIME media type "application/x-www-form-urlencoded"
  • Listener per la configurazione dell'injector (bind,AOP). Filter per il processing delle richieste.
  • Il log delle richieste già lo abbiamo sul access log del nostro webserver o application server. Ma per quanto riquarda il body in POST o PUT non ci viene in aiuto. Con questo Interceptor possiamo loggare sul nostro file applicativo le richieste che arrivano con tutti i parametri in input e il THREAD che evade la chiamata
  • RFC6585: Additional HTTP Status Codes, April 2012, tra le altre cose: 3. 428 Precondition 4. 429 Too Many Requests 5. 431 Request Header Fields Too Large 6. 511 Network Authentication Required
  • Come si usa
  • Jersey Guice AOP

    1. 1. Jersey + Guice + AOP Domenico Briganti dometec@gmail.com
    2. 2. Chi sono?@PerRequestpublic class Presentation { @GET @Path("/JugMilano/People/DomenicoBriganti") @Produces(MediaType.APPLICATION_JSON) public Response getUserDetails() { UserDetails userdet = new UserDetails(); userdet.setCompany("Eidon srl"); userdet.setEmail("dometec@gmail.com"); userdet.setLinkedin("http://www.linkedin.com/in/dometec"); userdet.setBlog("http://tipsaboutmywork.blogspot.com/"); ... return Response.ok(userdet).build();} JUG Milano – Meeting #48 2
    3. 3. AgendaJAX-RSJersey con Guice/AOPDemos:Log delle richiesteTrim dei parametri Stringa in ingressoEvitare chiamate identiche su un clusterTransazioniLogin cookie JUG Milano – Meeting #48 3
    4. 4. JAX-RSJava API for RESTful Web ServicesRelease 1.1, JSR 311, 2009, JEE6 FullRelease futura 2.0, JSR 339, (EDR2 2012), JEE7Package: javax.ws.restImplementazioni: Jersey (RI), Apache CXF, RESTEasy, Apache Wink JUG Milano – Meeting #48 4
    5. 5. JerseyOpen source, RI for JAX-RSJersey 1.x (1.13b1) implements JAX-RS 1.1Jersey 2.x (mileston 3) implements JAX-RS 2CDDL + GPL 1.1 JUG Milano – Meeting #48 5
    6. 6. Jersey Hello Worldimport javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.PathParam;import javax.ws.rs.core.Response;@Path("/hello")public class HelloWorldService { @GET @Path("/{param}") public Response getMsg(@PathParam("param") String msg) { String output = "Echo: " + msg; return Response.ok(output).build(); }} JUG Milano – Meeting #48 6
    7. 7. JAX-RS AnnotationVerbi HTTP: @GET, @POST, @PUT, @DELETE, @OPTION, @HEADIdentificazione risorse: @PathInput: @PathParam, @QueryParam, @MatrixParam, @HeaderParam, @CookieParam. @FormParam. @DefaultValue. MultivaluedMap<String, String>Content negotiation: @Produces, @Consume JUG Milano – Meeting #48 7
    8. 8. JAX-RS Annotation e FacilityAmbiente: @Context (ServletConfig, ServletContext, HttpServletRequest, HttpServletResponse, SecurityContext, UriInfo, HttpHeaders)Mapper, MessageBodyWriters, MessageBodyReaders: @ProviderResponseBuilder e UriBuilder JUG Milano – Meeting #48 8
    9. 9. DEMO 0 “Esecuzione” dellaslide di presentazione JUG Milano – Meeting #48 9
    10. 10. Jersey-Guice integration <listener> <listener-class>org.example.demo.GuiceConfig</listener-class> </listener> <filter> <filter-name>GuiceFilter</filter-name>web.xml:web.xml <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>GuiceFilter</filter-name> <url-pattern>/services/*</url-pattern> <url-pattern>/application.wadl</url-pattern> <url-pattern>/application.wadl/*</url-pattern> </filter-mapping> package org.example.demo; public class GuiceConfig extends GuiceServletContextListener { @Overridelistener protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { Map<String, String> params = new HashMap<String, String>(); params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "org.example.demo"); params.put(ResourceConfig.FEATURE_TRACE, "true"); params.put(ResourceConfig.FEATURE_TRACE_PER_REQUEST, "true"); ... JUG Milano – Meeting #48 10
    11. 11. Demo 1Log delle richieste JUG Milano – Meeting #48 11
    12. 12. Demo 1 – Log delle richieste (interc.)public class LogCall implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { Logger logger = LoggerFactory.getLogger(invocation.getThis().getClass()); String arg = Joiner.on(", ").useForNull("null").join(invocation.getArguments()); logger.debug("{} ({}).", invocation.getMethod().getName(), arg); Object result = invocation.proceed(); logger.trace("Output: {}.", result); return result; }} JUG Milano – Meeting #48 12
    13. 13. Demo 1 – Log delle richieste (bind)public class GuiceConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { Map<String, String> params = new HashMap<String, String>(); params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "org.example.demo"); ... filter("/*").through(GuiceContainer.class, params); install(new Module() { public void configure(Binder binder) { LogCall logCall = new LogCall(); TrimAndNullInterceptor trimAndNullableInterceptor = new TrimAndNullInterceptor(); bindInterceptor( Matchers.annotatedWith(Path.class), Matchers.annotatedWith(GET.class).or(Matchers.annotatedWith(POST.class)) .or(Matchers.annotatedWith(PUT.class)).or(Matchers.annotatedWith(DELETE.class)), trimAndNullableInterceptor, logCall); JUG Milano – Meeting #48 13
    14. 14. Demo 2 – Trim parametri (interc.)public class TrimAndNullInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { for (int i = 0; i < invocation.getArguments().length; i++) { if (invocation.getArguments()[i] != null && invocation.getArguments()[i] instanceof String) { String sparam = (String) invocation.getArguments()[i]; String trim = sparam.trim(); if (trim.isEmpty()) invocation.getArguments()[i] = null; else invocation.getArguments()[i] = trim; } } return invocation.proceed(); }} JUG Milano – Meeting #48 14
    15. 15. Demo 2 – Trim parametri (bind)public class GuiceConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { Map<String, String> params = new HashMap<String, String>(); params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "org.example.demo"); ... filter("/*").through(GuiceContainer.class, params); install(new Module() { public void configure(Binder binder) { LogCall logCall = new LogCall(); TrimAndNullInterceptor trimAndNullableInterceptor = new TrimAndNullInterceptor(); bindInterceptor( Matchers.annotatedWith(Path.class), Matchers.annotatedWith(GET.class).or(Matchers.annotatedWith(POST.class)) .or(Matchers.annotatedWith(PUT.class)).or(Matchers.annotatedWith(DELETE.class)), trimAndNullableInterceptor, logCall); JUG Milano – Meeting #48 15
    16. 16. Evitare richieste duplicateProblemi: Ristrasmissioni Doppi submit (anche Tripli...) da browser Timeout lato client che scatena altre prove di richiesteRimedi: Hashtable con chiamate attualmente in corso 429 Too Many Requests (RFC 6585) Infinispan con lock condiviso per sistemi cluster JUG Milano – Meeting #48 16
    17. 17. Demo 3 – Richieste duplicate (uso)@POST@UniqueCallOnClusterpublic Response getAccountBalance(@FormParam("fromuser")...@POST@UniqueCallOnClusterpublic Response getAccountBalance(@KeyParameter@FormParam("fromuser")... JUG Milano – Meeting #48 17
    18. 18. Demo 3 – Richieste duplicate (Inter.)public class UniqueCallOnClusterInterceptor implements MethodInterceptor { ... public Object invoke(MethodInvocation invocation) throws Throwable { String classname = invocation.getMethod().getDeclaringClass().getSimpleName(); String methodName = invocation.getMethod().getName(); String key = classname + "_" + methodName + "_" + extractParameterValue(invocation); TransactionManager tm = keyCallOnClusterService.getTransactionManager(); tm.begin(); boolean success = keyCallOnClusterService.lock(key); if (!success) { logger.info("Non posso effettuare il lock sul cluster per la chiave {}.", key); return Response.status(429).entity("Another call with same parameter is in progress.").build(); } String runningServer = (String) keyCallOnClusterService.get(key); if (runningServer != null) { logger.info("Chiamata già in corso, server {}.", runningServer); return Response.status(429).entity("Another call with same parameter is in progress.").build(); } keyCallOnClusterService.put(key, "todo-hostname"); tm.commit(); ... return invocation.proceed(); ... keyCallOnClusterService.remove(key);} JUG Milano – Meeting #48 18
    19. 19. Demo 3 – Richieste duplicate (bind)public class GuiceConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { Map<String, String> params = new HashMap<String, String>(); params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "org.example.demo"); ... filter("/*").through(GuiceContainer.class, params); install(new Module() { public void configure(Binder binder) { UniqueCallOnClusterInterceptor uniqueCallOnClusterInterceptor = new UniqueCallOnClusterInterceptor(); requestInjection(uniqueCallOnClusterInterceptor); bindInterceptor(Matchers.any(), Matchers.annotatedWith(UniqueCallOnCluster.class), uniqueCallOnClusterInterceptor); JUG Milano – Meeting #48 19
    20. 20. Transazioni con AOP JUG Milano – Meeting #48 20
    21. 21. Transazioni con AOP JUG Milano – Meeting #48 21
    22. 22. Transazioni con AOP JUG Milano – Meeting #48 22
    23. 23. Demo 4 – Transazioni (uso)package org.example.demo.controller;@PerRequest@Transactional@Path("services/transactionalresource3")public class TransactionalResource3Write extends AbstractTransactionalResource { @Inject public TransactionalResource3Write() { } @POST @Produces("text/plain") public String get() { ... JUG Milano – Meeting #48 23
    24. 24. Demo 4 – Transazioni (uso)package org.example.demo.controller;@PerRequest@Transactional(TransactionType.ReadOnly)@Path("services/transactionalresource1")public class TransactionalResource1ReadOnly extends AbstractTransactionalResource { @Inject public TransactionalResource1ReadOnly() { } @GET @Produces("text/plain") @SuppressWarnings("unchecked") public String get() { List<DatabaseLog> list = getSession().createCriteria(DatabaseLog.class).list(); if (list.size() == 0) return "No record!"; JUG Milano – Meeting #48 24
    25. 25. Demo 4 – Transazioni (uso)package org.example.demo.controller;@PerRequest@Transactional(TransactionType.RequiredNew)@Path("services/transactionalresource5")public class TransactionalResource5ReqNew extends AbstractTransactionalResource { @Inject public TransactionalResource5ReqNew() { } ... JUG Milano – Meeting #48 25
    26. 26. Demo 4 – Transazioni (uso)public abstract class AbstractTransactionalResource { private Session session; @NoTransactional public void setSession(Session session) { this.session = session; } @NoTransactional public Session getSession() { return session; } @Override @NoTransactional protected void finalize() throws Throwable { super.finalize(); }} JUG Milano – Meeting #48 26
    27. 27. Demo 4 – Transazioni 1/2 (interc.)public class TransactionInterceptor implements MethodInterceptor { private final ThreadLocal<Stack<Session>> sessionThreadLocal; public Object invoke(MethodInvocation invocation) throws Throwable { ... Transactional transactional =invocation.getMethod().getDeclaringClass().getAnnotation(Transactional.class); ... Stack<Session> sessionStack = sessionThreadLocal.get(); Transaction transaction = null; Session session = null; if (!sessionStack.isEmpty()) session = sessionStack.peek(); if (session == null || transType.equals(TransactionType.RequiredNew)) { boolean readonly = false; readonly = transType.equals(TransactionType.ReadOnly); session = hibernateSessionService.openSession(readonly); transaction = session.getTransaction(); transaction.begin(); sessionStack.push(session); } Session oldSession = null; AbstractTransactionalResource service = ((AbstractTransactionalResource)invocation.getThis()); oldSession = service.getSession(); service.setSession(session); Object result = invocation.proceed(); JUG Milano – Meeting #48 27
    28. 28. Demo 4 – Transazioni 2/2 (interc.) try { Object result = invocation.proceed(); if (transaction != null) { session.flush(); transaction.commit(); } return result; } catch (Exception e) { transaction.rollback(); throw e; } finally { if (transaction != null) { hibernateSessionService.closeSession(session); sessionStack.pop(); if (sessionStack.isEmpty()) sessionThreadLocal.remove(); } service.setSession(oldSession); } }} JUG Milano – Meeting #48 28
    29. 29. Demo 4 – Transazioni (bind)public class GuiceConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { Map<String, String> params = new HashMap<String, String>(); params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "org.example.demo"); ... filter("/*").through(GuiceContainer.class, params); install(new Module() { public void configure(Binder binder) { TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); requestInjection(transactionInterceptor); bindInterceptor(Matchers.annotatedWith(Transactional.class), Matchers.not(Matchers.annotatedWith(NoTransactional.class)), TransactionInterceptor); JUG Milano – Meeting #48 29
    30. 30. Demo 5 - Login Cookie (bind)Annotation: AuthenticatedUser ApplicationRolesAllowedProvider: AuthenticatedUserProviderException e ExceptionMapper: NotAuthenticatedException(+Mapper) NotAuthorizedException(+Mapper)Cookie: LoginCookieManagerUtente: DemoPrincipalInterceptor: ApplicationRolesAllowedInterceptor JUG Milano – Meeting #48 30
    31. 31. Grazie!Domande??Riferimenti:http://jersey.java.nethttp://code.google.com/p/google-guice/Demo webapp: https://github.com/dometec/shadedcode/tree/master/demo-webapp JUG Milano – Meeting #48 31
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×