/*
GNU GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
verion 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
/*
* Created on Jun 12, 2005
*/
package org.lobobrowser.request;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lobobrowser.store.CacheManager;
import org.lobobrowser.store.ClassLoaderObjectInputStream;
import org.lobobrowser.util.Urls;
public class CacheInfo {
private static final Logger logger = Logger.getLogger(CacheInfo.class.getName());
static final String HEADER_REQUEST_TIME = "X-Request-Time";
private final URL url;
private final MemoryCacheEntry memoryEntry;
private final byte[] persistentContent;
private URLConnection connection;
/**
*
*/
public CacheInfo(final MemoryCacheEntry memEntry, final byte[] persContent, final URL url) {
super();
this.persistentContent = persContent;
this.url = url;
this.memoryEntry = memEntry;
}
/**
* This method should only be called if the connection is later going to be
* closed.
*/
public final java.net.URLConnection getURLConnection() {
if (this.connection == null) {
final MemoryCacheEntry memEntry = this.memoryEntry;
if (memEntry != null) {
this.connection = new MemoryURLConnection(this.url, memEntry);
} else {
final byte[] content = this.persistentContent;
if (content == null) {
throw new IllegalStateException("Memory entry and persistent content unavailable.");
}
this.connection = new FileWithHeadersURLConnection(this.url, content);
}
}
return this.connection;
}
/**
* This method should be called when the CacheInfo instance is no longer
* needed in order to release resources.
*/
public final void dispose() {
final URLConnection connection = this.connection;
if (connection instanceof FileWithHeadersURLConnection) {
((FileWithHeadersURLConnection) connection).disconnect();
}
}
public final boolean isCacheConnection(final URLConnection connection) {
return connection == this.getURLConnection();
}
public final String getDateAsText() {
return this.getURLConnection().getHeaderField("date");
}
/**
* Adds the request time of the cached document to the given offset.
*/
public final Long getExpiresGivenOffset(final long offsetSeconds) {
final MemoryCacheEntry entry = this.memoryEntry;
if (entry != null) {
return entry.requestTime + (offsetSeconds * 1000);
} else {
final String rtText = this.getURLConnection().getHeaderField(HEADER_REQUEST_TIME);
if (rtText == null) {
return null;
}
final long rt = Long.parseLong(rtText);
return rt + (offsetSeconds * 1000);
}
}
/**
* Gets the timestamp when the cache entry should expire and must be
* revalidated. If <code>null</code>, the browser can use a default. When the
* entry must be revalidated, this method returns zero.
*/
public final Long getExpires() {
final MemoryCacheEntry entry = this.memoryEntry;
if (entry != null) {
return entry.expiration;
} else {
final URLConnection connection = this.getURLConnection();
final String requestTimeText = connection.getHeaderField(HEADER_REQUEST_TIME);
if (requestTimeText == null) {
if (logger.isLoggable(Level.INFO)) {
logger.info("getExpires(): Cached content does not have " + HEADER_REQUEST_TIME + " header: " + this.url + ".");
}
return new Long(0);
}
final long requestTime = Long.parseLong(requestTimeText);
return Urls.getExpiration(connection, requestTime);
}
}
public long getRequestTime() {
final MemoryCacheEntry entry = this.memoryEntry;
if (entry != null) {
return entry.requestTime;
} else {
final URLConnection connection = this.getURLConnection();
final String requestTimeText = connection.getHeaderField(HEADER_REQUEST_TIME);
if (requestTimeText == null) {
return 0;
}
return Long.parseLong(requestTimeText);
}
}
public boolean hasTransientEntry() {
return this.memoryEntry != null;
}
public Object getTransientObject() {
final MemoryCacheEntry memEntry = this.memoryEntry;
return memEntry != null ? memEntry.altObject : null;
}
public int getTransientObjectSize() {
final MemoryCacheEntry memEntry = this.memoryEntry;
return memEntry != null ? memEntry.altObjectSize : 0;
}
public Object getPersistentObject(final ClassLoader classLoader) {
try {
final byte[] content = CacheManager.getPersistent(this.url, true);
if (content == null) {
return null;
}
try (
final InputStream in = new ByteArrayInputStream(content);
final ObjectInputStream oin = new ClassLoaderObjectInputStream(in, classLoader);) {
return oin.readObject();
}
} catch (final IOException ioe) {
logger.log(Level.WARNING, "getPersistentObject(): Unable to load persistent cached object.", ioe);
return null;
} catch (final ClassNotFoundException ioe) {
logger.log(Level.WARNING, "getPersistentObject(): Failed to load persistent cached object apparently due to versioning issue.", ioe);
return null;
}
}
public void delete() {
final CacheManager cm = CacheManager.getInstance();
cm.removeTransient(this.url);
try {
CacheManager.removePersistent(this.url, false);
CacheManager.removePersistent(this.url, true);
} catch (final IOException ioe) {
logger.log(Level.WARNING, "delete()", ioe);
}
}
public byte[] getPersistentContent() {
return persistentContent;
}
@Override
public String toString() {
return "CacheInfo for " + url + ": " +
"memEntry: " + memoryEntry;
}
}