You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/09/01 02:01:42 UTC
svn commit: r991401 - in /tapestry/tapestry5/trunk/tapestry-ioc/src:
main/java/org/apache/tapestry5/ioc/internal/AbstractReloadableObjectCreator.java
test/java/org/apache/tapestry5/ioc/ReloadTest.java
Author: hlship
Date: Wed Sep 1 00:01:41 2010
New Revision: 991401
URL: http://svn.apache.org/viewvc?rev=991401&view=rev
Log:
TAP5-1188: Tune some of the logic related to which classes are reloaded
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractReloadableObjectCreator.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractReloadableObjectCreator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractReloadableObjectCreator.java?rev=991401&r1=991400&r2=991401&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractReloadableObjectCreator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/AbstractReloadableObjectCreator.java Wed Sep 1 00:01:41 2010
@@ -14,13 +14,10 @@
package org.apache.tapestry5.ioc.internal;
-import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
-import java.security.ProtectionDomain;
+import java.util.Set;
import javassist.CannotCompileException;
import javassist.ClassPath;
@@ -30,11 +27,17 @@ import javassist.Loader;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import javassist.Translator;
+import javassist.expr.ConstructorCall;
+import javassist.expr.ExprEditor;
+import javassist.expr.FieldAccess;
+import javassist.expr.MethodCall;
+import javassist.expr.NewExpr;
import org.apache.tapestry5.ioc.Invokable;
import org.apache.tapestry5.ioc.ObjectCreator;
import org.apache.tapestry5.ioc.OperationTracker;
import org.apache.tapestry5.ioc.internal.services.ClassFactoryClassPool;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.ClassFabUtils;
import org.apache.tapestry5.services.UpdateListener;
@@ -43,8 +46,6 @@ import org.slf4j.Logger;
@SuppressWarnings("all")
public abstract class AbstractReloadableObjectCreator implements ObjectCreator, UpdateListener, Translator
{
- private final ProtectionDomain domain = getClass().getProtectionDomain();
-
private class XLoader extends Loader
{
public XLoader(ClassLoader parent, ClassPool pool)
@@ -66,6 +67,8 @@ public abstract class AbstractReloadable
private final String implementationClassName;
+ private final String packageName;
+
private final String classFilePath;
private final Logger logger;
@@ -80,6 +83,8 @@ public abstract class AbstractReloadable
private boolean firstTime = true;
+ private final Set<String> classesToLoad = CollectionFactory.newSet();
+
protected AbstractReloadableObjectCreator(ClassLoader baseClassLoader, String implementationClassName,
Logger logger, OperationTracker tracker)
{
@@ -88,10 +93,19 @@ public abstract class AbstractReloadable
this.logger = logger;
this.tracker = tracker;
- this.classFilePath = ClassFabUtils.getPathForClassNamed(implementationClassName);
+ packageName = toPackageName(implementationClassName);
+
+ classFilePath = ClassFabUtils.getPathForClassNamed(implementationClassName);
}
+ private String toPackageName(String name)
+ {
+ int dotx = name.lastIndexOf('.');
+
+ return dotx < 0 ? "" : name.substring(0, dotx);
+ }
+
public synchronized void checkForUpdates()
{
if (instance == null)
@@ -147,10 +161,6 @@ public abstract class AbstractReloadable
ClassFactoryClassPool pool = new ClassFactoryClassPool(baseClassLoader);
- // For TAPESTRY-2561, we're introducing a class loader between the parent (i.e., the
- // context class loader), and the component class loader, to try and prevent the deadlocks
- // that we've been seeing.
-
ClassLoader threadDeadlockBuffer = new URLClassLoader(new URL[0], baseClassLoader);
Loader loader = new XLoader(threadDeadlockBuffer, pool);
@@ -159,13 +169,14 @@ public abstract class AbstractReloadable
pool.appendClassPath(path);
+ classesToLoad.clear();
+ add(implementationClassName);
+
try
{
loader.addTranslator(pool, this);
- CtClass implCtClass = pool.get(implementationClassName);
-
- Class result = pool.toClass(implCtClass, loader, domain);
+ Class result = loader.loadClass(implementationClassName);
firstTime = false;
@@ -178,44 +189,6 @@ public abstract class AbstractReloadable
}
}
- private byte[] readClassData(String name) throws ClassNotFoundException
- {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- byte[] buffer = new byte[10000];
-
- URL url = getURLForClass(name);
-
- InputStream in = null;
-
- try
- {
- in = url.openStream();
-
- while (true)
- {
- int length = in.read(buffer);
-
- if (length < 0)
- break;
-
- baos.write(buffer, 0, length);
- }
-
- in.close();
-
- in = null;
- }
- catch (IOException ex)
- {
- InternalUtils.close(in);
-
- throw new ClassNotFoundException(InternalUtils.toMessage(ex), ex);
- }
-
- return baos.toByteArray();
- }
-
private URL getURLForClass(String className) throws ClassNotFoundException
{
String path = ClassFabUtils.getPathForClassNamed(className);
@@ -249,12 +222,98 @@ public abstract class AbstractReloadable
private boolean shouldLoadClassNamed(String name)
{
- return name.equals(implementationClassName) || name.startsWith(implementationClassName + "$");
+ return classesToLoad.contains(name);
+ }
+
+ private void add(String className)
+ {
+ if (classesToLoad.contains(className))
+ return;
+
+ // System.err.printf("Adding %s\n", className);
+ logger.debug(String.format("Marking class %s to be (re-)loaded", className));
+
+ classesToLoad.add(className);
}
public void onLoad(ClassPool pool, String className) throws NotFoundException, CannotCompileException
{
+ logger.debug(String.format("BEGIN Analyzing %s", className));
+
+ CtClass ctClass = pool.get(className);
+
+ ctClass.instrument(new ExprEditor()
+ {
+ public void edit(ConstructorCall c) throws CannotCompileException
+ {
+ if (c.getMethodName().equals("this"))
+ return;
+
+ String cn = c.getClassName();
+
+ String classFilePath = ClassFabUtils.getPathForClassNamed(cn);
+
+ URL url = baseClassLoader.getResource(classFilePath);
+
+ // If the base class is also a file on the file system then mark
+ // that it should be loaded by the same class loader. This serves two
+ // purposes: first, if the base class is in the same package then
+ // protected access will work properly. Secondly, if the base implementation
+ // changes, the service implementation will be reloaded.
+
+ if (url != null && url.getProtocol().equals("file"))
+ add(cn);
+ }
+
+ public void edit(FieldAccess f) throws CannotCompileException
+ {
+
+ }
+
+ public void edit(MethodCall m) throws CannotCompileException
+ {
+ // String invokedMethodClassName = m.getClassName();
+ //
+ // if (classesToLoad.contains(invokedMethodClassName))
+ // return;
+ //
+ // try
+ // {
+ // CtMethod method = m.getMethod();
+ //
+ // if (!Modifier.isPublic(method.getModifiers()))
+ // return;
+ //
+ // add(invokedMethodClassName);
+ // }
+ // catch (NotFoundException ex)
+ // {
+ // throw new RuntimeException(ex);
+ // }
+ }
+
+ public void edit(NewExpr e) throws CannotCompileException
+ {
+ String newInstanceClassName = e.getClassName();
+
+ if (classesToLoad.contains(newInstanceClassName))
+ return;
+
+ if (isInnerClass(newInstanceClassName))
+ add(newInstanceClassName);
+ }
+
+ });
+
+ logger.debug(String.format(" END Analyzing %s", className));
+ }
+
+ /** Is the class an inner class of some other class already marked to be loaded by the special class loader? */
+ private boolean isInnerClass(String className)
+ {
+ int dollarx = className.indexOf("$");
+ return dollarx < 0 ? false : classesToLoad.contains(className.substring(0, dollarx));
}
public void start(ClassPool pool) throws NotFoundException, CannotCompileException
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java?rev=991401&r1=991400&r2=991401&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java Wed Sep 1 00:01:41 2010
@@ -226,14 +226,9 @@ public class ReloadTest extends TestBase
CtClass ctClass = pool.makeClass(CLASS);
+ ctClass.setModifiers(Modifier.ABSTRACT | Modifier.PUBLIC);
ctClass.addInterface(pool.get(ReloadableService.class.getName()));
- CtMethod method = new CtMethod(pool.get("java.lang.String"), "getStatus", null, ctClass);
-
- method.setBody("return \"unreachable\";");
-
- ctClass.addMethod(method);
-
CtConstructor constructor = new CtConstructor(new CtClass[0], ctClass);
constructor.setBody("return $0;");