]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-7082: Create a general mechanism for HTTP cache-control settings in the Services.
authorremillet <remillet@yahoo.com>
Mon, 6 Mar 2017 23:09:19 +0000 (15:09 -0800)
committerremillet <remillet@yahoo.com>
Mon, 6 Mar 2017 23:09:19 +0000 (15:09 -0800)
12 files changed:
services/authority/service/src/main/java/org/collectionspace/services/common/vocabulary/AuthorityResource.java
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java
services/blob/service/src/main/java/org/collectionspace/services/blob/BlobResource.java
services/common/src/main/cspace/config/services/tenants/tenant-bindings-proto-unified.xml
services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResourceImpl.java
services/common/src/main/java/org/collectionspace/services/common/AbstractMultiPartCollectionSpaceResourceImpl.java
services/common/src/main/java/org/collectionspace/services/common/NuxeoBasedResource.java
services/common/src/main/java/org/collectionspace/services/common/ServiceMessages.java
services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java
services/config/src/main/resources/service.xsd
services/media/service/src/main/java/org/collectionspace/services/media/MediaResource.java

index 6a71433e29accde1a475bde4279154929ad430b6..41d49dfb474b8d2f9ada1ff3f8281fbdd04578c1 100644 (file)
@@ -40,6 +40,7 @@ import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Response.ResponseBuilder;
 
 import org.collectionspace.services.client.IClientQueryParams;
 import org.collectionspace.services.client.IQueryManager;
@@ -417,14 +418,16 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
     @GET
     @Path("{csid}")
     @Override
-    public byte[] get(
+    public Response get(
             @Context Request request,
             @Context UriInfo uriInfo,
             @PathParam("csid") String specifier) {
+       Response result = null;
        uriInfo = new UriInfoWrapper(uriInfo);
-        PoxPayloadOut result = null;
+        PoxPayloadOut payloadout = null;
+        
         try {
-            ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(uriInfo);
+            ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(request, uriInfo);
             DocumentHandler<?, AbstractCommonList, DocumentModel, DocumentModelList> handler = createDocumentHandler(ctx);
 
             Specifier spec = Specifier.getSpecifier(specifier, "getAuthority", "GET");
@@ -439,20 +442,23 @@ public abstract class AuthorityResource<AuthCommon, AuthItemHandler>
                 handler.setDocumentFilter(myFilter);
                 getRepositoryClient(ctx).get(ctx, handler);
             }
-            result = ctx.getOutput();
-
+            
+            payloadout = ctx.getOutput();
+            ResponseBuilder responseBuilder = Response.ok(payloadout.getBytes());
+            this.setCacheControl(ctx, responseBuilder);
+            result = responseBuilder.build();            
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.GET_FAILED, specifier);
         }
 
         if (result == null) {
             Response response = Response.status(Response.Status.NOT_FOUND).entity(
-                    "Get failed, the requested Authority specifier:" + specifier + ": was not found.").type(
+                    "GET request failed. The requested Authority specifier:" + specifier + ": was not found.").type(
                     "text/plain").build();
             throw new CSWebApplicationException(response);
         }
 
-        return result.getBytes();
+        return result;
     }
 
     /**
index 0e510335c5a5afa94de89cb4a7bab61d0eabd774..b4ea9c4e5c15ea0642d6733bf58ceec2025f6690 100644 (file)
@@ -26,10 +26,8 @@ import org.collectionspace.services.common.NuxeoBasedResource;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.api.RefNameUtils;
 import org.collectionspace.services.common.api.Tools;
-import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.invocable.InvocationResults;
 import org.collectionspace.services.jaxb.AbstractCommonList;
-
 import org.dom4j.DocumentException;
 //import org.jboss.resteasy.specimpl.UriInfoImpl;
 import org.jdom.Document;
@@ -431,9 +429,21 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
     }
 
     protected PoxPayloadOut findByCsid(NuxeoBasedResource resource, String csid) throws URISyntaxException, DocumentException {
-        byte[] response = resource.get(null, createUriInfo(), csid);
-        PoxPayloadOut payload = new PoxPayloadOut(response);
-        return payload;
+       PoxPayloadOut result = null;
+       
+       try {
+                       result = resource.getResourceFromCsid(null, createUriInfo(), csid);
+               } catch (Exception e) {
+                       String msg = String.format("UpdateObjectLocation batch job could find/get resource CSID='%s' of type '%s'",
+                                       csid, resource.getServiceName());
+                       if (logger.isDebugEnabled()) {
+                               logger.debug(msg, e);
+                       } else {
+                               logger.error(msg);
+                       }
+               }
+       
+       return result;
     }
 
     protected UriInfo createUriInfo() throws URISyntaxException {
index cc86d029c16238c1e5cfa80bcddc458ace1fe834..25051d64771ee224d1110271c610294398a9aa00 100644 (file)
@@ -49,9 +49,11 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.CacheControl;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.UriInfo;
@@ -59,6 +61,8 @@ import javax.ws.rs.core.UriInfo;
 import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 //FIXME: REM - We should not have Nuxeo dependencies in our resource classes.
 
@@ -68,7 +72,8 @@ import java.util.Map;
 public class BlobResource extends NuxeoBasedResource {
        
        private static final int DEFAULT_MAX_CACHE_AGE = 86400; // 1 day of seconds.
-
+       private static final String DERIVATIVES_REGEX = "(\\w+)(/blobs/\\*/derivatives/)(\\w+)(/content)"; // matches things like 'GET/blobs/*/derivatives/Medium/content'
+       
        @Override
     public String getServiceName(){
         return BlobClient.SERVICE_NAME;
@@ -158,13 +163,14 @@ public class BlobResource extends NuxeoBasedResource {
     
     /*
      * This method can replace the 'createBlob' -specifically, this JAX-RS technique can replace the call to
-     * the BlobInput.createBlobFile() method.  In theory, this should reduce by 1 the number of time we need to copy
+     * the BlobInput.createBlobFile() method.  In theory, this should reduce by 1 the number of times we need to copy
      * bits around.
      */
     @POST
     @Path("{csid}/prototype")
     @Consumes("multipart/form-data")
     @Produces(MediaType.TEXT_PLAIN)
+    @Deprecated
     public Response prototype(@PathParam("csid") String csid,
                @Context HttpServletRequest req,
                @QueryParam(BlobClient.BLOB_URI_PARAM) String blobUri,
@@ -241,12 +247,28 @@ public class BlobResource extends NuxeoBasedResource {
                return response;
     }    
     
+    /**
+     * If there is no explicit setting in the Blobs service binding, we'll ask the HTTP client to cache blobs for 1 full day.
+     * @param ctx
+     * @param cacheKey
+     * @return
+     */
     @Override
-    protected int getCacheMaxAge(ServiceContext ctx) {
-       int result = super.getCacheMaxAge(ctx);
+    protected CacheControl getCacheControl(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx, String cacheKey) {
+       CacheControl result = null;
+       
+       if (cacheKey.matches(DERIVATIVES_REGEX)) {
+               Pattern p = Pattern.compile(DERIVATIVES_REGEX);
+               Matcher m = p.matcher(cacheKey);
+               if (m.find()) {
+                       cacheKey = String.format("%s%s*%s", m.group(1), m.group(2), m.group(4));  // Converts something like this "GET/blobs/*/derivatives/Medium/content" into this "GET/blobs/*/derivatives/*/content"
+               }
+       }
        
-       if (result <= 0) {
-               result = this.DEFAULT_MAX_CACHE_AGE;
+       result = super.getCacheControl(ctx, cacheKey);
+       if (result == null) {
+               result = new CacheControl();
+               result.setMaxAge(DEFAULT_MAX_CACHE_AGE);
        }
        
        return result;
@@ -254,12 +276,15 @@ public class BlobResource extends NuxeoBasedResource {
     
     @GET
     @Path("{csid}/content")
-    public Response getBlobContent(    @PathParam("csid") String csid) {
+    public Response getBlobContent(
+               @PathParam("csid") String csid,
+               @Context Request jaxRsRequest,
+               @Context UriInfo uriInfo) {
        Response result = null;
-       ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
+       ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null; 
        
        try {
-               ctx = createServiceContext();
+               ctx = createServiceContext(jaxRsRequest, uriInfo);
                        BlobsCommon blobsCommon = getBlobsCommon(csid);
                StringBuffer mimeType = new StringBuffer();
                InputStream contentStream = getBlobContent(ctx, csid, null /*derivative term*/, mimeType /*will get set*/);
@@ -276,7 +301,7 @@ public class BlobResource extends NuxeoBasedResource {
        return result;
     }
     
-    private BlobsCommon getBlobsCommon(String csid) throws Exception {
+       private BlobsCommon getBlobsCommon(String csid) throws Exception {
        BlobsCommon result = null;
        
        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext();
@@ -341,15 +366,20 @@ public class BlobResource extends NuxeoBasedResource {
     @Path("{csid}/derivatives/{derivativeTerm}/content")
     public Response getDerivativeContent(
                @PathParam("csid") String csid,
-               @PathParam("derivativeTerm") String derivativeTerm) {
+               @PathParam("derivativeTerm") String derivativeTerm,
+               @Context Request jaxRsRequest,
+               @Context UriInfo uriInfo) {
        Response result = null;
        ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = null;
        
                try {
-                       ctx = createServiceContext();
+                       // Setup the call to get the blob derivative
+                       ctx = createServiceContext(jaxRsRequest, uriInfo);
                                BlobsCommon blobsCommon = getBlobsCommon(csid);
                        StringBuffer mimeType = new StringBuffer();
+                       // Get the blob derivative from Nuxeo
                        InputStream contentStream = getBlobContent(ctx, csid, derivativeTerm, mimeType);
+                       // Build a response
                            Response.ResponseBuilder responseBuilder = Response.ok(contentStream, mimeType.toString());
                            setCacheControl(ctx, responseBuilder);
                        responseBuilder = responseBuilder.header("Content-Disposition","inline;filename=\""
@@ -358,7 +388,7 @@ public class BlobResource extends NuxeoBasedResource {
                } catch (Exception e) {
                        throw bigReThrow(e, ServiceMessages.CREATE_FAILED);
                }
-               
+
            return result;
     }
     
index d3511febc03e8ce496a9edbf69f4574f8ca6745f..b373c5d8536e8abe13d538eb2f081e84856b1240 100644 (file)
                        </service:documentHandler>
                        <service:DocHandlerParams xmlns:service="http://collectionspace.org/services/config/service">
                                <service:params>
-                                   <service:CacheMaxAge>86400</service:CacheMaxAge> <!-- By default, cache blobs for 1 full day -->
+                           <service:CacheControlConfigElement> <!-- See service.xsd XML Schema definitation for all potential cache settings -->
+                               <service:CacheControlConfigList>
+                                   <service:key>GET/blobs/*/content</service:key>
+                                   <service:maxAge>86401</service:maxAge> <!-- By default, cache blobs for 1 full day -->
+                               </service:CacheControlConfigList>
+                               <service:CacheControlConfigList>
+                                   <service:key>GET/blobs/*/derivatives/*/content</service:key>
+                                   <service:maxAge>86402</service:maxAge> <!-- By default, cache blobs for 1 full day -->
+                               </service:CacheControlConfigList>
+                       </service:CacheControlConfigElement>
                                        <service:ListResultsFields>
                                                <service:ListResultField>
                                                        <service:element>name</service:element>
index 74284e5a597e4144bcdab6ec85c146a70ad4cd81..1a5dde637f3b273d2640fc874269f39545ba48f3 100644 (file)
@@ -23,7 +23,6 @@
  */
 package org.collectionspace.services.common;
 
-import java.math.BigInteger;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -34,10 +33,13 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.CacheControl;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.services.client.CollectionSpaceClient;
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.CSWebApplicationException;
 import org.collectionspace.services.common.api.Tools;
 import org.collectionspace.services.common.config.ServiceConfigUtils;
@@ -51,13 +53,15 @@ import org.collectionspace.services.common.document.DocumentNotFoundException;
 import org.collectionspace.services.common.document.TransactionException;
 import org.collectionspace.services.common.repository.RepositoryClient;
 import org.collectionspace.services.common.repository.RepositoryClientFactory;
+import org.collectionspace.services.common.security.SecurityUtils;
 import org.collectionspace.services.common.security.UnauthorizedException;
 import org.collectionspace.services.common.storage.StorageClient;
 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
+import org.collectionspace.services.config.service.CacheControlConfig;
+import org.collectionspace.services.config.service.DocHandlerParams.Params.CacheControlConfigElement;
 import org.collectionspace.services.config.service.ServiceBindingType;
 import org.collectionspace.services.config.service.DocHandlerParams.Params;
 import org.collectionspace.services.description.ServiceDescription;
-
 import org.jboss.resteasy.spi.HttpRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -162,6 +166,14 @@ public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
         return docHandler;
     }    
     
+    protected ServiceContext<IT, OT> createServiceContext(Request requestInfo, UriInfo uriInfo) throws Exception {
+       ServiceContext<IT, OT> result = this.createServiceContext(uriInfo);
+
+       result.setRequestInfo(requestInfo);
+
+       return result;
+       }
+    
     /**
      * Creates the service context.
      * 
@@ -650,35 +662,105 @@ public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
     }
     
     /**
-     * Get max cache age for HTTP responses from the tenant's service bindings.
-     * 
-     * @param ctx
+     * Find a named CacheControlConfig instance.
+     * @param element
+     * @param cacheKey
      * @return
      */
-    protected int getCacheMaxAge(ServiceContext<IT, OT> ctx) {
-       BigInteger result = null;
+    private CacheControlConfig getCacheControl(CacheControlConfigElement element, String cacheKey) {
+       CacheControlConfig result = null;
+       
+       List<CacheControlConfig> list = element.getCacheControlConfigList();
+       for (CacheControlConfig cacheControlConfig : list) {
+               if (cacheControlConfig.getKey().equalsIgnoreCase(cacheKey)) {
+                       result = cacheControlConfig;
+                       break;
+               }
+       }
+       
+       return result;
+    }
+    
+    /*
+     * By default, use the request's URI and HTTP method to form the cache-key to use when looking up the
+     * cache control configuration from the service bindings
+     */
+    protected CacheControl getDefaultCacheControl(ServiceContext<IT, OT> ctx) {
+       UriInfo uriInfo = ctx.getUriInfo();
+       Request requestInfo = ctx.getRequestInfo();
+       
+       if (uriInfo != null && requestInfo != null) try {
+               String resName = SecurityUtils.getResourceName(uriInfo);
+               String requestMethod = requestInfo.getMethod();
+               return getCacheControl(ctx, String.format("%s/%s", requestMethod, resName));  // example, "GET/blobs/*/content"
+       } catch (Exception e) {
+               logger.debug(e.getMessage(), e);
+       }
+       
+       return getCacheControl(ctx, "default"); // Look for a default one if we couldn't find based on the resource request
+    }
+    
+    protected CacheControl getCacheControl(ServiceContext<IT, OT> ctx, String cacheKey) {
+       CacheControl result = null;
        
        try {
                        Params docHandlerParams = ServiceConfigUtils.getDocHandlerParams(ctx.getTenantId(), ctx.getServiceName());
-                       if (docHandlerParams.getCacheMaxAge() != null) {
-                               result = docHandlerParams.getCacheMaxAge();
+                       CacheControlConfig cacheControlConfig = getCacheControl(docHandlerParams.getCacheControlConfigElement(), cacheKey);
+                       if (cacheControlConfig != null) {
+                               result = new CacheControl();
+                               
+                               if (cacheControlConfig.isPrivate() != null) {
+                                       result.setPrivate(cacheControlConfig.isPrivate());
+                               }
+                               
+                               if (cacheControlConfig.isNoCache() != null) {
+                                       result.setNoCache(cacheControlConfig.isNoCache());
+                               }
+                               
+                               if (cacheControlConfig.isProxyRevalidate() != null) {
+                                       result.setProxyRevalidate(cacheControlConfig.isProxyRevalidate());
+                               }
+                               
+                               if (cacheControlConfig.isMustRevalidate() != null) {
+                                       result.setMustRevalidate(cacheControlConfig.isMustRevalidate());
+                               }
+                               
+                               if (cacheControlConfig.isNoStore() != null) {
+                                       result.setNoStore(cacheControlConfig.isNoStore());
+                               }
+                               
+                               if (cacheControlConfig.isNoTransform() != null) {
+                                       result.setNoTransform(cacheControlConfig.isNoTransform());
+                               }
+                               
+                               if (cacheControlConfig.getMaxAge() != null) { 
+                                       result.setMaxAge(cacheControlConfig.getMaxAge().intValue());
+                               }
+                               
+                               if (cacheControlConfig.getSMaxAge() != null) {
+                                       result.setSMaxAge(cacheControlConfig.getSMaxAge().intValue());
+                               }
                        }
                } catch (DocumentException e) {
-                       logger.debug("Failed to retrieve cache-age-max from service bindings.", e);
+                       result = null;
+                       logger.debug(String.format("Failed to retrieve CacheControlConfig with key '%s' from service bindings '%s'.", cacheKey, ctx.getServiceName()), e);
+               } catch (NullPointerException npe) {
+                       result = null;
+                       //
+                       // NPE might mean optional cache-control config is missing -that's usually ok.
+                       logger.trace(npe.getLocalizedMessage(), npe);
                }
 
-       return result != null ? result.intValue() : 0;
+       return result;
     }
     
     protected Response.ResponseBuilder setCacheControl(ServiceContext<IT, OT> ctx, Response.ResponseBuilder responseBuilder) {
-       int cacheMaxAge = getCacheMaxAge(ctx);
+       CacheControl cacheControl = getDefaultCacheControl(ctx);
        
-       if (cacheMaxAge > 0) {
-               CacheControl cacheControl = new CacheControl();
-                       cacheControl.setMaxAge(getCacheMaxAge(ctx));
+       if (cacheControl != null) {
                        responseBuilder.cacheControl(cacheControl);
-               logger.debug(String.format("Cache-max-age for service '%s' is set to '%d' in the service bindings for tenant ID='%s'.",
-                               ctx.getServiceName(), cacheMaxAge, ctx.getTenantId()));
+               logger.debug(String.format("Setting default CacheControl for service '%s' responses from the service bindings for tenant ID='%s'.",
+                               ctx.getServiceName(), ctx.getTenantId()));
        }
        
        return responseBuilder;
index 7d5d1810aabb1a15440d93a43ab6091e8aa6bbaa..74e3bc8fbe7ecfcc13f94e90c6ff5b2fa5aa9a7b 100644 (file)
@@ -34,6 +34,7 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Request;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.services.client.PayloadOutputPart;
@@ -146,7 +147,7 @@ public abstract class AbstractMultiPartCollectionSpaceResourceImpl extends Abstr
      */
     @GET
     @Path(WorkflowClient.SERVICE_PATH)
-    public Lifecycle getWorkflow(@Context UriInfo uriInfo) {
+    public Lifecycle getWorkflow(@Context Request jaxRsRequest, @Context UriInfo uriInfo) {
        Lifecycle result;
 
         String documentType = "undefined";
index 14cc33603e76077684b809121c1da83b595ed58c..37508b209be7c3e9175de862602787944a9d6d2c 100644 (file)
@@ -331,28 +331,42 @@ public abstract class NuxeoBasedResource
     //======================= GET ====================================================
     @GET
     @Path("{csid}")
-    public byte[] get(
+    public Response get(
             @Context Request request,
             @Context UriInfo uriInfo,
             @PathParam("csid") String csid) {
        uriInfo = new UriInfoWrapper(uriInfo);
         PoxPayloadOut result = null;
-        ensureCSID(csid, READ);
+        
         try {
-            RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(uriInfo);
-            result = get(csid, ctx);// ==> CALL implementation method, which subclasses may override.
-            if (result == null) {
-                Response response = Response.status(Response.Status.NOT_FOUND).entity(
-                        ServiceMessages.READ_FAILED + ServiceMessages.resourceNotFoundMsg(csid)).type("text/plain").build();
-                throw new CSWebApplicationException(response);
-            }
+            result = getResourceFromCsid(request, uriInfo, csid);
         } catch (Exception e) {
             throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
         }
+        
+        if (result == null) {
+            Response response = Response.status(Response.Status.NOT_FOUND).entity(
+                    ServiceMessages.READ_FAILED + ServiceMessages.resourceNotFoundMsg(csid)).type("text/plain").build();
+            throw new CSWebApplicationException(response);
+        }        
 
-        return result.getBytes();
+        return Response.ok(result.getBytes()).build();
     }
     
+    public PoxPayloadOut getResourceFromCsid(
+            Request request,
+            UriInfo uriInfo,
+            String csid) throws Exception {
+        PoxPayloadOut result = null;
+        
+        ensureCSID(csid, READ);
+        RemoteServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = 
+                       (RemoteServiceContext<PoxPayloadIn, PoxPayloadOut>) createServiceContext(request, uriInfo);
+        result = get(csid, ctx);// ==> CALL an implementation method, which subclasses may override.
+
+        return result;
+    }    
+    
     /**
      * Call this method only from other resources (like the Service Groups resource) obtained from the global resource map (ResourceMap).  If the a parent
      * context exists and it has an open Nuxeo repository session, we will use it; otherwise, we will create a new one.
index 3df268caf942078323d3330ca993005a2b4662bd..630bff3c4b9058bedc710891d1b42c23f1d30d4a 100644 (file)
@@ -33,28 +33,28 @@ package org.collectionspace.services.common;
  */
 public class ServiceMessages {
 
-    private static final String FAILED = "failed: ";
-    private static final String UNSUPPORTED = "unsupported: ";
+    private static final String FAILED = " failed: ";
+    private static final String UNSUPPORTED = " unsupported: ";
 
-    public static final String POST_FAILED = "POST " + FAILED;
-    public static final String GET_FAILED = "GET " + FAILED;
-    public static final String PUT_FAILED = "PUT " + FAILED;
+    public static final String POST_FAILED = "POST request" + FAILED;
+    public static final String GET_FAILED = "GET request" + FAILED;
+    public static final String PUT_FAILED = "PUT request" + FAILED;
     
-    public static final String CREATE_FAILED = "Create request " + FAILED;
-    public static final String READ_FAILED = "Read request " + FAILED;
-    public static final String REINDEX_FAILED = "Reindex request " + FAILED;
-    public static final String UPDATE_FAILED = "Update request " + FAILED;
+    public static final String CREATE_FAILED = "Create request" + FAILED;
+    public static final String READ_FAILED = "Read request" + FAILED;
+    public static final String REINDEX_FAILED = "Reindex request" + FAILED;
+    public static final String UPDATE_FAILED = "Update request" + FAILED;
     
-    public static final String POST_UNSUPPORTED = "POST " + UNSUPPORTED;
-    public static final String GET_UNSUPPORTED = "GET " + UNSUPPORTED;
-    public static final String GET_LIST_UNSUPPORTED = "GET/LIST " + UNSUPPORTED;
-    public static final String PUT_UNSUPPORTED = "PUT " + UNSUPPORTED;
-    public static final String DELETE_UNSUPPORTED = "DELETE " + UNSUPPORTED;
+    public static final String POST_UNSUPPORTED = "POST request" + UNSUPPORTED;
+    public static final String GET_UNSUPPORTED = "GET request" + UNSUPPORTED;
+    public static final String GET_LIST_UNSUPPORTED = "GET/LIST request" + UNSUPPORTED;
+    public static final String PUT_UNSUPPORTED = "PUT request" + UNSUPPORTED;
+    public static final String DELETE_UNSUPPORTED = "DELETE request" + UNSUPPORTED;
 
-    public static final String DELETE_FAILED = "Delete request " + FAILED;
-    public static final String LIST_FAILED = "List request " + FAILED;
-    public static final String SEARCH_FAILED = "Search request " + FAILED;
-    public static final String AUTH_REFS_FAILED = "Authority references request " + FAILED;
+    public static final String DELETE_FAILED = "Delete request" + FAILED;
+    public static final String LIST_FAILED = "List request" + FAILED;
+    public static final String SEARCH_FAILED = "Search request" + FAILED;
+    public static final String AUTH_REFS_FAILED = "Authority references request" + FAILED;
     
     public static final String UNKNOWN_ERROR_MSG = "Unknown error ";
     public static final String VALIDATION_FAILURE = "Validation failure ";
index d44059fdba5db23c462e7431772a6ee917fbe454..75af571d730438335946727788d103a3f7fd3d8d 100644 (file)
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.Properties;
 
 import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.authentication.spi.AuthNContext;
@@ -108,6 +109,8 @@ public abstract class AbstractServiceContextImpl<IT, OT>
     private SecurityContext securityContext;
     /** The sessions JAX-RS URI information */
     private UriInfo uriInfo;
+    /** The JAX-RS request information */
+    private Request requestInfo;
     /** The current repository session */
     private Object currentRepositorySession;
     /** A reference count for the current repository session */
@@ -843,6 +846,16 @@ public abstract class AbstractServiceContextImpl<IT, OT>
                return this.uriInfo;
        }
        
+       @Override
+       public Request getRequestInfo() {
+               return this.requestInfo;
+       }
+       
+       @Override
+       public void setRequestInfo(Request requestInfo) {
+               this.requestInfo = requestInfo;
+       }
+       
        /*
         * We expect the 'currentRepositorySession' member to be set only once per instance.  Also, we expect only one open repository session
         * per HTTP request.  We'll log an error if we see more than one attempt to set a service context's current repo session.
index 206d7ef5ac51c413c09b00aa8ad6304be76552a8..5027ac75ef369338702f2626ce873293f0abcb1e 100644 (file)
@@ -27,11 +27,10 @@ import java.util.List;
 import java.util.Map;
 
 import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.services.client.CollectionSpaceClient;
-import org.collectionspace.services.client.PoxPayloadIn;
-import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.CollectionSpaceResource;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.document.DocumentHandler;
@@ -255,6 +254,12 @@ public interface ServiceContext<IT, OT> {
      * @param map the map of service names to resource instances.
      */
     public void setResourceMap(ResourceMap map);
+    
+    /**
+     * 
+     * @param jaxsRsRequest - Keep track of the JAX-RS request information
+     */
+    public void setRequestInfo(Request jaxsRsRequest);
 
     /**
      * getPartsMetadata returns metadata for object parts used by the service
@@ -395,6 +400,12 @@ public interface ServiceContext<IT, OT> {
         * @return
         */
        public boolean shouldForceSync();
+
+       /**
+        * 
+        * @return The JAX-RS request information
+        */
+       Request getRequestInfo();
 }
 
 
index ea6682df231ed073d0d053a576fe200522f191ff..6d46597503f27757c08c9fcfbd12353a8e18c9c5 100644 (file)
             <xs:element name="params">
                 <xs:complexType>
                     <xs:sequence>
-                        <xs:element name="CacheMaxAge" type="xs:integer" minOccurs="0" maxOccurs="1" default="86400"/>  <!-- default of 1 day -->
+                       <xs:element name="CacheControlConfigElement" minOccurs="0" maxOccurs="1"> <!-- Create a cache control setting for a service's responses.  You can have different ones for different responses. -->
+                            <xs:complexType>
+                                <xs:sequence>
+                                    <xs:element name="CacheControlConfigList" type="CacheControlConfig" minOccurs="0" maxOccurs="unbounded"/>
+                                </xs:sequence>
+                            </xs:complexType>
+                        </xs:element>
                         <xs:element name="SchemaName" type="xs:string" minOccurs="0" maxOccurs="1"/>
                         <xs:element name="RefnameDisplayNameField" type="ListResultField" minOccurs="0" maxOccurs="1"/>  <!-- Should rename 'ListResultField' to a more generic name -->
                         <xs:element name="SupportsHierarchy" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/>
         </xs:sequence>
     </xs:complexType>
 
-
-
-
+    <xs:complexType name="CacheControlConfig">
+        <xs:sequence>
+               <xs:element name="key" type="xs:string" minOccurs="1" maxOccurs="1" default="default"/>                         <!-- The lookup name CSpace used to find these settings.  Set to "default" by default, but pick a unique name among sibling items. -->
+            <xs:element name="private" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/>                 <!-- only clients (mostly the browser) and no one else in the chain (like a proxy) should cache this -->
+            <xs:element name="public" type="xs:boolean" minOccurs="0" maxOccurs="1" default="true"/>                   <!-- any entity in the chain can cache this -->
+            <xs:element name="noCache" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/>                 <!-- should not be cached in any way/method -->
+            <xs:element name="mustRevalidate" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/>  <!-- See http://bit.ly/2mnCwIi -->
+            <xs:element name="proxyRevalidate" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/> 
+            <xs:element name="noStore" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/>                 <!-- can be cached but should not be stored on disk (most browsers will hold the resources in memory until they will be quit) -->
+            <xs:element name="noTransform" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false"/>             <!-- the resource should not be modified (for example shrink image by proxy) -->
+            <xs:element name="maxAge" type="xs:integer" minOccurs="0" maxOccurs="1" default="86400"/>                  <!-- how long the resource is valid (measured in seconds) -->
+            <xs:element name="sMaxAge" type="xs:integer" minOccurs="0" maxOccurs="1" default="-1"/>                            <!-- same like max-age but this value is just for non clients -->
+        </xs:sequence>
+    </xs:complexType>
 
 </xs:schema>
index b82573f757ad75cb1d1cfc1077eef750894fd12c..bc8de5746bbc534a398c879c15aa11c9d362c86d 100644 (file)
@@ -54,6 +54,7 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
@@ -299,13 +300,15 @@ public class MediaResource extends NuxeoBasedResource {
     @GET
     @Path("{csid}/blob/content")
     public Response getBlobContent(
-               @PathParam("csid") String csid) {
+               @PathParam("csid") String csid,
+               @Context Request requestInfo,
+               @Context UriInfo uriInfo) {
        Response result = null;
        
            try {
                ensureCSID(csid, READ);
                String blobCsid = this.getBlobCsid(csid);
-               result = getBlobResource().getBlobContent(blobCsid);            
+               result = getBlobResource().getBlobContent(blobCsid, requestInfo, uriInfo);              
            } catch (Exception e) {
                throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
            }
@@ -317,13 +320,15 @@ public class MediaResource extends NuxeoBasedResource {
     @Path("{csid}/blob/derivatives/{derivativeTerm}/content")
     public Response getDerivativeContent(
                @PathParam("csid") String csid,
-               @PathParam("derivativeTerm") String derivativeTerm) {
+               @PathParam("derivativeTerm") String derivativeTerm,
+               @Context Request requestInfo,
+               @Context UriInfo uriInfo) {
        Response result = null;
        
            try {
                ensureCSID(csid, READ);
                String blobCsid = this.getBlobCsid(csid);
-               result = getBlobResource().getDerivativeContent(blobCsid, derivativeTerm);              
+               result = getBlobResource().getDerivativeContent(blobCsid, derivativeTerm, requestInfo, uriInfo);                
            } catch (Exception e) {
                throw bigReThrow(e, ServiceMessages.READ_FAILED, csid);
            }