package com.sun.deploy.cache;
import java.io.*;
import java.net.*;
import java.security.SecureRandom;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.jar.JarFile;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import com.sun.deploy.util.VersionString;
import com.sun.deploy.config.Config;
import com.sun.deploy.util.Trace;
import com.sun.deploy.util.TraceLevel;
import com.sun.deploy.services.ServiceManager;
import com.sun.deploy.resources.ResourceManager;
import com.sun.deploy.net.*;
import com.sun.deploy.net.DownloadEngine.DownloadDelegate;
import com.sun.deploy.Environment;
public class Cache {
private static boolean doIPLookup = true;
private final static String IP_ADDR_CANNOT_RESOLVE = "0.0.0.0";
private final static int VERSION_INT = 603;
private final static String VERSION_STRING = "6.0";
private final static String DASH = "-";
final static String INDEX_FILE_EXT = ".idx";
private final static String MUFFIN_FILE_EXT = ".muf";
private final static String HOST_FILE_EXT = ".hst";
private final static int NUM_OF_CACHE_SUBDIR = 64;
final static char APPLICATION_TYPE = 'A'; final static char EXTENSION_TYPE = 'E';
private static SecureRandom random = null;
private static String cachePath;
private static File cacheDir;
private static File sysCacheDir;
private static File muffinDir;
private static File hostDir;
private final static int BUF_SIZE = 32 * 1024;
private final static Map loadedProperties = new HashMap();
private static CleanupThread ct;
private final static Object syncObject = new Object();
private static boolean cleanupEnabled = true;
public final static long TIME_WAIT_BEFORE_JAR_PERVERIFY = 30000;
public static void setCleanupEnabled(boolean enabled) {
cleanupEnabled = enabled;
}
static {
reset();
if (isCacheEnabled()) {
ct = new CleanupThread("CacheCleanUpThread", syncObject);
ct.start();
}
}
public static void setDoIPLookup(boolean b) {
doIPLookup = b;
}
private static void createCacheBucketDirectories(String cacheDirPath) {
for (int i = 0; i < NUM_OF_CACHE_SUBDIR; i++) {
File cacheSubDir = new File(cacheDirPath + File.separator + i);
cacheSubDir.mkdir();
}
}
public static void reset() {
synchronized (syncObject) {
MemoryCache.reset();
synchronized (loadedProperties) {
loadedProperties.clear();
}
cachePath = Config.getCacheDirectory() +
File.separator + VERSION_STRING;
String muffinPath = cachePath + File.separator + "muffin";
String hostPath = cachePath + File.separator + "host";
cacheDir = new File(cachePath);
muffinDir = new File(muffinPath);
hostDir = new File(hostPath);
cacheDir.mkdirs();
hostDir.mkdirs();
createCacheBucketDirectories(cachePath);
muffinDir.mkdirs();
if (Config.getSystemCacheDirectory() != null &&
Config.getSystemCacheDirectory().length() != 0) {
String sysCachePath = Config.getSystemCacheDirectory() +
File.separator + VERSION_STRING;
sysCacheDir = new File(sysCachePath);
if (Environment.isSystemCacheMode()) {
sysCacheDir.mkdirs();
createCacheBucketDirectories(sysCachePath);
}
} else {
sysCacheDir = null;
}
long cacheMax = Config.getCacheSizeMax();
if (cacheMax > 0 && cacheMax < 5 * 1024 * 1024) {
cacheMax = 5 * 1024 * 1024;
}
}
}
static void addToCleanupThreadLoadedResourceList(String url) {
if (ct != null && cleanupEnabled) {
ct.addToLoadedResourceList(url);
}
}
static void cleanup() {
if (ct != null && cleanupEnabled) {
ct.startCleanup();
}
}
private Cache() {
}
static void markResourceIncomplete(CacheEntry ce) {
if (ce != null) {
synchronized (ce) {
ce.setIncomplete(1);
try {
ce.updateIndexHeaderOnDisk();
} catch (IOException ioe) {
Trace.ignoredException(ioe);
}
}
}
}
static boolean isSystemCacheEntry(CacheEntry ce) {
if (ce != null && sysCacheDir != null) {
File idx = ce.getIndexFile();
if (idx != null && idx.getParentFile() != null) {
return sysCacheDir.equals(idx.getParentFile().getParentFile());
}
}
return false;
}
public final static CacheEntry getSystemCacheEntry(URL url, String version) {
if (url == null) {
return null;
}
CacheEntry ce = (CacheEntry) MemoryCache.getLoadedResource(url.toString());
if (isSystemCacheEntry(ce)) {
String currentVersion = ce.getVersion();
if ((version == null && currentVersion == null )||
(version != null && currentVersion != null &&
currentVersion.compareTo(version) >= 0)) {
return ce;
}
}
ce = Cache.getCacheEntry(url, null, version, sysCacheDir);
if (ce != null) {
MemoryCache.addLoadedResource(url.toString(), ce);
}
return ce;
}
public final static boolean isSupportedProtocol(URL url) {
String protocol = url.getProtocol();
if ((protocol != null) &&
(protocol.equalsIgnoreCase("http") ||
protocol.equalsIgnoreCase("https"))) {
return true;
} else {
return false;
}
}
public static boolean isCacheEnabled() {
return Config.getBooleanProperty(Config.CACHE_ENABLED_KEY);
}
public static void removeLoadedProperties(String key) {
synchronized(loadedProperties) {
loadedProperties.remove(key);
}
}
public static LocalApplicationProperties getLocalApplicationProperties(
CacheEntry ce) {
URL jnlpURL = null;
try {
jnlpURL = new URL(ce.getURL());
} catch (MalformedURLException mue) {
Trace.ignoredException(mue);
}
return getLocalApplicationProperties(jnlpURL, ce.getVersion(), true);
}
public static LocalApplicationProperties getLocalApplicationProperties(
String path) {
if (Cache.isCacheEnabled() == false) {
return null;
}
CacheEntry ce = com.sun.deploy.cache.Cache.getCacheEntryFromFile(
new File(path + INDEX_FILE_EXT));
if (ce == null) {
return null;
}
URL u = null;
try {
u = new URL(ce.getURL());
} catch (MalformedURLException mue) {
Trace.ignoredException(mue);
return null;
}
return getLocalApplicationProperties(u, ce.getVersion(), true);
}
public static LocalApplicationProperties getLocalApplicationProperties(
URL jnlpUrl) {
return getLocalApplicationProperties(jnlpUrl, null, true);
}
public static LocalApplicationProperties getLocalApplicationProperties(
URL jnlpUrl, String version, boolean isApplicationDesc) {
LocalApplicationProperties props = null;
if (isCacheEnabled() && jnlpUrl != null) {
String key = jnlpUrl.toString() + "?" + version;
synchronized(loadedProperties) {
props = (LocalApplicationProperties)loadedProperties.get(key);
if (props == null) {
props = new DefaultLocalApplicationProperties(
jnlpUrl, version, isApplicationDesc);
loadedProperties.put(key, props);
} else {
props.refreshIfNecessary();
}
}
}
return props;
}
public static String getLapFileName(URL url, String version) {
String key = getKey(url);
return getBucket(key) + File.separator + key + VERSION_STRING +
getVersionTag(version) + ".lap";
}
public static void putLapData(char type, URL url, String version,
byte[] data) throws IOException {
File dir = getActiveCacheDir();
File lapFile = new File(dir, getLapFileName(url, version));
InputStream is = new ByteArrayInputStream(data);
BufferedOutputStream bof = new BufferedOutputStream(
new FileOutputStream(lapFile));
byte[] buffer = new byte[BUF_SIZE];
try {
int n = is.read(buffer);
while(n >= 0) {
bof.write(buffer, 0, n);
n = is.read(buffer);
}
} finally {
bof.close();
is.close();
}
}
public static byte[] getLapData(char type, URL url, String version,
boolean fromSystemCache) throws IOException {
File dir = (fromSystemCache) ? sysCacheDir : cacheDir;
if (dir == null) {
return null;
}
File lapFile = new File(dir, getLapFileName(url, version));
long size = lapFile.length();
if (size > 0 && size < 1024 * 1024) {
BufferedInputStream is =
new BufferedInputStream(new FileInputStream(lapFile));
ByteArrayOutputStream baos =
new ByteArrayOutputStream((int)size);
byte[] buffer = new byte[BUF_SIZE];
try {
int n = is.read(buffer);
while(n >= 0) {
baos.write(buffer, 0, n);
n = is.read(buffer);
}
} finally {
baos.close();
is.close();
}
return baos.toByteArray();
}
return null;
}
public static String getNewExtensionInstallDirectory() throws IOException {
String dir = cacheDir.getAbsolutePath() +
File.separator + "ext";
String tempname = null;
int count = 0;
do {
tempname = dir + File.separator + "E" +
(new Date().getTime()) + File.separator;
File cacheDir = new File(tempname);
if (!cacheDir.mkdirs()) {
tempname = null;
}
Thread.yield(); } while(tempname == null && ++count < 50); if (tempname == null) {
throw new IOException("Unable to create temp. dir for extension");
}
return tempname;
}
public static String getCacheEntryVersion(final URL url,
final String resourceID) {
String currentVersion = null;
CacheEntry ce = Cache.getLatestCacheEntry(url, resourceID);
if (ce != null) {
currentVersion = ce.getVersion();
}
return currentVersion;
}
public static int getCacheEntryContentLength(URL href, String version) {
CacheEntry ce = Cache.getCacheEntry(href, null, version);
if (ce != null) {
return ce.getContentLength();
}
return 0;
}
public static long getCacheEntryLastModified(URL href, String version) {
CacheEntry ce = Cache.getCacheEntry(href, null, version);
if (ce != null) {
return ce.getLastModified();
}
return 0;
}
static CacheEntry downloadResourceToCache(final URL href, final String downloadVersion,
final URLConnection conn, final URL requestURL, final boolean applyJarDiff,
final int contentType,
final InputStream is) throws
IOException, CanceledDownloadException {
CacheEntry ce = null;
try {
ce = (CacheEntry)AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws IOException, CanceledDownloadException {
String cacheFileName = generateCacheFileName(href, downloadVersion);
File dir = getActiveCacheDir();
File indexFile = new File(dir, cacheFileName + getIndexFileExtension());
CacheEntry ce = new CacheEntry(indexFile);
ce.writeFileToDisk();
String encoding = conn.getContentEncoding();
if (DownloadEngine.isPackContentType(contentType)) {
encoding = HttpRequest.PACK200_GZIP_ENCODING;
}
DownloadEngine.getHttpDownloadImpl().download(
conn.getContentLength(), conn.getURL(), is,
encoding, ce.getTempDataFile(), null, contentType);
if (ce.processTempDataFile(applyJarDiff, null, href, requestURL,
downloadVersion)){
ce.setBusy(0);
ce.setIncomplete(0);
ce.setURL(downloadVersion == null ?
requestURL.toString() : href.toString());
if (applyJarDiff) {
ce.setContentLength(
(int)new File(ce.getResourceFilename()).length());
} else {
ce.setContentLength(conn.getContentLength());
}
ce.setLastModified(conn.getLastModified());
ce.setExpirationDate(conn.getExpiration());
if (downloadVersion != null) {
ce.setVersion(downloadVersion);
}
MessageHeader headerFields =
BasicHttpRequest.initializeHeaderFields(conn);
if (conn instanceof HttpURLConnection) {
((HttpURLConnection)conn).disconnect();
String requestContentType =
conn.getRequestProperty(HttpRequest.CONTENT_TYPE);
if (requestContentType != null &&
headerFields != null) {
headerFields.add(
HttpRequest.DEPLOY_REQUEST_CONTENT_TYPE,
requestContentType);
}
}
ce.setHeaders(headerFields);
ce.writeFileToDisk(contentType, null);
recordLastAccessed();
return ce;
}
return null;
}
});
} catch (PrivilegedActionException pae) {
if (pae.getException() instanceof IOException) {
throw (IOException)pae.getException();
} else if (pae.getException() instanceof CanceledDownloadException) {
throw (CanceledDownloadException)pae.getException();
}
}
return ce;
}
public static CacheEntry downloadResourceToCache(URL href, String downloadVersion,
HttpResponse response, HttpDownloadListener hdl,
DownloadDelegate dd, boolean removeCurrentCE, URL requestURL,
CacheEntry currentCE, boolean applyJarDiff, int contentType)
throws IOException, CanceledDownloadException {
CacheEntry tempCE = downloadResourceToTempFile(href, downloadVersion, response, hdl,
dd, removeCurrentCE, requestURL,
currentCE, applyJarDiff, contentType);
if (tempCE != null) {
return processNewCacheEntry(href, removeCurrentCE,
tempCE, currentCE);
}
return null;
}
public static CacheEntry downloadResourceToTempFile(URL href, String downloadVersion,
HttpResponse response, HttpDownloadListener hdl,
DownloadDelegate dd, boolean removeCurrentCE,
URL requestURL, CacheEntry currentCE,
boolean applyJarDiff, int contentType)
throws IOException, CanceledDownloadException {
String cacheFileName = generateCacheFileName(href, downloadVersion);
File dir = getActiveCacheDir();
File indexFile = new File(dir, cacheFileName + getIndexFileExtension());
CacheEntry ce = new CacheEntry(indexFile);
ce.writeFileToDisk();
String encoding = response.getContentEncoding();
if (DownloadEngine.isPackContentType(contentType)) {
encoding = HttpRequest.PACK200_GZIP_ENCODING;
}
DownloadEngine.getHttpDownloadImpl().download(response.getContentLength(),
response.getRequest(), response.getInputStream(),
encoding, ce.getTempDataFile(), hdl, contentType);
response.disconnect();
if (ce.processTempDataFile(applyJarDiff, dd, href, requestURL,
downloadVersion)){
ce.setURL((downloadVersion == null &&
Environment.isImportMode() == false) ?
requestURL.toString() : href.toString());
MessageHeader headerFields = response.getHeaders();
if (headerFields != null &&
DownloadEngine.isJarContentType(contentType)) {
headerFields.add(HttpRequest.DEPLOY_REQUEST_CONTENT_TYPE,
HttpRequest.JAR_MIME_TYPE);
}
ce.setHeaders(headerFields);
ce.setContentLength(response.getContentLength());
ce.setLastModified(response.getLastModified());
ce.setExpirationDate(response.getExpiration());
if (downloadVersion != null) {
ce.setVersion(downloadVersion);
}
ce.writeFileToDisk(contentType, dd);
return ce;
}
return null;
}
public static boolean isBackgroundVerificationEnabled() {
if (isCacheEnabled() == false) {
return false;
}
String s = System.getProperty("jnlp.disableBackgroundVerification");
if (s != null && s.equalsIgnoreCase("true")) {
Trace.println("Cached JAR background verification disabled",
TraceLevel.CACHE);
return false;
}
return true;
}
public static CacheEntry processNewCacheEntry (URL href, boolean removeCurrentCE,
CacheEntry ce,CacheEntry currentCE)
throws IOException {
Trace.println("Cache: Enable a new CacheEntry: "+href.toString(),
TraceLevel.NETWORK);
ce.setBusy(0);
ce.setIncomplete(0);
ce.updateIndexHeaderOnDisk();
if (removeCurrentCE && currentCE != null) {
if (removeCacheEntry(currentCE, false) == false) {
currentCE.setIncomplete(1);
currentCE.updateIndexHeaderOnDisk();
}
currentCE = null;
}
recordLastAccessed();
return ce;
}
public static int getCacheVersion() {
return VERSION_INT;
}
public static String getCacheVersionString() {
return VERSION_STRING;
}
public static long getCacheSize(boolean system) {
long size = 0;
File [] idxFiles = getCacheEntries(system);
for (int i=0; i<idxFiles.length; i++) {
size += idxFiles[i].length();
CacheEntry ce = Cache.getCacheEntryFromFile(idxFiles[i]);
if (ce != null) {
size += ce.getContentLength();
size += getTotalSize(new File(ce.getNativeLibPath()));
}
}
return size;
}
private static long getTotalSize(File f) {
long size = 0;
if (f != null && f.exists()) {
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
size += getTotalSize(files[i]);
}
} else {
size += f.length();
}
}
return size;
}
private static SecureRandom getSecureRandom() {
if (random == null) {
random = ServiceManager.getService().getSecureRandom();
random.nextInt();
}
return random;
}
public static boolean exists() {
if (Environment.isSystemCacheMode()) {
return ((sysCacheDir != null) && (sysCacheDir.exists()));
} else {
return cacheDir.exists();
}
}
public static boolean canWrite() {
if (Environment.isSystemCacheMode()) {
return ((sysCacheDir != null) && (sysCacheDir.canWrite()));
}
return cacheDir.canWrite();
}
public static CacheEntry addLoadedResource(URL url, String resourceID,
String version) {
if (url == null) {
return null;
}
CacheEntry ce = (CacheEntry) MemoryCache.getLoadedResource(url.toString());
if (ce != null)
return ce;
ce = getCacheEntry(url, resourceID, version);
if (ce != null) {
return (CacheEntry) MemoryCache.addLoadedResource(url.toString(), ce);
}
return null;
}
public static void createNoHrefCacheEntry(URL href, byte[] jnlpBytes)
throws IOException {
File dir = getActiveCacheDir();
CacheEntry currentCE = getCacheEntry(href, null, null, dir);
String cacheFileName = generateCacheFileName(href, null);
File indexFile = new File(dir,
cacheFileName + Cache.getIndexFileExtension());
File cacheFile = new File(dir, cacheFileName);
CacheEntry ce = new CacheEntry(indexFile);
ce.writeFileToDisk();
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(ce.getTempDataFile()));
try {
bos.write(jnlpBytes);
} finally {
bos.close();
}
if (ce.processTempDataFile(false, null, href, href, null)){
ce.setBusy(0);
ce.setIncomplete(0);
ce.setURL(href.toString());
ce.setNoHref(1);
ce.writeFileToDisk();
if (currentCE != null) {
removeCacheEntry(currentCE, false);
}
recordLastAccessed();
}
}
public static String getIndexFileExtension() {
return INDEX_FILE_EXT;
}
private static String getVersionTag(final String version) {
return version == null ? "" : DASH + version + DASH ;
}
public static File getCacheDir() {
return cacheDir;
}
public static void setSystemCacheDir(String path) {
if (path == null || path.length() == 0) {
sysCacheDir = null;
} else {
String sysCachePath = path + File.separator + VERSION_STRING;
sysCacheDir = new File(sysCachePath);
}
}
public static File getActiveCacheDir() {
return (Environment.isSystemCacheMode()) ? sysCacheDir : cacheDir;
}
public static File [] getCacheEntries(boolean system) {
File currentCacheDir = (system || Environment.isSystemCacheMode()) ?
sysCacheDir : cacheDir;
if (currentCacheDir == null) {
return new File[0];
}
ArrayList fileList = new ArrayList();
for (int i = 0; i < NUM_OF_CACHE_SUBDIR; i++) {
File cacheSubDir = new File(currentCacheDir.getPath() +
File.separator + i);
if (cacheSubDir.exists()) {
File[] files = cacheSubDir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
boolean ret = filename.endsWith(INDEX_FILE_EXT);
return ret;
}
});
for (int j = 0; j < files.length; j++) {
fileList.add(files[j]);
}
}
}
return (File[])fileList.toArray(new File[fileList.size()]);
}
public static Iterator getJnlpCacheEntries(boolean system) {
final ArrayList al = new ArrayList();
File[] files = getCacheEntries(system);
if (files != null) {
for (int i = 0; i < files.length; i++) {
String url = getURLFromIndexFile(files[i]);
if (url != null) {
int queryIndex = url.lastIndexOf('?');
if (queryIndex != -1) {
url = url.substring(0, queryIndex);
}
if (url.endsWith(".jnlp") || url.endsWith(".jarjnlp")) {
String idxpath = files[i].getPath();
String jnlppath =
idxpath.substring(0, idxpath.length() - 4);
al.add(new File(jnlppath));
}
}
}
}
return al.iterator();
}
public static void removeRemovedApp(String urlString, String title) {
Properties p = getRemovedApps();
String app = p.getProperty(urlString);
if (app != null && app.equals(title)) {
p.remove(urlString);
setRemovedApps(p);
}
}
public static void saveRemovedApp(URL href, String title) {
if (Environment.isSystemCacheMode()) {
if (getCacheEntry(href, null, null, cacheDir) != null) {
return;
}
} else {
if (getCacheEntry(href, null, null, sysCacheDir) != null) {
return;
}
}
Properties p = getRemovedApps();
p.setProperty(href.toString(), title);
setRemovedApps(p);
}
public static void setRemovedApps(Properties props) {
try {
FileOutputStream fos = new FileOutputStream(getRemovePath());
props.store(fos, "Removed JNLP Applications");
fos.close();
} catch (IOException ioe) { }
}
public static Properties getRemovedApps() {
Properties props = new Properties();
try {
InputStream is = new FileInputStream(getRemovePath());
props.load(is);
is.close();
} catch (IOException ioe) { }
return props;
}
static final String LAST_ACCESS_FILE = "lastAccessed";
public static long getLastAccessed(boolean system) {
File f = new File(system ? sysCacheDir : cacheDir, LAST_ACCESS_FILE);
return f.lastModified();
}
private static void recordLastAccessed() {
File f = new File(getActiveCacheDir(), LAST_ACCESS_FILE);
try {
OutputStream os = new FileOutputStream(f);
os.write((int) '.');
os.close();
} catch(IOException io) { }
}
public static String getRemovePath() {
return cachePath + File.separator + REMOVED_APPS;
}
final static String REMOVED_APPS = "removed.apps";
public static boolean removeCacheEntry(final URL resourceURL,
final String resourceID, final String version) {
CacheEntry ce = getCacheEntry(resourceURL, resourceID,
version, getActiveCacheDir());
return removeCacheEntry(ce);
}
public static final void touch(final File file) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws IOException {
file.setLastModified(System.currentTimeMillis());
return null;
}
});
} catch (PrivilegedActionException pae) {
Trace.ignoredException(pae);
}
}
public static void removeAllCacheEntries(CacheEntry ce) {
if (ce == null) {
return;
}
URL u = null;
try {
u = new URL(ce.getURL());
} catch (MalformedURLException mue) {
}
String version = ce.getVersion();
removeCacheEntry(ce);
if (u == null) {
return;
}
File[] idxFiles = getMatchingIndexFiles(getActiveCacheDir(), u);
for (int i = 0; i < idxFiles.length; i++) {
CacheEntry c = new CacheEntry(idxFiles[i]);
String cVers = c.getVersion();
if ( ( version == null && cVers==null ) ||
( version != null && version.equals(cVers) )) {
removeCacheEntry(c);
}
}
}
public static int removeDuplicateEntries(boolean system, boolean ignoreIP) {
int totalSize = 0;
File [] files = getCacheEntries(system);
for (int i=0; i<files.length; i++) {
CacheEntry ce = Cache.getCacheEntryFromFile(files[i]);
totalSize += removeDuplicateEntries(ce, ignoreIP);
}
if(totalSize>0) {
Trace.println("Remove All Duplicates: "+totalSize+" bytes",
TraceLevel.NETWORK);
}
return totalSize;
}
public static int removeDuplicateEntries(CacheEntry ce, boolean ignoreIP) {
int totalSize = 0;
String urlString = (null!=ce)?ce.getURL():null;
if (ce == null || urlString == null ||
ce.getIncomplete()!=0 || MemoryCache.contains(urlString))
{
return totalSize;
}
URL u = null;
try {
u = new URL(urlString);
} catch (MalformedURLException mue) {
}
if (u == null) {
return totalSize;
}
File[] idxFiles = getMatchingIndexFiles(cacheDir, u);
CacheEntry lc = ce;
for (int i = 0; i < idxFiles.length; i++) {
CacheEntry c = new CacheEntry(idxFiles[i]);
String version = lc.getVersion();
String cVers = c.getVersion();
if ( ( version == null && cVers==null ) ||
( version != null && version.equals(cVers) )) {
String ip = ignoreIP?null:lc.getCodebaseIP();
String cip = ignoreIP?null:c.getCodebaseIP();
if( ip == cip || ( ip!=null && ip.equals(cip) )) {
if(lc.removeBefore(c)) {
lc=c;
}
}
}
}
String version = lc.getVersion();
int num = 0;
for (int i = 0; i < idxFiles.length; i++) {
CacheEntry c = new CacheEntry(idxFiles[i]);
String cVers = c.getVersion();
if ( ( version == null && cVers==null ) ||
( version != null && version.equals(cVers) )) {
String ip = ignoreIP?null:lc.getCodebaseIP();
String cip = ignoreIP?null:c.getCodebaseIP();
if(ip == cip || ( ip!=null && ip.equals(cip) )) {
if(!c.getIndexFile().equals(lc.getIndexFile()))
{
if (removeCacheEntry(c, false)) {
totalSize += c.getContentLength();
num++;
}
}
}
}
}
if(totalSize>0) {
Trace.println("Remove "+num+" Duplicates of: ["+lc.getURL()+", ",
TraceLevel.NETWORK);
Trace.println("\tidx: "+lc.getIndexFile()+"], "+totalSize+" bytes",
TraceLevel.NETWORK);
}
return totalSize;
}
public static boolean removeCacheEntry(final CacheEntry ce,
final boolean removeLAP) {
Boolean ret = (Boolean) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
boolean ret = removeCacheEntryImpl(ce, removeLAP);
return Boolean.valueOf(String.valueOf(ret));
}
});
return ret.booleanValue();
}
private static boolean removeCacheEntryImpl(CacheEntry ce, boolean removeLAP) {
if (Trace.isTraceLevelEnabled(TraceLevel.NETWORK)) {
Trace.println(ResourceManager.getString("cache.removeCacheEntry",
ce == null ? "" : ce.getURL()), TraceLevel.NETWORK);
}
if (!ce.getIndexFile().getParentFile().getParentFile().equals(getActiveCacheDir())) {
return true;
}
File jarFile = new File(ce.getResourceFilename());
String urlString = ce.getURL();
String version = ce.getVersion();
boolean ret = false;
if (!MemoryCache.contains(urlString)) {
if (urlString != null &&
(urlString.toLowerCase().endsWith(".jar") ||
urlString.toLowerCase().endsWith(".jarjar"))) {
JarFile jf = ce.getJarFile();
if (jf != null) {
try {
jf.close();
} catch (IOException ioe) {
Trace.ignoredException(ioe);
}
}
}
ret = jarFile.delete();
} else {
jarFile.deleteOnExit();
}
clobber(new File(ce.getNativeLibPath()));
boolean ret2 = ce.getIndexFile().delete();
try {
String name = getLapFileName(new URL(urlString), version);
File lapFile = new File(getActiveCacheDir(), name);
if (lapFile.exists() && removeLAP) {
lapFile.delete();
}
} catch (MalformedURLException mfue) {
}
File icoFile = new File(ce.getResourceFilename() + ".ico");
if (icoFile.exists()) {
icoFile.delete();
}
recordLastAccessed();
MemoryCache.removeLoadedResource(ce.getURL());
return ret && ret2;
}
private static void clobber(File f) {
if (f.exists()) {
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i=0; i<files.length; i++) {
clobber(files[i]);
}
f.delete();
} else {
f.delete();
}
}
}
public static boolean removeCacheEntry(CacheEntry ce) {
return removeCacheEntry(ce, true);
}
private static File[] getMatchingIndexFiles(final File cacheDirectory, URL url) {
final String key = getKey(url);
final File directory = new File(cacheDirectory.getPath() + File.separator +
getBucket(key));
File[] idxFiles = (File[]) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
File[] files = directory.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
return filename.startsWith(key) &&
filename.endsWith(INDEX_FILE_EXT);
}
});
return files;
}
});
return idxFiles;
}
public static CacheEntry getCacheEntryFromFile(File idxFile) {
CacheEntry ce = new CacheEntry(idxFile);
if (ce != null && ce.getIncomplete() == 0 && isCacheEntryIPValid(ce)) {
return ce;
}
return null;
}
public static String getVersionFromFilename(String filename) {
StringTokenizer st = new StringTokenizer(filename, "-");
if (st.countTokens() != 4) {
return null;
}
st.nextToken();
st.nextToken();
return st.nextToken();
}
public static CacheEntry getLatestCacheEntry(final URL url,
final String resourceID) {
File latestCacheFile = null;
String latestVersion = null;
File[] idxFiles = getMatchingIndexFiles(cacheDir, url);
for (int i = 0 ; i < idxFiles.length; i++) {
if (latestCacheFile == null) {
latestCacheFile = idxFiles[i];
} else {
String curVer = getVersionFromFilename(idxFiles[i].getName());
String latestVer =
getVersionFromFilename(latestCacheFile.getName());
if (curVer != null && (latestVer == null ||
curVer.compareTo(latestVer) > 0)) {
latestCacheFile = idxFiles[i];
}
}
}
if (latestCacheFile != null) {
return getCacheEntryFromFile(latestCacheFile);
}
return null;
}
public static String getURLFromIndexFile(File idxFile) {
CacheEntry ce = new CacheEntry(idxFile);
return ce.getURL();
}
public static boolean isEntryIncomplete(File idxFile) {
CacheEntry ce = new CacheEntry(idxFile);
return (ce.getIncomplete() == 0);
}
private static CacheEntry getCacheEntryFromIdxFiles(File[] idxFiles,
URL url, String version, int contentType) {
CacheEntry ce = null;
CacheEntry found = null;
if (idxFiles != null) {
for (int i = 0 ; i < idxFiles.length; i++) {
ce = new CacheEntry(idxFiles[i]);
if (ce.getIncomplete() == 0) {
if (ce.getURL().equals(url.toString())) {
if (isCacheEntryIPValid(ce)) {
if (version == null && ce.getVersion() == null) {
found = ce;
break;
}
if (version != null &&
new VersionString(version).contains(
ce.getVersion())) {
if (found == null) {
found = ce;
} else {
if (ce.getVersion() != null) {
if (ce.getVersion().compareTo(
found.getVersion()) > 0) {
found = ce;
}
}
}
}
} } else {
if (ce.getURL().indexOf('?') != -1) {
removeCacheEntry(ce, false);
}
}
} else {
cleanup();
}
}
}
if (found != null && DownloadEngine.isNativeContentType(contentType)) {
File nativeDir = new File(found.getNativeLibPath());
if (nativeDir.isDirectory() == false) {
removeCacheEntry(found);
found = null;
}
}
return found;
}
public static void updateHostIPFile(String host) {
String cachedIP = getCachedHostIP(host);
if (cachedIP == null) {
createHostEntry(host);
} else {
String currentIP = getCurrentIP(host, cachedIP);
if (currentIP != null && currentIP.equals(cachedIP) == false) {
updateHostEntry(host);
}
}
}
private static URL getHostURL(String host) {
URL u = null;
try {
u = new URL("http://" + host);
} catch (MalformedURLException mue) {
}
return u;
}
private static void updateHostEntry(String host) {
URL u = getHostURL(host);
final File[] hostFiles = getMatchingHostFiles(hostDir, u);
AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
for (int i = 0; i < hostFiles.length; i++) {
hostFiles[i].delete();
}
return null;
}
});
createHostEntry(host);
}
private static String getCurrentIP(String host, String cachedIP) {
if (host == null || cachedIP == null) {
return null;
}
if (!doIPLookup) {
return null;
}
String hostIP = null;
Class inetClass = null;
try {
inetClass = Class.forName("java.net.InetAddress");
} catch (ClassNotFoundException cnfe) {
Trace.ignoredException(cnfe);
return null;
}
InetAddress cacheIna = null;
try {
cacheIna = InetAddress.getByName(cachedIP);
} catch (UnknownHostException uhe) {
Trace.ignoredException(uhe);
}
Object[] arguments = { host, cacheIna };
Class type[] = new Class[2];
try {
type[0] = Class.forName("java.lang.String");
type[1] = inetClass;
} catch (ClassNotFoundException cnfe) {
Trace.ignoredException(cnfe);
return null;
}
final Method lookupMethod;
try {
lookupMethod = inetClass.getDeclaredMethod("getByName", type);
} catch (NoSuchMethodException nsme) {
return null;
}
AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
lookupMethod.setAccessible(true);
return null;
}
});
if (!Modifier.isStatic(lookupMethod.getModifiers())) {
return null;
}
InetAddress ina = null;
try {
ina = (InetAddress) (lookupMethod.invoke((Object)null,
arguments));
} catch (IllegalAccessException iae) {
Trace.ignoredException(iae);
} catch (InvocationTargetException ite) {
}
if (ina != null) {
hostIP = ina.getHostAddress();
}
return hostIP;
}
private static boolean isCacheEntryIPValid(CacheEntry ce) {
boolean result = true;
if (ce != null && ce.isKnownToBeSigned()) {
return result;
}
String cacheEntryCodebaseIP = ce.getCodebaseIP();
if (cacheEntryCodebaseIP == null) {
return result;
}
URL u = null;
try {
u = new URL(ce.getURL());
} catch (MalformedURLException mue) {
Trace.ignoredException(mue);
return false;
}
String host = u.getHost();
String currentHostIP = getCurrentIP(host, cacheEntryCodebaseIP);
if (currentHostIP == null) {
return true;
}
if (currentHostIP.equals(cacheEntryCodebaseIP) == false) {
result = false;
}
return result;
}
public static CacheEntry getCacheEntry(final URL url,
final String resourceID, final String version) {
return getCacheEntry(url, resourceID, version,
DownloadEngine.NORMAL_CONTENT_BIT);
}
public static CacheEntry getCacheEntry(final URL url,
final String resourceID, final String version,
final int contentType) {
CacheEntry ce = (CacheEntry) MemoryCache.getLoadedResource(url.toString());
if (ce != null) {
String currentVersion = ce.getVersion();
if ((version == null && currentVersion == null )||
(version != null && currentVersion != null &&
currentVersion.compareTo(version) >= 0)) {
return ce;
}
}
CacheEntry found = getCacheEntry(url, resourceID, version, cacheDir,
contentType);
CacheEntry sysFound = getCacheEntry(url, resourceID,
version, sysCacheDir, contentType);
if (Environment.isSystemCacheMode()) {
if (sysFound != null) {
MemoryCache.addLoadedResource(url.toString(), sysFound);
Trace.println("System Cache: " +
ResourceManager.getString(
"cache.getCacheEntry.return.found",
url == null ? "" : url.toString(), version) +
" prevalidated=" + sysFound.isKnownToBeSigned() +
"/" + sysFound.getClassesVerificationStatus(),
TraceLevel.NETWORK);
}
return sysFound;
}
if (sysFound != null) {
if (found != null) {
if (found.getLastModified() <= sysFound.getLastModified()) {
found = sysFound;
}
} else {
found = sysFound;
}
}
if (found == null) {
if (Trace.isTraceLevelEnabled(TraceLevel.NETWORK)) {
Trace.println(ResourceManager.getString(
"cache.getCacheEntry.return.notfound",
url == null ? "" : url.toString(), version),
TraceLevel.NETWORK);
}
} else {
if (Trace.isTraceLevelEnabled(TraceLevel.NETWORK)) {
Trace.println(ResourceManager.getString(
"cache.getCacheEntry.return.found",
url == null ? "" : url.toString(), version) +
" prevalidated=" + found.isKnownToBeSigned() +
"/" + found.getClassesVerificationStatus(),
TraceLevel.NETWORK);
}
MemoryCache.addLoadedResource(url.toString(), found);
}
return found;
}
public static CacheEntry getCacheEntry(final URL url,
final String resourceID, final String version, final File dir) {
return getCacheEntry(url, resourceID, version, dir,
DownloadEngine.NORMAL_CONTENT_BIT);
}
private static CacheEntry getCacheEntry(final URL url,
final String resourceID, final String version, final File dir,
final int contentType) {
if (dir == null) {
return null;
}
File [] idxFiles = getMatchingIndexFiles(dir, url);
CacheEntry ce = getCacheEntryFromIdxFiles(idxFiles, url, version,
contentType);
return ce;
}
private static File[] getMatchingMuffinFiles(File directory, URL url) {
final String key = getKey(url);
final File[] files = directory.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
return filename.startsWith(key) &&
!filename.endsWith(MUFFIN_FILE_EXT);
}
});
return files;
}
private static File[] getMatchingMuffinAttributeFiles(File directory,
URL url) {
final String key = getKey(url);
final File[] files = directory.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
return filename.startsWith(key) &&
filename.endsWith(MUFFIN_FILE_EXT);
}
});
return files;
}
public static File getMuffinFile(URL url) {
String key = getKey(url);
File[] files = getMatchingMuffinFiles(muffinDir, url);
if (files == null || files.length == 0) {
return null;
}
return files[0];
}
public static File getMuffinAttributeFile(URL url) {
String key = getKey(url);
File[] files = getMatchingMuffinAttributeFiles(muffinDir, url);
if (files == null || files.length == 0) {
return null;
}
return files[0];
}
public static long [] getMuffinAttributes(URL url) throws IOException {
BufferedReader br = null;
long tag = -1;
long maxsize = -1;
try {
File muffinFile = getMuffinAttributeFile(url);
if (muffinFile == null) {
throw new FileNotFoundException("Muffin not found for " + url);
}
InputStream is = new FileInputStream(muffinFile);
br = new BufferedReader(new InputStreamReader(is));
String line = br.readLine();
try {
tag = (long) Integer.parseInt(line);
} catch (NumberFormatException nfe) {
throw new IOException(nfe.getMessage());
}
line = br.readLine();
try {
maxsize = Long.parseLong(line);
} catch (NumberFormatException nfe) {
throw new IOException(nfe.getMessage());
}
} finally {
if (br != null) br.close();
}
return new long [] {tag, maxsize};
}
public static void removeMuffinEntry(URL url) throws IOException {
File muffinFile = getMuffinFile(url);
if (muffinFile != null) {
if (!muffinFile.delete()) throw
new IOException("delete failed for muffin: " + url);
File maFile = new File(muffinFile.getPath() + MUFFIN_FILE_EXT);
if (!maFile.delete()) throw
new IOException("delete failed for muffin: " + url);
} else {
throw new FileNotFoundException(
"Muffin for " + url + " does not exists");
}
}
private static String getCachedHostIP(String host) {
if (host == null) return null;
URL u = getHostURL(host);
String cachedIP = null;
final File cachedHostFile = getHostFile(u);
if (cachedHostFile != null) {
cachedIP = (String) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
String ip = null;
try {
BufferedReader br = new BufferedReader(new FileReader(
cachedHostFile));
ip = br.readLine();
br.close();
} catch (IOException ioe) {
Trace.ignoredException(ioe);
}
return ip;
}
});
}
return cachedIP;
}
private static File getHostFile(URL url) {
File[] files = getMatchingHostFiles(hostDir, url);
if (files == null || files.length == 0) {
return null;
}
return files[0];
}
private static File[] getMatchingHostFiles(final File directory, URL url) {
final String key = getKey(url);
File[] hostFiles = (File[]) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
final File[] files = directory.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
return filename.startsWith(key) &&
filename.endsWith(HOST_FILE_EXT);
}
});
return files;
}
});
return hostFiles;
}
static InetAddress getHostIP(String host) {
InetAddress ina = null;
try {
ina = InetAddress.getByName(host);
} catch (UnknownHostException uhe) {
try {
ina = InetAddress.getByName(IP_ADDR_CANNOT_RESOLVE);
} catch (UnknownHostException uhe2) {
}
}
return ina;
}
private static void createHostEntry(String host) {
URL u = getHostURL(host);
String key = getKey(u);
String filename;
final File hostFile;
filename = key + Integer.toString(getRandom(), 16);
hostFile = new File(hostDir, filename + HOST_FILE_EXT);
InetAddress ina = getHostIP(host);
if (ina != null) {
final String hostAddr = ina.getHostAddress();
AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
try {
BufferedWriter bw = new BufferedWriter(
new FileWriter(hostFile));
bw.write(hostAddr);
bw.close();
} catch (IOException ioe) {
Trace.ignoredException(ioe);
}
return null;
}
});
}
}
public static void createMuffinEntry(URL url, int tag, long maxSize)
throws IOException {
String key = getKey(url);
File[] files = getMatchingMuffinAttributeFiles(muffinDir, url);
if (files.length != 0) {
throw new IOException(
"insert failed in cache: target already exixts");
}
String filename;
File muffinFile;
File muffinAttributeFile;
filename = key + Integer.toString(getRandom(), 16);
muffinAttributeFile = new File(muffinDir, filename + MUFFIN_FILE_EXT);
muffinFile = new File(muffinDir, filename);
putMuffinAttributes(muffinAttributeFile, url, tag, maxSize);
muffinFile.createNewFile();
}
public static String[] getMuffinNames(URL url) {
Vector v = new Vector();
final File[] files = muffinDir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
return filename.endsWith(MUFFIN_FILE_EXT);
}
});
URL u = null;
String entryName;
for (int i = 0; i < files.length; i++) {
try {
u = getCachedMuffinURL(files[i]);
} catch (IOException ioe) {
Trace.ignoredException(ioe);
}
if (u != null) {
URL urlNoQuery = HttpUtils.removeQueryStringFromURL(u);
entryName = urlNoQuery.getFile().substring(1 +
urlNoQuery.getFile().lastIndexOf('/'));
if (u.toString().equals(url.toString() + entryName)) {
v.add(entryName);
}
}
}
return (String [])v.toArray(new String[0]);
}
public static URL[] getAccessibleMuffins(URL url) throws IOException {
ArrayList list = new ArrayList();
final File[] files = muffinDir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String filename = pathname.getName();
return filename.endsWith(MUFFIN_FILE_EXT);
}
});
URL u;
int urlCount = 0;
for (int i = 0; i < files.length; i++) {
u = getCachedMuffinURL(files[i]);
if (u.getHost().equals(url.getHost())) {
list.add(u);
}
}
return (URL [])list.toArray(new URL[0]);
}
static URL getCachedMuffinURL(File muffinAttributeFile) throws IOException {
BufferedReader br = null;
long tag = -1;
long maxsize = -1;
String line = null;
try {
InputStream is = new FileInputStream(muffinAttributeFile);
br = new BufferedReader(new InputStreamReader(is));
line = br.readLine();
line = br.readLine();
line = br.readLine();
} catch (Exception e) {
Trace.ignoredException(e);
} finally {
if (br != null) br.close();
}
URL url = null;
try {
url = new URL(line);
} catch (MalformedURLException mue) {
Trace.ignoredException(mue);
}
return url;
}
public static long getMuffinSize(URL url) throws IOException {
long size = 0;
File muffinFile = getMuffinFile(url);
if (muffinFile != null && muffinFile.exists()) {
size += muffinFile.length();
}
return size;
}
private static void putMuffinAttributes(File muffinAttributeFile,
URL url, int tag, long maxsize) throws IOException {
PrintStream ps = new PrintStream(new FileOutputStream(
muffinAttributeFile));
try {
ps.println(tag);
ps.println(maxsize);
ps.println(url.toString());
} finally {
if (ps != null) ps.close();
}
}
public static void putMuffinAttributes(URL url, int tag,
long maxsize) throws IOException {
File muffinAttributeFile = getMuffinAttributeFile(url);
PrintStream ps = new PrintStream(new FileOutputStream(
muffinAttributeFile));
try {
ps.println(tag);
ps.println(maxsize);
ps.println(url.toString());
} finally {
if (ps != null) ps.close();
}
}
static String generateCacheFileName(final URL url,
final String version) throws IOException {
String filename = null;
try {
filename = (String)AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws IOException {
String key = getKey(url);
String filename;
File dataFile, indexFile;
do {
filename = getBucket(key) + File.separator +
key + Integer.toString(getRandom(), 16) +
getVersionTag(version);
dataFile = new File(cacheDir, filename);
indexFile = new File(cacheDir, filename + INDEX_FILE_EXT);
} while (indexFile.exists() || dataFile.exists());
indexFile = null;
dataFile = null;
return filename;
}
});
} catch (PrivilegedActionException pae) {
if (pae.getException() instanceof IOException) {
throw (IOException)pae.getException();
}
}
return filename;
}
public static int getBucket(String key) {
return Integer.valueOf(key.substring(0, key.length()-1), 16).intValue()
& (NUM_OF_CACHE_SUBDIR-1);
}
protected static String getKey(URL url) {
int hashCode = hashCode(HttpUtils.removeQueryStringFromURL(url));
if (hashCode < 0) {
hashCode += Integer.MAX_VALUE + 1;
}
String key = Integer.toString(hashCode, 16);
return key + "-";
}
protected static int hashCode(URL x) {
int h = x.toString().hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
protected static final String getFileExtension(String name) {
String ext = "";
int extIndex = name.lastIndexOf('.');
if(extIndex != -1) {
ext = name.substring(extIndex);
}
return ext;
}
protected static final int getRandom() {
return 0x10000000 + getSecureRandom().nextInt(Integer.MAX_VALUE - 0x10000000);
}
public static void insertFile(File dataFile, int contentType,
URL url, String version, long ts, long expiration)
throws IOException {
String cacheFileName = generateCacheFileName(url, version);
File dir = getActiveCacheDir();
File indexFile = new File(dir, cacheFileName + getIndexFileExtension());
CacheEntry ce = new CacheEntry(indexFile);
ce.writeFileToDisk();
try {
copyFile(dataFile, new File(dir, cacheFileName));
} catch (IOException e) {
removeCacheEntry(ce);
throw e;
}
ce.setBusy(0);
ce.setIncomplete(0);
ce.setURL(url.toString());
ce.setContentLength((int) dataFile.length());
ce.setLastModified(ts);
ce.setExpirationDate(expiration);
if (version != null) {
ce.setVersion(version);
}
if (DownloadEngine.isJarContentType(contentType)) {
MessageHeader headerFields = new MessageHeader();
headerFields.add(HttpRequest.DEPLOY_REQUEST_CONTENT_TYPE,
HttpRequest.JAR_MIME_TYPE);
ce.setHeaders(headerFields);
}
ce.writeFileToDisk(contentType, null);
recordLastAccessed();
}
public static void insertMuffin(URL url, File muffin,
int tag, long maxSize) throws IOException {
File[] files = getMatchingMuffinAttributeFiles(muffinDir, url);
if (files.length != 0) {
throw new IOException(
"insert failed in cache: target already exixts");
}
String filename;
File muffinAttributeFile;
String key = getKey(url);
filename = key + Integer.toString(getRandom(), 16);
muffinAttributeFile = new File(muffinDir, filename + MUFFIN_FILE_EXT);
putMuffinAttributes(muffinAttributeFile, url, tag, maxSize);
copyFile(muffin, new File(muffinDir, filename));
}
public static void copyFile(File src, File dst) throws IOException {
byte b[] = new byte[10240];
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(dst));
bis = new BufferedInputStream(new FileInputStream(src));
int n = bis.read(b);
while (n >= 0) {
bos.write(b, 0, n);
n = bis.read(b);
}
} finally {
try {
if (bos != null) {
bos.close();
}
} catch (Exception e) {}
try {
if (bis != null) {
bis.close();
}
} catch (Exception e) {}
}
}
public static void removeAllMuffins() {
File[] children = muffinDir.listFiles();
for (int i=0; i<children.length; i++) {
children[i].delete();
}
}
}