All Downloads are FREE. Search and download functionalities are using the official Maven repository.

Explore the source code of the class DefaultFileCacheBacking.java

/*******************************************************************************
 * Copyright (c) 2012 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution and is available at
 * http://eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   John Kew (vmware)         	initial implementation
 *   Lyor Goldstein (vmware)	add support for weaved class being re-defined
 *******************************************************************************/

package org.aspectj.weaver.tools.cache;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.OutputStream;
import java.util.Map;

import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.FileUtil;
import org.aspectj.util.LangUtil;


/**
 * Naive File-Backed Class Cache with no expiry or application
 * centric invalidation.
 * 

* Enabled with the system property, "aj.weaving.cache.dir" * If this system property is not set, no caching will be * performed. *

* A CRC checksum is stored alongside the class file to verify * the bytes on read. If for some reason there is an error * reading either the class or crc file, or if the crc does not * match the class data the cache entry is deleted. *

* An alternate implementation of this could store the class file * as a jar/zip directly, which would have the required crc; as * a first pass however it is somewhat useful to view these files * in expanded form for debugging. */ public class DefaultFileCacheBacking extends AbstractIndexedFileCacheBacking { private final Map index; private static final Object LOCK = new Object(); protected DefaultFileCacheBacking(File cacheDir) { super(cacheDir); index = readIndex(); } public static final DefaultFileCacheBacking createBacking(File cacheDir) { if (!cacheDir.exists()) { if (!cacheDir.mkdirs()) { MessageUtil.error("Unable to create cache directory at " + cacheDir.getName()); return null; } } else if (!cacheDir.isDirectory()) { MessageUtil.error("Not a cache directory at " + cacheDir.getName()); return null; } if (!cacheDir.canWrite()) { MessageUtil.error("Cache directory is not writable at " + cacheDir.getName()); return null; } return new DefaultFileCacheBacking(cacheDir); } @Override protected Map getIndex() { return index; } @Override protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) { File cacheEntry = new File(cacheDir, ie.key); if (ie.ignored || cacheEntry.canRead()) { return ie; } else { return null; } } private void removeIndexEntry(String key) { synchronized (LOCK) { index.remove(key); writeIndex(); } } private void addIndexEntry(IndexEntry ie) { synchronized (LOCK) { index.put(ie.key, ie); writeIndex(); } } @Override protected Map readIndex() { synchronized (LOCK) { return super.readIndex(); } } @Override protected void writeIndex() { synchronized (LOCK) { super.writeIndex(); } } public void clear() { File cacheDir=getCacheDirectory(); int numDeleted=0; synchronized (LOCK) { numDeleted = FileUtil.deleteContents(cacheDir); } if ((numDeleted > 0) && (logger != null) && logger.isTraceEnabled()) { logger.info("clear(" + cacheDir + ") deleted"); } } public static CacheBacking createBacking(String scope) { String cache = System.getProperty(WEAVED_CLASS_CACHE_DIR); if (cache == null) { return null; } File cacheDir = new File(cache, scope); return createBacking(cacheDir); } @Override public String[] getKeys(final String regex) { File cacheDirectory = getCacheDirectory(); File[] files = cacheDirectory.listFiles(new FilenameFilter() { public boolean accept(File file, String s) { if (s.matches(regex)) { return true; } return false; } }); if (LangUtil.isEmpty(files)) { return EMPTY_KEYS; } String[] keys = new String[files.length]; for (int i = 0; i < files.length; i++) { keys[i] = files[i].getName(); } return keys; } public CachedClassEntry get(CachedClassReference ref, byte[] originalBytes) { File cacheDirectory = getCacheDirectory(); String refKey=ref.getKey(); File cacheFile = new File(cacheDirectory, refKey); IndexEntry ie = index.get(refKey); if (ie == null) { // no index, delete delete(cacheFile); return null; } // check if original file changed if (crc(originalBytes) != ie.crcClass) { delete(cacheFile); return null; } if (ie.ignored) { return new CachedClassEntry(ref, WeavedClassCache.ZERO_BYTES, CachedClassEntry.EntryType.IGNORED); } if (cacheFile.canRead()) { byte[] bytes = read(cacheFile, ie.crcWeaved); if (bytes != null) { if (!ie.generated) { return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.WEAVED); } else { return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.GENERATED); } } } return null; } public void put(CachedClassEntry entry, byte[] originalBytes) { File cacheDirectory = getCacheDirectory(); String refKey = entry.getKey(); IndexEntry ie = index.get(refKey); File cacheFile = new File(cacheDirectory, refKey); final boolean writeEntryBytes; // check if original bytes changed or the ignored/generated flags if ((ie != null) && ((ie.ignored != entry.isIgnored()) || (ie.generated != entry.isGenerated()) || (crc(originalBytes) != ie.crcClass))) { delete(cacheFile); writeEntryBytes = true; } else { writeEntryBytes = !cacheFile.exists(); } if (writeEntryBytes) { ie = createIndexEntry(entry, originalBytes); if (!entry.isIgnored()) { ie.crcWeaved = write(cacheFile, entry.getBytes()); } addIndexEntry(ie); } } public void remove(CachedClassReference ref) { File cacheDirectory = getCacheDirectory(); String refKey = ref.getKey(); File cacheFile = new File(cacheDirectory, refKey); synchronized (LOCK) { removeIndexEntry(refKey); delete(cacheFile); } } @Override protected void delete(File file) { synchronized (LOCK) { super.delete(file); } } protected byte[] read(File file, long expectedCRC) { byte[] bytes=null; synchronized (LOCK) { FileInputStream fis = null; try { fis = new FileInputStream(file); bytes = FileUtil.readAsByteArray(fis); } catch (Exception e) { if ((logger != null) && logger.isTraceEnabled()) { logger.warn("read(" + file.getAbsolutePath() + ")" + " failed (" + e.getClass().getSimpleName() + ")" + " to read contents: " + e.getMessage(), e); } } finally { close(fis, file); } // delete the file if there was an exception reading it or mismatched crc if ((bytes == null) || (crc(bytes) != expectedCRC)) { delete(file); return null; } } return bytes; } protected long write(File file, byte[] bytes) { synchronized (LOCK) { if (file.exists()) { return -1L; } OutputStream out = null; try { out = new FileOutputStream(file); out.write(bytes); } catch (Exception e) { if ((logger != null) && logger.isTraceEnabled()) { logger.warn("write(" + file.getAbsolutePath() + ")" + " failed (" + e.getClass().getSimpleName() + ")" + " to write contents: " + e.getMessage(), e); } // delete the file if there was an exception writing it delete(file); return -1L; } finally { close(out, file); } return crc(bytes); } } }