diff options
author | Andy Clement <andrew.clement@gmail.com> | 2012-10-01 13:22:37 -0700 |
---|---|---|
committer | Andy Clement <andrew.clement@gmail.com> | 2012-10-01 13:22:37 -0700 |
commit | 9a3cc2bc5c824d252140fb3d1e2e27f2163e6d53 (patch) | |
tree | cb4bfaf7de826280933a898850894464b730c5c0 /weaver | |
parent | 0bbb4f252a1efa7408f55e06fc062baddce0dcba (diff) | |
download | aspectj-9a3cc2bc5c824d252140fb3d1e2e27f2163e6d53.tar.gz aspectj-9a3cc2bc5c824d252140fb3d1e2e27f2163e6d53.zip |
389967
Diffstat (limited to 'weaver')
12 files changed, 405 insertions, 382 deletions
diff --git a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java index f23794647..8b31ce586 100644 --- a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java +++ b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java @@ -7,7 +7,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Matthew Webster, Adrian Colyer, John Kew (caching) + * Matthew Webster, Adrian Colyer, John Kew + Lyor Goldstein (caching) * Martin Lippert initial implementation * ******************************************************************/ @@ -336,10 +336,10 @@ public class WeavingAdaptor implements IMessageContext { // Determine if we have the weaved class cached CachedClassReference cacheKey = null; - byte[] original_bytes = bytes; + final byte[] original_bytes = bytes; if (cache != null && !mustWeave) { - cacheKey = cache.createCacheKey(name, bytes); - CachedClassEntry entry = cache.get(cacheKey); + cacheKey = cache.createCacheKey(name, original_bytes); + CachedClassEntry entry = cache.get(cacheKey, original_bytes); if (entry != null) { // If the entry has been explicitly ignored // return the original bytes @@ -382,9 +382,9 @@ public class WeavingAdaptor implements IMessageContext { // If no transform has been applied, mark the class // as ignored. if (Arrays.equals(original_bytes, bytes)) { - cache.ignore(cacheKey); + cache.ignore(cacheKey, original_bytes); } else { - cache.put(cacheKey, bytes); + cache.put(cacheKey, original_bytes, bytes); } } } else if (debugOn) { @@ -881,9 +881,10 @@ public class WeavingAdaptor implements IMessageContext { } else { // Classes generated by weaver e.g. around closure advice String className = result.getClassName(); + byte[] resultBytes = result.getBytes(); generatedClasses.put(className, result); generatedClasses.put(wovenClass.getClassName(), result); - generatedClassHandler.acceptClass(className, result.getBytes()); + generatedClassHandler.acceptClass(className, null, resultBytes); } } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java index db3693dec..bcf7c0b60 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java @@ -7,7 +7,8 @@ * http://eclipse.org/legal/epl-v10.html * * Contributors: - * John Kew (vmware) initial implementation + * John Kew (vmware) initial implementation + * Lyor Goldstein (vmware) add support for weaved class being re-defined *******************************************************************************/ package org.aspectj.weaver.tools.cache; @@ -45,14 +46,18 @@ public interface CacheBacking { * Get a cache entry * * @param ref entry to retrieve + * @param originalBytes Pre-weaving class bytes - required in order to + * ensure that the cached entry refers to the same original class * @return the cached bytes or null, if the entry does not exist */ - public CachedClassEntry get(CachedClassReference ref); + public CachedClassEntry get(CachedClassReference ref, byte[] originalBytes); /** * Put an entry in the cache * * @param entry key of the entry + * @param originalBytes Pre-weaving class bytes - required in order to + * ensure that the cached entry refers to the same original class */ - public void put(CachedClassEntry entry); + public void put(CachedClassEntry entry, byte[] originalBytes); } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java b/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java index 3a1d4d7ad..1ccacfc18 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java @@ -92,6 +92,7 @@ public class CacheStatistics { puts_ignored = 0; } + @Override public String toString() { return "CacheStatistics{" + "hits=" + hits + diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java b/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java index 9ff7666b6..db74e7f92 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java @@ -7,7 +7,8 @@ * http://eclipse.org/legal/epl-v10.html * * Contributors: - * John Kew (vmware) initial implementation + * John Kew (vmware) initial implementation + * Lyor Goldstein (vmware) add support for weaved class being re-defined *******************************************************************************/ package org.aspectj.weaver.tools.cache; @@ -15,43 +16,75 @@ package org.aspectj.weaver.tools.cache; * Represents a class which has been cached */ public class CachedClassEntry { - enum EntryType { - GENERATED, - WEAVED, - IGNORED, - } - - private final CachedClassReference ref; - private final byte[] bytes; - private final EntryType type; - - public CachedClassEntry(CachedClassReference ref, byte[] bytes, EntryType type) { - this.bytes = bytes; - this.ref = ref; - this.type = type; - } - - public String getClassName() { - return ref.getClassName(); - } - - public byte[] getBytes() { - return bytes; - } - - public String getKey() { - return ref.getKey(); - } - - public boolean isGenerated() { - return type == EntryType.GENERATED; - } - - public boolean isWeaved() { - return type == EntryType.WEAVED; - } - - public boolean isIgnored() { - return type == EntryType.IGNORED; - } + static enum EntryType { + GENERATED, + WEAVED, + IGNORED, + } + + private final CachedClassReference ref; + private final byte[] weavedBytes; + private final EntryType type; + + public CachedClassEntry(CachedClassReference ref, byte[] weavedBytes, EntryType type) { + this.weavedBytes = weavedBytes; + this.ref = ref; + this.type = type; + } + + public String getClassName() { + return ref.getClassName(); + } + + public byte[] getBytes() { + return weavedBytes; + } + + public String getKey() { + return ref.getKey(); + } + + public boolean isGenerated() { + return type == EntryType.GENERATED; + } + + public boolean isWeaved() { + return type == EntryType.WEAVED; + } + + public boolean isIgnored() { + return type == EntryType.IGNORED; + } + + @Override + public int hashCode() { + return getClassName().hashCode() + + getKey().hashCode() + + type.hashCode() + ; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (this == obj) + return true; + if (getClass() != obj.getClass()) + return false; + + CachedClassEntry other=(CachedClassEntry) obj; + if (getClassName().equals(other.getClassName()) + && getKey().equals(other.getKey()) + && (type == other.type)) { + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return getClassName() + "[" + type + "]"; + } } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java b/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java index 06a0a97eb..7d48ff171 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java @@ -7,7 +7,8 @@ * http://eclipse.org/legal/epl-v10.html * * Contributors: - * John Kew (vmware) initial implementation + * John Kew (vmware) initial implementation + * Lyor Goldstein (vmware) add support for weaved class being re-defined *******************************************************************************/ package org.aspectj.weaver.tools.cache; @@ -22,7 +23,7 @@ package org.aspectj.weaver.tools.cache; * objects manually. */ public class CachedClassReference { - enum EntryType { + static enum EntryType { GENERATED, WEAVED, IGNORED, @@ -32,8 +33,7 @@ public class CachedClassReference { private final String className; protected CachedClassReference(String key, CacheKeyResolver resolver) { - this.key = key; - this.className = resolver.keyToClass(key); + this(key, resolver.keyToClass(key)); } /** @@ -54,4 +54,32 @@ public class CachedClassReference { public String getClassName() { return className; } + + @Override + public int hashCode() { + return getKey().hashCode() + getClassName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (this == obj) + return true; + if (getClass() != obj.getClass()) + return false; + + CachedClassReference other=(CachedClassReference) obj; + if (getKey().equals(other.getKey()) + && getClassName().equals(other.getClassName())) { + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return getClassName() + "[" + getKey() + "]"; + } } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java b/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java index 0c0d29ca9..7eb796e4b 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java @@ -21,6 +21,6 @@ public class DefaultCacheFactory implements CacheFactory { } public CacheBacking createBacking(String scope) { - return DefaultFileCacheBacking.createBacking(scope, createResolver()); + return DefaultFileCacheBacking.createBacking(scope); } } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java b/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java index 7383816b0..4951923d3 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java @@ -12,11 +12,8 @@ package org.aspectj.weaver.tools.cache; -import java.math.BigInteger; import java.net.URL; import java.net.URLClassLoader; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; diff --git a/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java index 8959ee442..de0cd9ab4 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java @@ -7,17 +7,22 @@ * http://eclipse.org/legal/epl-v10.html * * Contributors: - * John Kew (vmware) initial implementation + * 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 java.io.*; -import java.util.HashMap; -import java.util.zip.CRC32; +import org.aspectj.util.LangUtil; /** @@ -38,137 +43,112 @@ import java.util.zip.CRC32; * a first pass however it is somewhat useful to view these files * in expanded form for debugging. */ -public class DefaultFileCacheBacking implements CacheBacking { - public static final String WEAVED_CLASS_CACHE_DIR = "aj.weaving.cache.dir"; - public static final String INDEX_FILE = "cache.idx"; - - public static class IndexEntry implements Serializable { - public String key; - public boolean generated; - public boolean ignored; - public long crc; - } - - private final File cacheDirectory; - private final CacheKeyResolver resolver; - private final HashMap<String, IndexEntry> index = new HashMap<String, IndexEntry>(); +public class DefaultFileCacheBacking extends AbstractIndexedFileCacheBacking { + private final Map<String, IndexEntry> index; private static final Object LOCK = new Object(); - protected DefaultFileCacheBacking(File cacheDirectory, CacheKeyResolver resolver) { - this.cacheDirectory = cacheDirectory; - this.resolver = resolver; - readIndex(); + protected DefaultFileCacheBacking(File cacheDir) { + super(cacheDir); + index = readIndex(); } - public static CacheBacking createBacking(File cacheDir, CacheKeyResolver resolver) { + 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, resolver); + return new DefaultFileCacheBacking(cacheDir); } - public static IndexEntry[] readIndex(File indexFile) { - IndexEntry[] iea = new IndexEntry[0]; - FileInputStream fis = null; - ObjectInputStream ois = null; - try { - if (!indexFile.canRead()) { - return iea; - } - fis = new FileInputStream(indexFile); - ois = new ObjectInputStream(fis); - iea = (IndexEntry[]) ois.readObject(); - } catch (Exception e) { - delete(indexFile); - } finally { - close(fis, indexFile); - close(ois, indexFile); - } - return iea; + @Override + protected Map<String, IndexEntry> getIndex() { + return index; } - private void readIndex() { + @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) { - IndexEntry[] idx = readIndex(new File(cacheDirectory, INDEX_FILE)); - for (IndexEntry ie : idx) { - File cacheFile = new File(cacheDirectory, ie.key); - if (cacheFile.canRead() || ie.ignored) { - index.put(ie.key, ie); - } - } + index.remove(key); + writeIndex(); } } - private void writeIndex() { + private void addIndexEntry(IndexEntry ie) { synchronized (LOCK) { - if (!cacheDirectory.exists()) - cacheDirectory.mkdirs(); - File indexFile = new File(cacheDirectory, INDEX_FILE); - FileOutputStream fos = null; - ObjectOutputStream oos = null; - try { - delete(indexFile); - fos = new FileOutputStream(indexFile); - oos = new ObjectOutputStream(fos); - oos.writeObject(index.values().toArray(new IndexEntry[0])); - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - close(fos, indexFile); - close(oos, indexFile); - } + index.put(ie.key, ie); + writeIndex(); } } - private void removeIndexEntry(String key) { + @Override + protected Map<String, IndexEntry> readIndex() { synchronized (LOCK) { - index.remove(key); - writeIndex(); + return super.readIndex(); } } - private void addIndexEntry(IndexEntry ie) { + @Override + protected void writeIndex() { synchronized (LOCK) { - index.put(ie.key, ie); - writeIndex(); + super.writeIndex(); } } public void clear() { + File cacheDir=getCacheDirectory(); + int numDeleted=0; synchronized (LOCK) { - FileUtil.deleteContents(cacheDirectory); + numDeleted = FileUtil.deleteContents(cacheDir); + } + + if ((numDeleted > 0) && (logger != null) && logger.isTraceEnabled()) { + logger.info("clear(" + cacheDir + ") deleted"); } } - public static CacheBacking createBacking(String scope, CacheKeyResolver resolver) { + 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, resolver); + 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; + public boolean accept(File file, String s) { + if (s.matches(regex)) { + return true; + } + return false; } - return false; - } - }); - if (files == null) { - return new String[0]; + }); + if (LangUtil.isEmpty(files)) { + return EMPTY_KEYS; } String[] keys = new String[files.length]; for (int i = 0; i < files.length; i++) { @@ -177,19 +157,29 @@ public class DefaultFileCacheBacking implements CacheBacking { return keys; } - public CachedClassEntry get(CachedClassReference ref) { - IndexEntry ie = index.get(ref.getKey()); - if (ie != null && ie.ignored) { + 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); } - File cacheFile = new File(cacheDirectory, ref.getKey()); + if (cacheFile.canRead()) { - if (ie == null) { - // no index, delete - delete(cacheFile); - return null; - } - byte[] bytes = read(cacheFile, ie.crc); + byte[] bytes = read(cacheFile, ie.crcWeaved); if (bytes != null) { if (!ie.generated) { return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.WEAVED); @@ -198,112 +188,106 @@ public class DefaultFileCacheBacking implements CacheBacking { } } } + return null; } - public void put(CachedClassEntry entry) { - File cacheFile = new File(cacheDirectory, entry.getKey()); - if (!cacheFile.exists()) { - IndexEntry ie = new IndexEntry(); + 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 = new IndexEntry(); ie.key = entry.getKey(); ie.generated = entry.isGenerated(); ie.ignored = entry.isIgnored(); if (!entry.isIgnored()) { - ie.crc = write(cacheFile, entry.getBytes()); + ie.crcClass = crc(originalBytes); + 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) { - File cacheFile = new File(cacheDirectory, ref.getKey()); - removeIndexEntry(ref.getKey()); + removeIndexEntry(refKey); delete(cacheFile); } } + @Override + protected void delete(File file) { + synchronized (LOCK) { + super.delete(file); + } + } + protected byte[] read(File file, long expectedCRC) { - CRC32 checksum = new CRC32(); + byte[] bytes=null; synchronized (LOCK) { FileInputStream fis = null; try { fis = new FileInputStream(file); - byte[] bytes = FileUtil.readAsByteArray(fis); - checksum.update(bytes); - if (checksum.getValue() == expectedCRC) { - return bytes; + 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); } - } catch (FileNotFoundException e) { - // file disappeared - MessageUtil.error("File not found " + file.getName()); - } catch (IOException e) { - MessageUtil.error("Error reading cached class " + e.getLocalizedMessage()); } finally { close(fis, file); } - // delete the file if there was an exception reading it - // or the expected checksum does not match - delete(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 null; + + return bytes; } protected long write(File file, byte[] bytes) { - if (file.exists()) { - return -1; - } synchronized (LOCK) { if (file.exists()) { - return -1; + return -1L; } OutputStream out = null; - ObjectOutputStream crcOut = null; - CRC32 checksum = new CRC32(); try { out = new FileOutputStream(file); out.write(bytes); - checksum.update(bytes); - return checksum.getValue(); - } catch (FileNotFoundException e) { - MessageUtil.error("Error writing (File Not Found) " + file.getName() + ": " + e.getLocalizedMessage()); - } catch (IOException e) { - MessageUtil.error("Error writing " + file.getName()); - + } 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); } - // delete the file if there was an exception writing it - delete(file); - } - return -1; - } - protected static void delete(File file) { - if (file.exists()) { - file.delete(); + return crc(bytes); } } - protected static void close(OutputStream out, File file) { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - // error - MessageUtil.error("Error closing write file " + file.getName()); - } - } - } - - protected static void close(InputStream in, File file) { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - // error - MessageUtil.error("Error closing read file " + file.getName()); - } - } - } } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java b/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java index a89936a39..91c332b6b 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java @@ -7,7 +7,8 @@ * http://eclipse.org/legal/epl-v10.html * * Contributors: - * John Kew (vmware) initial implementation + * John Kew (vmware) initial implementation + * Lyor Goldstein (vmware) add support for weaved class being re-defined *******************************************************************************/ package org.aspectj.weaver.tools.cache; @@ -27,12 +28,12 @@ public class GeneratedCachedClassHandler implements GeneratedClassHandler { this.nextGeneratedClassHandler = nextHandler; } - public void acceptClass(String name, byte[] bytes) { + public void acceptClass (String name, byte[] originalBytes, byte[] wovenBytes) { // The cache expects classNames in dot form CachedClassReference ref = cache.createGeneratedCacheKey(name.replace('/', '.')); - cache.put(ref, bytes); + cache.put(ref, originalBytes, wovenBytes); if (nextGeneratedClassHandler != null) { - nextGeneratedClassHandler.acceptClass(name, bytes); + nextGeneratedClassHandler.acceptClass(name, originalBytes, wovenBytes); } } } diff --git a/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java b/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java index 1cc51a2a1..6888c6c23 100644 --- a/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java +++ b/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java @@ -7,7 +7,8 @@ * http://eclipse.org/legal/epl-v10.html * * Contributors: - * John Kew (vmware) initial implementation + * John Kew (vmware) initial implementation + * Lyor Goldstein (vmware) add support for weaved class being re-defined *******************************************************************************/ package org.aspectj.weaver.tools.cache; @@ -87,7 +88,6 @@ public class WeavedClassCache { this.name = name; this.backing = backing; this.messageHandler = messageHandler; - initializeGenerated(existingClassHandler); // wrap the existing class handler with a caching version cachingClassHandler = new GeneratedCachedClassHandler(this, existingClassHandler); this.stats = new CacheStatistics(); @@ -178,14 +178,15 @@ public class WeavedClassCache { * Put a class in the cache * * @param ref reference to the entry, as created through createCacheKey + * @param classBytes pre-weaving class bytes * @param weavedBytes bytes to cache */ - public void put(CachedClassReference ref, byte[] weavedBytes) { + public void put(CachedClassReference ref, byte[] classBytes, byte[] weavedBytes) { CachedClassEntry.EntryType type = CachedClassEntry.EntryType.WEAVED; if (ref.getKey().matches(resolver.getGeneratedRegex())) { type = CachedClassEntry.EntryType.GENERATED; } - backing.put(new CachedClassEntry(ref, weavedBytes, type)); + backing.put(new CachedClassEntry(ref, weavedBytes, type), classBytes); stats.put(); } @@ -193,10 +194,12 @@ public class WeavedClassCache { * Get a cache value * * @param ref reference to the cache entry, created through createCacheKey + * @param classBytes Pre-weaving class bytes - required to ensure that + * cached aspects refer to an unchanged original class * @return the CacheEntry, or null if no entry exists in the cache */ - public CachedClassEntry get(CachedClassReference ref) { - CachedClassEntry entry = backing.get(ref); + public CachedClassEntry get(CachedClassReference ref, byte[] classBytes) { + CachedClassEntry entry = backing.get(ref, classBytes); if (entry == null) { stats.miss(); } else { @@ -212,11 +215,12 @@ public class WeavedClassCache { * Put a cache entry to indicate that the class should not be * weaved; the original bytes of the class should be used. * - * @param ref + * @param ref The cache reference + * @param classBytes The un-weaved class bytes */ - public void ignore(CachedClassReference ref) { + public void ignore(CachedClassReference ref, byte[] classBytes) { stats.putIgnored(); - backing.put(new CachedClassEntry(ref, ZERO_BYTES, CachedClassEntry.EntryType.IGNORED)); + backing.put(new CachedClassEntry(ref, ZERO_BYTES, CachedClassEntry.EntryType.IGNORED), classBytes); } /** @@ -256,61 +260,6 @@ public class WeavedClassCache { } } - /** - * Get all generated classes which have been cached - * - * @return - */ - protected CachedClassEntry[] getGeneratedClasses() { - return getEntries(resolver.getGeneratedRegex()); - } - - /** - * Get all weaved classes which have been cached - * - * @return - */ - protected CachedClassEntry[] getWeavedClasses() { - return getEntries(resolver.getWeavedRegex()); - } - - /** - * For each cached, generated class, pass that class through the given - * GeneratedClassHandler, typically which defines that handler within the - * current ClassLoader. - * - * @param handler class handler - */ - private void initializeGenerated(GeneratedClassHandler handler) { - if (handler == null) - return; - CachedClassEntry[] classes = getGeneratedClasses(); - for (CachedClassEntry entry : classes) { - - handler.acceptClass(entry.getClassName(), entry.getBytes()); - } - } - - /** - * Gets an array of CacheClassEntries with the given regex - * - * @param regex filter - * @return array of entries - */ - protected CachedClassEntry[] getEntries(String regex) { - String[] keys = backing.getKeys(regex); - List<CachedClassEntry> entries = new LinkedList<CachedClassEntry>(); - for (int i = 0; i < keys.length; i++) { - String key = keys[i]; - CachedClassReference ref = new CachedClassReference(key, resolver); - CachedClassEntry entry = backing.get(ref); - if (entry != null) { - entries.add(entry); - } - } - return entries.toArray(new CachedClassEntry[entries.size()]); - } - protected void error(String message, Throwable th) { messageHandler.handleMessage(new Message(message, IMessage.ERROR, th, null)); } diff --git a/weaver/testsrc/org/aspectj/weaver/tools/cache/DefaultFileCacheBackingTest.java b/weaver/testsrc/org/aspectj/weaver/tools/cache/DefaultFileCacheBackingTest.java index 88dce0d98..682869750 100644 --- a/weaver/testsrc/org/aspectj/weaver/tools/cache/DefaultFileCacheBackingTest.java +++ b/weaver/testsrc/org/aspectj/weaver/tools/cache/DefaultFileCacheBackingTest.java @@ -8,26 +8,36 @@ * * Contributors: * John Kew (vmware) initial implementation + * Lyor Goldstein (vmware) add support for weaved class being re-defined *******************************************************************************/ package org.aspectj.weaver.tools.cache; -import junit.framework.TestCase; -import org.aspectj.util.FileUtil; - import java.io.File; import java.util.zip.CRC32; +import junit.framework.TestCase; + +import org.aspectj.util.FileUtil; +import org.aspectj.util.LangUtil; +import org.aspectj.weaver.tools.cache.AbstractIndexedFileCacheBacking.IndexEntry; + /** */ public class DefaultFileCacheBackingTest extends TestCase { - File root = null; - byte[] FAKE_BYTES = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - String FAKE_CLASS = "com.example.foo.Bar"; - CacheKeyResolver resolver = new DefaultCacheKeyResolver(); - CachedClassReference fakeRef = resolver.weavedKey(FAKE_CLASS, FAKE_BYTES); + private final byte[] FAKE_BYTES = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + private final String FAKE_CLASS = "com.example.foo.Bar"; + private final CacheKeyResolver resolver = new DefaultCacheKeyResolver(); + private final CachedClassReference fakeRef = resolver.weavedKey(FAKE_CLASS, FAKE_BYTES); + private final String fakeKey=fakeRef.getKey(); + + private File root; + public DefaultFileCacheBackingTest () { + super(); + } + @Override public void setUp() throws Exception { if (root == null) { File tempFile = File.createTempFile("aspectj", "test"); @@ -36,24 +46,25 @@ public class DefaultFileCacheBackingTest extends TestCase { } } + @Override public void tearDown() throws Exception { FileUtil.deleteContents(root); root = null; } public void testCreateBacking() throws Exception { - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); + CacheBacking backing = DefaultFileCacheBacking.createBacking(root); assertNotNull(backing); - assertTrue(root.exists()); - assertTrue(root.isDirectory()); + assertTrue("Root folder not created: " + root, root.exists()); + assertTrue("Root folder not a directory: " + root, root.isDirectory()); } public void testClear() { - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); - backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED)); - assertNotNull(backing.get(fakeRef)); + CacheBacking backing = DefaultFileCacheBacking.createBacking(root); + backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED), FAKE_BYTES); + assertNotNull(backing.get(fakeRef, FAKE_BYTES)); backing.clear(); - assertNull(backing.get(fakeRef)); + assertNull(backing.get(fakeRef, FAKE_BYTES)); } private CachedClassEntry createTestEntry(String key) { @@ -61,10 +72,10 @@ public class DefaultFileCacheBackingTest extends TestCase { } public void testGetKeys() throws Exception { - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); - backing.put(createTestEntry("apple")); - backing.put(createTestEntry("apply")); - backing.put(createTestEntry("orange")); + CacheBacking backing = DefaultFileCacheBacking.createBacking(root); + backing.put(createTestEntry("apple"), FAKE_BYTES); + backing.put(createTestEntry("apply"), FAKE_BYTES); + backing.put(createTestEntry("orange"), FAKE_BYTES); String[] matches = backing.getKeys("app.*"); assertEquals(2, matches.length); matches = backing.getKeys("orange"); @@ -73,99 +84,116 @@ public class DefaultFileCacheBackingTest extends TestCase { } public void testPut() throws Exception { - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); - backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED)); - File cachedFile = new File(root, fakeRef.getKey()); + CacheBacking backing = DefaultFileCacheBacking.createBacking(root); + backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED), FAKE_BYTES); + File cachedFile = new File(root, fakeKey); assertTrue(cachedFile.exists()); assertTrue(cachedFile.isFile()); assertEquals(FAKE_BYTES.length, cachedFile.length()); } - private boolean indexEntryExists(String key, long expectedCRC) throws Exception { - long storedCRC = 0; - DefaultFileCacheBacking.IndexEntry[] index = DefaultFileCacheBacking.readIndex(new File(root, DefaultFileCacheBacking.INDEX_FILE)); - if (index == null) { - throw new NullPointerException("No index at " + root.getAbsolutePath()); - } - for (DefaultFileCacheBacking.IndexEntry ie : index) { - if (ie.key.equals(key)) { - storedCRC = ie.crc; - if (!ie.ignored) { - assertEquals(expectedCRC, storedCRC); - } - return true; - } - } - return false; - } - public void testGet() throws Exception { - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); - assertNull(backing.get(fakeRef)); - backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED)); - File cachedFile = new File(root, fakeRef.getKey()); + DefaultFileCacheBacking backing = DefaultFileCacheBacking.createBacking(root); + assertNull(backing.get(fakeRef, FAKE_BYTES)); + backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED), FAKE_BYTES); + File cachedFile = new File(root, fakeKey); assertTrue(cachedFile.isFile()); assertEquals(FAKE_BYTES.length, cachedFile.length()); CRC32 expectedCRC = new CRC32(); expectedCRC.update(FAKE_BYTES); - assertTrue(indexEntryExists(fakeRef.getKey(), expectedCRC.getValue())); - CachedClassEntry entry = backing.get(fakeRef); + assertTrue(indexEntryExists(backing, fakeKey, expectedCRC.getValue())); + CachedClassEntry entry = backing.get(fakeRef, FAKE_BYTES); assertEquals(FAKE_BYTES.length, entry.getBytes().length); - } public void testRemove() throws Exception { - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); - backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED)); - File cachedFile = new File(root, fakeRef.getKey()); - assertTrue(cachedFile.exists()); - assertTrue(cachedFile.isFile()); + DefaultFileCacheBacking backing = DefaultFileCacheBacking.createBacking(root); + backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED), FAKE_BYTES); + File cachedFile = new File(root, fakeKey); + assertTrue("Cached file not found: " + cachedFile, cachedFile.exists()); + assertTrue("Cached file not a file: " + cachedFile, cachedFile.isFile()); CRC32 expectedCRC = new CRC32(); expectedCRC.update(FAKE_BYTES); - assertTrue(indexEntryExists(fakeRef.getKey(), expectedCRC.getValue())); + assertTrue("Cached entry index not found", indexEntryExists(backing, fakeKey, expectedCRC.getValue())); backing.remove(fakeRef); - cachedFile = new File(root, fakeRef.getKey()); - assertFalse("CacheFile Still exists!" + cachedFile.getAbsolutePath(), cachedFile.exists()); - assertFalse(cachedFile.isFile()); - assertFalse(indexEntryExists(fakeRef.getKey(), expectedCRC.getValue())); - } + assertFalse("CacheFile Still exists: " + cachedFile, cachedFile.exists()); + assertFalse("Cached file is a file: " + cachedFile, cachedFile.isFile()); + assertFalse("Cached entry index not removed", indexEntryExists(backing, fakeKey, expectedCRC.getValue())); + } public void testMultiFile() throws Exception { CachedClassEntry entry; File cachedFile; CRC32 expectedCRC = new CRC32(); expectedCRC.update(FAKE_BYTES); - CacheBacking backing = DefaultFileCacheBacking.createBacking(root, resolver); + DefaultFileCacheBacking backing = DefaultFileCacheBacking.createBacking(root); // add weaved CachedClassReference wref = resolver.weavedKey(FAKE_CLASS + "WEAVED", FAKE_BYTES); entry = new CachedClassEntry(wref, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED); - backing.put(entry); + backing.put(entry, FAKE_BYTES); cachedFile = new File(root, wref.getKey()); assertTrue(cachedFile.exists()); assertTrue(cachedFile.isFile()); - assertTrue(indexEntryExists(wref.getKey(), expectedCRC.getValue())); + assertTrue(indexEntryExists(backing, wref.getKey(), expectedCRC.getValue())); // add generated CachedClassReference gref = resolver.generatedKey(FAKE_CLASS + "GENERATED"); entry = new CachedClassEntry(gref, FAKE_BYTES, CachedClassEntry.EntryType.GENERATED); - backing.put(entry); + backing.put(entry, FAKE_BYTES); cachedFile = new File(root, gref.getKey()); assertTrue(cachedFile.exists()); assertTrue(cachedFile.isFile()); - assertTrue(indexEntryExists(gref.getKey(), expectedCRC.getValue())); + assertTrue(indexEntryExists(backing, gref.getKey(), expectedCRC.getValue())); // add ignored CachedClassReference iref = resolver.generatedKey(FAKE_CLASS + "IGNORED"); entry = new CachedClassEntry(iref, FAKE_BYTES, CachedClassEntry.EntryType.IGNORED); - backing.put(entry); + backing.put(entry, FAKE_BYTES); cachedFile = new File(root, iref.getKey()); assertFalse(cachedFile.exists()); - assertTrue(indexEntryExists(iref.getKey(), expectedCRC.getValue())); + assertTrue(indexEntryExists(backing, iref.getKey(), expectedCRC.getValue())); backing.remove(wref); backing.remove(gref); backing.remove(iref); } + public void testOriginalClassBytesChanged () { + DefaultFileCacheBacking backing = DefaultFileCacheBacking.createBacking(root); + backing.put(new CachedClassEntry(fakeRef, FAKE_BYTES, CachedClassEntry.EntryType.WEAVED), FAKE_BYTES); + + CachedClassEntry entry = backing.get(fakeRef, FAKE_BYTES); + assertNotNull("No initial entry", entry); + + byte[] newBytes=new byte[FAKE_BYTES.length]; + for (int index=0; index < FAKE_BYTES.length; index++) { + newBytes[index] = (byte) (0 - FAKE_BYTES[index]); + } + + entry = backing.get(fakeRef, newBytes); + assertNull("Unexpected modified bytes entry: " + entry, entry); + + File cachedFile = new File(root, fakeKey); + assertFalse("Cache file not removed", cachedFile.exists()); + } + + private boolean indexEntryExists(AbstractIndexedFileCacheBacking cache, String key, long expectedCRC) throws Exception { + long storedCRC = 0L; + IndexEntry[] index = cache.readIndex(new File(root, AbstractIndexedFileCacheBacking.INDEX_FILE)); + if (LangUtil.isEmpty(index)) { + return false; + } + + for (IndexEntry ie : index) { + if (ie.key.equals(key)) { + storedCRC = ie.crcWeaved; + if (!ie.ignored) { + assertEquals(expectedCRC, storedCRC); + } + return true; + } + } + return false; + } } diff --git a/weaver/testsrc/org/aspectj/weaver/tools/cache/WeavedClassCacheTest.java b/weaver/testsrc/org/aspectj/weaver/tools/cache/WeavedClassCacheTest.java index 6c3d75a29..d972bff8b 100644 --- a/weaver/testsrc/org/aspectj/weaver/tools/cache/WeavedClassCacheTest.java +++ b/weaver/testsrc/org/aspectj/weaver/tools/cache/WeavedClassCacheTest.java @@ -51,11 +51,12 @@ public class WeavedClassCacheTest extends TestCase { cache.clear(); } - public CachedClassEntry get(CachedClassReference ref) { + public CachedClassEntry get(CachedClassReference ref, byte[] originalBytes) { return cache.get(ref.getKey()); } - public void put(CachedClassEntry entry) { + public void put(CachedClassEntry entry, byte[] originalBytes) { + assertNotNull("put(" + entry + ") no original bytes", originalBytes); cache.put(entry.getKey(), entry); } } @@ -82,7 +83,8 @@ public class WeavedClassCacheTest extends TestCase { public int accepts = 0; public List<String> classesISaw = new LinkedList<String>(); - public void acceptClass(String name, byte[] bytes) { + @Override + public void acceptClass (String name, byte[] originalBytes, byte[] wovenBytes) { accepts++; classesISaw.add(name); } @@ -110,41 +112,35 @@ public class WeavedClassCacheTest extends TestCase { } - public void testExistingGeneratedClassesPassedThroughHandler() throws Exception { - String classA = "com.generated.A"; - String classB = "com.generated.B"; - reset(); - memoryBacking.put(new CachedClassEntry(resolver.generatedKey(classA), FAKE_BYTES, CachedClassEntry.EntryType.GENERATED)); - memoryBacking.put(new CachedClassEntry(resolver.generatedKey(classB), FAKE_BYTES, CachedClassEntry.EntryType.GENERATED)); - createCache(); - assertEquals(2, generatedClassHandler.accepts); - for (String cName : generatedClassHandler.classesISaw) { - assertTrue("Got: " + cName, cName.equals(classA) || cName.equals(classB)); - } - } +// public void testExistingGeneratedClassesPassedThroughHandler() throws Exception { +// String classA = "com.generated.A"; +// String classB = "com.generated.B"; +// reset(); +// memoryBacking.put(new CachedClassEntry(resolver.generatedKey(classA), FAKE_BYTES, CachedClassEntry.EntryType.GENERATED), FAKE_BYTES); +// memoryBacking.put(new CachedClassEntry(resolver.generatedKey(classB), FAKE_BYTES, CachedClassEntry.EntryType.GENERATED), FAKE_BYTES); +// createCache(); +// assertEquals(2, generatedClassHandler.accepts); +// for (String cName : generatedClassHandler.classesISaw) { +// assertTrue("Got: " + cName, cName.equals(classA) || cName.equals(classB)); +// } +// } public void testCache() throws Exception { reset(); WeavedClassCache cache = createCache(); CacheStatistics stats = cache.getStats(); CachedClassReference ref = cache.createCacheKey(FAKE_CLASS, FAKE_BYTES); - assertNull(cache.get(ref)); - cache.put(ref, FAKE_BYTES); - assertNotNull(cache.get(ref)); + assertNull(cache.get(ref, FAKE_BYTES)); + cache.put(ref, FAKE_BYTES, FAKE_BYTES); + assertNotNull(cache.get(ref, FAKE_BYTES)); - assertEquals(new String(FAKE_BYTES), new String(cache.get(ref).getBytes())); - - assertEquals(1, cache.getWeavedClasses().length); - assertEquals(ref.getKey(), cache.getWeavedClasses()[0].getKey()); + assertEquals(new String(FAKE_BYTES), new String(cache.get(ref, FAKE_BYTES).getBytes())); ref = cache.createGeneratedCacheKey(FAKE_CLASS); - assertNull(cache.get(ref)); - cache.put(ref, FAKE_BYTES); - assertNotNull(cache.get(ref)); - assertEquals(new String(FAKE_BYTES), new String(cache.get(ref).getBytes())); - - assertEquals(1, cache.getGeneratedClasses().length); - assertEquals(ref.getKey(), cache.getGeneratedClasses()[0].getKey()); + assertNull(cache.get(ref, FAKE_BYTES)); + cache.put(ref, FAKE_BYTES, FAKE_BYTES); + assertNotNull(cache.get(ref, FAKE_BYTES)); + assertEquals(new String(FAKE_BYTES), new String(cache.get(ref, FAKE_BYTES).getBytes())); assertEquals(4, stats.getHits()); assertEquals(2, stats.getMisses()); @@ -156,11 +152,11 @@ public class WeavedClassCacheTest extends TestCase { reset(); WeavedClassCache cache = createCache(); CachedClassReference ref = cache.createCacheKey(FAKE_CLASS, FAKE_BYTES); - assertNull(cache.get(ref)); - cache.put(ref, FAKE_BYTES); - assertNotNull(cache.get(ref)); + assertNull(cache.get(ref, FAKE_BYTES)); + cache.put(ref, FAKE_BYTES, FAKE_BYTES); + assertNotNull(cache.get(ref, FAKE_BYTES)); cache.remove(ref); - assertNull(cache.get(ref)); + assertNull(cache.get(ref, FAKE_BYTES)); } } |