/* * ==================================================================== * 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package com.apigee.sdk.apm.http.impl.client.cache; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import com.apigee.sdk.apm.http.annotation.ThreadSafe; import com.apigee.sdk.apm.http.client.cache.HeaderConstants; import com.apigee.sdk.apm.http.client.cache.HttpCacheEntry; import com.apigee.sdk.apm.http.client.cache.HttpCacheStorage; /** * Given a particular HttpRequest, flush any cache entries that this request * would invalidate. * * @since 4.1 */ @ThreadSafe // so long as the cache implementation is thread-safe class CacheInvalidator { private final HttpCacheStorage storage; private final URIExtractor uriExtractor; private final Log log = LogFactory.getLog(getClass()); /** * Create a new {@link CacheInvalidator} for a given {@link HttpCache} and * {@link URIExtractor}. * * @param uriExtractor * Provides identifiers for the keys to store cache entries * @param storage * the cache to store items away in */ public CacheInvalidator(final URIExtractor uriExtractor, final HttpCacheStorage storage) { this.uriExtractor = uriExtractor; this.storage = storage; } /** * Remove cache entries from the cache that are no longer fresh or have been * invalidated in some way. * * @param host * The backend host we are talking to * @param req * The HttpRequest to that host */ public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest req) throws IOException { if (requestShouldNotBeCached(req)) { log.debug("Request should not be cached"); String theUri = uriExtractor.getURI(host, req); HttpCacheEntry parent = storage.getEntry(theUri); log.debug("parent entry: " + parent); if (parent != null) { for (String variantURI : parent.getVariantURIs()) { storage.removeEntry(variantURI); } storage.removeEntry(theUri); } URL reqURL; try { reqURL = new URL(theUri); } catch (MalformedURLException mue) { log.error("Couldn't transform request into valid URL"); return; } Header clHdr = req.getFirstHeader("Content-Location"); if (clHdr != null) { String contentLocation = clHdr.getValue(); if (!flushAbsoluteUriFromSameHost(reqURL, contentLocation)) { flushRelativeUriFromSameHost(reqURL, contentLocation); } } Header lHdr = req.getFirstHeader("Location"); if (lHdr != null) { flushAbsoluteUriFromSameHost(reqURL, lHdr.getValue()); } } } protected void flushUriIfSameHost(URL requestURL, URL targetURL) throws IOException { URL canonicalTarget = new URL(uriExtractor.canonicalizeUri(targetURL .toString())); if (canonicalTarget.getAuthority().equalsIgnoreCase( requestURL.getAuthority())) { storage.removeEntry(canonicalTarget.toString()); } } protected void flushRelativeUriFromSameHost(URL reqURL, String relUri) throws IOException { URL relURL; try { relURL = new URL(reqURL, relUri); } catch (MalformedURLException e) { log.debug("Invalid relative URI", e); return; } flushUriIfSameHost(reqURL, relURL); } protected boolean flushAbsoluteUriFromSameHost(URL reqURL, String uri) throws IOException { URL absURL; try { absURL = new URL(uri); } catch (MalformedURLException mue) { return false; } flushUriIfSameHost(reqURL, absURL); return true; } protected boolean requestShouldNotBeCached(HttpRequest req) { String method = req.getRequestLine().getMethod(); return notGetOrHeadRequest(method); } private boolean notGetOrHeadRequest(String method) { return !(HeaderConstants.GET_METHOD.equals(method) || HeaderConstants.HEAD_METHOD .equals(method)); } }