cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject cxf git commit: [CXF-5996] Better support for reading caching various entity types
Date Wed, 26 Nov 2014 17:48:21 GMT
Repository: cxf
Updated Branches:
  refs/heads/3.0.x-fixes 2b3a7b173 -> a77eeb984


[CXF-5996] Better support for reading caching various entity types


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/a77eeb98
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/a77eeb98
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/a77eeb98

Branch: refs/heads/3.0.x-fixes
Commit: a77eeb9848dce575079a76a8a8a12981679dbc6b
Parents: 2b3a7b1
Author: Sergey Beryozkin <sberyozkin@talend.com>
Authored: Wed Nov 26 15:06:34 2014 +0000
Committer: Sergey Beryozkin <sberyozkin@talend.com>
Committed: Wed Nov 26 17:48:05 2014 +0000

----------------------------------------------------------------------
 rt/rs/client/pom.xml                            |  15 +-
 .../cxf/jaxrs/client/cache/BytesEntity.java     |  47 ++++++
 .../CacheControlClientReaderInterceptor.java    | 109 +++++++++---
 .../cache/CacheControlClientRequestFilter.java  |  14 +-
 .../jaxrs/client/cache/CacheControlFeature.java |  34 ++--
 .../cxf/jaxrs/client/cache/ClientCache.java     |  32 ----
 .../apache/cxf/jaxrs/client/cache/Entry.java    |  10 +-
 .../cxf/jaxrs/client/cache/ClientCacheTest.java | 165 +++++++++++++++++--
 8 files changed, 335 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/pom.xml
----------------------------------------------------------------------
diff --git a/rt/rs/client/pom.xml b/rt/rs/client/pom.xml
index 9552789..68d3010 100644
--- a/rt/rs/client/pom.xml
+++ b/rt/rs/client/pom.xml
@@ -83,7 +83,7 @@
 	      <version>1.0-alpha-1</version>
 	      <scope>provided</scope>
 	      <optional>true</optional>
-	    </dependency>
+	</dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
@@ -102,6 +102,12 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>${cxf.servlet-api.group}</groupId>
+            <artifactId>${cxf.servlet-api.artifact}</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl-over-slf4j</artifactId>
             <scope>test</scope>
@@ -111,6 +117,13 @@
             <artifactId>slf4j-jdk14</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-databinding-jaxb</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
 <!--
         <dependency>
           <groupId>org.apache.commons</groupId>

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/BytesEntity.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/BytesEntity.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/BytesEntity.java
new file mode 100644
index 0000000..91e8c6c
--- /dev/null
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/BytesEntity.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.client.cache;
+
+import java.io.Serializable;
+
+public class BytesEntity implements Serializable {
+    
+    private static final long serialVersionUID = -6010007172900653981L;
+    private byte[] entity; 
+    private boolean fromStream;
+    public BytesEntity() {
+        
+    }
+    public BytesEntity(byte[] entity, boolean fromStream) {
+        this.entity = entity;
+        this.setFromStream(fromStream);
+    }
+    public byte[] getEntity() {
+        return entity;
+    }
+    public void setEntity(byte[] entity) {
+        this.entity = entity;
+    }
+    public boolean isFromStream() {
+        return fromStream;
+    }
+    public void setFromStream(boolean fromStream) {
+        this.fromStream = fromStream;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientReaderInterceptor.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientReaderInterceptor.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientReaderInterceptor.java
index 8c9e1f6..1cba11f 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientReaderInterceptor.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientReaderInterceptor.java
@@ -18,7 +18,10 @@
  */
 package org.apache.cxf.jaxrs.client.cache;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
 import java.net.URI;
 import java.text.ParseException;
 import java.util.HashMap;
@@ -36,16 +39,17 @@ import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.ReaderInterceptor;
 import javax.ws.rs.ext.ReaderInterceptorContext;
 
+import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.transport.http.Headers;
 
-@ClientCache
 @Priority(Priorities.USER - 1)
 public class CacheControlClientReaderInterceptor implements ReaderInterceptor {
     private Cache<Key, Entry> cache;
 
     @Context
     private UriInfo uriInfo;
-
+    private boolean cacheResponseInputStream;
+    
     public CacheControlClientReaderInterceptor(final Cache<Key, Entry> cache) {
         setCache(cache);
     }
@@ -61,21 +65,50 @@ public class CacheControlClientReaderInterceptor implements ReaderInterceptor
{
 
     @Override
     public Object aroundReadFrom(final ReaderInterceptorContext context) throws IOException,
WebApplicationException {
-        if (Boolean.parseBoolean((String)context.getProperty("no_client_cache"))) {
+        Object cachedEntity = context.getProperty(CacheControlClientRequestFilter.CACHED_ENTITY_PROPERTY);
+        if (cachedEntity != null) {
+            if (cachedEntity instanceof BytesEntity) {
+                // InputStream or byte[]
+                BytesEntity bytesEntity = (BytesEntity)cachedEntity;
+                byte[] bytes = bytesEntity.getEntity();
+                cachedEntity = bytesEntity.isFromStream() ? new ByteArrayInputStream(bytes)
: bytes;
+                if (cacheResponseInputStream) {
+                    InputStream is = bytesEntity.isFromStream() ? (InputStream)cachedEntity

+                        : new ByteArrayInputStream((byte[])cachedEntity); 
+                    context.setInputStream(is);
+                    return context.proceed();
+                }
+            }
+            return cachedEntity;
+        }
+        
+        if (Boolean.parseBoolean((String)context.getProperty(CacheControlClientRequestFilter.NO_CACHE_PROPERTY)))
{
+            // non GET HTTP method or other restriction applies
             return context.proceed();
         }
         final MultivaluedMap<String, String> headers = context.getHeaders(); 
         final String cacheControlHeader = headers.getFirst(HttpHeaders.CACHE_CONTROL);
-        String expiresHeader = headers.getFirst(HttpHeaders.EXPIRES);
+        final CacheControl cacheControl = CacheControl.valueOf(cacheControlHeader.toString());
         
-        long expiry = -1;
-        if (cacheControlHeader != null) {
-            final CacheControl value = CacheControl.valueOf(cacheControlHeader.toString());
-            if (value.isNoCache()) {
-                return context.proceed();
-            }
-            expiry = value.getMaxAge();
-        } else if (expiresHeader != null) {
+        byte[] cachedBytes = null;
+        if (cacheControl != null && !cacheControl.isNoCache() && !cacheControl.isNoStore()

+            && cacheResponseInputStream) {
+            // if Cache-Control is set and the stream needs to be cached then do it
+            cachedBytes = IOUtils.readBytesFromStream((InputStream)context.getInputStream());
+            context.setInputStream(new ByteArrayInputStream(cachedBytes));
+        }
+        // Read the stream and get the actual entity
+        Object responseEntity = context.proceed();
+        
+        if (cacheControl == null || cacheControl.isNoCache() || cacheControl.isNoStore())
{
+            // TODO: apparently no-cache also means the local cache has to be revalidated
+            return responseEntity;
+        }
+        // if a max-age property is set then it overrides Expires
+        long expiry = cacheControl.getMaxAge();
+        if (expiry == -1) {
+            //TODO: Review if Expires can be supported as an alternative to Cache-Control
+            String expiresHeader = headers.getFirst(HttpHeaders.EXPIRES);
             if (expiresHeader.startsWith("'") && expiresHeader.endsWith("'")) {
                 expiresHeader = expiresHeader.substring(1, expiresHeader.length() - 1);
             }
@@ -83,22 +116,33 @@ public class CacheControlClientReaderInterceptor implements ReaderInterceptor
{
                 expiry = (Headers.getHttpDateFormat().parse(expiresHeader).getTime() 
                     - System.currentTimeMillis()) / 1000;
             } catch (final ParseException e) {
-                // try next
+                // TODO: Revisit the possibility of supporting multiple formats 
             }
-            
-        } else { // no cache
-            return context.proceed();
+        }
+        Serializable ser = null;
+        if (cachedBytes != null) {
+            // store the cached bytes - they will be parsed again when a client cache will
return them
+            ser = new BytesEntity(cachedBytes, responseEntity instanceof InputStream);
+        } else if (responseEntity instanceof Serializable) {
+            // store the entity directly
+            ser = (Serializable)responseEntity;
+        } else if (responseEntity instanceof InputStream) {
+            // read the stream, cache it, the cached bytes will be returned immediately
+            // when a client cache will return them
+            byte[] bytes = IOUtils.readBytesFromStream((InputStream)responseEntity);
+            ser = new BytesEntity(bytes, true);
+            responseEntity = new ByteArrayInputStream(bytes);
+        } else if (responseEntity instanceof byte[]) {
+            // the cached bytes will be returned immediately when a client cache will return
them
+            ser = new BytesEntity((byte[])responseEntity, false);
         }
 
-        final Object proceed = context.proceed();
-        
-        final Entry entry = new Entry(((String)proceed).getBytes(), context.getHeaders(),

-                                      computeCacheHeaders(context.getHeaders()), expiry);
+        final Entry entry = new Entry(ser, context.getHeaders(), computeCacheHeaders(context.getHeaders()),
expiry);
         final URI uri = uriInfo.getRequestUri();
-        final String accepts = headers.getFirst(HttpHeaders.ACCEPT);
+        final String accepts = (String)context.getProperty(CacheControlClientRequestFilter.CLIENT_ACCEPTS);
         cache.put(new Key(uri, accepts), entry);
 
-        return proceed;
+        return responseEntity;
     }
 
     private Map<String, String> computeCacheHeaders(final MultivaluedMap<String,
String> httpHeaders) {
@@ -106,13 +150,30 @@ public class CacheControlClientReaderInterceptor implements ReaderInterceptor
{
 
         final String etagHeader = httpHeaders.getFirst(HttpHeaders.ETAG);
         if (etagHeader != null) {
-            cacheHeaders.put("If-None-Match", etagHeader);
+            cacheHeaders.put(HttpHeaders.IF_NONE_MATCH, etagHeader);
         }
         final String lastModifiedHeader = httpHeaders.getFirst(HttpHeaders.LAST_MODIFIED);
         if (lastModifiedHeader != null) {
-            cacheHeaders.put("If-Modified-Since", lastModifiedHeader);
+            cacheHeaders.put(HttpHeaders.IF_MODIFIED_SINCE, lastModifiedHeader);
         }
 
         return cacheHeaders;
     }
+
+    public boolean isCacheInputStream() {
+        return cacheResponseInputStream;
+    }
+    /**
+     * Enforce the caching of the response stream. 
+     * This is not recommended if the client code expects Serializable data,
+     * example, String or custom JAXB beans marked as Serializable, 
+     * which can be stored in the cache directly.
+     * Use this property only if returning a cached entity does require a 
+     * repeated stream parsing.
+     * 
+     * @param cacheInputStream
+     */
+    public void setCacheResponseInputStream(boolean cacheInputStream) {
+        this.cacheResponseInputStream = cacheInputStream;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientRequestFilter.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientRequestFilter.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientRequestFilter.java
index 3656c9f..0e46d17 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientRequestFilter.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlClientRequestFilter.java
@@ -25,15 +25,18 @@ import java.util.Map;
 
 import javax.annotation.Priority;
 import javax.cache.Cache;
+import javax.ws.rs.HttpMethod;
 import javax.ws.rs.Priorities;
 import javax.ws.rs.client.ClientRequestContext;
 import javax.ws.rs.client.ClientRequestFilter;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 
-@ClientCache
 @Priority(Priorities.USER - 1)
 public class CacheControlClientRequestFilter implements ClientRequestFilter {
+    public static final String NO_CACHE_PROPERTY = "no_client_cache";
+    public static final String CACHED_ENTITY_PROPERTY = "client_cached_entity";
+    public static final String CLIENT_ACCEPTS = "client_accepts";
     private Cache<Key, Entry> cache;
 
     public CacheControlClientRequestFilter(final Cache<Key, Entry> cache) {
@@ -46,8 +49,8 @@ public class CacheControlClientRequestFilter implements ClientRequestFilter
{
 
     @Override
     public void filter(final ClientRequestContext request) throws IOException {
-        if (!"GET".equals(request.getMethod())) {
-            request.setProperty("no_client_cache", "true");
+        if (!HttpMethod.GET.equals(request.getMethod())) {
+            request.setProperty(NO_CACHE_PROPERTY, "true");
             return;
         }
         final URI uri = request.getUri();
@@ -58,7 +61,8 @@ public class CacheControlClientRequestFilter implements ClientRequestFilter
{
             if (entry.isOutDated()) {
                 cache.remove(key, entry);
             } else {
-                Response.ResponseBuilder ok = Response.ok(new String(entry.getData()));
+                Object cachedEntity = entry.getData();
+                Response.ResponseBuilder ok = Response.ok(cachedEntity);
                 if (entry.getHeaders() != null) {
                     for (Map.Entry<String, List<String>> h : entry.getHeaders().entrySet())
{
                         for (final Object instance : h.getValue()) {
@@ -66,9 +70,11 @@ public class CacheControlClientRequestFilter implements ClientRequestFilter
{
                         }
                     }
                 }
+                request.setProperty(CACHED_ENTITY_PROPERTY, cachedEntity);
                 request.abortWith(ok.build());
             }
         }
+        request.setProperty(CLIENT_ACCEPTS, accepts);
     }
 
     public CacheControlClientRequestFilter setCache(final Cache<Key, Entry> c) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlFeature.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlFeature.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlFeature.java
index 9b626d5..db8094d 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlFeature.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/CacheControlFeature.java
@@ -26,31 +26,34 @@ import java.util.Map;
 import java.util.Properties;
 
 import javax.annotation.PreDestroy;
-import javax.annotation.Priority;
 import javax.cache.Cache;
 import javax.cache.CacheManager;
 import javax.cache.Caching;
 import javax.cache.configuration.Factory;
 import javax.cache.configuration.MutableConfiguration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheWriter;
 import javax.cache.spi.CachingProvider;
-import javax.ws.rs.Priorities;
 import javax.ws.rs.core.Feature;
 import javax.ws.rs.core.FeatureContext;
 
 
 
-@Priority(Priorities.HEADER_DECORATOR)
 public class CacheControlFeature implements Feature {
     private CachingProvider provider;
     private CacheManager manager;
     private Cache<Key, Entry> cache;
-
+    private boolean cacheResponseInputStream;
+    
     @Override
     public boolean configure(final FeatureContext context) {
         // TODO: read context properties to exclude some patterns?
         final Cache<Key, Entry> entryCache = createCache(context.getConfiguration().getProperties());
         context.register(new CacheControlClientRequestFilter(entryCache));
-        context.register(new CacheControlClientReaderInterceptor(entryCache));
+        CacheControlClientReaderInterceptor reader = new CacheControlClientReaderInterceptor(entryCache);
+        reader.setCacheResponseInputStream(cacheResponseInputStream);
+        context.register(reader);
         return true;
     }
 
@@ -71,9 +74,9 @@ public class CacheControlFeature implements Feature {
         final Properties props = new Properties();
         props.putAll(properties);
 
-        final String prefix = ClientCache.class.getName() + ".";
+        final String prefix = this.getClass().getName() + ".";
         final String uri = props.getProperty(prefix + "config-uri");
-        final String name = props.getProperty(prefix + "name", ClientCache.class.getName());
+        final String name = props.getProperty(prefix + "name", this.getClass().getName());
 
         final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
 
@@ -95,15 +98,21 @@ public class CacheControlFeature implements Feature {
 
             final String loader = props.getProperty(prefix + "loaderFactory");
             if (loader != null) {
-                configuration.setCacheLoaderFactory(newInstance(contextClassLoader, loader,
Factory.class));
+                @SuppressWarnings("unchecked")
+                Factory<? extends CacheLoader<Key, Entry>> f = newInstance(contextClassLoader,
loader, Factory.class);
+                configuration.setCacheLoaderFactory(f);
             }
             final String writer = props.getProperty(prefix + "writerFactory");
             if (writer != null) {
-                configuration.setCacheWriterFactory(newInstance(contextClassLoader, writer,
Factory.class));
+                @SuppressWarnings("unchecked")
+                Factory<? extends CacheWriter<Key, Entry>> f = newInstance(contextClassLoader,
writer, Factory.class);
+                configuration.setCacheWriterFactory(f);
             }
             final String expiry = props.getProperty(prefix + "expiryFactory");
             if (expiry != null) {
-                configuration.setExpiryPolicyFactory(newInstance(contextClassLoader, expiry,
Factory.class));
+                @SuppressWarnings("unchecked")
+                Factory<? extends ExpiryPolicy> f = newInstance(contextClassLoader,
expiry, Factory.class);
+                configuration.setExpiryPolicyFactory(f);
             }
 
             cache = manager.createCache(name, configuration);
@@ -113,6 +122,7 @@ public class CacheControlFeature implements Feature {
         }
     }
 
+    @SuppressWarnings("unchecked")
     private static <T> T newInstance(final ClassLoader contextClassLoader, final String
clazz, final Class<T> cast) {
         try {
             return (T) contextClassLoader.loadClass(clazz).newInstance();
@@ -120,4 +130,8 @@ public class CacheControlFeature implements Feature {
             throw new IllegalArgumentException(e);
         }
     }
+
+    public void setCacheResponseInputStream(boolean cacheStream) {
+        this.cacheResponseInputStream = cacheStream;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/ClientCache.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/ClientCache.java
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/ClientCache.java
deleted file mode 100644
index 45f629a..0000000
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/ClientCache.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.jaxrs.client.cache;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import javax.ws.rs.NameBinding;
-
-@NameBinding
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.TYPE, ElementType.METHOD })
-public @interface ClientCache {
-}

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/Entry.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/Entry.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/Entry.java
index 4f01713..a93df67 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/Entry.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/cache/Entry.java
@@ -27,14 +27,14 @@ import javax.ws.rs.core.MultivaluedMap;
 public class Entry implements Serializable {
     private static final long serialVersionUID = -3551501551331222546L;
     private Map<String, String> cacheHeaders = Collections.emptyMap();
-    private byte[] data;
+    private Serializable data;
     private MultivaluedMap<String, String> headers;
     private long expiresValue;
     private long initialTimestamp = now();
 
-    public Entry(final byte[] bytes, final MultivaluedMap<String, String> headers,
+    public Entry(final Serializable data, final MultivaluedMap<String, String> headers,
                  final Map<String, String> cacheHeaders, final long expiresHeaderValue)
{
-        this.data = bytes;
+        this.data = data;
         this.headers = headers;
         this.cacheHeaders = cacheHeaders;
         this.expiresValue = expiresHeaderValue;
@@ -56,11 +56,11 @@ public class Entry implements Serializable {
         this.cacheHeaders = cacheHeaders;
     }
 
-    public byte[] getData() {
+    public Serializable getData() {
         return data;
     }
 
-    public void setData(final byte[] data) {
+    public void setData(final Serializable data) {
         this.data = data;
     }
 

http://git-wip-us.apache.org/repos/asf/cxf/blob/a77eeb98/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
index 027c7aa..1a9ee54 100644
--- a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
+++ b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
@@ -19,23 +19,27 @@
 package org.apache.cxf.jaxrs.client.cache;
 
 
-import java.net.HttpURLConnection;
+import java.io.InputStream;
+import java.io.Serializable;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.Invocation;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.CacheControl;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
+import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
 import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.cxf.jaxrs.client.spec.InvocationBuilderImpl;
 import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
 import org.apache.cxf.transport.local.LocalConduit;
+import org.apache.cxf.transport.local.LocalTransportFactory;
 
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -52,6 +56,7 @@ public class ClientCacheTest extends Assert {
         final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
         sf.setResourceClasses(TheServer.class);
         sf.setResourceProvider(TheServer.class, new SingletonResourceProvider(new TheServer(),
false));
+        sf.setTransportId(LocalTransportFactory.TRANSPORT_ID);
         sf.setAddress(ADDRESS);
         server = sf.create();
     }
@@ -64,19 +69,104 @@ public class ClientCacheTest extends Assert {
 
     @Test
     @Ignore
-    public void testCache() {
-        final WebTarget base = ClientBuilder.newBuilder().register(CacheControlFeature.class).build().target(ADDRESS);
-        final Invocation.Builder cached = setAsLocal(base.request()).header(HttpHeaders.CACHE_CONTROL,
"public");
-        final Response r = cached.get();
-        assertEquals(r.getStatus(), HttpURLConnection.HTTP_OK);
-        final String r1 = r.readEntity(String.class);
-        waitABit();
-        assertEquals(r1, cached.get().readEntity(String.class));
+    public void testGetTimeString() {
+        CacheControlFeature feature = new CacheControlFeature();
+        try {
+            final WebTarget base = ClientBuilder.newBuilder().register(feature).build().target(ADDRESS);
+            final Invocation.Builder cached = base.request("text/plain").header(HttpHeaders.CACHE_CONTROL,
"public");
+            final Response r = cached.get();
+            assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+            final String r1 = r.readEntity(String.class);
+            waitABit();
+            assertEquals(r1, cached.get().readEntity(String.class));
+        } finally {
+            feature.close();
+        }    
     }
-
+    
+    @Test
+    @Ignore
+    public void testGetTimeStringAsInputStream() throws Exception {
+        CacheControlFeature feature = new CacheControlFeature();
+        try {
+            final WebTarget base = ClientBuilder.newBuilder().register(feature).build().target(ADDRESS);
+            final Invocation.Builder cached = base.request("text/plain").header(HttpHeaders.CACHE_CONTROL,
"public");
+            final Response r = cached.get();
+            assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+            InputStream is = r.readEntity(InputStream.class);
+            final String r1 = IOUtils.readStringFromStream(is);
+            waitABit();
+            is = cached.get().readEntity(InputStream.class);
+            final String r2 = IOUtils.readStringFromStream(is);
+            assertEquals(r1, r2);
+        } finally {
+            feature.close();
+        }
+    }
+    
+    @Test
+    @Ignore
+    public void testGetTimeStringAsInputStreamAndString() throws Exception {
+        CacheControlFeature feature = new CacheControlFeature();
+        try {
+            feature.setCacheResponseInputStream(true);
+            final WebTarget base = ClientBuilder.newBuilder().register(feature).build().target(ADDRESS);
+            final Invocation.Builder cached = base.request("text/plain").header(HttpHeaders.CACHE_CONTROL,
"public");
+            final Response r = cached.get();
+            assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+            InputStream is = r.readEntity(InputStream.class);
+            final String r1 = IOUtils.readStringFromStream(is);
+            waitABit();
+            // CassCastException would occur without a cached stream support
+            final String r2 = cached.get().readEntity(String.class);
+            assertEquals(r1, r2);
+        } finally {
+            feature.close();
+        }
+    }
+    @Test
+    @Ignore
+    public void testGetTimeStringAsStringAndInputStream() throws Exception {
+        CacheControlFeature feature = new CacheControlFeature();
+        try {
+            feature.setCacheResponseInputStream(true);
+            final WebTarget base = ClientBuilder.newBuilder().register(feature).build().target(ADDRESS);
+            final Invocation.Builder cached = base.request("text/plain").header(HttpHeaders.CACHE_CONTROL,
"public");
+            final Response r = cached.get();
+            assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+            final String r1 = r.readEntity(String.class);
+            waitABit();
+            // CassCastException would occur without a cached stream support
+            InputStream is = cached.get().readEntity(InputStream.class);
+            final String r2 = IOUtils.readStringFromStream(is);
+            assertEquals(r1, r2);
+        } finally {
+            feature.close();
+        }
+    }
+    
+    @Test
+    @Ignore
+    public void testGetJaxbBookCache() {
+        CacheControlFeature feature = new CacheControlFeature();
+        try {
+            final WebTarget base = ClientBuilder.newBuilder().register(feature).build().target(ADDRESS);
+            final Invocation.Builder cached = 
+                setAsLocal(base.request("application/xml")).header(HttpHeaders.CACHE_CONTROL,
"public");
+            final Response r = cached.get();
+            assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+            final Book b1 = r.readEntity(Book.class);
+            assertEquals("JCache", b1.getName());
+            assertNotNull(b1.getId());
+            waitABit();
+            assertEquals(b1, cached.get().readEntity(Book.class));
+        } finally {
+            feature.close();
+        }    
+    }
+    
     private static Invocation.Builder setAsLocal(final Invocation.Builder client) {
-        WebClient.getConfig(InvocationBuilderImpl.class.cast(client).getWebClient())
-            .getRequestContext().put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);
+        WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_DISPATCH,
Boolean.TRUE);
         return client;
     }
 
@@ -91,10 +181,55 @@ public class ClientCacheTest extends Assert {
     @Path("/")
     public static class TheServer {
         @GET
-        @ClientCache
-        public Response array() {
+        @Produces("text/plain")
+        public Response getString() {
             return Response.ok(Long.toString(System.currentTimeMillis()))
                 .tag("123").cacheControl(CacheControl.valueOf("max-age=50000")).build();
         }
+        @GET
+        @Produces("application/xml")
+        public Response getJaxbBook() {
+            Book b = new Book();
+            b.setId(System.currentTimeMillis());
+            b.setName("JCache");
+            return Response.ok(b).tag("123").cacheControl(CacheControl.valueOf("max-age=50000")).build();
+        }
+    }
+    @XmlRootElement
+    public static class Book implements Serializable {
+        private static final long serialVersionUID = 4924824780883333782L;
+        private String name;
+        private Long id;
+        public Book() {
+            
+        }
+        public Book(String name, long id) {
+            this.name = name;
+            this.id = id;
+        }
+        public String getName() {
+            return name;
+        }
+        public void setName(String name) {
+            this.name = name;
+        }
+        public Long getId() {
+            return id;
+        }
+        public void setId(Long id) {
+            this.id = id;
+        }
+        public int hashCode() {
+            return id.hashCode() + 37 * name.hashCode();
+        }
+        public boolean equals(Object o) {
+            if (o instanceof Book) {
+                Book other = (Book)o;
+                return other.id.equals(id) && other.name.equals(name);
+            } else {
+                return false;
+            }
+        }
     }
+    
 }


Mime
View raw message