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 2006/09/04 19:34:29 UTC
svn commit: r440132 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/ main/java/org/apache/tapestry/internal/
main/java/org/apache/tapestry/internal/bindings/
main/java/org/apache/tapestry/internal/ioc/services/ main/java...
Author: hlship
Date: Mon Sep 4 10:34:27 2006
New Revision: 440132
URL: http://svn.apache.org/viewvc?view=rev&rev=440132
Log:
Add "prop:" binding, which allows a component to bind to a named property of its containing component.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html
Removed:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassLoader.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalConstants.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/LocationImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryException.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/CtClassSource.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHub.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHubImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties
tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/LocationImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UpdateListenerHubImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/ClassFabUtilsTest.java
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java Mon Sep 4 10:34:27 2006
@@ -26,13 +26,16 @@
public interface Binding
{
/**
- * Reads the current value of the property (or other resource).
+ * Reads the current value of the property (or other resource). When reading properties of
+ * objects that are primitive types, this will return an instance of the wrapper type. In some
+ * cases, a binding is read only and this method will throw a runtime exception.
*/
Object get();
/**
- * Updates the current value. Most types of bindings are read-only, and this method will throw
- * an exception.
+ * Updates the current value. Most types of bindings are read-only, and this method will throw a
+ * runtime exception. It is the caller's responsibility to ensure that the value passed in is of
+ * the appropriate type.
*
* @param value
*/
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalConstants.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalConstants.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalConstants.java Mon Sep 4 10:34:27 2006
@@ -22,7 +22,6 @@
@Utility
public final class InternalConstants
{
-
/**
* Init parameter used to identify the package from which application classes are loaded. Such
* classes are in the pages, components and mixins sub-packages.
@@ -31,4 +30,7 @@
/** Binding expression prefix used for literal strings. */
public static final String LITERAL_BINDING_PREFIX = "literal";
+
+ /** Binding expression prefix used to bind to a property of the component. */
+ public static final String PROP_BINDING_PREFIX = "prop";
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/LocationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/LocationImpl.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/LocationImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/LocationImpl.java Mon Sep 4 10:34:27 2006
@@ -69,18 +69,14 @@
@Override
public String toString()
{
- StringBuilder buffer = new StringBuilder();
+ StringBuilder buffer = new StringBuilder(_resource.toString());
Formatter formatter = new Formatter(buffer);
- formatter.format("<Location: %s", _resource);
-
if (_line != UNKNOWN)
formatter.format(", line %d", _line);
if (_column != UNKNOWN)
formatter.format(", column %d", _column);
-
- formatter.format(">");
return buffer.toString();
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryException.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryException.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryException.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryException.java Mon Sep 4 10:34:27 2006
@@ -64,4 +64,14 @@
{
return _location;
}
+
+ @Override
+ public String toString()
+ {
+ if (_location == null)
+ return super.toString();
+
+ return String.format("%s [at %s]", super.toString(), _location);
+ }
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java Mon Sep 4 10:34:27 2006
@@ -35,7 +35,7 @@
}
/**
- * @throws UnsupportedOperationException
+ * @throws TapestryException
* always
*/
public void set(Object value)
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,42 @@
+package org.apache.tapestry.internal.bindings;
+
+import org.apache.tapestry.Location;
+import org.apache.tapestry.internal.TapestryException;
+
+/**
+ * Base class for bindings created by the
+ * {@link org.apache.tapestry.internal.bindings.PropBindingFactory}. A subclass of this is created
+ * at runtime.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public abstract class BasePropBinding extends AbstractBinding
+{
+ private final String _toString;
+
+ public BasePropBinding(String toString, Location location)
+ {
+ super(location);
+
+ _toString = toString;
+ }
+
+ /** The default implementation of get() will throw a TapestryException (binding is write only). */
+ public Object get()
+ {
+ throw new TapestryException(BindingsMessages.bindingIsWriteOnly(this), this, null);
+ }
+
+ @Override
+ public String toString()
+ {
+ return _toString;
+ }
+
+ /** Returns false; these properties are always dynamic. */
+ @Override
+ public boolean isInvariant()
+ {
+ return false;
+ }
+}
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java Mon Sep 4 10:34:27 2006
@@ -31,4 +31,14 @@
{
return MESSAGES.format("binding-is-read-only", binding);
}
+
+ static String bindingIsWriteOnly(Binding binding)
+ {
+ return MESSAGES.format("binding-is-write-only", binding);
+ }
+
+ static String noSuchProperty(Class targetClass, String propertyName)
+ {
+ return MESSAGES.format("no-such-property", targetClass.getName(), propertyName);
+ }
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,170 @@
+package org.apache.tapestry.internal.bindings;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Location;
+import org.apache.tapestry.events.InvalidationEvent;
+import org.apache.tapestry.events.InvalidationListener;
+import org.apache.tapestry.internal.TapestryException;
+import org.apache.tapestry.internal.annotations.Concurrent;
+import org.apache.tapestry.ioc.services.ClassFab;
+import org.apache.tapestry.ioc.services.ClassFabUtils;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.MethodSignature;
+import org.apache.tapestry.ioc.services.PropertyAccess;
+import org.apache.tapestry.ioc.services.PropertyAdapter;
+import org.apache.tapestry.services.BindingFactory;
+import org.apache.tapestry.util.BodyBuilder;
+import org.apache.tapestry.util.CollectionFactory;
+
+/**
+ * Binding factory for reading and updating JavaBean properties. Uses
+ * {@link org.apache.tapestry.ioc.services.PropertyAccess} to analyze the properties, and generates
+ * a binding class using the component {@link org.apache.tapestry.ioc.services.ClassFactory}.
+ *
+ * @author Howard M. Lewis Ship
+ */
+@Concurrent
+public class PropBindingFactory implements BindingFactory, InvalidationListener
+{
+ private final PropertyAccess _propertyAccess;
+
+ private final ClassFactory _classFactory;
+
+ private final Map<String, Class> _cache = CollectionFactory.newMap();
+
+ private static final MethodSignature GET_SIGNATURE = new MethodSignature(Object.class, "get",
+ null, null);
+
+ private static final MethodSignature SET_SIGNATURE = new MethodSignature(void.class, "set",
+ new Class[]
+ { Object.class }, null);
+
+ public PropBindingFactory(PropertyAccess propertyAccess, ClassFactory classFactory)
+ {
+ _propertyAccess = propertyAccess;
+ _classFactory = classFactory;
+ }
+
+ public Binding newBinding(String description, ComponentResources component, String expression,
+ Location location)
+ {
+ Object target = component.getComponent();
+ Class targetClass = target.getClass();
+
+ try
+ {
+ Class bindingClass = findBindingClass(targetClass, expression);
+
+ String toString = String.format("PropBinding[%s %s(%s)]", description, component
+ .getCompleteId(), expression);
+
+ Constructor cons = bindingClass.getConstructors()[0];
+
+ return (Binding) cons.newInstance(target, toString, location);
+ }
+ catch (Exception ex)
+ {
+ throw new TapestryException(ex.getMessage(), location, ex);
+ }
+ }
+
+ @Concurrent.Read
+ private Class findBindingClass(Class targetClass, String propertyName)
+ {
+ // The only problem with this key is if we can get in a situation where two different
+ // versions of the class (from the default class loader, and the component class loader)
+ // are accessed in this way at the same time. I'm pretty sure that can't happen.
+
+ String key = targetClass.getName() + ":" + propertyName;
+
+ Class result = _cache.get(key);
+
+ if (result == null)
+ result = fillCache(key, targetClass, propertyName);
+
+ return result;
+ }
+
+ @Concurrent.Write
+ private Class fillCache(String key, Class targetClass, String propertyName)
+ {
+ // Race condition: simulataneous calls to fillCache() for the same targetClass/propertyName
+ // combination may result in duplicate binding classes being created, which causes no great
+ // harm.
+
+ PropertyAdapter adapter = _propertyAccess.getAdapter(targetClass).getPropertyAdapter(
+ propertyName);
+
+ if (adapter == null)
+ throw new RuntimeException(BindingsMessages.noSuchProperty(targetClass, propertyName));
+
+ Class bindingClass = createBindingClass(targetClass, propertyName, adapter);
+
+ _cache.put(key, bindingClass);
+
+ return bindingClass;
+ }
+
+ private Class createBindingClass(Class targetClass, String propertyName, PropertyAdapter adapter)
+ {
+ String name = ClassFabUtils.generateClassName("PropBinding");
+
+ ClassFab classFab = _classFactory.newClass(name, BasePropBinding.class);
+
+ classFab.addField("_target", targetClass);
+
+ classFab.addConstructor(new Class[]
+ { targetClass, String.class, Location.class }, null, "{ super($2, $3); _target = $1; }");
+
+ if (adapter.isRead())
+ {
+ String body = String.format("return ($w) _target.%s();", adapter.getReadMethod()
+ .getName());
+
+ classFab.addMethod(Modifier.PUBLIC, GET_SIGNATURE, body);
+ }
+
+ if (adapter.isUpdate())
+ {
+ Class propertyType = adapter.getType();
+
+ BodyBuilder builder = new BodyBuilder();
+ builder.begin();
+
+ String propertyTypeName = propertyType.getName();
+ builder.add("%s value = ", propertyTypeName);
+
+ if (propertyType.isPrimitive())
+ {
+ String wrapperType = ClassFabUtils.getWrapperType(propertyTypeName);
+ String unwrapMethod = ClassFabUtils.getUnwrapMethodName(propertyTypeName);
+
+ // Cast the value to the wrapper type, and then extract the primitive
+ // value from that.
+
+ builder.addln("((%s) $1).%s();", wrapperType, unwrapMethod);
+ }
+ else
+ builder.addln("(%s) $1;", propertyTypeName);
+
+ builder.addln("_target.%s(value);", adapter.getWriteMethod().getName());
+ builder.end();
+
+ classFab.addMethod(Modifier.PUBLIC, SET_SIGNATURE, builder.toString());
+ }
+
+ return classFab.createClass();
+ }
+
+ @Concurrent.Write
+ public void objectWasInvalidated(InvalidationEvent event)
+ {
+ _cache.clear();
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java Mon Sep 4 10:34:27 2006
@@ -28,14 +28,18 @@
/**
* Used to ensure that {@link javassist.ClassPool#appendClassPath(javassist.ClassPath)} is invoked
- * with a synchronized lock. Additionally, wraps around a shared
- * {@link org.apache.tapestry.internal.ioc.services.ClassFactoryClassLoader}.
+ * with a synchronized lock, and also handles tricky class loading issues (caused by the creation of
+ * classes, and class loaders, at runtime).
*
* @author Howard Lewis Ship
*/
class ClassFactoryClassPool extends ClassPool
{
- private ClassFactoryClassLoader _loader = new ClassFactoryClassLoader();
+ // This is the loader with the widest visibility yet seen.
+
+ private ClassLoader _loader;
+
+ private ClassPath _priorClassPath;
/**
* Used to identify which class loaders have already been integrated into the pool.
@@ -46,35 +50,47 @@
{
super(null);
- appendClassLoader(contextClassLoader);
+ addClassLoaderIfNeeded(contextClassLoader);
}
/**
* Convienience method for adding to the ClassPath for a particular class loader.
+ * <p>
+ * TODO: This code assumes that ClassLoaders are structured as a "line" not a proper "tree". That
+ * is, if the ClassLoader hiearchy actually does have branches, rather than a straight line from
+ * root to leaf, it may not work.
*
* @param loader
* the class loader to add (derived from a loaded class, and may be null for some
* system classes)
*/
@SuppressNullCheck
- public synchronized void appendClassLoader(ClassLoader loader)
+ public synchronized void addClassLoaderIfNeeded(ClassLoader loader)
{
if (loader == null || loader == _loader || _loaders.contains(loader))
return;
- _loader.addDelegateLoader(loader);
-
ClassPath path = new LoaderClassPath(loader);
+ if (_priorClassPath != null)
+ removeClassPath(_priorClassPath);
+
appendClassPath(path);
- _loaders.add(loader);
+ _priorClassPath = path;
+
+ ClassLoader l = loader;
+ while (l != null)
+ {
+ _loaders.add(l);
+ l = l.getParent();
+ }
+
+ _loader = loader;
}
/**
- * Invoked to convert an fabricated class into a real class. The new classes' class loader will
- * be the delegating ClassFactoryClassLoader, which has visibility to all class loaders for all
- * modules.
+ * Invoked to convert an fabricated class into a real class.
*/
@Override
public synchronized Class toClass(CtClass ctClass) throws CannotCompileException
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryImpl.java Mon Sep 4 10:34:27 2006
@@ -40,9 +40,9 @@
private final ClassLoader _loader;
- public ClassFactoryImpl(ClassLoader contextClassLoader)
+ public ClassFactoryImpl(ClassLoader classLoader)
{
- this(contextClassLoader, LogFactory.getLog(ClassFactoryImpl.class));
+ this(classLoader, LogFactory.getLog(ClassFactoryImpl.class));
}
public ClassFactoryImpl()
@@ -50,11 +50,12 @@
this(Thread.currentThread().getContextClassLoader());
}
- public ClassFactoryImpl(ClassLoader contextClassLoader, Log log)
+ /** Main constructor where a specific class loader and log is provided. */
+ public ClassFactoryImpl(ClassLoader classLoader, Log log)
{
- _loader = contextClassLoader;
+ _loader = classLoader;
- _pool = new ClassFactoryClassPool(contextClassLoader);
+ _pool = new ClassFactoryClassPool(classLoader);
_classSource = new CtClassSource(_pool);
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/CtClassSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/CtClassSource.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/CtClassSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/CtClassSource.java Mon Sep 4 10:34:27 2006
@@ -20,10 +20,8 @@
import org.apache.tapestry.ioc.services.ClassFabUtils;
/**
- * Wrapper around Javassist's {@link javassist.ClassPool} and our own
- * {@link org.apache.tapestry.internal.ioc.services.ClassFactoryClassLoader} that manages the
- * creation of new instances of {@link javassist.CtClass} and converts finished CtClass's into
- * instantiable Classes.
+ * Wrapper around Javassist's {@link javassist.ClassPool} that manages the creation of new instances
+ * of {@link javassist.CtClass} and converts finished CtClass's into instantiable Classes.
*
* @author Howard Lewis Ship
*/
@@ -53,7 +51,7 @@
// Add the class loader for the searchClass to the class pool and
// delegating class loader if needed.
- _pool.appendClassLoader(loader);
+ _pool.addClassLoaderIfNeeded(loader);
String name = ClassFabUtils.getJavaClassName(searchClass);
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java Mon Sep 4 10:34:27 2006
@@ -32,7 +32,6 @@
import org.apache.tapestry.events.UpdateListener;
import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
import org.apache.tapestry.internal.util.URLChangeTracker;
-import org.apache.tapestry.ioc.services.ClassFactory;
import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.util.Defense;
@@ -58,8 +57,6 @@
private Loader _loader;
- private ClassFactory _classFactory;
-
private final ComponentClassTransformer _transformer;
private final Log _log;
@@ -67,25 +64,8 @@
/** Map from class name to Instantiator. */
private final Map<String, Instantiator> _instantiatorMap = newMap();
- /** @return the class loader used when loading enhanced/modified classes */
- public ClassLoader getClassLoader()
- {
- return _loader;
- }
-
- public ComponentInstantiatorSourceImpl(ClassLoader parent,
- ComponentClassTransformer transformer, Log log)
- {
- _parent = parent;
- _transformer = transformer;
- _log = log;
-
- initializeService();
- }
-
private class PackageAwareLoader extends Loader
{
-
public PackageAwareLoader(ClassLoader parent, ClassPool classPool)
{
super(parent, classPool);
@@ -102,6 +82,22 @@
return null;
}
+ }
+
+ public ComponentInstantiatorSourceImpl(ClassLoader parent,
+ ComponentClassTransformer transformer, Log log)
+ {
+ _parent = parent;
+ _transformer = transformer;
+ _log = log;
+
+ initializeService();
+ }
+
+ /** @return the class loader used when loading enhanced/modified classes */
+ public ClassLoader getClassLoader()
+ {
+ return _loader;
}
public synchronized void checkForUpdates(UpdateEvent event)
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Mon Sep 4 10:34:27 2006
@@ -22,7 +22,10 @@
import org.apache.tapestry.annotations.BeforeRenderBody;
import org.apache.tapestry.annotations.RenderCloseTag;
import org.apache.tapestry.annotations.RenderTag;
+import org.apache.tapestry.events.InvalidationEvent;
+import org.apache.tapestry.events.InvalidationListener;
import org.apache.tapestry.internal.InternalConstants;
+import org.apache.tapestry.internal.bindings.PropBindingFactory;
import org.apache.tapestry.ioc.IOCUtilities;
import org.apache.tapestry.ioc.LogSource;
import org.apache.tapestry.ioc.OrderedConfiguration;
@@ -34,9 +37,11 @@
import org.apache.tapestry.ioc.annotations.Order;
import org.apache.tapestry.ioc.services.ClassFactory;
import org.apache.tapestry.ioc.services.LoggingDecorator;
+import org.apache.tapestry.ioc.services.PropertyAccess;
import org.apache.tapestry.ioc.services.ThreadCleanupHub;
import org.apache.tapestry.services.ApplicationInitializer;
import org.apache.tapestry.services.ApplicationInitializerFilter;
+import org.apache.tapestry.services.BindingFactory;
import org.apache.tapestry.services.BindingSource;
import org.apache.tapestry.services.ComponentClassResolver;
import org.apache.tapestry.services.ComponentClassTransformWorker;
@@ -255,11 +260,12 @@
*/
@Contribute("tapestry.ApplicationInitializer")
public void contributeApplicationInitializerFilters(
- OrderedConfiguration<ApplicationInitializerFilter> configuration)
+ OrderedConfiguration<ApplicationInitializerFilter> configuration,
+ @InjectService("tapestry.ioc.PropertyAccess")
+ final PropertyAccess propertyAccess)
{
- ApplicationInitializerFilter filter = new ApplicationInitializerFilter()
+ ApplicationInitializerFilter setApplicationPackage = new ApplicationInitializerFilter()
{
-
public void initializeApplication(WebContext context, ApplicationInitializer initializer)
{
String packageName = context
@@ -272,7 +278,42 @@
};
- configuration.add("SetApplicationPackage", filter, "before:*.*");
+ configuration.add("SetApplicationPackage", setApplicationPackage, "before:*.*");
+
+ final InvalidationListener listener = new InvalidationListener()
+ {
+ public void objectWasInvalidated(InvalidationEvent event)
+ {
+ propertyAccess.clear();
+ }
+
+ };
+
+ ApplicationInitializerFilter clearPropertyAccess = new ApplicationInitializerFilter()
+ {
+ public void initializeApplication(WebContext context, ApplicationInitializer initializer)
+ {
+ // Snuck in here is the logic to clear the PropertyAccess service's cache whenever
+ // the component class loader is invalidated.
+
+ _componentInstantiatorSource.addInvalidationListener(listener);
+
+ initializer.initializeApplication(context);
+ }
+ };
+
+ configuration.add("ClearPropertyAccessCacheOnInvalidation", clearPropertyAccess);
+ }
+
+ public BindingFactory buildPropBindingFactory(@InjectService("tapestry.ioc.PropertyAccess")
+ PropertyAccess propertyAccess, @InjectService("tapestry.ComponentClassFactory")
+ ClassFactory classFactory)
+ {
+ PropBindingFactory service = new PropBindingFactory(propertyAccess, classFactory);
+
+ _componentInstantiatorSource.addInvalidationListener(service);
+ return service;
}
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java Mon Sep 4 10:34:27 2006
@@ -18,6 +18,7 @@
import java.util.Locale;
import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.events.InvalidationEvent;
import org.apache.tapestry.events.InvalidationListener;
import org.apache.tapestry.internal.InternalConstants;
@@ -84,6 +85,12 @@
workComponentQueue();
+ // The page is *loaded* before it is attached to the request.
+ // This is to help ensure that no client-specific information leaks
+ // into the page.
+
+ _page.loaded();
+
return _page;
}
finally
@@ -102,6 +109,7 @@
componentName);
_page.setRootElement(rootComponent);
+ _page.addLifecycleListener(rootComponent.getComponent());
push(_componentQueue, rootComponent);
}
@@ -219,6 +227,8 @@
add(loadingComponent, activeComponent, newComponent);
+ _page.addLifecycleListener(newComponent.getComponent());
+
// Make sure container knows about the new component.
loadingComponent.addChild(newComponent);
@@ -250,7 +260,7 @@
if (directlyInsideSubcomponent)
{
- addBindingToComponent(activeComponent, attribute);
+ addBindingToComponent(loadingComponent, activeComponent, attribute);
}
else
add(loadingComponent, activeComponent, _pageElementFactory
@@ -265,7 +275,8 @@
}
- private void addBindingToComponent(ComponentPageElement component, AttributeToken token)
+ private void addBindingToComponent(ComponentResources loadingComponent,
+ ComponentPageElement component, AttributeToken token)
{
String name = token.getName();
String description = "parameter " + name;
@@ -274,7 +285,7 @@
Binding binding = _bindingSource.newBinding(
description,
- component,
+ loadingComponent,
InternalConstants.LITERAL_BINDING_PREFIX,
token.getValue(),
token.getLocation());
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHub.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHub.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHub.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHub.java Mon Sep 4 10:34:27 2006
@@ -22,7 +22,8 @@
* locked down so that only a single thread is active, and the active thread invokes
* {@link #fireUpdateEvent()}. Various services that are dependent on external resource files (such
* as classes or template files) can check to see if any file they've used has changed. If so, the
- * service can invalidate its internal cache, or notify other services that they should do the same.
+ * service can invalidate its internal cache, or notify other services (typically via
+ * {@link org.apache.tapestry.events.InvalidationListener} that they should do the same.
*
* @author Howard M. Lewis Ship
* @see org.apache.tapestry.internal.util.URLChangeTracker
@@ -30,9 +31,6 @@
public interface UpdateListenerHub
{
void addUpdateListener(UpdateListener listener);
-
- /** For completeness. */
- void removeUpdateListener(UpdateListener listener);
/**
* Invoked periodically to allow services to check if underlying state has changed. For example,
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHubImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHubImpl.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHubImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/UpdateListenerHubImpl.java Mon Sep 4 10:34:27 2006
@@ -43,11 +43,4 @@
listener.checkForUpdates(event);
}
}
-
- public void removeUpdateListener(UpdateListener listener)
- {
- _listeners.remove(listener);
-
- }
-
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Mon Sep 4 10:34:27 2006
@@ -71,6 +71,20 @@
private boolean _rendering;
+ private static final Map<Class, Class> PRIMITIVE_TO_WRAPPER = newMap();
+
+ static
+ {
+ PRIMITIVE_TO_WRAPPER.put(boolean.class, Boolean.class);
+ PRIMITIVE_TO_WRAPPER.put(byte.class, Byte.class);
+ PRIMITIVE_TO_WRAPPER.put(short.class, Short.class);
+ PRIMITIVE_TO_WRAPPER.put(int.class, Integer.class);
+ PRIMITIVE_TO_WRAPPER.put(long.class, Long.class);
+ PRIMITIVE_TO_WRAPPER.put(char.class, Character.class);
+ PRIMITIVE_TO_WRAPPER.put(float.class, Float.class);
+ PRIMITIVE_TO_WRAPPER.put(double.class, Double.class);
+ }
+
/** Constructor for the root component of a page. */
public ComponentPageElementImpl(Page page, Instantiator instantiator, ComponentModel model)
{
@@ -408,6 +422,7 @@
return b != null && b.isInvariant();
}
+ @SuppressWarnings("unchecked")
public <T> T readParameter(String parameterName, Class<T> expectedType)
{
Binding b = getBinding(parameterName);
@@ -415,6 +430,12 @@
// TODO: If binding is null ...
// TODO: Type coercion to expected type
+
+ // Easier to do primitive-to-wrapper conversions in this code than in
+ // the generated component code.
+
+ if (expectedType.isPrimitive())
+ expectedType = PRIMITIVE_TO_WRAPPER.get(expectedType);
return expectedType.cast(b.get());
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ClassFabUtils.java Mon Sep 4 10:34:27 2006
@@ -83,22 +83,55 @@
return method.getReturnType().equals(String.class);
}
- /**
- * Mapping between a primitive type and its Java VM representation Used for the encoding of
- * array types
- */
- private static Map<String, String> PRIMITIVE_TYPE_CODES = newMap();
+ private static class PrimitiveInfo
+ {
+ private final String _typeCode;
+
+ private final String _wrapperType;
+
+ private final String _unwrapMethod;
+
+ public PrimitiveInfo(String typeCode, String wrapperType, String unwrapMethod)
+ {
+ _typeCode = typeCode;
+ _wrapperType = wrapperType;
+ _unwrapMethod = unwrapMethod;
+ }
+
+ public String getTypeCode()
+ {
+ return _typeCode;
+ }
+
+ public String getUnwrapMethod()
+ {
+ return _unwrapMethod;
+ }
+
+ public String getWrapperType()
+ {
+ return _wrapperType;
+ }
+ }
+
+ private static final Map<String, PrimitiveInfo> PRIMITIVE_INFO = newMap();
static
{
- PRIMITIVE_TYPE_CODES.put("boolean", "Z");
- PRIMITIVE_TYPE_CODES.put("short", "S");
- PRIMITIVE_TYPE_CODES.put("int", "I");
- PRIMITIVE_TYPE_CODES.put("long", "J");
- PRIMITIVE_TYPE_CODES.put("float", "F");
- PRIMITIVE_TYPE_CODES.put("double", "D");
- PRIMITIVE_TYPE_CODES.put("char", "C");
- PRIMITIVE_TYPE_CODES.put("byte", "B");
+ add("boolean", "Z", "java.lang.Boolean", "booleanValue");
+ add("short", "S", "java.lang.Short", "shortValue");
+ add("int", "I", "java.lang.Integer", "intValue");
+ add("long", "J", "java.lang.Long", "longValue");
+ add("float", "F", "java.lang.Float", "floatValue");
+ add("double", "D", "java.lang.Double", "doubleValue");
+ add("char", "C", "java.lang.Character", "charValue");
+ add("byte", "B", "java.lang.Byte", "byteValue");
+ }
+
+ private static void add(String primitiveType, String typeCode, String wrapperType,
+ String unwrapMethod)
+ {
+ PRIMITIVE_INFO.put(primitiveType, new PrimitiveInfo(typeCode, wrapperType, unwrapMethod));
}
/**
@@ -121,9 +154,10 @@
type = type.substring(0, type.length() - 2);
}
- String primitiveIdentifier = (String) PRIMITIVE_TYPE_CODES.get(type);
- if (primitiveIdentifier != null)
- buffer.append(primitiveIdentifier);
+ PrimitiveInfo pi = PRIMITIVE_INFO.get(type);
+
+ if (pi != null)
+ buffer.append(pi.getTypeCode());
else
{
buffer.append("L");
@@ -132,5 +166,21 @@
}
return buffer.toString();
+ }
+
+ /**
+ * Given one of the primitive types, returns the name of the method that will unwrap the wrapped
+ * type to the primitive type.
+ */
+ public static String getUnwrapMethodName(String primitiveTypeName)
+ {
+ return PRIMITIVE_INFO.get(primitiveTypeName).getUnwrapMethod();
+ }
+
+ /** Given the name of a primitive type, returns the name of the corresponding wrapper class. */
+
+ public static String getWrapperType(String primitiveType)
+ {
+ return PRIMITIVE_INFO.get(primitiveType).getWrapperType();
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Mon Sep 4 10:34:27 2006
@@ -363,9 +363,12 @@
}
/** Contributes the factory for "literal:" bindings. */
- public void contributeBindingSource(MappedConfiguration<String, BindingFactory> configuration)
+ public void contributeBindingSource(MappedConfiguration<String, BindingFactory> configuration,
+ @InjectService("tapestry.internal.PropBindingFactory")
+ BindingFactory propBindingFactory)
{
configuration.add(InternalConstants.LITERAL_BINDING_PREFIX, new LiteralBindingFactory());
+ configuration.add(InternalConstants.PROP_BINDING_PREFIX, propBindingFactory);
}
/**
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/bindings/BindingsStrings.properties Mon Sep 4 10:34:27 2006
@@ -12,4 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-binding-is-read-only=Binding %s is read-only.
\ No newline at end of file
+binding-is-read-only=Binding %s is read-only.
+binding-is-write-only=Binding %s is write-only.
+no-such-property=Class %s does not contain a property named '%s'.
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/ioc/services/ServiceStrings.properties Mon Sep 4 10:34:27 2006
@@ -13,6 +13,7 @@
# limitations under the License.
unable-to-add-method=Unable to add method %s to class %s: %s
+unable-to-add-field=Unable to add field %s to class %s: %s
unable-to-add-constructor=Unable to add constructor to class %s: %s
unable-to-create-class=Unable to create class %s as subclass of %s: %s
unable-to-lookup-class=Unable to lookup class %s: %s
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Mon Sep 4 10:34:27 2006
@@ -10,8 +10,13 @@
</p>
<p>
Tapestry 5 Integration Application 1:
- <a href="Start.html">Start Page</a>
+
+ <ul>
+ <a href="Start.html">Start Page</a>
+ <a href="MerryChristmas.html">Loop Page</a>
+ </ul>
</p>
+
<p>
Feast your eyes:
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Mon Sep 4 10:34:27 2006
@@ -32,16 +32,16 @@
{ "integration" })
public class IntegrationTests extends Assert
{
+ private static final String BASE_URL = "http://localhost/";
+
+ public static final String PAGE_LOAD_TIMEOUT = "1000";
+
private Selenium _selenium;
private SeleniumServer _server;
private JettyRunner _jettyRunner;
- public static final String BASE_URL = String.format(
- "http://localhost:%d",
- SeleniumServer.DEFAULT_PORT);
-
@BeforeClass
public void startupBackground() throws Exception
{
@@ -81,12 +81,10 @@
_jettyRunner = null;
}
- public static final String PAGE_LOAD_TIMEOUT = "1000";
-
@Test
- public void app1_basic_output() throws Exception
+ public void app1_basic_output_and_parameters() throws Exception
{
- _selenium.open("http://localhost/");
+ _selenium.open(BASE_URL);
_selenium.click("link=Start Page");
_selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT);
@@ -104,5 +102,20 @@
// This is text passed from Start.html to Output as a parameter
assertTrue(body.contains("we have basic parameters working"));
+
+ // OK ... this could be a separate test, but for efficiency, we'll mix it in here.
+ // It takes a while to start up Selenium RC (and a Firefox browser).
+
+ _selenium.open(BASE_URL);
+
+ _selenium.click("link=Loop Page");
+ _selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT);
+
+ body = _selenium.getBodyText();
+
+ // Selenium is nice enough to remove the elements and excess whitespace.
+
+ assertTrue(body.contains("Ho! Ho! Ho!"));
}
+
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,39 @@
+package org.apache.tapestry.integration.app1.components;
+
+import org.apache.tapestry.annotations.BeforeRender;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.annotations.RenderCloseTag;
+
+@ComponentClass
+public class Loop
+{
+ @Parameter(required = true)
+ private int _min;
+
+ @Parameter(required = true)
+ private int _max;
+
+ @Parameter(required = true)
+ private int _value;
+
+ @BeforeRender
+ void initializeValue()
+ {
+ _value = _min;
+ }
+
+ @RenderCloseTag
+ boolean startLoop()
+ {
+ int newValue = _value + 1;
+
+ if (newValue <= _max)
+ {
+ _value = newValue;
+ return true;
+ }
+
+ return false;
+ }
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,30 @@
+package org.apache.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+
+@ComponentClass
+public class MerryChristmas
+{
+ private int _value;
+
+ public int getMin()
+ {
+ return 0;
+ }
+
+ public int getMax()
+ {
+ return 2;
+ }
+
+ public int getValue()
+ {
+ return _value;
+ }
+
+ public void setValue(int value)
+ {
+ _value = value;
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/LocationImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/LocationImplTest.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/LocationImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/LocationImplTest.java Mon Sep 4 10:34:27 2006
@@ -63,10 +63,7 @@
assertEquals(l.getLine(), line);
assertEquals(l.getColumn(), column);
- assertEquals(l.toString(), String.format(
- "<Location: <Resource>, line %d, column %d>",
- line,
- column));
+ assertEquals(l.toString(), String.format("<Resource>, line %d, column %d", line, column));
}
@Test
@@ -82,7 +79,7 @@
assertEquals(l.getLine(), line);
assertEquals(l.getColumn(), -1);
- assertEquals(l.toString(), String.format("<Location: <Resource>, line %d>", line));
+ assertEquals(l.toString(), String.format("<Resource>, line %d", line));
}
@Test
@@ -96,6 +93,6 @@
assertEquals(l.getLine(), -1);
assertEquals(l.getColumn(), -1);
- assertEquals(l.toString(), "<Location: <Resource>>");
+ assertEquals(l.toString(), "<Resource>");
}
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,57 @@
+package org.apache.tapestry.internal.bindings;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.apache.tapestry.runtime.LifecycleEvent;
+
+/**
+ * For use in places where we don't want to have to transform a class just for testing purposes.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class DefaultComponentLifecyle implements ComponentLifecycle
+{
+
+ public void cleanupAfterRender()
+ {
+ }
+
+ public void beforeRender(MarkupWriter writer, LifecycleEvent<Boolean> event)
+ {
+ }
+
+ public void renderTag(MarkupWriter writer, LifecycleEvent<Boolean> event)
+ {
+ }
+
+ public void beforeRenderBody(MarkupWriter writer, LifecycleEvent<Boolean> event)
+ {
+ }
+
+ public void renderCloseTag(MarkupWriter writer, LifecycleEvent<Boolean> event)
+ {
+ }
+
+ public void afterRender(MarkupWriter writer, LifecycleEvent<Boolean> event)
+ {
+ }
+
+ public ComponentResources getResources()
+ {
+ return null;
+ }
+
+ public void containingPageDidLoad()
+ {
+ }
+
+ public void containingPageDidDetach()
+ {
+ }
+
+ public void containingPageDidAttach()
+ {
+ }
+
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,223 @@
+package org.apache.tapestry.internal.bindings;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Location;
+import org.apache.tapestry.events.InvalidationEvent;
+import org.apache.tapestry.internal.ioc.IOCUtilities;
+import org.apache.tapestry.internal.ioc.services.ClassFactoryImpl;
+import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class PropBindingFactoryTest extends InternalBaseTestCase
+{
+ private PropBindingFactory newPropBindingFactory()
+ {
+ return new PropBindingFactory(new PropertyAccessImpl(), new ClassFactoryImpl());
+ }
+
+ private ComponentResources newComponentResources(ComponentLifecycle component)
+ {
+ ComponentResources resources = newComponentResources();
+ train_getComponent(resources, component);
+
+ train_getCompleteId(resources, "foo.Bar:baz");
+
+ return resources;
+ }
+
+ protected void train_getCompleteId(ComponentResources resources, String completeId)
+ {
+ resources.getCompleteId();
+ setReturnValue(completeId);
+ }
+
+ private void train_getComponent(ComponentResources resources, ComponentLifecycle component)
+ {
+ resources.getComponent();
+ setReturnValue(component);
+ }
+
+ @Test
+ public void object_property()
+ {
+ PropBindingFactory factory = newPropBindingFactory();
+ TargetBean bean = new TargetBean();
+ ComponentResources resources = newComponentResources(bean);
+ Location l = newLocation();
+
+ replay();
+
+ Binding binding = factory.newBinding("test binding", resources, "objectValue", l);
+
+ bean.setObjectValue("first");
+
+ assertEquals(binding.get(), "first");
+
+ binding.set("second");
+
+ assertEquals(bean.getObjectValue(), "second");
+ assertEquals(IOCUtilities.locationOf(binding), l);
+
+ assertEquals(binding.toString(), "PropBinding[test binding foo.Bar:baz(objectValue)]");
+
+ verify();
+ }
+
+ @Test
+ public void primitive_property()
+ {
+ PropBindingFactory factory = newPropBindingFactory();
+ TargetBean bean = new TargetBean();
+ ComponentResources resources = newComponentResources(bean);
+ Location l = newLocation();
+
+ replay();
+
+ Binding binding = factory.newBinding("test binding", resources, "intValue", l);
+
+ bean.setIntValue(1);
+
+ assertEquals(binding.get(), 1);
+
+ binding.set(2);
+
+ assertEquals(bean.getIntValue(), 2);
+
+ verify();
+ }
+
+ @Test
+ public void read_only_property()
+ {
+ PropBindingFactory factory = newPropBindingFactory();
+ TargetBean bean = new TargetBean();
+ ComponentResources resources = newComponentResources(bean);
+ Location l = newLocation();
+
+ replay();
+
+ Binding binding = factory.newBinding("test binding", resources, "readOnly", l);
+
+ assertEquals(binding.get(), "ReadOnly");
+
+ try
+ {
+ binding.set("fail");
+ unreachable();
+ }
+ catch (RuntimeException ex)
+ {
+ assertEquals(
+ "Binding PropBinding[test binding foo.Bar:baz(readOnly)] is read-only.",
+ ex.getMessage());
+ assertEquals(IOCUtilities.locationOf(ex), l);
+ }
+
+ verify();
+ }
+
+ @Test
+ public void write_only_property()
+ {
+ PropBindingFactory factory = newPropBindingFactory();
+ TargetBean bean = new TargetBean();
+ ComponentResources resources = newComponentResources(bean);
+ Location l = newLocation();
+
+ replay();
+
+ Binding binding = factory.newBinding("test binding", resources, "writeOnly", l);
+
+ binding.set("updated");
+
+ assertEquals(bean._writeOnly, "updated");
+
+ try
+ {
+ assertEquals(binding.get(), "ReadOnly");
+ unreachable();
+ }
+ catch (RuntimeException ex)
+ {
+ assertEquals(
+ "Binding PropBinding[test binding foo.Bar:baz(writeOnly)] is write-only.",
+ ex.getMessage());
+ assertEquals(IOCUtilities.locationOf(ex), l);
+ }
+
+ verify();
+ }
+
+ @Test
+ public void caching()
+ {
+ PropBindingFactory factory = newPropBindingFactory();
+ TargetBean bean1 = new TargetBean();
+ ComponentResources resources1 = newComponentResources(bean1);
+ TargetBean bean2 = new TargetBean();
+ ComponentResources resources2 = newComponentResources(bean2);
+ TargetBean bean3 = new TargetBean();
+ ComponentResources resources3 = newComponentResources(bean3);
+
+ Location l = newLocation();
+
+ replay();
+
+ Binding binding1 = factory.newBinding("test binding 1", resources1, "objectValue", l);
+ Binding binding2 = factory.newBinding("test binding 2", resources2, "objectValue", l);
+
+ assertSame(binding2.getClass(), binding1.getClass());
+
+ binding1.set("foo");
+ binding2.set("bar");
+
+ assertEquals(bean1.getObjectValue(), "foo");
+ assertEquals(bean2.getObjectValue(), "bar");
+
+ // Now, clear the cache.
+
+ factory.objectWasInvalidated(new InvalidationEvent(this));
+
+ Binding binding3 = factory.newBinding("test binding 3", resources3, "objectValue", l);
+
+ // We'll assume the behavior is the same, but expect the class to be different.
+
+ assertNotSame(binding3.getClass(), binding1.getClass());
+
+ verify();
+ }
+
+ @Test
+ public void unknown_property()
+ {
+ PropBindingFactory factory = newPropBindingFactory();
+ TargetBean bean = new TargetBean();
+ ComponentResources resources = newComponentResources();
+ Location l = newLocation();
+
+ train_getComponent(resources, bean);
+
+ replay();
+
+ try
+ {
+ factory.newBinding("test binding", resources, "missingProperty", l);
+ unreachable();
+ }
+ catch (RuntimeException ex)
+ {
+ assertEquals(ex.getMessage(), String.format(
+ "Class %s does not contain a property named 'missingProperty'.",
+ bean.getClass().getName()));
+ assertSame(IOCUtilities.locationOf(ex), l);
+ }
+
+ verify();
+ }
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java Mon Sep 4 10:34:27 2006
@@ -0,0 +1,40 @@
+package org.apache.tapestry.internal.bindings;
+
+public class TargetBean extends DefaultComponentLifecyle
+{
+ private String _objectValue;
+
+ private int _intValue;
+
+ String _writeOnly;
+
+ public int getIntValue()
+ {
+ return _intValue;
+ }
+
+ public void setIntValue(int intValue)
+ {
+ _intValue = intValue;
+ }
+
+ public String getObjectValue()
+ {
+ return _objectValue;
+ }
+
+ public void setObjectValue(String objectValue)
+ {
+ _objectValue = objectValue;
+ }
+
+ public void setWriteOnly(String value)
+ {
+ _writeOnly = value;
+ }
+
+ public String getReadOnly()
+ {
+ return "ReadOnly";
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ClassFabImplTest.java Mon Sep 4 10:34:27 2006
@@ -61,7 +61,7 @@
ClassFactoryClassPool pool = new ClassFactoryClassPool(threadLoader);
- pool.appendClassLoader(threadLoader);
+ pool.addClassLoaderIfNeeded(threadLoader);
_source = new CtClassSource(pool);
}
@@ -375,22 +375,25 @@
// You'd think some of these would fail, but the ultimate failure
// occurs when we create the class.
- cf.addField(".", String.class);
- cf.addField("buffy", int.class);
+ cf.addField("a%b", String.class);
cf.addField("", int.class);
+ // Aha! Adding a duplicate fails!
+
+ cf.addField("buffy", int.class);
+
try
{
- cf.createClass();
+ cf.addField("buffy", String.class);
unreachable();
}
catch (RuntimeException ex)
{
- assertExceptionSubstring(ex, "Unable to create class InvalidField");
+ assertEquals(
+ ex.getMessage(),
+ "Unable to add field buffy to class InvalidField: duplicate field: buffy");
}
- // Javassist lets us down here; I can't think of a way to get addField() to actually
- // fail.
}
@Test
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UpdateListenerHubImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UpdateListenerHubImplTest.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UpdateListenerHubImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UpdateListenerHubImplTest.java Mon Sep 4 10:34:27 2006
@@ -42,13 +42,5 @@
hub.fireUpdateEvent();
verify();
-
- hub.removeUpdateListener(listener);
-
- replay();
-
- hub.fireUpdateEvent();
-
- verify();
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/ClassFabUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/ClassFabUtilsTest.java?view=diff&rev=440132&r1=440131&r2=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/ClassFabUtilsTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ioc/services/ClassFabUtilsTest.java Mon Sep 4 10:34:27 2006
@@ -44,4 +44,16 @@
{ "byte[][]", "[[B" },
{ "java.lang.Runnable[][]", "[[Ljava.lang.Runnable;" } };
}
+
+ @Test
+ public void unwrap_method()
+ {
+ assertEquals(ClassFabUtils.getUnwrapMethodName("int"), "intValue");
+ }
+
+ @Test
+ public void wrapper_type()
+ {
+ assertEquals(ClassFabUtils.getWrapperType("int"), "java.lang.Integer");
+ }
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html?view=auto&rev=440132
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/MerryChristmas.html Mon Sep 4 10:34:27 2006
@@ -0,0 +1,11 @@
+<t:comp id="border" type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+ <p> The Loop component demonstrates reading and writing of properties with the prop: binding
+ prefix.</p>
+
+ <p>
+ Merry Christmas:
+ <t:comp id="loop" type="Loop" min="prop:min" max="prop:max" value="prop:value">
+ Ho!
+ </t:comp>
+ </p>
+</t:comp>