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/13 18:44:23 UTC
svn commit: r463734 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/annotations/
main/java/org/apache/tapestry/internal/services/
main/java/org/apache/tapestry/internal/structure/
main/java/org/apache/tapestry/runtime/ m...
Author: hlship
Date: Fri Oct 13 09:44:20 2006
New Revision: 463734
URL: http://svn.apache.org/viewvc?view=rev&rev=463734
Log:
Continue adding support for component events.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java
- copied, changed from r462686, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HTMLDispatcher.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/EventHandlerTarget.java
Removed:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HTMLDispatcher.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/OnEvent.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.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/Page.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.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/services/TransformConstants.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.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/test/java/org/apache/tapestry/integration/app1/pages/ActionPage.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/services/ComponentEventImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/ActionPage.html
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/OnEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/OnEvent.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/OnEvent.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/OnEvent.java Fri Oct 13 09:44:20 2006
@@ -46,7 +46,7 @@
* @return
* @see TapestryConstants
*/
- String[] value() default "";
+ String[] value() default {};
/**
* A list of component ids. The handler will only be invoked if the id of the event originating
@@ -54,6 +54,6 @@
*
* @return
*/
- String[] component() default "";
+ String[] component() default {};
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java?view=auto&rev=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventDispatcher.java Fri Oct 13 09:44:20 2006
@@ -0,0 +1,81 @@
+package org.apache.tapestry.internal.services;
+
+import java.io.IOException;
+
+import org.apache.tapestry.ComponentEventHandler;
+import org.apache.tapestry.internal.structure.ComponentPageElement;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.services.Dispatcher;
+import org.apache.tapestry.services.WebRequest;
+import org.apache.tapestry.services.WebResponse;
+
+/**
+ * Processes component action events sent as requests from the client. Action events include an
+ * event type, identify a page and a component, and may provide additional context strings.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class ComponentEventDispatcher implements Dispatcher
+{
+ private final PageResponseRenderer _renderer;
+
+ private final RequestPageCache _cache;
+
+ public ComponentEventDispatcher(final PageResponseRenderer renderer, final RequestPageCache cache)
+ {
+ _renderer = renderer;
+ _cache = cache;
+ }
+
+ public boolean dispatch(WebRequest request, WebResponse response) throws IOException
+ {
+ String path = request.getPath();
+
+ int dotx = path.indexOf('.');
+
+ if (dotx < 0)
+ return false;
+
+ // Skip the leading slash, the rest is logical page name.
+
+ String logicalPageName = path.substring(1, dotx);
+
+ Page page = _cache.get(logicalPageName);
+
+ int slashx = path.indexOf('/', dotx + 1);
+
+ String eventType = path.substring(dotx + 1, slashx);
+
+ String remainder = path.substring(slashx + 1);
+
+ String[] chunks = remainder.split("/");
+
+ String nestedComponentId = chunks[0];
+
+ String[] context = new String[chunks.length - 1];
+ for (int i = 1; i < chunks.length; i++)
+ context[i - 1] = chunks[i];
+
+ ComponentPageElement element = page.getComponentByNestedId(nestedComponentId);
+
+ ComponentEventHandler handler = new ComponentEventHandler()
+ {
+ public void handleResult(Object result, String methodDescription)
+ {
+ // Does nothing, right now. Accepts any return value.
+ }
+ };
+
+ element.triggerEvent(eventType, context, handler);
+
+ // TODO: maybe the return value from triggerEvent should be true if any handler was found,
+ // false if no handler was found. The latter feels like an error condition.
+
+ // Once the pieces fall into place, we won't just blindly re-render the page.
+
+ _renderer.renderPageResponse(page, response);
+
+ return true;
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentEventImpl.java Fri Oct 13 09:44:20 2006
@@ -68,8 +68,14 @@
public boolean storeResult(Object result, String methodDescription)
{
+ // Given that this method is *only* invoked from code
+ // that is generated at runtime and proven to be correct,
+ // this should never, ever happen. But what the hell,
+ // let's check anyway.
+
if (_aborted)
- throw new IllegalStateException();
+ throw new IllegalStateException(ServicesMessages
+ .componentEventIsAborted(methodDescription));
if (result == null)
return false;
@@ -81,7 +87,8 @@
return true;
}
- public <T> T coerceContext(int index, Class<T> desiredType, String methodDescription)
+ @SuppressWarnings("unchecked")
+ public Object coerceContext(int index, String desiredTypeName, String methodDescription)
{
if (index >= _context.length)
throw new IllegalArgumentException(ServicesMessages
@@ -89,6 +96,8 @@
try
{
+ Class desiredType = Class.forName(desiredTypeName);
+
return _typeCoercer.coerce(_context[index], desiredType);
}
catch (Exception ex)
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java Fri Oct 13 09:44:20 2006
@@ -269,6 +269,23 @@
return findAnnotationInList(annotationClass, annotations);
}
+ public <T extends Annotation> T getMethodAnnotation(MethodSignature signature,
+ Class<T> annotationClass)
+ {
+ failIfFrozen();
+
+ CtMethod method = findMethod(signature);
+
+ if (method == null)
+ throw new IllegalArgumentException(ServicesMessages.noDeclaredMethod(
+ _ctClass,
+ signature));
+
+ List<Annotation> annotations = findMethodAnnotations(method);
+
+ return findAnnotationInList(annotationClass, annotations);
+ }
+
/**
* Searches an array of objects (that are really annotations instances) to find one that is of
* the correct type, which is returned.
@@ -581,7 +598,10 @@
}
catch (CannotCompileException ex)
{
- throw new RuntimeException(ex);
+ throw new MethodCompileException(ServicesMessages.methodCompileError(
+ methodSignature,
+ methodBody,
+ ex), methodBody, ex);
}
addMethodToDescription("extend", methodSignature, methodBody);
@@ -622,11 +642,10 @@
private CtMethod findMethod(MethodSignature methodSignature)
{
- for (CtMethod method : _ctClass.getDeclaredMethods())
- {
- if (match(method, methodSignature))
- return method;
- }
+ CtMethod method = findDeclaredMethod(methodSignature);
+
+ if (method != null)
+ return method;
CtMethod result = addOverrideOfSuperclassMethod(methodSignature);
@@ -634,8 +653,19 @@
return result;
throw new IllegalArgumentException(ServicesMessages.noDeclaredMethod(
- methodSignature,
- _ctClass));
+ _ctClass,
+ methodSignature));
+ }
+
+ private CtMethod findDeclaredMethod(MethodSignature methodSignature)
+ {
+ for (CtMethod method : _ctClass.getDeclaredMethods())
+ {
+ if (match(method, methodSignature))
+ return method;
+ }
+
+ return null;
}
private CtMethod addOverrideOfSuperclassMethod(MethodSignature methodSignature)
@@ -932,7 +962,10 @@
throw new RuntimeException(ex);
}
- String fieldName = addField(Modifier.PROTECTED, type.getName(), suggestedName);
+ String fieldName = addField(
+ Modifier.PROTECTED | Modifier.FINAL,
+ type.getName(),
+ suggestedName);
addInjectToConstructor(fieldName, ctType, value);
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java?view=auto&rev=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/OnEventWorker.java Fri Oct 13 09:44:20 2006
@@ -0,0 +1,138 @@
+package org.apache.tapestry.internal.services;
+
+import java.util.List;
+
+import org.apache.tapestry.annotations.OnEvent;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.MethodSignature;
+import org.apache.tapestry.services.TransformConstants;
+import org.apache.tapestry.services.TransformUtils;
+import org.apache.tapestry.util.BodyBuilder;
+
+/**
+ * Provides implementations of the
+ * {@link ComponentLifecycle#handleComponentEvent(org.apache.tapestry.runtime.ComponentEvent)}
+ * method, based on {@link OnEvent} annotations.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class OnEventWorker implements ComponentClassTransformWorker
+{
+ public void transform(ClassTransformation transformation, MutableComponentModel model)
+ {
+ List<MethodSignature> methods = transformation.findMethodsWithAnnotation(OnEvent.class);
+
+ // No methods, no work.
+
+ if (methods.isEmpty())
+ return;
+
+ BodyBuilder builder = new BodyBuilder();
+ builder.begin();
+
+ builder.addln("if ($1.isAborted()) return;");
+ builder.addln("String methodName = null;");
+
+ for (MethodSignature method : methods)
+ addCodeForMethod(builder, method, transformation);
+
+ builder.end();
+
+ transformation.extendMethod(TransformConstants.HANDLE_COMPONENT_EVENT, builder.toString());
+ }
+
+ private void addCodeForMethod(BodyBuilder builder, MethodSignature method,
+ ClassTransformation transformation)
+ {
+ // $1 is the event
+
+ int closeCount = 0;
+
+ OnEvent annotation = transformation.getMethodAnnotation(method, OnEvent.class);
+
+ String[] eventTypes = annotation.value();
+
+ if (eventTypes.length > 0)
+ {
+ String fieldName = transformation.addInjectedField(
+ String[].class,
+ "eventTypes",
+ eventTypes);
+
+ builder.addln("if ($1.matchesByEventType(%s))", fieldName);
+ builder.begin();
+
+ closeCount++;
+ }
+
+ String[] componentIds = annotation.component();
+
+ if (componentIds.length > 0)
+ {
+ String fieldName = transformation.addInjectedField(
+ String[].class,
+ "componentIds",
+ componentIds);
+
+ builder.addln("if ($1.matchesByComponentId(%s, %s))", transformation
+ .getResourcesFieldName(), fieldName);
+ builder.begin();
+
+ closeCount++;
+ }
+
+ // Several subsequent calls need to know the method name.
+
+ builder.addln("methodName = \"%s.%s\";", transformation.getClassName(), method
+ .getMediumDescription());
+
+ boolean isNonVoid = !method.getReturnType().equals("void");
+
+ if (isNonVoid)
+ builder.add("if ($1.storeResult(");
+
+ builder.add("%s(", method.getMethodName());
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ builder.add(", ");
+
+ addCoercedContextAsParameter(builder, i, method.getParameterTypes()[i]);
+ }
+
+ if (isNonVoid)
+ builder.addln("), methodName) return;");
+ else
+ builder.addln(");");
+
+ for (int i = 0; i < closeCount; i++)
+ builder.end();
+ }
+
+ private void addCoercedContextAsParameter(BodyBuilder builder, int index, String type)
+ {
+ boolean isPrimitive = TransformUtils.isPrimitive(type);
+ String wrapperType = TransformUtils.getWrapperTypeName(type);
+
+ // Add a cast to the wrapper type up front
+
+ if (isPrimitive)
+ builder.add("((%s)", wrapperType);
+
+ // The strings for desired type name will likely repeat a bit; it may be
+ // worth it to inject them as final fields. Could increase the number
+ // of constructor parameters pretty dramatically, however, and will reduce
+ // the readability of the output method bodies.
+
+ builder.add("$1.coerceContext(%d, \"%s\", methodName)", index, wrapperType);
+
+ // and invoke a method on the cast value to get back to primitive
+ if (isPrimitive)
+ builder.add(").%s()", TransformUtils.getUnwrapperMethodName(type));
+ }
+
+}
Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java (from r462686, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HTMLDispatcher.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java?view=diff&rev=463734&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HTMLDispatcher.java&r1=462686&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HTMLDispatcher.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageRenderDispatcher.java Fri Oct 13 09:44:20 2006
@@ -27,13 +27,13 @@
*
* @author Howard M. Lewis Ship
*/
-public class HTMLDispatcher implements Dispatcher
+public class PageRenderDispatcher implements Dispatcher
{
private final PageResponseRenderer _renderer;
private final RequestPageCache _cache;
- public HTMLDispatcher(PageResponseRenderer renderer, RequestPageCache cache)
+ public PageRenderDispatcher(PageResponseRenderer renderer, RequestPageCache cache)
{
_renderer = renderer;
_cache = cache;
@@ -54,9 +54,9 @@
// The first character will be the leading slash
- String minimalPageName = path.substring(1, pos);
+ String logicalPageName = path.substring(1, pos);
- Page page = _cache.get(minimalPageName);
+ Page page = _cache.get(logicalPageName);
_renderer.renderPageResponse(page, response);
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=463734&r1=463733&r2=463734
==============================================================================
--- 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 Fri Oct 13 09:44:20 2006
@@ -84,9 +84,9 @@
{ fieldName, ctClass.getName(), existingTag, newTag });
}
- static String noDeclaredMethod(MethodSignature methodSignature, CtClass ctClass)
+ static String noDeclaredMethod(CtClass ctClass, MethodSignature methodSignature)
{
- return MESSAGES.format("no-declared-method", methodSignature, ctClass.getName());
+ return MESSAGES.format("no-declared-method", ctClass.getName(), methodSignature);
}
static String incorrectClassForInstantiator(String className, Class componentClass)
@@ -211,5 +211,10 @@
{
return MESSAGES
.format("exception-in-method-parameter", methodDescription, index + 1, cause);
+ }
+
+ static String componentEventIsAborted(String methodDescription)
+ {
+ return MESSAGES.format("component-event-is-aborted", methodDescription);
}
}
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=463734&r1=463733&r2=463734
==============================================================================
--- 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 Fri Oct 13 09:44:20 2006
@@ -15,6 +15,7 @@
package org.apache.tapestry.internal.structure;
import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentEventHandler;
import org.apache.tapestry.internal.InternalComponentResources;
import org.apache.tapestry.runtime.RenderCommand;
import org.apache.tapestry.runtime.RenderQueue;
@@ -64,6 +65,32 @@
*/
void addEmbeddedElement(ComponentPageElement child);
+ /**
+ * Retrieves a component page element by its id.
+ *
+ * @param id
+ * used to locate the element
+ * @return the page element
+ * @throws IllegalArgumentException
+ * if no component exists with the given id
+ */
+ ComponentPageElement getEmbeddedElement(String id);
+
/** Invoked when the component should render its body. */
void enqueueBeforeRenderBody(RenderQueue queue);
+
+ /**
+ * Triggers a component event. A search for a event handling method will occur, first in the
+ * component, then its container, and so on.
+ *
+ * @param eventType
+ * event type (as determined from the request)
+ * @param context
+ * the request context (as extracted from the request)
+ * @param handler
+ * the handler to be informed of the result
+ * @return true if the event was handled ("aborted", meaning a non-null result was obtained from
+ * an event handler method)
+ */
+ boolean triggerEvent(String eventType, String[] context, ComponentEventHandler handler);
}
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=463734&r1=463733&r2=463734
==============================================================================
--- 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 Fri Oct 13 09:44:20 2006
@@ -22,15 +22,18 @@
import org.apache.tapestry.BaseLocatable;
import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentEventHandler;
import org.apache.tapestry.Link;
import org.apache.tapestry.Location;
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.internal.TapestryException;
import org.apache.tapestry.internal.annotations.SuppressNullCheck;
import org.apache.tapestry.internal.ioc.IOCUtilities;
+import org.apache.tapestry.internal.services.ComponentEventImpl;
import org.apache.tapestry.internal.services.Instantiator;
import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.model.ParameterModel;
+import org.apache.tapestry.runtime.ComponentEvent;
import org.apache.tapestry.runtime.ComponentLifecycle;
import org.apache.tapestry.runtime.LifecycleEvent;
import org.apache.tapestry.runtime.PageLifecycleListener;
@@ -218,12 +221,7 @@
public ComponentLifecycle getEmbeddedComponent(String embeddedId)
{
- ComponentPageElement embeddedElement = IOCUtilities.get(_children, embeddedId);
-
- if (embeddedElement == null)
- throw new IllegalArgumentException(StructureMessages.noSuchComponent(this, embeddedId));
-
- return embeddedElement.getComponent();
+ return getEmbeddedElement(embeddedId).getComponent();
}
public String getId()
@@ -549,6 +547,38 @@
public Link createActionLink(String action, boolean forForm, Object... context)
{
return _page.createActionLink(this, action, forForm, context);
+ }
+
+ public boolean triggerEvent(String eventType, String[] context, ComponentEventHandler handler)
+ {
+ ComponentEvent event = new ComponentEventImpl(eventType, _id, context, handler,
+ _typeCoercer);
+
+ ComponentPageElement component = this;
+
+ while (component != null)
+ {
+ component.getComponent().handleComponentEvent(event);
+
+ if (event.isAborted())
+ return true;
+
+ component = component.getContainer();
+ }
+
+ // Made it to the top and never found a handler to provide a result value.
+
+ return false;
+ }
+
+ public ComponentPageElement getEmbeddedElement(String embeddedId)
+ {
+ ComponentPageElement embeddedElement = IOCUtilities.get(_children, embeddedId);
+
+ if (embeddedElement == null)
+ throw new IllegalArgumentException(StructureMessages.noSuchComponent(this, embeddedId));
+
+ return embeddedElement;
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java Fri Oct 13 09:44:20 2006
@@ -52,7 +52,10 @@
*/
void setRootElement(ComponentPageElement component);
- /** The root component of the page. This is the wrapper around the end developer's view of the page. */
+ /**
+ * The root component of the page. This is the wrapper around the end developer's view of the
+ * page.
+ */
ComponentPageElement getRootElement();
/**
@@ -86,6 +89,14 @@
/** Returns the log of the root element. */
Log getLog();
+
+ /**
+ * Retrieves a component by its nested id (a sequence of simple ids, separated by dots).
+ *
+ * @throws IllegalArgumentException
+ * if the nestedId does not correspond to a component
+ */
+ ComponentPageElement getComponentByNestedId(String nestedId);
/**
* Creates a link that will trigger behavior in a component within the page.
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java Fri Oct 13 09:44:20 2006
@@ -52,6 +52,16 @@
return String.format("Page[%s %s]", _name, _locale);
}
+ public ComponentPageElement getComponentByNestedId(String nestedId)
+ {
+ ComponentPageElement element = _rootElement;
+
+ for (String id : nestedId.split("\\."))
+ element = element.getEmbeddedElement(id);
+
+ return element;
+ }
+
public String getName()
{
return _name;
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentEvent.java Fri Oct 13 09:44:20 2006
@@ -50,11 +50,11 @@
* @param <T>
* @param index
* the index of the context value
- * @param desiredType
+ * @param desiredTypeName
* the desired type
* @param methodDescription
* the method for which the conversion will take place (used if reporting an error)
* @return the coerced value (a wrapper type if the desired type is a primitive)
*/
- <T> T coerceContext(int index, Class<T> desiredType, String methodDescription);
-}
+ Object coerceContext(int index, String desiredTypeName, String methodDescription);
+}
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java Fri Oct 13 09:44:20 2006
@@ -15,6 +15,7 @@
package org.apache.tapestry.runtime;
import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.annotations.OnEvent;
/**
* Interface that defining the lifecycle of a component, within a page, allowing for callbacks into
@@ -80,4 +81,12 @@
* complete.
*/
void cleanupRender(MarkupWriter writer, LifecycleEvent<Boolean> event);
+
+ /**
+ * Invoked to handle a component event. Methods with the {@link OnEvent} annotation will be
+ * invoked until one returns a non-null value.
+ *
+ * @param event
+ */
+ void handleComponentEvent(ComponentEvent event);
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java Fri Oct 13 09:44:20 2006
@@ -103,6 +103,21 @@
<T extends Annotation> T getFieldAnnotation(String fieldName, Class<T> annotationClass);
/**
+ * Finds an annotation on a declared method.
+ *
+ * @param <T>
+ * constrains parameter and return value to Annotation types
+ * @param method
+ * the method signature to search
+ * @param annotationClass
+ * the type of annotation to access
+ * @return the annotation if present, or null otherwise
+ * @throws IllegalArgumentException
+ * if the method signature does not correspond to a declared method
+ */
+ <T extends Annotation> T getMethodAnnotation(MethodSignature method, Class<T> annotationClass);
+
+ /**
* Claims a field so as to ensure that only a single annotation is applied to any single field.
* When a transformation occurs (driven by a field annotation), the first thing that occurs is
* to claim the field, on behalf of the annotation.
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=463734&r1=463733&r2=463734
==============================================================================
--- 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 Fri Oct 13 09:44:20 2006
@@ -19,6 +19,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -40,6 +41,7 @@
import org.apache.tapestry.internal.services.BindingSourceImpl;
import org.apache.tapestry.internal.services.ComponentClassFactoryImpl;
import org.apache.tapestry.internal.services.ComponentClassResolverImpl;
+import org.apache.tapestry.internal.services.ComponentEventDispatcher;
import org.apache.tapestry.internal.services.ComponentInstantiatorSource;
import org.apache.tapestry.internal.services.ComponentLifecycleMethodWorker;
import org.apache.tapestry.internal.services.ComponentResourcesInjectionProvider;
@@ -47,13 +49,14 @@
import org.apache.tapestry.internal.services.DefaultInjectionProvider;
import org.apache.tapestry.internal.services.EnvironmentImpl;
import org.apache.tapestry.internal.services.EnvironmentalWorker;
-import org.apache.tapestry.internal.services.HTMLDispatcher;
+import org.apache.tapestry.internal.services.PageRenderDispatcher;
import org.apache.tapestry.internal.services.InfrastructureImpl;
import org.apache.tapestry.internal.services.InfrastructureManagerImpl;
import org.apache.tapestry.internal.services.InjectWorker;
import org.apache.tapestry.internal.services.InjectionProvider;
import org.apache.tapestry.internal.services.InternalModule;
import org.apache.tapestry.internal.services.MarkupWriterImpl;
+import org.apache.tapestry.internal.services.OnEventWorker;
import org.apache.tapestry.internal.services.PageResponseRenderer;
import org.apache.tapestry.internal.services.ParameterWorker;
import org.apache.tapestry.internal.services.RequestGlobalsImpl;
@@ -102,6 +105,10 @@
private final PropertyShadowBuilder _shadowBuilder;
+ private final RequestPageCache _requestPageCache;
+
+ private final PageResponseRenderer _pageResponseRenderer;
+
// Yes, you can inject services defined by this module into this module. The service proxy is
// created without instantiating the module itself.
@@ -110,13 +117,17 @@
PropertyShadowBuilder shadowBuilder, @InjectService("RequestGlobals")
RequestGlobals requestGlobals, @InjectService("ApplicationGlobals")
ApplicationGlobals applicationGlobals, @InjectService("tapestry.ioc.ChainBuilder")
- ChainBuilder chainBuilder)
+ ChainBuilder chainBuilder, @InjectService("tapestry.internal.RequestPageCache")
+ RequestPageCache requestPageCache, @InjectService("tapestry.internal.PageResponseRenderer")
+ PageResponseRenderer pageResponseRenderer)
{
_pipelineBuilder = pipelineBuilder;
_shadowBuilder = shadowBuilder;
_requestGlobals = requestGlobals;
_applicationGlobals = applicationGlobals;
_chainBuilder = chainBuilder;
+ _requestPageCache = requestPageCache;
+ _pageResponseRenderer = pageResponseRenderer;
}
private <T> void add(Configuration<InfrastructureContribution> configuration,
@@ -203,14 +214,6 @@
return _chainBuilder.build(ComponentClassTransformWorker.class, configuration);
}
- /** Dispatcher that recognizes full-page HTML documents by the .html extension. */
- public Dispatcher buildHTMLDispatcher(@InjectService("tapestry.internal.PageResponseRenderer")
- PageResponseRenderer renderer, @InjectService("tapestry.internal.RequestPageCache")
- RequestPageCache cache)
- {
- return new HTMLDispatcher(renderer, cache);
- }
-
public HttpServletRequestHandler buildHttpServletRequestHandler(Log log,
List<HttpServletRequestFilter> configuration, @InjectService("WebRequestHandler")
final WebRequestHandler handler)
@@ -397,11 +400,16 @@
configuration.add("infrastructure", infrastructure.getObjectProvider());
}
- public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
- @InjectService("HTMLDispatcher")
- Dispatcher HTMLDispatcher)
+ public void contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration)
{
- configuration.add("HTML", HTMLDispatcher);
+ configuration.add(
+ "HTML",
+ new PageRenderDispatcher(_pageResponseRenderer, _requestPageCache));
+
+ // This goes after the HTML one so that the "." in ".html" doesn't confuse it.
+
+ configuration.add("ComponentEvent", new ComponentEventDispatcher(_pageResponseRenderer,
+ _requestPageCache), "after:HTML");
}
public ComponentClassResolver buildComponentClassResolver(
@@ -502,6 +510,8 @@
configuration.add("Component", new ComponentWorker());
configuration.add("Environment", new EnvironmentalWorker(environment));
+ configuration.add("OnEvent", new OnEventWorker());
+
// Workers for the component rendering state machine methods; this is in typical
// execution order.
@@ -561,6 +571,7 @@
* <li>Long to Boolean (true if long value is non zero)</li>
* <li>Null to Boolean (always false)</li>
* <li>Collection to Boolean (false if empty)</li>
+ * <li>Object to List (by wrapping as a singleton list)</li>
* </ul>
*
* @see #buildTypeCoercer(Collection, ComponentInstantiatorSource)
@@ -702,6 +713,14 @@
public Boolean coerce(Collection input)
{
return !input.isEmpty();
+ }
+ });
+
+ add(configuration, Object.class, List.class, new Coercion<Object, List>()
+ {
+ public List coerce(Object input)
+ {
+ return Collections.singletonList(input);
}
});
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java Fri Oct 13 09:44:20 2006
@@ -18,6 +18,7 @@
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.internal.annotations.Utility;
+import org.apache.tapestry.runtime.ComponentEvent;
import org.apache.tapestry.runtime.LifecycleEvent;
/**
@@ -33,6 +34,16 @@
// component render states.
private static final String[] LIFECYCLE_METHOD_PARAMETER_TYPES =
{ MarkupWriter.class.getName(), LifecycleEvent.class.getName() };
+
+ /**
+ * Signature for
+ * {@link org.apache.tapestry.runtime.ComponentLifecycle#handleComponentEvent(ComponentEvent event)
+ *
+ * @see org.apache.tapestry.annotations.OnEvent
+ */
+ public static final MethodSignature HANDLE_COMPONENT_EVENT = new MethodSignature(
+ Modifier.PUBLIC, "void", "handleComponentEvent", new String[]
+ { ComponentEvent.class.getName() }, null);
/**
* Signature for
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java Fri Oct 13 09:44:20 2006
@@ -18,6 +18,7 @@
import java.util.Map;
+import org.apache.tapestry.internal.annotations.SuppressNullCheck;
import org.apache.tapestry.internal.annotations.Utility;
/**
@@ -32,18 +33,27 @@
private static final Map<Class, PrimitiveTypeInfo> _classToInfo = newMap();
+ @SuppressNullCheck
static class PrimitiveTypeInfo
{
- private Class _wrapperType;
+ private final Class _wrapperType;
- private String _defaultValue;
+ private final String _unwrapperMethodName;
- public PrimitiveTypeInfo(Class wrapperType, String defaultValue)
+ private final String _defaultValue;
+
+ public PrimitiveTypeInfo(Class wrapperType, String unwrapperMethodName, String defaultValue)
{
_wrapperType = wrapperType;
+ _unwrapperMethodName = unwrapperMethodName;
_defaultValue = defaultValue;
}
+ public String getUnwrapperMethodName()
+ {
+ return _unwrapperMethodName;
+ }
+
public String getDefaultValue()
{
return _defaultValue;
@@ -57,25 +67,35 @@
static
{
- add(boolean.class, Boolean.class, "false");
- add(byte.class, Byte.class, "0");
- add(char.class, Character.class, "0");
- add(short.class, Short.class, "0");
- add(int.class, Integer.class, "0");
- add(long.class, Long.class, "0L");
- add(float.class, Float.class, "0.0f");
- add(double.class, Double.class, "0.0d");
+ add(boolean.class, Boolean.class, "booleanValue", "false");
+ add(byte.class, Byte.class, "byteValue", "0");
+ add(char.class, Character.class, "charValue", "0");
+ add(short.class, Short.class, "shortValue", "0");
+ add(int.class, Integer.class, "intValue", "0");
+ add(long.class, Long.class, "longValue", "0L");
+ add(float.class, Float.class, "floatValue", "0.0f");
+ add(double.class, Double.class, "doubleValue", "0.0d");
}
- private static void add(Class primitiveType, Class wrapperType, String defaultValue)
+ private static void add(Class primitiveType, Class wrapperType, String unwrapperMethodName,
+ String defaultValue)
{
- PrimitiveTypeInfo info = new PrimitiveTypeInfo(wrapperType, defaultValue);
+ PrimitiveTypeInfo info = new PrimitiveTypeInfo(wrapperType, unwrapperMethodName,
+ defaultValue);
_classToInfo.put(primitiveType, info);
_nameToInfo.put(primitiveType.getName(), info);
}
/**
+ * Returns true if the specified type is a primitive type.
+ */
+ public static boolean isPrimitive(String type)
+ {
+ return _nameToInfo.containsKey(type);
+ }
+
+ /**
* Returns the name of wrapper type for a given input type. For primitive types, returns the
* wrapper type. For other types, returns the input type name.
*
@@ -87,6 +107,21 @@
PrimitiveTypeInfo info = _nameToInfo.get(type);
return info == null ? type : info.getWrapperType().getName();
+ }
+
+ /**
+ * For primitive types, returns the method on the <em>wrapper type</em> that converts back to
+ * the primitive.
+ *
+ * @param type
+ * the primitive type
+ * @return the method of the corresponding wrapper type, or null if type is not a primitive type
+ */
+ public static String getUnwrapperMethodName(String type)
+ {
+ PrimitiveTypeInfo info = _nameToInfo.get(type);
+
+ return info == null ? null : info.getUnwrapperMethodName();
}
/**
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=463734&r1=463733&r2=463734
==============================================================================
--- 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 Fri Oct 13 09:44:20 2006
@@ -37,7 +37,6 @@
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.Resource;
import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.annotations.SetupRender;
import org.apache.tapestry.internal.annotations.SuppressNullCheck;
import org.apache.tapestry.internal.services.InjectionProvider;
import org.apache.tapestry.ioc.Configuration;
@@ -443,9 +442,9 @@
}
protected final void train_findMethodsWithAnnotation(ClassTransformation tf,
- List<MethodSignature> sigs)
+ Class<? extends Annotation> annotationType, List<MethodSignature> sigs)
{
- tf.findMethodsWithAnnotation(SetupRender.class);
+ tf.findMethodsWithAnnotation(annotationType);
setReturnValue(sigs);
}
@@ -499,7 +498,8 @@
setReturnValue(Arrays.asList(names));
}
- protected <S, T> void train_coerce(TypeCoercer coercer, S input, Class<T> expectedType, T coercedValue)
+ protected <S, T> void train_coerce(TypeCoercer coercer, S input, Class<T> expectedType,
+ T coercedValue)
{
coercer.coerce(input, expectedType);
setReturnValue(coercedValue);
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=463734&r1=463733&r2=463734
==============================================================================
--- 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 Fri Oct 13 09:44:20 2006
@@ -53,3 +53,4 @@
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.
\ No newline at end of file
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/ActionPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/ActionPage.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/ActionPage.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/ActionPage.java Fri Oct 13 09:44:20 2006
@@ -1,6 +1,7 @@
package org.apache.tapestry.integration.app1.pages;
import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.OnEvent;
/**
* @author Howard M. Lewis Ship
@@ -8,5 +9,16 @@
@ComponentClass
public class ActionPage
{
+ private boolean _clicked;
+ public boolean getClicked()
+ {
+ return _clicked;
+ }
+
+ @OnEvent
+ void click()
+ {
+ _clicked = true;
+ }
}
Modified: 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=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java Fri Oct 13 09:44:20 2006
@@ -16,6 +16,7 @@
import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.runtime.ComponentEvent;
import org.apache.tapestry.runtime.ComponentLifecycle;
import org.apache.tapestry.runtime.LifecycleEvent;
@@ -68,4 +69,8 @@
{
}
+ public void handleComponentEvent(ComponentEvent event)
+ {
+
+ }
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentEventImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentEventImplTest.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentEventImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentEventImplTest.java Fri Oct 13 09:44:20 2006
@@ -1,7 +1,11 @@
package org.apache.tapestry.internal.services;
+import org.apache.tapestry.ComponentEventHandler;
import org.apache.tapestry.internal.test.InternalBaseTestCase;
import org.apache.tapestry.runtime.ComponentEvent;
+import org.apache.tapestry.services.TypeCoercer;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
@@ -9,10 +13,24 @@
*/
public class ComponentEventImplTest extends InternalBaseTestCase
{
+ private TypeCoercer _coercer;
+
+ @BeforeClass
+ public void setup_coercer()
+ {
+ _coercer = getService("tapestry.TypeCoercer", TypeCoercer.class);
+ }
+
+ @AfterClass
+ public void cleanup_coercer()
+ {
+ _coercer = null;
+ }
+
@Test
public void matches_on_event_type()
{
- ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, null, null);
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, null, _coercer);
assertTrue(event.matchesByEventType(new String[]
{ "foo", "eventType", "bar" }));
@@ -23,12 +41,138 @@
@Test
public void matches_on_component_id()
{
- ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, null, null);
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, null, _coercer);
assertTrue(event.matchesByComponentId(null, new String[]
{ "foo", "someId", "bar" }));
assertFalse(event.matchesByComponentId(null, new String[]
{ "foo", "bar" }));
+ }
+
+ @Test
+ public void coerce_context()
+ {
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", new String[]
+ { "27" }, null, _coercer);
+
+ assertEquals(event.coerceContext(0, "java.lang.Integer", "method descrip"), new Integer(27));
+ }
+
+ @Test
+ public void coerce_when_not_enough_context()
+ {
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", new String[]
+ { "27" }, null, _coercer);
+
+ try
+ {
+ event.coerceContext(1, "java.lang.Integer", "foo.Bar.baz()");
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Method foo.Bar.baz() has more parameters than there are context values for this component event.");
+ }
+ }
+
+ @Test
+ public void unable_to_coerce()
+ {
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", new String[]
+ { "abc" }, null, _coercer);
+
+ try
+ {
+ event.coerceContext(0, "java.lang.Integer", "foo.Bar.baz()");
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ // Different JVMs will report the conversion error slightly differently,
+ // so we don't try to check that part of the error message.
+
+ assertTrue(ex.getMessage().startsWith(
+ "Exception in method foo.Bar.baz(), parameter #1:"));
+ }
+ }
+
+ @Test
+ public void store_result()
+ {
+ Object result = new Object();
+ String methodDescription = "foo.Bar.baz()";
+
+ ComponentEventHandler handler = newComponentEventHandler();
+
+ handler.handleResult(result, methodDescription);
+
+ replay();
+
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, handler,
+ _coercer);
+
+ assertFalse(event.isAborted());
+
+ assertTrue(event.storeResult(result, methodDescription));
+
+ assertTrue(event.isAborted());
+
+ verify();
+ }
+
+ @Test
+ public void store_null_result_does_not_abort_or_invoke_handler()
+ {
+ String methodDescription = "foo.Bar.baz()";
+
+ ComponentEventHandler handler = newComponentEventHandler();
+
+ replay();
+
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, handler,
+ _coercer);
+
+ assertFalse(event.storeResult(null, methodDescription));
+
+ assertFalse(event.isAborted());
+
+ verify();
+ }
+
+ protected final ComponentEventHandler newComponentEventHandler()
+ {
+ return newMock(ComponentEventHandler.class);
+ }
+
+ @Test
+ public void store_result_when_aborted_is_failure()
+ {
+ Object result = new Object();
+ String methodDescription = "foo.Bar.baz()";
+
+ ComponentEventHandler handler = newComponentEventHandler();
+
+ handler.handleResult(result, methodDescription);
+
+ replay();
+
+ ComponentEvent event = new ComponentEventImpl("eventType", "someId", null, handler,
+ _coercer);
+
+ event.storeResult(result, methodDescription);
+
+ try
+ {
+ event.storeResult(null, "foo.Bar.biff()");
+ unreachable();
+ }
+ catch (IllegalStateException ex)
+ {
+ assertEquals(ex.getMessage(), ServicesMessages
+ .componentEventIsAborted("foo.Bar.biff()"));
+ }
+ verify();
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java Fri Oct 13 09:44:20 2006
@@ -42,7 +42,7 @@
List<MethodSignature> sigs = newList();
- train_findMethodsWithAnnotation(tf, sigs);
+ train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
replay();
@@ -64,7 +64,7 @@
sigs.add(new MethodSignature("aMethod"));
- train_findMethodsWithAnnotation(tf, sigs);
+ train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
train_extendMethod(
tf,
@@ -92,7 +92,7 @@
sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "aMethod", new String[]
{ MarkupWriter.class.getName() }, null));
- train_findMethodsWithAnnotation(tf, sigs);
+ train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
train_extendMethod(
tf,
@@ -120,7 +120,7 @@
sigs.add(new MethodSignature(Modifier.PROTECTED, "boolean", "aMethod", null, null));
- train_findMethodsWithAnnotation(tf, sigs);
+ train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
train_getClassName(tf, "biff.Baz");
@@ -153,7 +153,7 @@
sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "bMethod", new String[]
{ MarkupWriter.class.getName() }, null));
- train_findMethodsWithAnnotation(tf, sigs);
+ train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
train_getClassName(tf, "foo.Bar");
train_extendMethod(
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java Fri Oct 13 09:44:20 2006
@@ -33,6 +33,7 @@
import org.apache.commons.logging.Log;
import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.OnEvent;
import org.apache.tapestry.annotations.Retain;
import org.apache.tapestry.annotations.SetupRender;
import org.apache.tapestry.internal.InternalComponentResources;
@@ -43,6 +44,7 @@
import org.apache.tapestry.internal.transform.pages.BasicComponent;
import org.apache.tapestry.internal.transform.pages.ChildClassInheritsAnnotation;
import org.apache.tapestry.internal.transform.pages.ClaimedFields;
+import org.apache.tapestry.internal.transform.pages.EventHandlerTarget;
import org.apache.tapestry.internal.transform.pages.ParentClass;
import org.apache.tapestry.internal.transform.pages.TargetObject;
import org.apache.tapestry.internal.transform.pages.TargetObjectSubclass;
@@ -829,6 +831,51 @@
assertEquals(ct.newMemberName("_$myLong"), "_$myLong_0");
assertEquals(ct.newMemberName("_$myStatic"), "_$myStatic_0");
assertEquals(ct.newMemberName("_$myProtected"), "_$myProtected_0");
+
+ verify();
+ }
+
+ @Test
+ public void find_annotation_in_method() throws Exception
+ {
+ Log log = newLog();
+
+ replay();
+
+ ClassTransformation ct = createClassTransformation(EventHandlerTarget.class, log);
+
+ OnEvent annotation = ct.getMethodAnnotation(new MethodSignature("handler"), OnEvent.class);
+
+ // Check that the attributes of the annotation match the expectation.
+
+ assertEquals(annotation.value(), new String[]
+ { "fred", "barney" });
+ assertEquals(annotation.component(), new String[]
+ { "alpha", "beta" });
+
+ verify();
+ }
+
+ @Test
+ public void find_annotation_in_unknown_method() throws Exception
+ {
+ Log log = newLog();
+
+ replay();
+
+ ClassTransformation ct = createClassTransformation(ParentClass.class, log);
+
+ try
+ {
+ ct.getMethodAnnotation(new MethodSignature("foo"), OnEvent.class);
+ unreachable();
+ }
+ catch (IllegalArgumentException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Class org.apache.tapestry.internal.transform.pages.ParentClass does not declare method 'public void foo()'.");
+ }
verify();
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java?view=auto&rev=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/OnEventWorkerTest.java Fri Oct 13 09:44:20 2006
@@ -0,0 +1,410 @@
+package org.apache.tapestry.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry.annotations.OnEvent;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.MethodSignature;
+import org.apache.tapestry.services.TransformConstants;
+import org.apache.tapestry.util.CollectionFactory;
+import org.testng.annotations.Test;
+
+/**
+ * I'd prefer to test these in terms of the behavior of the final class, rather than the generated
+ * Javassist method bodies, but that'll have to be saved for later integration tests.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class OnEventWorkerTest extends InternalBaseTestCase
+{
+ private static final String BOILERPLATE_2 = "String methodName = null;";
+
+ private static final String BOILERPLATE_1 = "if ($1.isAborted()) return;";
+
+ @Test
+ public void no_methods_with_annotation()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+
+ List<MethodSignature> methods = CollectionFactory.newList();
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+ }
+
+ @Test
+ public void minimal_case()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ MethodSignature signature = new MethodSignature("foo");
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, new String[0]);
+ train_component(annotation, new String[0]);
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "methodName = \"foo.Bar.foo()\";",
+ "foo();",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+ }
+
+ @Test
+ public void filter_by_event_type()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ String[] eventTypes = new String[]
+ { "gnip", "gnop" };
+
+ MethodSignature signature = new MethodSignature("foo");
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, eventTypes);
+
+ train_addInjectedField(ct, String[].class, "eventTypes", eventTypes, "_v");
+
+ train_component(annotation, new String[0]);
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "if ($1.matchesByEventType(_v))",
+ "{",
+ "methodName = \"foo.Bar.foo()\";",
+ "foo();",
+ "}",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+ }
+
+ @Test
+ public void filter_by_component_id()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ String[] componentIds = new String[]
+ { "zork" };
+
+ MethodSignature signature = new MethodSignature("foo");
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, new String[0]);
+ train_component(annotation, componentIds);
+
+ train_addInjectedField(ct, java.lang.String[].class, "componentIds", componentIds, "_ids");
+
+ train_getResourcesFieldName(ct, "_res");
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "if ($1.matchesByComponentId(_res, _ids))",
+ "{",
+ "methodName = \"foo.Bar.foo()\";",
+ "foo();",
+ "}",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+ }
+
+ @Test
+ public void filter_by_both()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ String[] eventTypes = new String[]
+ { "gnip", "gnop" };
+ String[] componentIds = new String[]
+ { "zork" };
+
+ MethodSignature signature = new MethodSignature("foo");
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, eventTypes);
+
+ train_addInjectedField(ct, java.lang.String[].class, "eventTypes", eventTypes, "_v");
+
+ train_component(annotation, componentIds);
+
+ train_addInjectedField(ct, java.lang.String[].class, "componentIds", componentIds, "_ids");
+
+ train_getResourcesFieldName(ct, "_res");
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "if ($1.matchesByEventType(_v))",
+ "{",
+ "if ($1.matchesByComponentId(_res, _ids))",
+ "{",
+ "methodName = \"foo.Bar.foo()\";",
+ "foo();",
+ "}",
+ "}",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+
+ }
+
+ @Test
+ public void method_with_non_void_return_value()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ MethodSignature signature = new MethodSignature(Modifier.PRIVATE, "java.lang.String",
+ "foo", null, null);
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, new String[0]);
+ train_component(annotation, new String[0]);
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "methodName = \"foo.Bar.foo()\";",
+ "if ($1.storeResult(foo(), methodName) return;",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+ }
+
+ @Test
+ public void method_with_non_primitive_parameter()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ MethodSignature signature = new MethodSignature(Modifier.PRIVATE, "void", "foo",
+ new String[]
+ { "java.lang.String" }, null);
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, new String[0]);
+ train_component(annotation, new String[0]);
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "methodName = \"foo.Bar.foo(java.lang.String)\";",
+ "foo($1.coerceContext(0, \"java.lang.String\", methodName));",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+ }
+
+ @Test
+ public void method_with_primitive_parameter()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ MethodSignature signature = new MethodSignature(Modifier.PRIVATE, "void", "foo",
+ new String[]
+ { "boolean" }, null);
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, new String[0]);
+ train_component(annotation, new String[0]);
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "methodName = \"foo.Bar.foo(boolean)\";",
+ "foo(((java.lang.Boolean)$1.coerceContext(0, \"java.lang.Boolean\", methodName)).booleanValue());",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+
+ }
+
+ @Test
+ public void method_with_multiple_parameters()
+ {
+ ClassTransformation ct = newClassTransformation();
+ MutableComponentModel model = newMutableComponentModel();
+ OnEvent annotation = newOnEvent();
+
+ MethodSignature signature = new MethodSignature(Modifier.PRIVATE, "void", "foo",
+ new String[]
+ { "java.lang.String", "java.lang.Integer" }, null);
+
+ List<MethodSignature> methods = Collections.singletonList(signature);
+ train_findMethodsWithAnnotation(ct, OnEvent.class, methods);
+
+ train_getMethodAnnotation(ct, signature, OnEvent.class, annotation);
+
+ train_value(annotation, new String[0]);
+ train_component(annotation, new String[0]);
+
+ train_getClassName(ct, "foo.Bar");
+
+ train_extendMethod(
+ ct,
+ TransformConstants.HANDLE_COMPONENT_EVENT,
+ "{",
+ BOILERPLATE_1,
+ BOILERPLATE_2,
+ "methodName = \"foo.Bar.foo(java.lang.String, java.lang.Integer)\";",
+ "foo($1.coerceContext(0, \"java.lang.String\", methodName), ",
+ "$1.coerceContext(1, \"java.lang.Integer\", methodName));",
+ "}");
+
+ replay();
+
+ new OnEventWorker().transform(ct, model);
+
+ verify();
+
+ }
+
+ protected final OnEvent newOnEvent()
+ {
+ return newMock(OnEvent.class);
+ }
+
+ protected final void train_getClassName(ClassTransformation ct, String className)
+ {
+ ct.getClassName();
+ setReturnValue(className);
+ }
+
+ protected final void train_value(OnEvent annotation, String[] values)
+ {
+ annotation.value();
+ setReturnValue(values);
+ }
+
+ protected final void train_component(OnEvent annotation, String[] values)
+ {
+ annotation.component();
+ setReturnValue(values);
+ }
+
+ protected final <T extends Annotation> void train_getMethodAnnotation(ClassTransformation ct,
+ MethodSignature signature, Class<T> annotationClass, T annotation)
+ {
+ ct.getMethodAnnotation(signature, annotationClass);
+ setReturnValue(annotation);
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java Fri Oct 13 09:44:20 2006
@@ -16,8 +16,9 @@
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.Collection;
import java.util.Collections;
+import java.util.List;
+import java.util.Map;
import org.apache.tapestry.internal.annotations.SuppressNullCheck;
import org.apache.tapestry.internal.test.InternalBaseTestCase;
@@ -92,7 +93,7 @@
{
try
{
- _coercer.coerce("", Collection.class);
+ _coercer.coerce("", Map.class);
unreachable();
}
catch (IllegalArgumentException ex)
@@ -100,7 +101,7 @@
assertTrue(ex
.getMessage()
.contains(
- "Could not find a coercion from type java.lang.String to type java.util.Collection"));
+ "Could not find a coercion from type java.lang.String to type java.util.Map"));
}
}
@@ -117,6 +118,7 @@
String bigDecimalValue = "12345656748352435842385234598234958234574358723485.35843534285293857298457234587";
String bigIntegerValue = "12384584574874385743";
+ Object object = new Object();
// Over time, some of these may evolve from testing specific tuples to
// compound tuples (built around specific tuples).
@@ -153,6 +155,8 @@
// BigInteger
{ new BigInteger("12345678"), Long.class, 12345678l },
{ -12345678l, BigInteger.class, new BigInteger("-12345678") },
+ // Object --> List
+ { object, List.class, Collections.singletonList(object) },
};
}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/EventHandlerTarget.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/EventHandlerTarget.java?view=auto&rev=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/EventHandlerTarget.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/transform/pages/EventHandlerTarget.java Fri Oct 13 09:44:20 2006
@@ -0,0 +1,16 @@
+package org.apache.tapestry.internal.transform.pages;
+
+import org.apache.tapestry.annotations.OnEvent;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class EventHandlerTarget
+{
+ @OnEvent(value =
+ { "fred", "barney" }, component =
+ { "alpha", "beta" })
+ public void handler()
+ {
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java Fri Oct 13 09:44:20 2006
@@ -15,8 +15,10 @@
package org.apache.tapestry.services;
import static org.apache.tapestry.services.TransformUtils.getDefaultValue;
+import static org.apache.tapestry.services.TransformUtils.getUnwrapperMethodName;
import static org.apache.tapestry.services.TransformUtils.getWrapperType;
import static org.apache.tapestry.services.TransformUtils.getWrapperTypeName;
+import static org.apache.tapestry.services.TransformUtils.isPrimitive;
import java.util.Map;
@@ -47,5 +49,20 @@
{
assertEquals(getDefaultValue("long"), "0L");
assertEquals(getDefaultValue("java.util.Map"), "null");
+ }
+
+ @Test
+ public void is_primitive()
+ {
+ assertTrue(isPrimitive("int"));
+ assertFalse(isPrimitive("java.lang.Integer"));
+ }
+
+ @Test
+ public void unwrapper_method_name()
+ {
+ assertEquals(getUnwrapperMethodName("boolean"), "booleanValue");
+ assertEquals(getUnwrapperMethodName("int"), "intValue");
+ assertNull(getUnwrapperMethodName("java.lang.Integer"));
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/ActionPage.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/ActionPage.html?view=diff&rev=463734&r1=463733&r2=463734
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/ActionPage.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/ActionPage.html Fri Oct 13 09:44:20 2006
@@ -1,7 +1,10 @@
<t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<p>
- <t:comp id="action" type="ActionLink">
- This link is an action.
- </t:comp>
- </p>
+ <t:comp id="action" type="ActionLink"> Click here! </t:comp>
+ </p>
+
+ <t:comp type="If" test="prop:clicked">
+ <p> You clicked the link! </p>
+ </t:comp>
+
</t:comp>