com.gistlabs.mechanize.cache.inMemory.InMemoryCacheEntry.java Source code

Java tutorial

Introduction

Here is the source code for com.gistlabs.mechanize.cache.inMemory.InMemoryCacheEntry.java

Source

/**
 * Copyright (C) 2012-2014 Gist Labs, LLC. (http://gistlabs.com)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.gistlabs.mechanize.cache.inMemory;

import java.util.Calendar;
import java.util.Date;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHttpResponse;

import com.gistlabs.mechanize.cache.api.CacheEntry;
import com.gistlabs.mechanize.exceptions.MechanizeExceptionFactory;

public class InMemoryCacheEntry implements CacheEntry {
    private static final Date OLD = new Date(0);

    @SuppressWarnings("unused") // debug tool
    final private HttpUriRequest request;
    final private HttpResponse response;

    /**
     * Used when the response doesn't include a Date header...
     */
    final Date date = new Date();

    public InMemoryCacheEntry(final HttpUriRequest request, final HttpResponse response) {
        if (request == null)
            throw new NullPointerException("request can't be null!");
        this.request = request;
        if (response == null)
            throw new NullPointerException("response can't be null!");
        this.response = response;

    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#isCacheable()
     */
    @Override
    public boolean isCacheable() {
        boolean supportsConditionals = has("Last-Modified", this.response) || has("ETag", this.response);
        boolean isCacheable = has("Cache-Control", "s-maxage", this.response)
                || has("Cache-Control", "max-age", this.response) || has("Expires", this.response);
        return supportsConditionals || isCacheable;
    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#isValid()
     */
    @Override
    public boolean isValid() {
        boolean mustNotCache = has("Pragma", "no-cache", this.response)
                || has("Cache-Control", "no-cache", this.response);

        if (mustNotCache)
            return false;

        Date now = new Date();
        Date cacheControl = getCacheControlExpiresDate();
        Date expires = getExpiresDate();

        return now.before(cacheControl) || now.before(expires);
    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#byteCount()
     */
    @Override
    public long byteCount() {
        return this.response.getEntity().getContentLength();
    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#getResponse()
     */
    @Override
    public HttpResponse getResponse() {
        return this.response;
    }

    /**
     *
     * @return
     */
    private Date getDate() {
        String expires = get("Date", this.response);

        if (expires.equals(""))
            return date; // will this ever happen?
        else
            return parseDate(expires);
    }

    private Date getCacheControlExpiresDate() {
        String maxage = get("Cache-Control", "max-age", this.response);
        if (maxage.equals(""))
            return OLD;

        int seconds = Integer.parseInt(maxage);
        Calendar cal = Calendar.getInstance();
        cal.setTime(getDate());
        cal.add(Calendar.SECOND, seconds);
        return cal.getTime();
    }

    private Date getExpiresDate() {
        String expires = get("Expires", this.response);

        try {
            return DateUtils.parseDate(expires);
        } catch (Exception e) { // if not present or parsable... just ignore
            return OLD;
        }
    }

    protected Date parseDate(final String expires) {
        try {
            return DateUtils.parseDate(expires);
        } catch (DateParseException e) {
            throw MechanizeExceptionFactory.newException(e);
        }
    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#updateCacheValues(org.apache.http.HttpResponse)
     */
    @Override
    public CacheEntry updateCacheValues(final HttpResponse response) {
        transferFirstHeader("Date", response, this.response);
        transferFirstHeader("ETag", response, this.response);
        transferFirstHeader("Last-Modified", response, this.response);
        transferFirstHeader("Cache-Control", response, this.response);
        transferFirstHeader("Expires", response, this.response);
        return this;
    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#prepareConditionalGet(org.apache.http.client.methods.HttpUriRequest)
     */
    @Override
    public void prepareConditionalGet(final HttpUriRequest newRequest) {
        transferFirstHeader("ETag", "If-None-Match", this.response, newRequest);
        transferFirstHeader("Last-Modified", "If-Modified-Since", this.response, newRequest);
    }

    /* (non-Javadoc)
     * @see com.gistlabs.mechanize.cache.InMemoryCacheEntry#head()
     */
    @Override
    public HttpResponse head() {
        BasicHttpResponse response = new BasicHttpResponse(this.response.getStatusLine());
        Header[] allHeaders = this.response.getAllHeaders();
        for (Header allHeader : allHeaders)
            response.addHeader(allHeader);
        response.setEntity(new ByteArrayEntity(new byte[] {}));
        return response;
    }

    protected void transferFirstHeader(final String headerName, final HttpMessage origin, final HttpMessage dest) {
        transferFirstHeader(headerName, headerName, origin, dest);
    }

    protected void transferFirstHeader(final String headerName, final String destName, final HttpMessage origin,
            final HttpMessage dest) {
        Header header = origin.getFirstHeader(headerName);
        if (header != null)
            dest.setHeader(destName, header.getValue());
    }

    protected boolean has(final String headerName, final HttpMessage message) {
        return message.getHeaders(headerName).length > 0;
    }

    protected String get(final String headerName, final HttpMessage message) {
        Header header = message.getFirstHeader(headerName);
        if (header != null)
            return header.getValue();
        else
            return "";
    }

    protected boolean has(final String headerName, final String headerValueOrElement, final HttpMessage message) {
        Header[] headers = message.getHeaders(headerName);
        for (Header header : headers) {
            if (header.getValue().equals(headerValueOrElement))
                return true;

            HeaderElement[] elements = header.getElements();
            for (HeaderElement element : elements)
                if (element.getName().equals(headerValueOrElement))
                    return true;
        }
        return false;
    }

    protected String get(final String headerName, final String elementName, final HttpMessage message) {
        Header header = message.getFirstHeader(headerName);
        if (header == null)
            return "";

        HeaderElement[] elements = header.getElements();
        for (HeaderElement element : elements)
            if (element.getName().equals(elementName))
                return element.getValue();

        return "";
    }
}