Author: hlship
Date: Thu Jul 21 21:53:37 2011
New Revision: 1149384
URL: http://svn.apache.org/viewvc?rev=1149384&view=rev
Log:
TAP5-1508: Convert CachedWorker to CCTW2
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java?rev=1149384&r1=1149383&r2=1149384&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/CachedWorker.java
Thu Jul 21 21:53:37 2011
@@ -1,4 +1,4 @@
-// Copyright 2008, 2010 The Apache Software Foundation
+// Copyright 2008, 2010, 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.
@@ -14,9 +14,6 @@
package org.apache.tapestry5.internal.transform;
-import java.lang.reflect.Modifier;
-import java.util.List;
-
import org.apache.tapestry5.Binding;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
@@ -25,14 +22,19 @@ import org.apache.tapestry5.internal.Tap
import org.apache.tapestry5.ioc.services.PerThreadValue;
import org.apache.tapestry5.ioc.services.PerthreadManager;
import org.apache.tapestry5.model.MutableComponentModel;
-import org.apache.tapestry5.runtime.Component;
-import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.plastic.*;
+import org.apache.tapestry5.services.BindingSource;
+import org.apache.tapestry5.services.TransformConstants;
+import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
+import org.apache.tapestry5.services.transform.TransformationSupport;
+
+import java.util.List;
/**
* Caches method return values for methods annotated with {@link Cached}.
*/
@SuppressWarnings("all")
-public class CachedWorker implements ComponentClassTransformWorker
+public class CachedWorker implements ComponentClassTransformWorker2
{
private final BindingSource bindingSource;
@@ -40,13 +42,10 @@ public class CachedWorker implements Com
interface MethodResultCacheFactory
{
- MethodResultCache create(Component instance);
+ MethodResultCache create(Object instance);
}
- /**
- * Handles the watching of a binding (usually a property or property
expression), invalidating the
- * cache early if the watched binding's value changes.
- */
+
private class SimpleMethodResultCache implements MethodResultCache
{
private boolean cached;
@@ -75,6 +74,21 @@ public class CachedWorker implements Com
}
}
+ /**
+ * When there is no watch, all cached methods look the same.
+ */
+ private final MethodResultCacheFactory nonWatchFactory = new
MethodResultCacheFactory()
+ {
+ public MethodResultCache create(Object instance)
+ {
+ return new SimpleMethodResultCache();
+ }
+ };
+
+ /**
+ * Handles the watching of a binding (usually a property or property
expression), invalidating the
+ * cache early if the watched binding's value changes.
+ */
private class WatchedBindingMethodResultCache extends
SimpleMethodResultCache
{
private final Binding binding;
@@ -108,65 +122,63 @@ public class CachedWorker implements Com
this.perThreadManager = perthreadManager;
}
- public void transform(ClassTransformation transformation,
MutableComponentModel model)
+
+ public void transform(PlasticClass plasticClass, TransformationSupport
support, MutableComponentModel model)
{
- List<TransformMethod> methods =
transformation.matchMethodsWithAnnotation(Cached.class);
+ List<PlasticMethod> methods =
plasticClass.getMethodsWithAnnotation(Cached.class);
- for (TransformMethod method : methods)
+ for (PlasticMethod method : methods)
{
validateMethod(method);
- adviseMethod(transformation, method);
+ adviseMethod(plasticClass, method);
}
}
- private void adviseMethod(ClassTransformation transformation,
TransformMethod method)
+ private void adviseMethod(PlasticClass plasticClass, PlasticMethod method)
{
// The key needs to reflect not just the method name, but also the
containing
// page and component (otherwise, there would be unwanted sharing of
cache
// between different instances of the same component within or across
pages). This
// name can't be calculated until page instantiation time.
- FieldAccess fieldAccess = createPerThreadValueField(transformation,
method);
-
- Cached annotation = method.getAnnotation(Cached.class);
-
- MethodResultCacheFactory factory = createFactory(transformation,
annotation.watch(), method);
-
- ComponentMethodAdvice advice = createAdvice(fieldAccess, factory);
-
- method.addAdvice(advice);
- }
-
- private FieldAccess createPerThreadValueField(ClassTransformation
transformation, TransformMethod method)
- {
- TransformField field = transformation.createField(Modifier.PROTECTED,
PerThreadValue.class.getName(),
- "perThreadMethodCache$" + method.getName());
+ PlasticField cacheField =
+ plasticClass.introduceField(PerThreadValue.class, "cache$" +
method.getDescription().methodName);
- // Each instance of the component will get a new PerThreadValue.
- field.injectIndirect(new
ComponentValueProvider<PerThreadValue<MethodResultCache>>()
+ cacheField.injectComputed(new ComputedValue<PerThreadValue>()
{
- public PerThreadValue<MethodResultCache> get(ComponentResources
resources)
+ public PerThreadValue get(InstanceContext context)
{
+ // Each instance will get a new PerThreadValue
return perThreadManager.createValue();
}
});
- return field.getAccess();
+ Cached annotation = method.getAnnotation(Cached.class);
+
+
+ MethodResultCacheFactory factory = createFactory(plasticClass,
annotation.watch(), method);
+
+ MethodAdvice advice = createAdvice(cacheField, factory);
+
+ method.addAdvice(advice);
}
- private ComponentMethodAdvice createAdvice(final FieldAccess
perThreadValueAccess,
- final MethodResultCacheFactory factory)
+
+ private MethodAdvice createAdvice(PlasticField cacheField,
+ final MethodResultCacheFactory factory)
{
- return new ComponentMethodAdvice()
+ final FieldHandle fieldHandle = cacheField.getHandle();
+
+ return new MethodAdvice()
{
- public void advise(ComponentMethodInvocation invocation)
+ public void advise(MethodInvocation invocation)
{
MethodResultCache cache = getOrCreateCache(invocation);
if (cache.isCached())
{
- invocation.overrideResult(cache.get());
+ invocation.setReturnValue(cache.get());
return;
}
@@ -174,78 +186,87 @@ public class CachedWorker implements Com
invocation.rethrow();
- cache.set(invocation.getResult());
+ cache.set(invocation.getReturnValue());
}
- private MethodResultCache
getOrCreateCache(ComponentMethodInvocation invocation)
+ private MethodResultCache getOrCreateCache(MethodInvocation
invocation)
{
- Component instance = invocation.getInstance();
+ Object instance = invocation.getInstance();
- PerThreadValue<MethodResultCache> value =
(PerThreadValue<MethodResultCache>) perThreadValueAccess
- .read(instance);
+ // The PerThreadValue is created in the instance constructor.
+ PerThreadValue<MethodResultCache> value =
(PerThreadValue<MethodResultCache>) fieldHandle
+ .get(instance);
+
+ // But it will be empty when first created, or at the start of
a new request.
if (value.exists())
+ {
return value.get();
+ }
+
+ // Use the factory to create a MethodResultCache for the
combination of instance, method, and thread.
return value.set(factory.create(instance));
}
};
}
- private MethodResultCacheFactory createFactory(ClassTransformation
transformation, final String watch,
- TransformMethod method)
+
+ private MethodResultCacheFactory createFactory(PlasticClass plasticClass,
final String watch,
+ PlasticMethod method)
{
+ // When there's no watch, a shared factory that just returns a new
SimpleMethodResultCache
+ // will suffice.
if (watch.equals(""))
- return new MethodResultCacheFactory()
- {
- public MethodResultCache create(Component instance)
- {
- return new SimpleMethodResultCache();
- }
- };
+ {
+ return nonWatchFactory;
+ }
+
+ // Because of the watch, its necessary to create a factory for
instances of this component and method.
+
+ final FieldHandle bindingFieldHandle =
plasticClass.introduceField(Binding.class, "cache$watchBinding$" +
method.getDescription().methodName).getHandle();
+
// Each component instance will get its own Binding instance. That
handles both different locales,
- // and reuse of a component (with a cached method) within a page or
across pages.
+ // and reuse of a component (with a cached method) within a page or
across pages. However, the binding can't be initialized
+ // until the page loads.
+
- TransformField bindingField =
transformation.createField(Modifier.PROTECTED, Binding.class.getName(),
- "cache$watchBinding$" + method.getName());
+
plasticClass.introduceMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_DESCRIPTION).addAdvice(new
MethodAdvice()
+ {
+ public void advise(MethodInvocation invocation)
+ {
+ ComponentResources resources =
invocation.getInstanceContext().get(ComponentResources.class);
- final FieldAccess bindingAccess = bindingField.getAccess();
+ Binding binding = bindingSource.newBinding("@Cached watch",
resources,
+ BindingConstants.PROP, watch);
-
transformation.getOrCreateMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE).addAdvice(
- new ComponentMethodAdvice()
- {
- public void advise(ComponentMethodInvocation invocation)
- {
- Binding binding = bindingSource.newBinding("@Cached
watch", invocation.getComponentResources(),
- BindingConstants.PROP, watch);
-
- bindingAccess.write(invocation.getInstance(), binding);
-
- invocation.proceed();
- }
- });
+ bindingFieldHandle.set(invocation.getInstance(), binding);
+
+ invocation.proceed();
+ }
+ });
return new MethodResultCacheFactory()
{
- public MethodResultCache create(Component instance)
+ public MethodResultCache create(Object instance)
{
- Binding binding = (Binding) bindingAccess.read(instance);
+ Binding binding = (Binding) bindingFieldHandle.get(instance);
return new WatchedBindingMethodResultCache(binding);
}
};
}
- private void validateMethod(TransformMethod method)
+ private void validateMethod(PlasticMethod method)
{
- TransformMethodSignature signature = method.getSignature();
+ MethodDescription description = method.getDescription();
- if (signature.getReturnType().equals("void"))
+ if (description.returnType.equals("void"))
throw new IllegalArgumentException(String.format(
"Method %s may not be used with @Cached because it returns
void.", method.getMethodIdentifier()));
- if (signature.getParameterTypes().length != 0)
+ if (description.argumentTypes.length != 0)
throw new IllegalArgumentException(String.format(
"Method %s may not be used with @Cached because it has
parameters.", method.getMethodIdentifier()));
}
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=1149384&r1=1149383&r2=1149384&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
Thu Jul 21 21:53:37 2011
@@ -515,6 +515,8 @@ public final class TapestryModule
* <dd>Allows fields to retain their values between requests</dd>
* <dt>Meta</dt>
* <dd>Checks for meta data annotations and adds it to the component
model</dd>
+ * <dt>Cached</dt>
+ * <dd>Checks for the {@link org.apache.tapestry5.annotations.Cached}
annotation</dd>
* </dl>
*/
@Contribute(ComponentClassTransformWorker2.class)
@@ -563,6 +565,8 @@ public final class TapestryModule
configuration.add("Retain", new RetainWorker());
+ configuration.addInstance("Cached", CachedWorker.class);
+
// This one is always last. Any additional private fields that aren't
// annotated will
// be converted to clear out at the end of the request.
@@ -592,8 +596,6 @@ public final class TapestryModule
* <dd>Allows a block from the template to be injected into a field</dd>
* <dt>ApplicationState</dt>
* <dd>Converts fields that reference application state objects
- * <dt>Cached</dt>
- * <dd>Checks for the {@link org.apache.tapestry5.annotations.Cached}
annotation</dd>
* <dt>Log</dt>
* <dd>Checks for the {@link org.apache.tapestry5.annotations.Log}
annotation</dd>
* <dt>PageReset
@@ -609,7 +611,6 @@ public final class TapestryModule
public static void provideOldStyleClassTransformWorkers(
OrderedConfiguration<ComponentClassTransformWorker> configuration)
{
- configuration.addInstance("Cached", CachedWorker.class);
configuration.addInstance("Inject", InjectWorker.class);