Index: src/main/java/org/apache/magma/tools/classloading/CachingTransformingProvider.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/CachingTransformingProvider.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/CachingTransformingProvider.java (working copy) @@ -1,138 +0,0 @@ -package org.apache.magma.tools.classloading; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.HashSet; -import java.util.Set; - -import org.apache.magma.tools.classloading.caching.ClassCache; -import org.apache.magma.tools.classloading.caching.SavedEntity; - -public class CachingTransformingProvider implements ClassTransformationReceiver, BytecodeProvider { - - protected BytecodeProvider fixedPart = null; - protected File cacheDir = null; - //protected Set missings = new HashSet(); - protected ClassTransformer transformer; - protected String context = null; - - public CachingTransformingProvider(File cacheDir, ClassTransformer transformer) { - this.transformer = transformer; - transformer.setReceiver(this); - this.cacheDir = cacheDir; - context = cacheDir.getName(); - } - - public void setChainProvider(BytecodeProvider provider) { - this.fixedPart = provider; - } - - protected boolean shouldWeave(String name) { - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("sun.")) return false; - return true; - } - - public URL findBytecode(String name) { - //if (missings.contains(name)) return fixedPart.findBytecode(name); - URL ret = findResourceInCache(name); - if (ret != null) return ret; - try { - ret = weave(name); - } catch (ClassNotFoundException e) { - return null; - } - return ret; - } - - private URL weave(String name) throws ClassNotFoundException { - if (!shouldWeave(name)) { - //missings.add(name); - return null; - } - URL res = fixedPart.findBytecode(name); - if (res == null) throw new ClassNotFoundException(name); - InputStream stream = null; - try { - byte[] buff = ClassCache.rawRetrieve(res); - if (buff == null) { - stream = res.openStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); - buff = new byte[2048]; - int len = 0; - while ((len = stream.read(buff)) > 0) { - baos.write(buff, 0, len); - } - buff = baos.toByteArray(); - } - buff = transformer.transform(name, buff, null); - URL ret = acceptClass(name, buff); - return ret == null ? res : ret; - } catch (IOException e1) { - throw new RuntimeException("Error reading class " + name, e1); - } finally { - try { - if (stream != null) stream.close(); - } catch (IOException e1) { - } - } - } - - public URL acceptClass(String name, byte[] bytes) { - if (bytes == null) { - //missings.add(name); - return null; - } else { - //missings.remove(name); - } - return ClassCache.save(context, name, bytes); - /* - name = name.replace('.', File.separatorChar); - name += ".class"; - FileOutputStream fos = null; - File cachefile = null; - try { - cachefile = new File(cacheDir, name); - if (!cachefile.getParentFile().exists() && !cachefile.getParentFile().mkdirs()) throw new RuntimeException("Cannot create directory for " + cachefile.getAbsolutePath()); - fos = new FileOutputStream(cachefile); - fos.write(bytes); - ramCache.put(cachefile.toURI().toURL().toString(), bytes); - } catch (Exception e) { - if (cachefile != null) { - cachefile.delete(); - } - throw new RuntimeException("Error caching " + name, e); - } finally { - try { - if (fos != null) fos.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - */ - } - - protected URL findResourceInCache(String name) { - SavedEntity entity = ClassCache.retrieve(context + ":" + name); - if (entity == null) return null; - return entity.url; - /* - name = name.replace('.', File.separatorChar); - name += ".class"; - File cachefile = new File(cacheDir, name); - if (!cachefile.exists()) return null; - try { - return cachefile.toURI().toURL(); - } catch (MalformedURLException e) { - // Should never happen - throw new RuntimeException("Internal error on " + name, e); - } - */ - } - - - -} Index: src/main/java/org/apache/magma/tools/classloading/ClassLoaderBytecodeProvider.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/ClassLoaderBytecodeProvider.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/ClassLoaderBytecodeProvider.java (working copy) @@ -1,8 +1,5 @@ package org.apache.magma.tools.classloading; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; import java.net.URL; import org.apache.magma.tools.classloading.caching.ClassCache; @@ -11,10 +8,6 @@ private ClassLoader loader = null; - private byte[] buff = new byte[20480]; - private ByteArrayOutputStream baos = new ByteArrayOutputStream(20480); - - public ClassLoaderBytecodeProvider(ClassLoader loader) { this.loader = loader; } @@ -25,18 +18,7 @@ URL res = loader.getResource(resname); if (res == null) return null; - try { - InputStream stream = res.openStream(); - int len = 0; - baos.reset(); - while ((len = stream.read(buff)) > 0) { - baos.write(buff, 0, len); - } - return ClassCache.save("raw", className, baos.toByteArray()); - } catch (IOException e) { - throw new RuntimeException("Error loading " + resname, e); - } - + return ClassCache.saveRaw(className, res); } } Index: src/main/java/org/apache/magma/tools/classloading/TransformingClassloader.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/TransformingClassloader.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/TransformingClassloader.java (working copy) @@ -33,14 +33,18 @@ try { byte[] classBytes = ClassCache.rawRetrieve(url); if (classBytes == null) { - InputStream resource = url.openStream(); - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - for (int n = 0; (n = resource.read(b, 0, b.length)) != -1; - bout.write(b, 0, n)) - ; - classBytes = bout.toByteArray(); + InputStream resource = null; + try { + resource = url.openStream(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + for (int n = 0; (n = resource.read(b, 0, b.length)) != -1; + bout.write(b, 0, n)) + ; + classBytes = bout.toByteArray(); + } finally { + if (resource != null) resource.close(); + } } try { int i = name.lastIndexOf('.'); Index: src/main/java/org/apache/magma/tools/classloading/TransformingProvider.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/TransformingProvider.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/TransformingProvider.java (working copy) @@ -8,22 +8,23 @@ import java.util.HashSet; import java.util.Set; +import org.apache.magma.tools.classloading.caching.CachedEntity; import org.apache.magma.tools.classloading.caching.ClassCache; +import org.apache.magma.tools.classloading.caching.MissingEntity; import org.apache.magma.tools.classloading.caching.SavedEntity; -public class CachingTransformingProvider implements ClassTransformationReceiver, BytecodeProvider { +public class TransformingProvider implements ClassTransformationReceiver, BytecodeProvider { protected BytecodeProvider fixedPart = null; - protected File cacheDir = null; - //protected Set missings = new HashSet(); protected ClassTransformer transformer; protected String context = null; + protected boolean reentring = false; - public CachingTransformingProvider(File cacheDir, ClassTransformer transformer) { + public TransformingProvider(String context, ClassTransformer transformer) { this.transformer = transformer; transformer.setReceiver(this); - this.cacheDir = cacheDir; - context = cacheDir.getName(); + ClassCache.addContext(context); + this.context = context; } public void setChainProvider(BytecodeProvider provider) { @@ -36,9 +37,15 @@ } public URL findBytecode(String name) { - //if (missings.contains(name)) return fixedPart.findBytecode(name); - URL ret = findResourceInCache(name); - if (ret != null) return ret; + CachedEntity entity = ClassCache.retrieve(this.context + ":" + name); + if (entity != null) { + if (entity instanceof MissingEntity) { + return fixedPart.findBytecode(name); + } else if (entity instanceof SavedEntity) { + return ((SavedEntity)entity).url; + } + } + URL ret = null; try { ret = weave(name); } catch (ClassNotFoundException e) { @@ -49,90 +56,47 @@ private URL weave(String name) throws ClassNotFoundException { if (!shouldWeave(name)) { - //missings.add(name); return null; } - URL res = fixedPart.findBytecode(name); - if (res == null) throw new ClassNotFoundException(name); - InputStream stream = null; + reentring = true; try { - byte[] buff = ClassCache.rawRetrieve(res); - if (buff == null) { - stream = res.openStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); - buff = new byte[2048]; - int len = 0; - while ((len = stream.read(buff)) > 0) { - baos.write(buff, 0, len); - } - buff = baos.toByteArray(); - } - buff = transformer.transform(name, buff, null); - URL ret = acceptClass(name, buff); - return ret == null ? res : ret; - } catch (IOException e1) { - throw new RuntimeException("Error reading class " + name, e1); - } finally { + URL res = fixedPart.findBytecode(name); + if (res == null) throw new ClassNotFoundException(name); + InputStream stream = null; try { - if (stream != null) stream.close(); + byte[] buff = ClassCache.rawRetrieve(res); + if (buff == null) { + stream = res.openStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); + buff = new byte[2048]; + int len = 0; + while ((len = stream.read(buff)) > 0) { + baos.write(buff, 0, len); + } + buff = baos.toByteArray(); + } + buff = transformer.transform(name, buff, null); + URL ret = acceptClass(name, buff); + return ret == null ? res : ret; } catch (IOException e1) { + throw new RuntimeException("Error reading class " + name, e1); + } finally { + try { + if (stream != null) stream.close(); + } catch (IOException e1) { + } } + } finally { + reentring = false; } } public URL acceptClass(String name, byte[] bytes) { if (bytes == null) { - //missings.add(name); + if (!reentring) ClassCache.saveMissing(context, name); return null; - } else { - //missings.remove(name); } return ClassCache.save(context, name, bytes); - /* - name = name.replace('.', File.separatorChar); - name += ".class"; - FileOutputStream fos = null; - File cachefile = null; - try { - cachefile = new File(cacheDir, name); - if (!cachefile.getParentFile().exists() && !cachefile.getParentFile().mkdirs()) throw new RuntimeException("Cannot create directory for " + cachefile.getAbsolutePath()); - fos = new FileOutputStream(cachefile); - fos.write(bytes); - ramCache.put(cachefile.toURI().toURL().toString(), bytes); - } catch (Exception e) { - if (cachefile != null) { - cachefile.delete(); - } - throw new RuntimeException("Error caching " + name, e); - } finally { - try { - if (fos != null) fos.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - */ } - protected URL findResourceInCache(String name) { - SavedEntity entity = ClassCache.retrieve(context + ":" + name); - if (entity == null) return null; - return entity.url; - /* - name = name.replace('.', File.separatorChar); - name += ".class"; - File cachefile = new File(cacheDir, name); - if (!cachefile.exists()) return null; - try { - return cachefile.toURI().toURL(); - } catch (MalformedURLException e) { - // Should never happen - throw new RuntimeException("Internal error on " + name, e); - } - */ - } - - - } Property changes on: src/main/java/org/apache/magma/tools/classloading/TransformingProvider.java ___________________________________________________________________ Added: svn:mergeinfo Index: src/main/java/org/apache/magma/tools/classloading/caching/CacheURLStreamHandler.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/caching/CacheURLStreamHandler.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/caching/CacheURLStreamHandler.java (working copy) @@ -10,9 +10,10 @@ @Override protected URLConnection openConnection(URL u) throws IOException { String path = u.getPath(); - SavedEntity entity = ClassCache.retrieve(path); + CachedEntity entity = ClassCache.retrieve(path); if (entity == null) throw new IOException("No element in cache for " + path); - return new CacheURLConnection(u, entity); + if (!(entity instanceof SavedEntity)) throw new IOException("No SAVED element in cache for " + path); + return new CacheURLConnection(u, (SavedEntity)entity); } } Index: src/main/java/org/apache/magma/tools/classloading/caching/CachedEntity.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/caching/CachedEntity.java (revision 0) +++ src/main/java/org/apache/magma/tools/classloading/caching/CachedEntity.java (revision 0) @@ -0,0 +1,8 @@ +package org.apache.magma.tools.classloading.caching; + +public class CachedEntity { + + public String classname; + public String context; + +} Index: src/main/java/org/apache/magma/tools/classloading/caching/ClassCache.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/caching/ClassCache.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/caching/ClassCache.java (working copy) @@ -1,35 +1,322 @@ package org.apache.magma.tools.classloading.caching; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; public class ClassCache { - private static Map cache = new HashMap(); + private static Map cache = new HashMap(); + private static Set contexts = new HashSet(); + + private static File savedir = null; + private static Timer savetimer = null; + + private static byte[] buff = new byte[20480]; + private static ByteArrayOutputStream baos = new ByteArrayOutputStream(20480); + + private static boolean modified = false; + + static { URL.setURLStreamHandlerFactory(new CacheURLStreamHandlerFactory()); } - public static SavedEntity retrieve(String path) { + public static void addContext(String context) { + contexts.add(context); + } + + public static void setSaveDir(File save) { + savedir = save; + loadData(); + if (savetimer == null) { + TimerTask tt = new TimerTask() { + @Override + public void run() { + try { + saveData(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + }; + + savetimer = new Timer(); + savetimer.schedule(tt, 40000, 15000); + } + } + + public static void loadData() { + System.out.println("LTW Cache - loading data"); + System.gc(); + FileInputStream keysfos = null; + DataInputStream keys = null; try { - return cache.get(new URL("classcache:" + path)); + File keysfile = new File(savedir, "keys.dat"); + try { + keysfos = new FileInputStream(keysfile); + } catch (FileNotFoundException e) { + return; + } + keys = new DataInputStream(keysfos); + + while (true) { + try { + int chunk = keys.readInt(); + if (chunk == 1) { + String classname = keys.readUTF(); + String url = keys.readUTF(); + long lastmod = keys.readLong(); + int length = keys.readInt(); + + URL pre = new URL(url); + URLConnection conn = pre.openConnection(); + if (conn.getContentLength() != length || conn.getLastModified() != lastmod) { + purge(classname); + } else { + saveRaw(classname, pre); + } + } else if (chunk == 2) { + keys.readUTF(); + keys.readUTF(); + } else { + throw new RuntimeException("Illegal cache file format"); + } + } catch (EOFException e) { + break; + } catch (IOException e) { + keysfile.delete(); + synchronized (cache) { + cache.clear(); + } + } + } + try { + keys.close(); + keysfos.close(); + } catch (IOException e) { + keysfile.delete(); + synchronized (cache) { + cache.clear(); + } + } + try { + keysfos = new FileInputStream(keysfile); + } catch (FileNotFoundException e) { + return; + } + keys = new DataInputStream(keysfos); + while (true) { + try { + int chunk = keys.readInt(); + if (chunk == 2) { + String ctx = keys.readUTF(); + String classname = keys.readUTF(); + saveMissing(ctx, classname); + } else if (chunk == 1) { + keys.readUTF(); + keys.readUTF(); + keys.readLong(); + keys.readInt(); + } else { + throw new RuntimeException("Illegal cache file format"); + } + } catch (EOFException e) { + break; + } catch (IOException e) { + keysfile.delete(); + synchronized (cache) { + cache.clear(); + } + } + } + + } finally { + if (keys != null) { + try { + keys.close(); + } catch (IOException e) { + } + } + if (keysfos != null) { + try { + keysfos.close(); + } catch (IOException e) { + } + } + System.gc(); + } + } + + public static void purge(String classname) { + for (String ctx : contexts) { + File ctxdir = new File(savedir, ctx); + if (!ctxdir.exists()) continue; + File cachefile = new File(ctxdir, classname.replace('.', File.separatorChar)); + if (!cachefile.exists()) continue; + System.out.println("LTW Cache - purging " + ctx + ":" + classname); + cachefile.delete(); + } + } + + public static void saveData() { + if (!modified) return; + System.out.println("LTW Cache - saving data"); + System.gc(); + FileOutputStream keysfos = null; + DataOutputStream keys = null; + try { + File keysfile = new File(savedir, "keys.dat"); + try { + keysfos = new FileOutputStream(keysfile); + } catch (FileNotFoundException e) { + throw new RuntimeException("Error creating cache keys file", e); + } + keys = new DataOutputStream(keysfos); + synchronized (cache) { + for (Map.Entry entry : cache.entrySet()) { + String path = entry.getKey().getPath(); + CachedEntity value = entry.getValue(); + if (value instanceof RawSavedEntity) { + RawSavedEntity rawvalue = (RawSavedEntity) value; + try { + keys.writeInt(1); + keys.writeUTF(rawvalue.classname); + keys.writeUTF(rawvalue.base.toString()); + keys.writeLong(rawvalue.lastmod); + keys.writeInt(rawvalue.content.length); + } catch (IOException e) { + keysfile.delete(); + throw new RuntimeException("Error writing to keys file", e); + } + } else if (value instanceof MissingEntity) { + try { + keys.writeInt(2); + keys.writeUTF(value.context); + keys.writeUTF(value.classname); + } catch (IOException e) { + keysfile.delete(); + throw new RuntimeException("Error writing to keys file", e); + } + } else if (value instanceof SavedEntity) { + SavedEntity savevalue = (SavedEntity) value; + if (!savevalue.persisted) { + path = path.replace('.', File.separatorChar); + path = path.replace(':', File.separatorChar); + File cachefile = new File(savedir, path); + cachefile.getParentFile().mkdirs(); + FileOutputStream fos = null; + try { + fos = new FileOutputStream(cachefile); + fos.write(savevalue.content); + savevalue.persisted = true; + } catch (IOException e) { + throw new RuntimeException("Error writing to cache file", e); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + } + } + } + } + } + } + } + modified = false; + } finally { + if (keys != null) { + try { + keys.close(); + } catch (IOException e) { + } + } + if (keysfos != null) { + try { + keysfos.close(); + } catch (IOException e) { + } + } + System.gc(); + } + } + + public static CachedEntity retrieve(String path) { + try { + URL url = new URL("classcache:" + path); + return retrieve(url); } catch (MalformedURLException e) { // should never happen throw new RuntimeException("Error creating url ", e); } } - public static SavedEntity retrieve(URL url) { - return cache.get(url); + public static CachedEntity retrieve(URL url) { + CachedEntity entity = cache.get(url); + if (entity == null) { + entity = fetch(url); + } + return entity; } + private static SavedEntity fetch(URL url) { + if (savedir == null) return null; + String origpath = url.getPath(); + String path = origpath.replace('.', File.separatorChar); + path = path.replace(':', File.separatorChar); + File cachefile = new File(savedir, path); + if (!cachefile.exists()) return null; + System.out.println("LTW Cache - recovering " + origpath); + SavedEntity entity = new SavedEntity(); + entity.classname = origpath.substring(origpath.indexOf(':') + 1); + entity.context = origpath.substring(0, origpath.indexOf(':')); + entity.persisted = true; + entity.url = url; + FileInputStream fis = null; + try { + fis = new FileInputStream(cachefile); + entity.content = new byte[(int) cachefile.length()]; + fis.read(entity.content); + synchronized (cache) { + cache.put(url, entity); + } + return entity; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + } + } + } + } + public static byte[] rawRetrieve(URL url) { - SavedEntity entity = cache.get(url); + CachedEntity entity = retrieve(url); if (entity == null) return null; - return entity.content; + if (!(entity instanceof SavedEntity)) return null; + return ((SavedEntity)entity).content; } public static URL save(String context, String name, byte[] content) { @@ -37,7 +324,6 @@ entity.context = context; entity.classname = name; entity.content = content; - String ckey = context + ":" + name; URL ret; try { @@ -47,9 +333,88 @@ throw new RuntimeException("Error creating url ", e); } entity.url = ret; - cache.put(ret, entity); - + synchronized (cache) { + cache.put(ret, entity); + } + modified = true; return ret; } + + public static URL saveMissing(String context, String name) { + MissingEntity entity = new MissingEntity(); + entity.context = context; + entity.classname = name; + String ckey = context + ":" + name; + URL ret; + try { + ret = new URL("classcache:" + ckey); + } catch (MalformedURLException e) { + // should never happen + throw new RuntimeException("Error creating url ", e); + } + synchronized (cache) { + cache.put(ret, entity); + } + //modified = true; + return ret; + } + + public static URL saveRaw(String name, URL res) { + RawSavedEntity entity = new RawSavedEntity(); + entity.context = "raw"; + entity.classname = name; + InputStream stream = null; + try { + URLConnection connection = res.openConnection(); + entity.lastmod = connection.getLastModified(); + stream = connection.getInputStream(); + int len = 0; + baos.reset(); + while ((len = stream.read(buff)) > 0) { + baos.write(buff, 0, len); + } + entity.content = baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Error loading " + res, e); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + entity.base = res; + String ckey = "raw:" + name; + URL ret; + try { + ret = new URL("classcache:" + ckey); + } catch (MalformedURLException e) { + // should never happen + throw new RuntimeException("Error creating url ", e); + } + entity.url = ret; + synchronized (cache) { + cache.put(ret, entity); + } + modified = true; + return ret; + } + + static void cleanAll() { + modified = true; + if (savedir != null) { + if (savetimer != null) { + savetimer.cancel(); + savetimer = null; + } + } + savedir = null; + synchronized (cache) { + cache.clear(); + } + contexts.clear(); + } + } Index: src/main/java/org/apache/magma/tools/classloading/caching/MissingEntity.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/caching/MissingEntity.java (revision 0) +++ src/main/java/org/apache/magma/tools/classloading/caching/MissingEntity.java (revision 0) @@ -0,0 +1,5 @@ +package org.apache.magma.tools.classloading.caching; + +public class MissingEntity extends CachedEntity { + +} Index: src/main/java/org/apache/magma/tools/classloading/caching/RawSavedEntity.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/caching/RawSavedEntity.java (revision 0) +++ src/main/java/org/apache/magma/tools/classloading/caching/RawSavedEntity.java (revision 0) @@ -0,0 +1,10 @@ +package org.apache.magma.tools.classloading.caching; + +import java.net.URL; + +public class RawSavedEntity extends SavedEntity { + + public URL base; + public long lastmod; + +} Index: src/main/java/org/apache/magma/tools/classloading/caching/SavedEntity.java =================================================================== --- src/main/java/org/apache/magma/tools/classloading/caching/SavedEntity.java (revision 736835) +++ src/main/java/org/apache/magma/tools/classloading/caching/SavedEntity.java (working copy) @@ -2,12 +2,11 @@ import java.net.URL; -public final class SavedEntity { +public class SavedEntity extends CachedEntity { public URL url; - public String classname; - public String context; public byte[] content; - public long lastget; + + public boolean persisted; } Index: src/main/java/org/apache/magma/tools/maven/MagmaJettyRun.java =================================================================== --- src/main/java/org/apache/magma/tools/maven/MagmaJettyRun.java (revision 736835) +++ src/main/java/org/apache/magma/tools/maven/MagmaJettyRun.java (working copy) @@ -30,16 +30,16 @@ import java.util.zip.ZipFile; import org.apache.magma.tools.classloading.AspectJClassTransformer; -import org.apache.magma.tools.classloading.CachingTransformingProvider; import org.apache.magma.tools.classloading.ClassLoaderBytecodeProvider; import org.apache.magma.tools.classloading.JPAClassTransformer; import org.apache.magma.tools.classloading.JettyTransformingClassLoader; +import org.apache.magma.tools.classloading.TransformingProvider; +import org.apache.magma.tools.classloading.caching.ClassCache; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.FileUtils; import org.mortbay.jetty.Handler; import org.mortbay.jetty.Server; import org.mortbay.jetty.handler.ContextHandlerCollection; @@ -190,7 +190,7 @@ jettypath.append(','); } webapp.setExtraClasspath(jettypath.toString()); - + try { WebAppClassLoader rootrepo = new WebAppClassLoader(webapp); URLClassLoader limitedrepo = new URLClassLoader(urlarray, null); @@ -198,11 +198,8 @@ root.setRawResources(rootrepo); ClassLoaderBytecodeProvider rootprovider = new ClassLoaderBytecodeProvider(limitedrepo); - File ajccache = new File(project.getBasedir(), "ajccache"); - ajccache.mkdirs(); - FileUtils.cleanDirectory(ajccache); AspectJClassTransformer ajctransformer = new AspectJClassTransformer(rootrepo, aspects.toArray(new URL[] {})); - CachingTransformingProvider ajcprovider = new CachingTransformingProvider(ajccache, ajctransformer); + TransformingProvider ajcprovider = new TransformingProvider("ajc", ajctransformer); root.setChainProvider(ajcprovider); ajcprovider.setChainProvider(rootprovider); @@ -217,10 +214,7 @@ JPAClassTransformer jpatransformer = (JPAClassTransformer) jpact. getConstructor(ClassLoader.class, String.class, String.class) .newInstance(root, "org.apache.magma.database.openjpa.SupportTransformer", paths.toString()); - File jpacache = new File(project.getBasedir(), "jpacache"); - jpacache.mkdirs(); - FileUtils.cleanDirectory(jpacache); - CachingTransformingProvider jpaprovider = new CachingTransformingProvider(jpacache, jpatransformer); + TransformingProvider jpaprovider = new TransformingProvider("jpa", jpatransformer); jpaprovider.setChainProvider(ajcprovider); root.setChainProvider(jpaprovider); } @@ -228,6 +222,10 @@ } catch (Exception e) { throw new MojoExecutionException("Error setting up classloaders ", e); } + + File classcache = new File(new File(project.getBuild().getOutputDirectory()).getParentFile(), "classcache"); + classcache.mkdirs(); + ClassCache.setSaveDir(classcache); // Setup the handler chains ContextHandlerCollection contexts = new ContextHandlerCollection(); Index: src/test/java/org/apache/magma/tools/classloading/caching/DiskCachingTest.java =================================================================== --- src/test/java/org/apache/magma/tools/classloading/caching/DiskCachingTest.java (revision 0) +++ src/test/java/org/apache/magma/tools/classloading/caching/DiskCachingTest.java (revision 0) @@ -0,0 +1,149 @@ +package org.apache.magma.tools.classloading.caching; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; + +import org.apache.magma.tools.classloading.ClassLoaderBytecodeProvider; +import org.apache.magma.tools.classloading.TransformingProvider; +import org.codehaus.plexus.util.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static junit.framework.Assert.*; + + +public class DiskCachingTest { + + private File tmpdir = null; + + @Before + public void createTempDir() throws Exception { + ClassCache.cleanAll(); + tmpdir = File.createTempFile("magmatest", "tempdir"); + tmpdir.delete(); + System.gc(); + tmpdir.mkdir(); + } + + @After + public void deleteTempDir() throws Exception { + ClassCache.cleanAll(); + if (tmpdir == null) return; + FileUtils.deleteDirectory(tmpdir); + } + + @Test + public void simpleDiskCached() throws Exception { + ClassLoaderBytecodeProvider clp = new ClassLoaderBytecodeProvider(Thread.currentThread().getContextClassLoader()); + + DummyTransformer dt = new DummyTransformer(); + TransformingProvider tp = new TransformingProvider("dummy", dt); + tp.setChainProvider(clp); + + ClassCache.setSaveDir(tmpdir); + + String myname = getClass().getName(); + + URL url = tp.findBytecode(myname); + assertEquals("classcache:dummy:" + myname, url.toString()); + + CachedEntity entity = ClassCache.retrieve("raw:" + myname); + assertNotNull(entity); + + ClassCache.saveData(); + + File ctxdir = new File(tmpdir, "dummy"); + assertTrue(ctxdir.exists()); + File cached = new File(ctxdir, myname.replace('.', '/')); + assertTrue(cached.exists()); + assertEquals(3, cached.length()); + + ClassCache.cleanAll(); + + ClassCache.addContext("dummy"); + ClassCache.setSaveDir(tmpdir); + + entity = ClassCache.retrieve("dummy:" + myname); + assertNotNull(entity); + assertEquals(3, ((SavedEntity)entity).content.length); + } + + @Test + public void cleaningDiskCached() throws Exception { + File classpathdir = new File(tmpdir, "classpath"); + classpathdir.mkdir(); + File dummyclassfile = new File(classpathdir, "org/dummy/DummyClass.class"); + dummyclassfile.getParentFile().mkdirs(); + FileOutputStream fos = new FileOutputStream(dummyclassfile); + fos.write(new byte[] { 5,6,7,8,9,10 }); + fos.close(); + + URLClassLoader ucl = new URLClassLoader(new URL[] { classpathdir.toURI().toURL() }, Thread.currentThread().getContextClassLoader()); + ClassLoaderBytecodeProvider clp = new ClassLoaderBytecodeProvider(ucl); + + DummyTransformer dt = new DummyTransformer(); + TransformingProvider tp = new TransformingProvider("dummy", dt); + tp.setChainProvider(clp); + + ClassCache.setSaveDir(tmpdir); + + String myname = getClass().getName(); + + URL url = tp.findBytecode(myname); + assertEquals("classcache:dummy:" + myname, url.toString()); + CachedEntity entity = ClassCache.retrieve("raw:" + myname); + assertNotNull(entity); + + url = tp.findBytecode("org.dummy.DummyClass"); + assertEquals("classcache:dummy:org.dummy.DummyClass", url.toString()); + entity = ClassCache.retrieve("raw:org.dummy.DummyClass"); + assertNotNull(entity); + assertEquals(6, ((SavedEntity)entity).content.length); + assertEquals(tmpdir.toURI().toURL().toString() + "classpath/org/dummy/DummyClass.class", ((RawSavedEntity)entity).base.toString()); + + + ClassCache.saveData(); + + File ctxdir = new File(tmpdir, "dummy"); + assertTrue(ctxdir.exists()); + File cached = new File(ctxdir, myname.replace('.', '/')); + assertTrue(cached.exists()); + assertEquals(3, cached.length()); + cached = new File(ctxdir, "org/dummy/DummyClass"); + assertTrue(cached.exists()); + assertEquals(3, cached.length()); + + ClassCache.cleanAll(); + + fos = new FileOutputStream(dummyclassfile); + fos.write(new byte[] { 5,6,7,8 }); + fos.close(); + + ClassCache.addContext("dummy"); + ClassCache.setSaveDir(tmpdir); + + + entity = ClassCache.retrieve("dummy:org.dummy.DummyClass"); + assertNull(entity); + cached = new File(ctxdir, "org/dummy/DummyClass"); + assertFalse(cached.exists()); + url = tp.findBytecode("org.dummy.DummyClass"); + assertEquals("classcache:dummy:org.dummy.DummyClass", url.toString()); + entity = ClassCache.retrieve("raw:org.dummy.DummyClass"); + assertNotNull(entity); + assertEquals(4, ((SavedEntity)entity).content.length); + assertEquals(tmpdir.toURI().toURL().toString() + "classpath/org/dummy/DummyClass.class", ((RawSavedEntity)entity).base.toString()); + + ClassCache.saveData(); + + assertTrue(cached.exists()); + assertEquals(3, cached.length()); + + + } + + +} Index: src/test/java/org/apache/magma/tools/classloading/caching/DummyTransformer.java =================================================================== --- src/test/java/org/apache/magma/tools/classloading/caching/DummyTransformer.java (revision 0) +++ src/test/java/org/apache/magma/tools/classloading/caching/DummyTransformer.java (revision 0) @@ -0,0 +1,20 @@ +package org.apache.magma.tools.classloading.caching; + +import java.security.ProtectionDomain; + +import org.apache.magma.tools.classloading.ClassTransformationReceiver; +import org.apache.magma.tools.classloading.ClassTransformer; + +public class DummyTransformer implements ClassTransformer { + + + + public void setReceiver(ClassTransformationReceiver receiver) { + } + + public byte[] transform(String classname, byte[] classbytecode, + ProtectionDomain domain) { + return new byte[] {1,2,3}; + } + +} Index: src/test/java/org/apache/magma/tools/classloading/caching/SimpleCachingTest.java =================================================================== --- src/test/java/org/apache/magma/tools/classloading/caching/SimpleCachingTest.java (revision 0) +++ src/test/java/org/apache/magma/tools/classloading/caching/SimpleCachingTest.java (revision 0) @@ -0,0 +1,35 @@ +package org.apache.magma.tools.classloading.caching; + +import java.net.URL; + +import org.apache.magma.tools.classloading.ClassLoaderBytecodeProvider; +import org.junit.Before; +import org.junit.Test; + +import static junit.framework.Assert.*; + +public class SimpleCachingTest { + + @Before + public void cleanBefore() { + ClassCache.cleanAll(); + } + + @Test + public void cacheAndGet() throws Exception { + ClassCache.addContext("testing"); + CachedEntity entity = ClassCache.retrieve(new URL("classcache:wrongctx:org.apache.magma.Something")); + assertNull(entity); + entity = ClassCache.retrieve(new URL("classcache:testing:org.apache.magma.Something")); + assertNull(entity); + + ClassCache.save("testing", "org.apache.magma.Something", new byte[] { 1,2,3 }); + entity = ClassCache.retrieve(new URL("classcache:testing:org.apache.magma.Something")); + assertNotNull(entity); + + assertEquals("org.apache.magma.Something", entity.classname); + assertEquals("testing", entity.context); + assertEquals(3, ((SavedEntity)entity).content.length); + } + +}