You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2011/04/30 04:05:24 UTC
svn commit: r1098037 - in /tapestry/tapestry5/trunk/plastic/src:
main/java/org/apache/tapestry5/internal/plastic/
main/java/org/apache/tapestry5/plastic/
test/groovy/org/apache/tapestry5/plastic/
Author: hlship
Date: Sat Apr 30 02:05:23 2011
New Revision: 1098037
URL: http://svn.apache.org/viewvc?rev=1098037&view=rev
Log:
TAP5-853: Add support for listener notifications as classes are loaded
Added:
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassEvent.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListener.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListenerHub.java
Modified:
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticInternalUtils.java
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java?rev=1098037&r1=1098036&r2=1098037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java Sat Apr 30 02:05:23 2011
@@ -41,6 +41,7 @@ import org.apache.tapestry5.internal.pla
import org.apache.tapestry5.internal.plastic.asm.tree.VarInsnNode;
import org.apache.tapestry5.plastic.AnnotationAccess;
import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.ClassType;
import org.apache.tapestry5.plastic.ComputedValue;
import org.apache.tapestry5.plastic.Condition;
import org.apache.tapestry5.plastic.FieldConduit;
@@ -1309,7 +1310,7 @@ public class PlasticClassImpl extends Lo
private void rewriteOriginalMethod()
{
- pool.realize(invocationClassNode);
+ pool.realize(className, ClassType.METHOD_INVOCATION, invocationClassNode);
String fieldName = String.format("methodinvocationbundle_%s_%s", description.methodName,
PlasticUtils.nextUID());
@@ -1566,7 +1567,7 @@ public class PlasticClassImpl extends Lo
// TODO: Perhaps we should defer this private check until it is needed,
// i.e., when we do some work on the field that requires it to be private?
// However, given class loading issues, public fields are likely to cause
- // their own problems when passing the ClassLoader boundrary.
+ // their own problems when passing the ClassLoader boundary.
if (!Modifier.isPrivate(node.access))
throw new IllegalArgumentException(
@@ -2069,10 +2070,10 @@ public class PlasticClassImpl extends Lo
private PlasticClassHandleShim instantiateShim(ClassNode shimClassNode)
{
- Class shimClass = pool.realize(shimClassNode);
-
try
{
+ Class shimClass = pool.realize(className, ClassType.SUPPORT, shimClassNode);
+
return (PlasticClassHandleShim) shimClass.newInstance();
}
catch (Exception ex)
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java?rev=1098037&r1=1098036&r2=1098037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java Sat Apr 30 02:05:23 2011
@@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.tapestry5.internal.plastic.asm.ClassReader;
import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
@@ -33,6 +34,10 @@ import org.apache.tapestry5.internal.pla
import org.apache.tapestry5.internal.plastic.asm.tree.ClassNode;
import org.apache.tapestry5.plastic.AnnotationAccess;
import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.ClassType;
+import org.apache.tapestry5.plastic.PlasticClassEvent;
+import org.apache.tapestry5.plastic.PlasticClassListener;
+import org.apache.tapestry5.plastic.PlasticClassListenerHub;
import org.apache.tapestry5.plastic.PlasticClassTransformation;
import org.apache.tapestry5.plastic.PlasticManagerDelegate;
@@ -41,7 +46,7 @@ import org.apache.tapestry5.plastic.Plas
* to be instantiated as runtime classes.
*/
@SuppressWarnings("rawtypes")
-public class PlasticClassPool implements ClassLoaderDelegate, Opcodes
+public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticClassListenerHub
{
final PlasticClassLoader loader;
@@ -55,6 +60,8 @@ public class PlasticClassPool implements
private final StaticContext emptyStaticContext = new StaticContext();
+ private final List<PlasticClassListener> listeners = new CopyOnWriteArrayList<PlasticClassListener>();
+
private final Cache<String, TypeCategory> typeName2Category = new Cache<String, TypeCategory>()
{
@@ -108,16 +115,19 @@ public class PlasticClassPool implements
public synchronized Class realizeTransformedClass(ClassNode classNode, MethodBundle methodBundle,
StaticContext staticContext)
{
- Class result = realize(classNode);
+ Class result = realize(PlasticInternalUtils.toClassName(classNode.name), ClassType.PRIMARY, classNode);
baseClassDefs.put(result.getName(), new BaseClassDef(methodBundle, staticContext));
return result;
}
- public synchronized Class realize(ClassNode classNode)
+ public synchronized Class realize(String primaryClassName, ClassType classType, final ClassNode classNode)
{
- PlasticInternalUtils.debugClass(classNode);
+ if (!listeners.isEmpty())
+ {
+ fire(toEvent(primaryClassName, classType, classNode));
+ }
byte[] bytecode = toBytecode(classNode);
@@ -126,6 +136,41 @@ public class PlasticClassPool implements
return loader.defineClassWithBytecode(className, bytecode);
}
+ private PlasticClassEvent toEvent(final String primaryClassName, final ClassType classType,
+ final ClassNode classNode)
+ {
+ return new PlasticClassEvent()
+ {
+ public ClassType getType()
+ {
+ return classType;
+ }
+
+ public String getPrimaryClassName()
+ {
+ return primaryClassName;
+ }
+
+ public String getDissasembledBytecode()
+ {
+ return PlasticInternalUtils.dissasembleBytecode(classNode);
+ }
+
+ public String getClassName()
+ {
+ return PlasticInternalUtils.toClassName(classNode.name);
+ }
+ };
+ }
+
+ private void fire(PlasticClassEvent event)
+ {
+ for (PlasticClassListener listener : listeners)
+ {
+ listener.classWillLoad(event);
+ }
+ }
+
private byte[] toBytecode(ClassNode classNode)
{
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
@@ -468,4 +513,19 @@ public class PlasticClassPool implements
return typeName2Category.get(typeName);
}
+
+ public void addPlasticClassListener(PlasticClassListener listener)
+ {
+ assert listener != null;
+
+ listeners.add(listener);
+ }
+
+ public void removePlasticClassListener(PlasticClassListener listener)
+ {
+ assert listener != null;
+
+ listeners.remove(listener);
+ }
+
}
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticInternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticInternalUtils.java?rev=1098037&r1=1098036&r2=1098037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticInternalUtils.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticInternalUtils.java Sat Apr 30 02:05:23 2011
@@ -17,6 +17,7 @@ package org.apache.tapestry5.internal.pl
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
@@ -37,11 +38,6 @@ import org.apache.tapestry5.plastic.Meth
@SuppressWarnings("rawtypes")
public class PlasticInternalUtils
{
-
- private static final String SEP = "================================================";
-
- public static final boolean DEBUG_ENABLED = Boolean.getBoolean("plastic-classnode-debug");
-
public static final String[] EMPTY = new String[0];
public static boolean isEmpty(Object[] input)
@@ -218,22 +214,18 @@ public class PlasticInternalUtils
return new ArrayList<T>();
}
- public static void debugClass(ClassNode classNode)
+ public static String dissasembleBytecode(ClassNode classNode)
{
- if (!DEBUG_ENABLED)
- return;
-
- PrintWriter pw = new PrintWriter(System.out);
-
- TraceClassVisitor visitor = new TraceClassVisitor(pw);
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
- System.out.println(SEP);
+ TraceClassVisitor visitor = new TraceClassVisitor(writer);
classNode.accept(visitor);
- pw.flush();
+ writer.close();
- System.out.println(SEP);
+ return stringWriter.toString();
}
private static final Pattern PROPERTY_PATTERN = Pattern.compile("^(m?_+)?(.+?)_*$", Pattern.CASE_INSENSITIVE);
Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java?rev=1098037&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java Sat Apr 30 02:05:23 2011
@@ -0,0 +1,37 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.plastic;
+
+/**
+ * Identifies the type of class referenced in a {@link PlasticClassEvent}.
+ *
+ * @see PlasticClassListener
+ */
+public enum ClassType
+{
+ /**
+ * A primary class, either created new or by transforming an existing class.
+ */
+ PRIMARY,
+
+ /** A supporting class, needed to implement some of the logic of the primary class. */
+ SUPPORT,
+
+ /**
+ * An implementation of {@link MethodInvocation}, needed to handle advice added to
+ * a method of a primary class.
+ */
+ METHOD_INVOCATION
+}
Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassEvent.java?rev=1098037&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassEvent.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassEvent.java Sat Apr 30 02:05:23 2011
@@ -0,0 +1,44 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.plastic;
+
+/**
+ * Describes a transformed class about to be loaded.
+ */
+public interface PlasticClassEvent
+{
+ /**
+ * The primary class name, i.e., the class being created or transformed.
+ */
+ String getPrimaryClassName();
+
+ /**
+ * The name of the actual class, which will differ from the primary class name
+ * for some types.
+ */
+ String getClassName();
+
+ /**
+ * Identifies what type of class is being loaded. Typically, the supporting and method invocation
+ * types will <em>precede</em> the primary class.
+ */
+ ClassType getType();
+
+ /**
+ * The bytecode for the class, dissassembled and formatted as a string. This is useful
+ * for debugging purposes.
+ */
+ String getDissasembledBytecode();
+}
Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListener.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListener.java?rev=1098037&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListener.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListener.java Sat Apr 30 02:05:23 2011
@@ -0,0 +1,37 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.plastic;
+
+/**
+ * Allows a listener to be notified about classes about to be loaded by the manager's class loader.
+ * Some classes are loaded by the same class loader but not transformed (for example, inner classes). These
+ * do not generate events. In many cases, transforming a class will cause supporting classes (representing
+ * {@link MethodInvocation}s, and other things) to be created; these do generate events, and can be distinguished
+ * by the {@linkplain PlasticClassEvent#getType() event's type property}.
+ *
+ * @see PlasticClassListenerHub
+ */
+public interface PlasticClassListener
+{
+ /**
+ * Invoked just before a class is to be loaded. Separate events are fired for supporting classes before
+ * the event for the primary class (the class being transformed or created from scratch).
+ *
+ * @param event
+ * describes the class to be loaded, and gives access to its dissasembled
+ * bytecode (for debugging purposes)
+ */
+ void classWillLoad(PlasticClassEvent event);
+}
Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListenerHub.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListenerHub.java?rev=1098037&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListenerHub.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassListenerHub.java Sat Apr 30 02:05:23 2011
@@ -0,0 +1,22 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.plastic;
+
+public interface PlasticClassListenerHub
+{
+ void addPlasticClassListener(PlasticClassListener listener);
+
+ void removePlasticClassListener(PlasticClassListener listener);
+}
Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java?rev=1098037&r1=1098036&r2=1098037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java Sat Apr 30 02:05:23 2011
@@ -26,7 +26,7 @@ import org.apache.tapestry5.internal.pla
* or to create new classes dynamically at runtime.
*/
@SuppressWarnings("unchecked")
-public class PlasticManager
+public class PlasticManager implements PlasticClassListenerHub
{
private final PlasticClassPool pool;
@@ -182,7 +182,7 @@ public class PlasticManager
"Class %s is not an interface; proxies may only be created for interfaces.",
interfaceType.getName()));
- String name = String.format("$PlasticProxy$%s_%s", interfaceType.getSimpleName(), PlasticUtils.nextUID());
+ String name = String.format("$%s_%s", interfaceType.getSimpleName(), PlasticUtils.nextUID());
PlasticClassTransformation<T> result = pool.createTransformation("java.lang.Object", name);
@@ -190,4 +190,14 @@ public class PlasticManager
return result;
}
+
+ public void addPlasticClassListener(PlasticClassListener listener)
+ {
+ pool.addPlasticClassListener(listener);
+ }
+
+ public void removePlasticClassListener(PlasticClassListener listener)
+ {
+ pool.removePlasticClassListener(listener);
+ }
}
Modified: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy?rev=1098037&r1=1098036&r2=1098037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy (original)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy Sat Apr 30 02:05:23 2011
@@ -36,7 +36,7 @@ class ProxyCreation extends Specificatio
def "create a method delegating proxy"() {
setup:
"Each method of the interface delegates through a method that returns the new target for the method."
-
+
def mgr = new PlasticManager()
Runnable r = Mock(Runnable)
@@ -90,4 +90,34 @@ class ProxyCreation extends Specificatio
e.message == "Class java.lang.String is not an interface; proxies may only be created for interfaces."
}
+
+ def "listen to plastic class events"() {
+ Runnable r = Mock(Runnable)
+ PlasticClassListener listener = { PlasticClassEvent event ->
+
+ assert event.className == event.primaryClassName
+
+ assert event.dissasembledBytecode.contains(event.primaryClassName)
+
+ assert event.type == ClassType.PRIMARY
+ } as PlasticClassListener
+
+ def mgr = new PlasticManager()
+
+ mgr.addPlasticClassListener listener
+
+ def ins = mgr.createProxy(Runnable.class, {
+ def f = it.introduceField(Runnable.class, "delegate").inject(r)
+
+ it.introduceMethod(new MethodDescription("void", "run")).delegateTo(f)
+ } as PlasticClassTransformer)
+
+ when:
+
+ def proxy = ins.newInstance()
+
+ then:
+
+ proxy != null
+ }
}
Re: svn commit: r1098037 - in /tapestry/tapestry5/trunk/plastic/src:
main/java/org/apache/tapestry5/internal/plastic/ main/java/org/apache/tapestry5/plastic/
test/groovy/org/apache/tapestry5/plastic/
Posted by Howard Lewis Ship <hl...@gmail.com>.
It's there to support tapestry.transform logging; fun to see the bytecode
stream by. Out could also be useful for some kind of JMX monitoring.
On May 3, 2011 1:59 AM, "Massimo Lusetti" <ml...@gmail.com> wrote:
> On Sat, Apr 30, 2011 at 4:05 AM, <hl...@apache.org> wrote:
>
>> Author: hlship
>> Date: Sat Apr 30 02:05:23 2011
>> New Revision: 1098037
>>
>> URL: http://svn.apache.org/viewvc?rev=1098037&view=rev
>> Log:
>> TAP5-853: Add support for listener notifications as classes are loaded
>
> Oh man... this is cool and nice to play with!
>
> Cheers
> --
> Massimo
> http://meridio.blogspot.com
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: dev-help@tapestry.apache.org
>
Re: svn commit: r1098037 - in /tapestry/tapestry5/trunk/plastic/src:
main/java/org/apache/tapestry5/internal/plastic/ main/java/org/apache/tapestry5/plastic/
test/groovy/org/apache/tapestry5/plastic/
Posted by Massimo Lusetti <ml...@gmail.com>.
On Sat, Apr 30, 2011 at 4:05 AM, <hl...@apache.org> wrote:
> Author: hlship
> Date: Sat Apr 30 02:05:23 2011
> New Revision: 1098037
>
> URL: http://svn.apache.org/viewvc?rev=1098037&view=rev
> Log:
> TAP5-853: Add support for listener notifications as classes are loaded
Oh man... this is cool and nice to play with!
Cheers
--
Massimo
http://meridio.blogspot.com
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org