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/10/26 18:30:11 UTC
svn commit: r468058 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/annotations/
main/java/org/apache/tapestry/internal/
main/java/org/apache/tapestry/internal/model/
main/java/org/apache/tapestry/internal/services/ main...
Author: hlship
Date: Thu Oct 26 09:30:09 2006
New Revision: 468058
URL: http://svn.apache.org/viewvc?view=rev&rev=468058
Log:
Initial support for implementation mixins
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Mixin.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MixinWorker.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/FormSupport.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactory.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.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/ServicesMessages.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.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/internal/structure/InternalComponentResourcesImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/mixins.apt
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Mixin.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Mixin.java?view=auto&rev=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Mixin.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Mixin.java Thu Oct 26 09:30:09 2006
@@ -0,0 +1,26 @@
+package org.apache.tapestry.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Defines an <em>implementation</em> mixin for a comopnent.
+ */
+@Target(FIELD)
+@Documented
+@Retention(RUNTIME)
+public @interface Mixin {
+
+ /**
+ * Defines the type of mixin, using a logical mixin name. This value takes precendence over the
+ * type of field (to which the annotation is attached). In such cases, it is presumed that the
+ * field's type is an interface implemented by the actual mixin. The default value (the empty
+ * string) directs Tapestry to use the field type as the mixin class to instantiate and attach
+ * to the component.
+ */
+ String value() default "";
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java Thu Oct 26 09:30:09 2006
@@ -17,10 +17,13 @@
import org.apache.tapestry.Binding;
import org.apache.tapestry.internal.structure.ComponentPageElement;
import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.ComponentLifecycle;
import org.apache.tapestry.services.PersistentFieldManager;
/**
* Operations shared by {@link InternalComponentResources} and {@link ComponentPageElement}.
+ * Typically, these means methods of InternalComponentResources that are delegated to the component
+ * page element.
*/
public interface InternalComponentResourcesCommon
{
@@ -57,4 +60,13 @@
* TODO: Would prefer to move this to a sub-interface, say "MutableInternalComponentResources".
*/
void addParameter(String parameterName, Binding binding);
+
+ /**
+ * Returns the mixin instance for the fully qualfied mixin class name.
+ *
+ * @param mixinClassName
+ * fully qualified class name
+ * @return IllegalArgumentException if no such mixin is associated with the core component
+ */
+ ComponentLifecycle getMixinByClassName(String mixinClassName);
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java Thu Oct 26 09:30:09 2006
@@ -55,6 +55,8 @@
/** Maps from field name to strategy. */
private Map<String, String> _persistentFields;
+ private List<String> _mixinClassNames;
+
@SuppressNullCheck
public MutableComponentModelImpl(String componentClassName, Log log, Resource baseResource,
ComponentModel parentModel)
@@ -224,4 +226,21 @@
{
return _parentModel == null;
}
+
+ public void addMixinClassName(String mixinClassName)
+ {
+ if (_mixinClassNames == null)
+ _mixinClassNames = newList();
+
+ _mixinClassNames.add(mixinClassName);
+ }
+
+ public List<String> getMixinClassNames()
+ {
+ if (_mixinClassNames == null)
+ return Collections.emptyList();
+
+ return Collections.unmodifiableList(_mixinClassNames);
+ }
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java Thu Oct 26 09:30:09 2006
@@ -103,17 +103,32 @@
public String resolvePageNameToClassName(String pageName)
{
- return resolve(pageName, "pages", _pageClassCache);
+ String result = resolve(pageName, "pages", _pageClassCache);
+
+ if (result == null)
+ throw new IllegalArgumentException(ServicesMessages.couldNotResolvePageName(pageName));
+
+ return result;
}
public String resolveComponentTypeToClassName(String componentType)
{
- return resolve(componentType, "components", _componentClassCache);
+ String result = resolve(componentType, "components", _componentClassCache);
+
+ if (result == null)
+ throw new IllegalArgumentException(ServicesMessages.couldNotResolveComponentType(componentType));
+
+ return result;
}
public String resolveMixinTypeToClassName(String mixinType)
{
- return resolve(mixinType, "mixins", _mixinClassCache);
+ String result = resolve(mixinType, "mixins", _mixinClassCache);
+
+ if (result == null)
+ throw new IllegalArgumentException(ServicesMessages.couldNotResolveMixinType(mixinType));
+
+ return result;
}
// Used a thread-safe (concurrent) map rather than making this method itself
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MixinWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MixinWorker.java?view=auto&rev=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MixinWorker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MixinWorker.java Thu Oct 26 09:30:09 2006
@@ -0,0 +1,59 @@
+package org.apache.tapestry.internal.services;
+
+import java.util.List;
+
+import org.apache.tapestry.annotations.Mixin;
+import org.apache.tapestry.internal.util.InternalUtils;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassResolver;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.TransformConstants;
+
+/**
+ * Supports the {@link Mixin} annotation, which allows a mixin to be part of the implementation of a
+ * component. The annotation is applied to a field, which will become read-only, and contain a
+ * reference to the mixin instance.
+ */
+public class MixinWorker implements ComponentClassTransformWorker
+{
+ private final ComponentClassResolver _resolver;
+
+ public MixinWorker(final ComponentClassResolver resolver)
+ {
+ _resolver = resolver;
+ }
+
+ public void transform(ClassTransformation transformation, MutableComponentModel model)
+ {
+ List<String> fields = transformation.findFieldsWithAnnotation(Mixin.class);
+
+ for (String fieldName : fields)
+ {
+ Mixin annotation = transformation.getFieldAnnotation(fieldName, Mixin.class);
+
+ String mixinType = annotation.value();
+
+ String fieldType = transformation.getFieldType(fieldName);
+
+ String mixinClassName = InternalUtils.isBlank(mixinType) ? fieldType : _resolver
+ .resolveMixinTypeToClassName(mixinType);
+
+ model.addMixinClassName(mixinClassName);
+
+ transformation.makeReadOnly(fieldName);
+
+ String body = String.format(
+ "%s = (%s) %s.getMixinByClassName(\"%s\");",
+ fieldName,
+ fieldType,
+ transformation.getResourcesFieldName(),
+ mixinClassName);
+
+ transformation
+ .extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, body);
+
+ transformation.claimField(fieldName, annotation);
+ }
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactory.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactory.java Thu Oct 26 09:30:09 2006
@@ -65,7 +65,7 @@
String componentType, String componentClassName, Location location);
/**
- * Creates a new root component for a page.
+ * Creates a new root component for a page. Adds any mixins defined by the components model.
*
* @param page
* the page that will contain the root component
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java Thu Oct 26 09:30:09 2006
@@ -34,8 +34,8 @@
import org.apache.tapestry.internal.structure.StartElementPageElement;
import org.apache.tapestry.internal.structure.TextPageElement;
import org.apache.tapestry.internal.util.InternalUtils;
-import org.apache.tapestry.ioc.IOCUtilities;
import org.apache.tapestry.ioc.services.TypeCoercer;
+import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.runtime.RenderQueue;
import org.apache.tapestry.services.BindingSource;
import org.apache.tapestry.services.ComponentClassResolver;
@@ -126,11 +126,15 @@
// by the type of the field. In many scenarios, the field type is a common interface,
// and the type is used to determine the concrete class to instantiate.
- finalClassName = _componentClassResolver.resolveComponentTypeToClassName(componentType);
-
- if (finalClassName == null)
- throw new TapestryException(ServicesMessages
- .unableToResolveComponentType(componentType), location, null);
+ try
+ {
+ finalClassName = _componentClassResolver
+ .resolveComponentTypeToClassName(componentType);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new TapestryException(ex.getMessage(), location, ex);
+ }
}
Instantiator instantiator = _componentInstantiatorSource.findInstantiator(finalClassName);
@@ -146,6 +150,8 @@
container.addEmbeddedElement(result);
+ addMixins(result, instantiator);
+
return result;
}
@@ -156,11 +162,20 @@
ComponentPageElementImpl result = new ComponentPageElementImpl(page, instantiator,
_typeCoercer);
+ addMixins(result, instantiator);
+
page.addLifecycleListener(result);
return result;
}
+ private void addMixins(ComponentPageElement component, Instantiator instantiator)
+ {
+ ComponentModel model = instantiator.getModel();
+ for (String mixinClassName : model.getMixinClassNames())
+ addMixinByClassName(component, mixinClassName);
+ }
+
public PageElement newRenderBodyElement(final ComponentPageElement component)
{
return new PageElement()
@@ -191,9 +206,7 @@
Instantiator mixinInstantiator = _componentInstantiatorSource
.findInstantiator(mixinClassName);
- String mixinName = IOCUtilities.toSimpleId(mixinClassName);
-
- component.addMixin(mixinName, mixinInstantiator);
+ component.addMixin(mixinInstantiator);
}
}
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=468058&r1=468057&r2=468058
==============================================================================
--- 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 Thu Oct 26 09:30:09 2006
@@ -366,6 +366,14 @@
}
}
+ private void addMixinsToComponent(ComponentPageElement component, ComponentModel model)
+ {
+ for (String mixinClassName : model.getMixinClassNames())
+ {
+ _pageElementFactory.addMixinByClassName(component, mixinClassName);
+ }
+ }
+
private void addMixinsToComponent(ComponentPageElement component, EmbeddedComponentModel model,
String mixins)
{
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java Thu Oct 26 09:30:09 2006
@@ -183,11 +183,6 @@
return MESSAGES.format("context-index-out-of-range", methodDescription);
}
- static String unableToResolveComponentType(String componentType)
- {
- return MESSAGES.format("unable-to-resolve-component-type", componentType);
- }
-
static String pageDoesNotExist(String pageName)
{
return MESSAGES.format("page-does-not-exist", pageName);
@@ -212,5 +207,20 @@
static String unknownPersistentFieldStrategy(String stategyName, String catalog)
{
return MESSAGES.format("unknown-persistent-field-strategy", stategyName, catalog);
+ }
+
+ static String couldNotResolvePageName(String pageName)
+ {
+ return MESSAGES.format("could-not-resolve-page-name", pageName);
+ }
+
+ static String couldNotResolveComponentType(String componentType)
+ {
+ return MESSAGES.format("could-not-resolve-component-type", componentType);
+ }
+
+ static String couldNotResolveMixinType(String mixinType)
+ {
+ return MESSAGES.format("could-not-resolve-mixin-type", mixinType);
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElement.java Thu Oct 26 09:30:09 2006
@@ -73,13 +73,10 @@
/**
* Adds a mixin.
*
- * @param mixinName
- * the logical name of the mixin, which consists of just the class name portion of
- * the mixin's fully qualified class name (and will be unique for a single component)
* @param instantiator
* used to instantiate an instance of the mixin
*/
- void addMixin(String mixinName, Instantiator instantiator);
+ void addMixin(Instantiator instantiator);
/**
* Retrieves a component page element by its id.
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=468058&r1=468057&r2=468058
==============================================================================
--- 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 Thu Oct 26 09:30:09 2006
@@ -34,6 +34,7 @@
import org.apache.tapestry.internal.services.ComponentEventImpl;
import org.apache.tapestry.internal.services.Instantiator;
import org.apache.tapestry.internal.util.InternalUtils;
+import org.apache.tapestry.ioc.IOCUtilities;
import org.apache.tapestry.ioc.services.TypeCoercer;
import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.model.ParameterModel;
@@ -93,7 +94,7 @@
private final TypeCoercer _typeCoercer;
/** Map from mixin name to resources for the mixin. */
- private Map<String, InternalComponentResources> _mixins;
+ private Map<String, InternalComponentResources> _mixinsByShortName;
/**
* Component lifecycle instances for all mixins; the core component is added to this list during
@@ -211,7 +212,9 @@
if (dotx > 0)
{
String mixinName = parameterName.substring(0, dotx);
- InternalComponentResources mixinResources = InternalUtils.get(_mixins, mixinName);
+ InternalComponentResources mixinResources = InternalUtils.get(
+ _mixinsByShortName,
+ mixinName);
if (mixinResources == null)
throw new TapestryException(StructureMessages.missingMixinForParameter(
@@ -219,7 +222,7 @@
mixinName,
parameterName), binding, null);
- String simpleName = mixinName.substring(dotx + 1);
+ String simpleName = parameterName.substring(dotx + 1);
mixinResources.addParameter(simpleName, binding);
}
@@ -232,9 +235,9 @@
return;
}
- for (String mixinName : InternalUtils.sortedKeys(_mixins))
+ for (String mixinName : InternalUtils.sortedKeys(_mixinsByShortName))
{
- InternalComponentResources resources = _mixins.get(mixinName);
+ InternalComponentResources resources = _mixinsByShortName.get(mixinName);
if (resources.getComponentModel().getParameterModel(parameterName) != null)
{
resources.addParameter(parameterName, binding);
@@ -512,8 +515,8 @@
addUnboundParameterNames(null, unbound, _coreResources);
- for (String name : InternalUtils.sortedKeys(_mixins))
- addUnboundParameterNames(name, unbound, _mixins.get(name));
+ for (String name : InternalUtils.sortedKeys(_mixinsByShortName))
+ addUnboundParameterNames(name, unbound, _mixinsByShortName.get(name));
if (unbound.isEmpty())
return;
@@ -618,17 +621,20 @@
return getFieldChange(fieldName) != null;
}
- public void addMixin(String mixinName, Instantiator instantiator)
+ public void addMixin(Instantiator instantiator)
{
- if (_mixins == null)
- _mixins = newMap();
+ if (_mixinsByShortName == null)
+ _mixinsByShortName = newMap();
+
+ String mixinClassName = instantiator.getModel().getComponentClassName();
+ String mixinName = IOCUtilities.toSimpleId(mixinClassName);
InternalComponentResourcesImpl resources = new InternalComponentResourcesImpl(this,
instantiator, _typeCoercer);
// TODO: Check for name collision?
- _mixins.put(mixinName, resources);
+ _mixinsByShortName.put(mixinName, resources);
_components.add(resources.getComponent());
}
@@ -641,4 +647,29 @@
{
return _coreResources.getLog();
}
+
+ public ComponentLifecycle getMixinByClassName(String mixinClassName)
+ {
+ ComponentLifecycle result = null;
+
+ if (_mixinsByShortName != null)
+ {
+ for (InternalComponentResources resources : _mixinsByShortName.values())
+ {
+ if (resources.getComponentModel().getComponentClassName().equals(mixinClassName))
+ {
+ result = resources.getComponent();
+ break;
+ }
+ }
+ }
+
+ if (result == null)
+ throw new IllegalArgumentException(StructureMessages.unknownMixin(
+ _completeId,
+ mixinClassName));
+
+ return result;
+ }
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java Thu Oct 26 09:30:09 2006
@@ -214,4 +214,9 @@
return _componentModel.getLog();
}
+ public ComponentLifecycle getMixinByClassName(String mixinClassName)
+ {
+ return _element.getMixinByClassName(mixinClassName);
+ }
+
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java Thu Oct 26 09:30:09 2006
@@ -53,4 +53,9 @@
return MESSAGES
.format("missing-mixin-for-parameter", componentId, mixinName, parameterName);
}
+
+ static String unknownMixin(String componentId, String mixinClassName)
+ {
+ return MESSAGES.format("unknown-mixin", componentId, mixinClassName);
+ }
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java Thu Oct 26 09:30:09 2006
@@ -92,4 +92,7 @@
* @return true if a root class, false if a subclass
*/
boolean isRootClass();
+
+ /** Returns a list of the class names of mixins that are part of the component's implementation. */
+ List<String> getMixinClassNames();
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/MutableComponentModel.java Thu Oct 26 09:30:09 2006
@@ -64,4 +64,7 @@
* {@link InternalComponentResources#postFieldChange(String, Object)}, etc.
*/
String setFieldPersistenceStrategy(String fieldName, String strategy);
+
+ /** Adds a mixin to the component's implementation. */
+ void addMixinClassName(String mixinClassName);
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentClassResolver.java Thu Oct 26 09:30:09 2006
@@ -86,7 +86,9 @@
*
* @param componentType
* a logical component type
- * @return fully qualified class name or null if the component type can not be resolved
+ * @return fully qualified class name
+ * @throws IllegalArgumentException
+ * if the component type can not be resolved
*/
String resolveComponentTypeToClassName(String componentType);
@@ -95,7 +97,9 @@
*
* @param mixinType
* a logical mixin type
- * @return fully qualified class name or null if the mixin type can not be resolved
+ * @return fully qualified class name
+ * @throws IllegalArgumentException
+ * if the mixin type can not be resolved
*/
String resolveMixinTypeToClassName(String mixinType);
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/FormSupport.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/FormSupport.java?view=auto&rev=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/FormSupport.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/FormSupport.java Thu Oct 26 09:30:09 2006
@@ -0,0 +1,12 @@
+package org.apache.tapestry.services;
+
+/**
+ * Services provided by an enclosing Form control component to the various form element components
+ * it encloses.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public interface FormSupport
+{
+
+}
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=468058&r1=468057&r2=468058
==============================================================================
--- 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 Thu Oct 26 09:30:09 2006
@@ -53,6 +53,7 @@
import org.apache.tapestry.internal.services.InternalModule;
import org.apache.tapestry.internal.services.LinkFactory;
import org.apache.tapestry.internal.services.MarkupWriterImpl;
+import org.apache.tapestry.internal.services.MixinWorker;
import org.apache.tapestry.internal.services.OnEventWorker;
import org.apache.tapestry.internal.services.PageRenderDispatcher;
import org.apache.tapestry.internal.services.PageResponseRenderer;
@@ -480,6 +481,7 @@
* {@link org.apache.tapestry.annotations.Parameter} annotation</li>
* <li>Component -- identifies embedded components based on the
* {@link org.apache.tapestry.annotations.Component} annotation</li>
+ * <li>Mixin -- adds a mixin as part of a component's implementation</li>
* <li>Environment -- allows fields to contain values extracted from the {@link Environment}
* service</li>
* <li>UnclaimedField -- identifies unclaimed fields and resets them to null/0/false at the end
@@ -503,7 +505,7 @@
configuration.add("Parameter", new ParameterWorker());
configuration.add("Component", new ComponentWorker(resolver));
configuration.add("Environment", new EnvironmentalWorker(environment));
-
+ configuration.add("Mixin", new MixinWorker(resolver));
configuration.add("OnEvent", new OnEventWorker());
// Workers for the component rendering state machine methods; this is in typical
@@ -511,10 +513,14 @@
add(configuration, TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class, false);
add(configuration, TransformConstants.BEGIN_RENDER_SIGNATURE, BeginRender.class, false);
- add(configuration, TransformConstants.BEFORE_RENDER_BODY_SIGNATURE, BeforeRenderBody.class, false);
-
+ add(
+ configuration,
+ TransformConstants.BEFORE_RENDER_BODY_SIGNATURE,
+ BeforeRenderBody.class,
+ false);
+
// These phases operate in reverse order.
-
+
add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class, true);
add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class, true);
@@ -530,7 +536,8 @@
String name = IOCUtilities.toSimpleId(annotationClass.getName());
- configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass, reverse));
+ configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass,
+ reverse));
}
@Lifecycle("perthread")
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java Thu Oct 26 09:30:09 2006
@@ -480,7 +480,7 @@
protected final void train_getComponentClassName(ComponentModel model, String className)
{
model.getComponentClassName();
- setReturnValue(className);
+ setReturnValue(className).anyTimes();
}
protected final void train_isRequired(ParameterModel model, boolean isRequired)
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Thu Oct 26 09:30:09 2006
@@ -47,10 +47,12 @@
or define the component inside class %s using the @Component annotation on a private instance variable.
embedded-components-not-in-template=Embedded component(s) %s are defined within component class %s, but are not present in the component template.
binding-source-failure=Could not convert '%s' into a component parameter binding: %s
-unable-to-resolve-component-type=Unable to resolve component '%s' to a component class name.
page-does-not-exist=Page '%s' is not defined by this application.
page-name-unresolved=Unable to resolve class name %s to a logical page name.
context-index-out-of-range=Method %s has more parameters than there are context values for this component event.
exception-in-method-parameter=Exception in method %s, parameter #%d: %s
component-event-is-aborted=Can not store result from invoking method %s, because an event result value has already been obtained from some other event handler method.
-unknown-persistent-field-strategy='%s' is not a defined persistent strategy. Defined stategies: %s.
\ No newline at end of file
+unknown-persistent-field-strategy='%s' is not a defined persistent strategy. Defined stategies: %s.
+could-not-resolve-page-name=Unable to resolve page '%s' to a component class name.
+could-not-resolve-component-type=Unable to resolve component type '%s' to a component class name.
+could-not-resolve-mixin-type=Unable to resolve mixin type '%s' to a component class name.
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties Thu Oct 26 09:30:09 2006
@@ -16,4 +16,5 @@
no-such-component=Component %s does not contain an embedded component with id '%s'.
get-parameter-failure=Failure reading parameter %s of component %s: %s
write-parameter-failure=Failure writing parameter %s of component %s: %s
-missing-mixin-for-parameter=Component %s does not contain a mixin named '%s' (setting parameter '%s').
\ No newline at end of file
+missing-mixin-for-parameter=Component %s does not contain a mixin named '%s' (setting parameter '%s').
+unknown-mixin=Component %s does not contain a mixin of type %s.
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/mixins.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/mixins.apt?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/mixins.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/mixins.apt Thu Oct 26 09:30:09 2006
@@ -68,6 +68,40 @@
This example defines a component of type TextField and mixes in the <hypothetical> Autocomplete
and DefaultFromCookie mixins.
+
+Implementation Mixins
+
+ Implementation mixins, mixins which apply to all isntances of a component, are added using the
+ {{{../apidocs/org/apache/tapestry/annotations/Mixin.html}Mixin annotation}}. This annotation
+ defines a field that will containg the mixin instance.
+
++---+
+@ComponentClass
+public class AutocompleteField extendes TextField
+{
+ @Mixin
+ private Autocomplete _autocompleteMixin;
+
+ . . .
+}
++---+
+
+ Often, the type of the field is the exact mixin class to be instantiated.
+
+ In other cases, such as when the field's type is an interface or a base class, the value
+ attribute of the annotation will be used to determine the mixin class name:
+
++---+
+@ComponentClass
+public class AutocompleteField extendes TextField
+{
+ @Mixin("Autocomplete")
+ private Object _autocompleteMixin;
+
+ . . .
+}
++---+
+
Mixin Parameters
Mixins are allowed to have parameters, just like components.
@@ -89,9 +123,6 @@
private TextField _userId;
+-----+
-Implementation Mixins
-
- Not yet implemented.
Render Phase Ordering
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java Thu Oct 26 09:30:09 2006
@@ -348,7 +348,17 @@
new LibraryMapping(LIB_PREFIX, LIB_ROOT_PACKAGE),
new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
- assertNull(resolver.resolvePageNameToClassName("lib/deep/DeepPage"));
+ try
+ {
+ resolver.resolvePageNameToClassName("lib/deep/DeepPage");
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Unable to resolve page 'lib/deep/DeepPage' to a component class name.");
+ }
verify();
}
@@ -371,7 +381,17 @@
ComponentClassResolver resolver = create(source, new LibraryMapping(LIB_PREFIX,
LIB_ROOT_PACKAGE), new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
- assertNull(resolver.resolvePageNameToClassName("lib/MissingPage"));
+ try
+ {
+ resolver.resolvePageNameToClassName("lib/MissingPage");
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Unable to resolve page 'lib/MissingPage' to a component class name.");
+ }
verify();
}
@@ -427,9 +447,69 @@
ComponentClassResolver resolver = create(source);
+ resolver.setApplicationPackage(APP_ROOT_PACKAGE);
+
assertEquals(resolver.resolveMixinTypeToClassName("SimpleMixin"), expectedClassName);
verify();
+ }
+
+ @Test
+ public void mixin_type_not_found()
+ {
+ ComponentInstantiatorSource source = newComponentInstantiatorSource();
+
+ train_for_packages(source, CORE_ROOT_PACKAGE);
+ train_for_app_packages(source);
+
+ replay();
+
+ ComponentClassResolver resolver = create(source, new LibraryMapping(CORE_PREFIX,
+ CORE_ROOT_PACKAGE));
+
+ try
+ {
+ resolver.resolveMixinTypeToClassName("SimpleMixin");
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Unable to resolve mixin type 'SimpleMixin' to a component class name.");
+ }
+
+ verify();
+
+ }
+
+ @Test
+ public void component_type_not_found()
+ {
+ ComponentInstantiatorSource source = newComponentInstantiatorSource();
+
+ train_for_packages(source, CORE_ROOT_PACKAGE);
+ train_for_app_packages(source);
+
+ replay();
+
+ ComponentClassResolver resolver = create(source, new LibraryMapping(CORE_PREFIX,
+ CORE_ROOT_PACKAGE));
+
+ try
+ {
+ resolver.resolveComponentTypeToClassName("SimpleComponent");
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Unable to resolve component type 'SimpleComponent' to a component class name.");
+ }
+
+ verify();
+
}
@Test
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java?view=auto&rev=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java Thu Oct 26 09:30:09 2006
@@ -0,0 +1,108 @@
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.annotations.Mixin;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassResolver;
+import org.apache.tapestry.services.TransformConstants;
+import org.testng.annotations.Test;
+
+public class MixinWorkerTest extends InternalBaseTestCase
+{
+ @Test
+ public void no_fields_with_mixin_annotation()
+ {
+ ComponentClassResolver resolver = newComponentClassResolver();
+ ClassTransformation transformation = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+
+ train_findFieldsWithAnnotation(transformation, Mixin.class);
+
+ replay();
+
+ new MixinWorker(resolver).transform(transformation, model);
+
+ verify();
+ }
+
+ @Test
+ public void field_with_explicit_type()
+ {
+ ComponentClassResolver resolver = newComponentClassResolver();
+ ClassTransformation transformation = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ Mixin annotation = newMixin("Bar");
+
+ train_findFieldsWithAnnotation(transformation, Mixin.class, "fred");
+ train_getFieldAnnotation(transformation, "fred", Mixin.class, annotation);
+ train_getFieldType(transformation, "fred", "foo.bar.Baz");
+
+ train_resolveMixinTypeToClassName(resolver, "Bar", "foo.bar.BazMixin");
+
+ model.addMixinClassName("foo.bar.BazMixin");
+
+ transformation.makeReadOnly("fred");
+
+ train_getResourcesFieldName(transformation, "rez");
+
+ train_extendMethod(
+ transformation,
+ TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+ "fred = (foo.bar.Baz) rez.getMixinByClassName(\"foo.bar.BazMixin\");");
+
+ replay();
+
+ new MixinWorker(resolver).transform(transformation, model);
+
+ verify();
+ }
+
+ @Test
+ public void field_with_no_specific_mixin_type()
+ {
+ ComponentClassResolver resolver = newComponentClassResolver();
+ ClassTransformation transformation = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ Mixin annotation = newMixin("");
+
+ train_findFieldsWithAnnotation(transformation, Mixin.class, "fred");
+ train_getFieldAnnotation(transformation, "fred", Mixin.class, annotation);
+ train_getFieldType(transformation, "fred", "foo.bar.Baz");
+
+ model.addMixinClassName("foo.bar.Baz");
+
+ transformation.makeReadOnly("fred");
+
+ train_getResourcesFieldName(transformation, "rez");
+
+ train_extendMethod(
+ transformation,
+ TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+ "fred = (foo.bar.Baz) rez.getMixinByClassName(\"foo.bar.Baz\");");
+
+ replay();
+
+ new MixinWorker(resolver).transform(transformation, model);
+
+ verify();
+
+ }
+
+ protected final void train_resolveMixinTypeToClassName(ComponentClassResolver resolver,
+ String mixinType, String mixinClassName)
+ {
+ resolver.resolveMixinTypeToClassName(mixinType);
+ setReturnValue(mixinClassName);
+ }
+
+ private Mixin newMixin(String value)
+ {
+ Mixin annotation = newMock(Mixin.class);
+
+ annotation.value();
+ setReturnValue(value);
+
+ return annotation;
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PageLoaderImplTest.java Thu Oct 26 09:30:09 2006
@@ -31,9 +31,6 @@
import org.apache.tapestry.services.BindingSource;
import org.testng.annotations.Test;
-/**
- *
- */
public class PageLoaderImplTest extends InternalBaseTestCase
{
private static final String PAGE_CLASS_NAME = "foo.page.Bar";
@@ -94,6 +91,7 @@
ComponentPageElement rootElement = newComponentPageElement();
InternalComponentResources resources = newInternalComponentResources();
ComponentModel model = newComponentModel();
+ ComponentModel childModel = newComponentModel();
ComponentTemplate template = newComponentTemplate();
Log log = newLog();
EmbeddedComponentModel emodel = newEmbeddedComponentModel();
@@ -148,8 +146,8 @@
// Alas, what comes next is the recursive call to load the child element
train_getComponentResources(childElement, childResources);
- train_getComponentModel(childResources, model);
- train_getComponentClassName(model, CHILD_CLASS_NAME);
+ train_getComponentModel(childResources, childModel);
+ train_getComponentClassName(childModel, CHILD_CLASS_NAME);
train_getTemplate(templateSource, CHILD_CLASS_NAME, LOCALE, null);
train_newRenderBodyElement(elementFactory, childElement, body);
childElement.addToTemplate(body);
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java?view=diff&rev=468058&r1=468057&r2=468058
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java Thu Oct 26 09:30:09 2006
@@ -330,6 +330,74 @@
}
@Test
+ public void get_mixin_by_class_name()
+ {
+ Log log = newLog();
+ Page page = newPage();
+ ComponentLifecycle component = newComponentLifecycle();
+ ComponentModel model = newComponentModel();
+ TypeCoercer coercer = newTypeCoercer();
+ final String mixinClassName = "foo.Bar";
+ ComponentLifecycle mixin = newComponentLifecycle();
+ ComponentModel mixinModel = newComponentModel();
+
+ Instantiator ins = newInstantiator(component, model);
+ Instantiator mixinIns = newInstantiator(mixin, mixinModel);
+
+ train_getComponentClassName(mixinModel, mixinClassName);
+
+ train_getLog(model, log);
+
+ replay();
+
+ ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, coercer);
+
+ cpe.addMixin(mixinIns);
+
+ assertSame(cpe.getMixinByClassName(mixinClassName), mixin);
+
+ verify();
+ }
+
+ @Test
+ public void get_mixin_by_unknown_class_name()
+ {
+ Log log = newLog();
+ Page page = newPage();
+ ComponentLifecycle component = newComponentLifecycle();
+ ComponentModel model = newComponentModel();
+ TypeCoercer coercer = newTypeCoercer();
+ ComponentLifecycle mixin = newComponentLifecycle();
+ ComponentModel mixinModel = newComponentModel();
+
+ Instantiator ins = newInstantiator(component, model);
+ Instantiator mixinIns = newInstantiator(mixin, mixinModel);
+
+ train_getComponentClassName(mixinModel, "foo.Bar");
+
+ train_getLog(model, log);
+
+ replay();
+
+ ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, coercer);
+
+ cpe.addMixin(mixinIns);
+
+ try
+ {
+ cpe.getMixinByClassName("foo.Baz");
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertTrue(ex.getMessage().endsWith(" does not contain a mixin of type foo.Baz."));
+ }
+
+ verify();
+
+ }
+
+ @Test
public void set_explicit_parameter_of_unknown_mixin()
{
Log log = newLog();
@@ -346,11 +414,13 @@
train_getLog(model, log);
+ train_getComponentClassName(mixinModel, "foo.Fred");
+
replay();
ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, coercer);
- cpe.addMixin("Fred", mixinInstantiator);
+ cpe.addMixin(mixinInstantiator);
try
{