org.aspectj.weaver.tools.cache.AbstractIndexedFileCacheBacking Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjweaver Show documentation
Show all versions of aspectjweaver Show documentation
The AspectJ weaver introduces advices to java classes
/*******************************************************************************
* 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.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import org.aspectj.util.LangUtil;
/**
* Uses an index
file to keep track of the cached entries
*/
public abstract class AbstractIndexedFileCacheBacking extends AbstractFileCacheBacking {
/**
* Default name of cache index file - assumed to contain {@link IndexEntry}-s
*/
public static final String INDEX_FILE = "cache.idx";
protected static final IndexEntry[] EMPTY_INDEX=new IndexEntry[0];
protected static final String[] EMPTY_KEYS=new String[0];
private final File indexFile;
protected AbstractIndexedFileCacheBacking(File cacheDir) {
super(cacheDir);
indexFile = new File(cacheDir, INDEX_FILE);
}
public File getIndexFile () {
return indexFile;
}
public String[] getKeys(String regex) {
Map index=getIndex();
if ((index == null) || index.isEmpty()) {
return EMPTY_KEYS;
}
Collection matches=new LinkedList();
synchronized(index) {
for (String key : index.keySet()) {
if (key.matches(regex)) {
matches.add(key);
}
}
}
if (matches.isEmpty()) {
return EMPTY_KEYS;
} else {
return matches.toArray(new String[matches.size()]);
}
}
protected Map readIndex () {
return readIndex(getCacheDirectory(), getIndexFile());
}
protected void writeIndex () {
writeIndex(getIndexFile());
}
protected void writeIndex (File file) {
try {
writeIndex(file, getIndex());
} catch(Exception e) {
if ((logger != null) && logger.isTraceEnabled()) {
logger.warn("writeIndex(" + file + ") " + e.getClass().getSimpleName() + ": " + e.getMessage(), e);
}
}
}
protected abstract Map getIndex ();
protected Map readIndex (File cacheDir, File cacheFile) {
Map indexMap=new TreeMap();
IndexEntry[] idxValues=readIndex(cacheFile);
if (LangUtil.isEmpty(idxValues)) {
if ((logger != null) && logger.isTraceEnabled()) {
logger.debug("readIndex(" + cacheFile + ") no index entries");
}
return indexMap;
}
for (IndexEntry ie : idxValues) {
IndexEntry resEntry=resolveIndexMapEntry(cacheDir, ie);
if (resEntry != null) {
indexMap.put(resEntry.key, resEntry);
} else if ((logger != null) && logger.isTraceEnabled()) {
logger.debug("readIndex(" + cacheFile + ") skip " + ie.key);
}
}
return indexMap;
}
protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) {
return ie;
}
public IndexEntry[] readIndex(File indexFile) {
if (!indexFile.canRead()) {
return EMPTY_INDEX;
}
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(indexFile));
return (IndexEntry[]) ois.readObject();
} catch (Exception e) {
if ((logger != null) && logger.isTraceEnabled()) {
logger.error("Failed (" + e.getClass().getSimpleName() + ")"
+ " to read index from " + indexFile.getAbsolutePath()
+ " : " + e.getMessage(), e);
}
delete(indexFile);
} finally {
close(ois, indexFile);
}
return EMPTY_INDEX;
}
protected void writeIndex (File indexFile, Map index) throws IOException {
writeIndex(indexFile, LangUtil.isEmpty(index) ? Collections.emptyList() : index.values());
}
protected void writeIndex (File indexFile, IndexEntry ... entries) throws IOException {
writeIndex(indexFile, LangUtil.isEmpty(entries) ? Collections.emptyList() : Arrays.asList(entries));
}
protected void writeIndex (File indexFile, Collection extends IndexEntry> entries) throws IOException {
File indexDir=indexFile.getParentFile();
if ((!indexDir.exists()) && (!indexDir.mkdirs())) {
throw new IOException("Failed to create path to " + indexFile.getAbsolutePath());
}
int numEntries=LangUtil.isEmpty(entries) ? 0 : entries.size();
IndexEntry[] entryValues=(numEntries <= 0) ? null : entries.toArray(new IndexEntry[numEntries]);
// if no entries, simply delete the index file
if (LangUtil.isEmpty(entryValues)) {
if (indexFile.exists() && (!indexFile.delete())) {
throw new StreamCorruptedException("Failed to clean up index file at " + indexFile.getAbsolutePath());
}
return;
}
ObjectOutputStream oos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(indexFile), 4096));
try {
oos.writeObject(entryValues);
} finally {
close(oos, indexFile);
}
}
public static final IndexEntry createIndexEntry (CachedClassEntry classEntry, byte[] originalBytes) {
if (classEntry == null) {
return null;
}
IndexEntry indexEntry = new IndexEntry();
indexEntry.key = classEntry.getKey();
indexEntry.generated = classEntry.isGenerated();
indexEntry.ignored = classEntry.isIgnored();
indexEntry.crcClass = crc(originalBytes);
if (!classEntry.isIgnored()) {
indexEntry.crcWeaved = crc(classEntry.getBytes());
}
return indexEntry;
}
/**
* The default index entry in the index file
*/
public static class IndexEntry implements Serializable, Cloneable {
private static final long serialVersionUID = 756391290557029363L;
public String key;
public boolean generated;
public boolean ignored;
public long crcClass;
public long crcWeaved;
public IndexEntry () {
super();
}
@Override
public IndexEntry clone () {
try {
return getClass().cast(super.clone());
} catch(CloneNotSupportedException e) {
throw new RuntimeException("Failed to clone: " + toString() + ": " + e.getMessage(), e);
}
}
@Override
public int hashCode() {
return (int) (key.hashCode()
+ (generated ? 1 : 0)
+ (ignored ? 1 : 0)
+ crcClass
+ crcWeaved);
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
IndexEntry other=(IndexEntry) obj;
if (this.key.equals(other.key)
&& (this.ignored == other.ignored)
&& (this.generated == other.generated)
&& (this.crcClass == other.crcClass)
&& (this.crcWeaved == other.crcWeaved)) {
return true;
} else {
return false;
}
}
@Override
public String toString() {
return key
+ "[" + (generated ? "generated" : "ignored") + "]"
+ ";crcClass=0x" + Long.toHexString(crcClass)
+ ";crcWeaved=0x" + Long.toHexString(crcWeaved)
;
}
}
}