Search code examples
cxf

CXF's readEntity() got "Entity is not available"


I am working on a piece of code that uses CXF (3.1.2)

I am seeing this error intermittently:

java.lang.IllegalStateException: Entity is not available
at org.apache.cxf.jaxrs.impl.ResponseImpl.checkEntityIsClosed(ResponseImpl.java:481)
at org.apache.cxf.jaxrs.impl.ResponseImpl.doReadEntity(ResponseImpl.java:333)
at org.apache.cxf.jaxrs.impl.ResponseImpl.readEntity(ResponseImpl.java:320)
at org.apache.cxf.jaxrs.impl.ResponseImpl.readEntity(ResponseImpl.java:310)

To improve performance, the Response objects are held through a Google Guava LoadingCache (com.google.common.cache.LoadingCache). It seems like I would get this error after an object has been in the cache for a few minutes. Could the Response object because invalid after a few minutes?

private static LoadingCache<String, Response> cachedLdapRespMap
    = CacheBuilder.newBuilder()
        .maximumSize(Constants.LDAP_RESP_CACHE_SIZE)
        .expireAfterWrite(Constants.LDAP_RESP_CACHE_KEEP_ALIVE_MINUTE
                            , TimeUnit.MINUTES)
        .build(
                new CacheLoader<String, Response>() {

                    @Override
                    public Response load(String uid)
                            throws Exception {
                        Response res = makeLdapRequest(uid);
                        return res;
                    }

                }
            );

Solution

  • (I am answer the question myself)

    The problem was that I have concurrent processes that attempted to readEntity(), the first process consumed the input stream (or may have even closed the stream), and the second process would either get thrown an IllegalStateException or got an empty message. Here is what the JavaDoc of javax.ws.rs.core.Response (which org.apache.cxf.jaxrs.impl.ResponseImpl extends) says:

    Throws:

    IllegalStateException - if the entity is not backed by an input stream, the response has been closed already, or if the entity input stream has been fully consumed already and has not been buffered prior consuming.

    So to fix the problem, I changed my design to cache not the Response object but rather the string message that is the result of the readEntity() call. The call would be done exactly once when the response comes back:

    Response resp ...
    String respStr = resp.readEntity(String.class);
    

    and the problem is solved.