2012-07-03 13 views
12

In one of the few questions (with answers) Ho trovato su SO per quanto riguarda JAX-RS e la memorizzazione nella cache, la risposta alla generazione di ETags (per la memorizzazione nella cache) è impostando alcuni valori sull'oggetto Response. Come nella seguente:È possibile impostare ETags usando JAX-RS senza ricorrere agli oggetti Response?

@GET 
@Path("/person/{id}") 
public Response getPerson(@PathParam("id") String name, @Context Request request){ 
    Person person = _dao.getPerson(name); 

    if (person == null) { 
    return Response.noContent().build(); 
    } 

    EntityTag eTag = new EntityTag(person.getUUID() + "-" + person.getVersion()); 

    CacheControl cc = new CacheControl(); 
    cc.setMaxAge(600); 

    ResponseBuilder builder = request.evaluatePreconditions(person.getUpdated(), eTag); 

    if (builder == null) { 
    builder = Response.ok(person); 
    } 

    return builder.cacheControl(cc).lastModified(person.getUpdated()).build(); 
} 

Il problema è che non funziona per noi, dato che usiamo gli stessi metodi sia per SOAP e REST servizi, annotando i metodi con @WebMethod (SOAP), @GET (e qualsiasi altra cosa potremmo aver bisogno di esporre il servizio). Il servizio precedente sarebbe simile a questa a noi (esclusa la creazione di intestazioni):

@WebMethod 
@GET 
@Path("/person/{id}") 
public Person getPerson(@WebParam(name="id") @PathParam("id") String name){ 
    return _dao.getPerson(name); 
} 

C'è un modo - attraverso qualche configurazione aggiuntiva - di impostare queste intestazioni? Questa è la prima volta che ho scoperto che l'utilizzo degli oggetti Response ha effettivamente dei vantaggi rispetto alla semplice conversione automatica ...

Stiamo usando Apache CXF.

+0

Potrei usare qualche tipo di Intercettore? http://stackoverflow.com/questions/3165647/apache-cxf-how-to-add-custom-http-header-to-jax-rs-response?rq=1 – oligofren

risposta

7

Sì, è possibile utilizzare gli intercettatori per ottenere questo risultato se è possibile generare il tag E DOPO aver creato l'oggetto risposta.

public class MyInterceptor extends AbstractPhaseInterceptor<Message> { 

    public MyInterceptor() { 
     super(Phase.MARSHAL); 
    } 

    public final void handleMessage(Message message) { 
     MultivaluedMap<String, Object> headers = (MetadataMap<String, Object>) message.get(Message.PROTOCOL_HEADERS); 

     if (headers == null) { 
      headers = new MetadataMap<String, Object>(); 
     }    

     //generate E-tag here 
     String etag = getEtag(); 
     // 
     String cc = 600; 

     headers.add("E-Tag", etag); 
     headers.add("Cache-Control", cc); 
     message.put(Message.PROTOCOL_HEADERS, headers); 
    } 
} 

Se in questo modo non è praticabile, vorrei utilizzare la soluzione originale che hai postato, e basta aggiungere il soggetto persona al costruttore:

Person p = _dao.getPerson(name); 
return builder.entity(p).cacheControl(cc).lastModified(person.getUpdated()).build(); 
1

o può essere semplice come l'invio indietro un codice "errore" ... a seconda di cosa vuoi fare.

@Path("/{id}") 
@GET 
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) 
public ProductSearchResultBean getProductById(@PathParam("id") Integer productId, @QueryParam("expand") List<String> expand, @Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException { 

    ProductSearchResultBean productDetail = loadProductDetail(productId, expand); 

    EntityTag etag = new EntityTag(((Integer)(productDetail.toString().hashCode())).toString()); 
    String otherEtag = request.getHeader("ETag"); 
    if(etag.getValue().equals(otherEtag)){ 
     response.sendError(304, "not Modified"); 
    } 

    response.addHeader("ETag", etag.getValue()); 

    return productDetail; 
} 

Ecco come ho affrontato l'emissione in ogni caso. In bocca al lupo! (Usa Spring MVC invece ... c'è un filtro fuori dalla scatola che fa TUTTO per te ... anche facendo un buon ETag :))