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 2011/08/08 01:31:15 UTC
svn commit: r1154797 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
test/groovy/org/apache/tapestry5/integration/app1/ComponentParameterTests.groovy
Author: hlship
Date: Sun Aug 7 23:31:15 2011
New Revision: 1154797
URL: http://svn.apache.org/viewvc?rev=1154797&view=rev
Log:
TAP5-1596: Enhance OnEventWorker to check that component ids for event handler methods match against actual component ids
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ComponentParameterTests.groovy
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java?rev=1154797&r1=1154796&r2=1154797&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/OnEventWorker.java Sun Aug 7 23:31:15 2011
@@ -14,21 +14,26 @@
package org.apache.tapestry5.internal.transform;
+import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.EventContext;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.RequestParameter;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Flow;
+import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
import org.apache.tapestry5.internal.services.ComponentClassCache;
import org.apache.tapestry5.ioc.OperationTracker;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.plastic.*;
import org.apache.tapestry5.runtime.ComponentEvent;
import org.apache.tapestry5.runtime.Event;
+import org.apache.tapestry5.runtime.PageLifecycleListener;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.TransformConstants;
import org.apache.tapestry5.services.ValueEncoderSource;
@@ -62,6 +67,53 @@ public class OnEventWorker implements Co
}
};
+ class ComponentIdValidator
+ {
+ final String componentId;
+
+ final String methodIdentifier;
+
+ ComponentIdValidator(String componentId, String methodIdentifier)
+ {
+ this.componentId = componentId;
+ this.methodIdentifier = methodIdentifier;
+ }
+
+ void validate(ComponentResources resources)
+ {
+ try
+ {
+ resources.getEmbeddedComponent(componentId);
+ } catch (UnknownValueException ex)
+ {
+ throw new TapestryException(String.format("Method %s references component id '%s' which does not exist.",
+ methodIdentifier, componentId), resources.getLocation(), ex);
+ }
+ }
+ }
+
+ class ValidateComponentIds implements MethodAdvice
+ {
+ final ComponentIdValidator[] validators;
+
+ ValidateComponentIds(ComponentIdValidator[] validators)
+ {
+ this.validators = validators;
+ }
+
+ public void advise(MethodInvocation invocation)
+ {
+ ComponentResources resources = invocation.getInstanceContext().get(ComponentResources.class);
+
+ for (ComponentIdValidator validator : validators)
+ {
+ validator.validate(resources);
+ }
+
+ invocation.proceed();
+ }
+ }
+
/**
* Encapsulates information needed to invoke a method as an event handler method, including the logic
* to construct parameter values, and match the method against the {@link ComponentEvent}.
@@ -251,11 +303,54 @@ public class OnEventWorker implements Co
return;
}
- implementDispatchComponentEvent(plasticClass, support.isRootTransformation(), methods, model);
+ addEventHandlingLogic(plasticClass, support.isRootTransformation(), methods, model);
}
- private void implementDispatchComponentEvent(final PlasticClass plasticClass, final boolean isRoot, final Flow<PlasticMethod> eventMethods, final MutableComponentModel model)
+ private void addEventHandlingLogic(final PlasticClass plasticClass, final boolean isRoot, final Flow<PlasticMethod> plasticMethods, final MutableComponentModel model)
+ {
+ Flow<EventHandlerMethod> eventHandlerMethods = plasticMethods.map(new Mapper<PlasticMethod, EventHandlerMethod>()
+ {
+ public EventHandlerMethod map(PlasticMethod element)
+ {
+ return new EventHandlerMethod(element);
+ }
+ });
+
+ implementDispatchMethod(plasticClass, isRoot, model, eventHandlerMethods);
+
+ addComponentIdValidationLogicOnPageLoad(plasticClass, eventHandlerMethods);
+ }
+
+ private void addComponentIdValidationLogicOnPageLoad(PlasticClass plasticClass, Flow<EventHandlerMethod> eventHandlerMethods)
+ {
+ ComponentIdValidator[] validators = extractComponentIdValidators(eventHandlerMethods);
+
+
+ if (validators.length > 0)
+ {
+ plasticClass.introduceInterface(PageLifecycleListener.class);
+ plasticClass.introduceMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_DESCRIPTION).addAdvice(new ValidateComponentIds(validators));
+ }
+ }
+
+ private ComponentIdValidator[] extractComponentIdValidators(Flow<EventHandlerMethod> eventHandlerMethods)
+ {
+ return eventHandlerMethods.map(new Mapper<EventHandlerMethod, ComponentIdValidator>()
+ {
+ public ComponentIdValidator map(EventHandlerMethod element)
+ {
+ if (element.componentId.equals(""))
+ {
+ return null;
+ }
+
+ return new ComponentIdValidator(element.componentId, element.method.getMethodIdentifier());
+ }
+ }).removeNulls().toArray(ComponentIdValidator.class);
+ }
+
+ private void implementDispatchMethod(final PlasticClass plasticClass, final boolean isRoot, final MutableComponentModel model, final Flow<EventHandlerMethod> eventHandlerMethods)
{
plasticClass.introduceMethod(TransformConstants.DISPATCH_COMPONENT_EVENT_DESCRIPTION).changeImplementation(new InstructionBuilderCallback()
{
@@ -281,13 +376,11 @@ public class OnEventWorker implements Co
builder.loadConstant(false).storeVariable(resultVariable);
}
- for (PlasticMethod method : eventMethods)
+ for (EventHandlerMethod method : eventHandlerMethods)
{
- EventHandlerMethod eventHandlerMethod = new EventHandlerMethod(method);
-
- eventHandlerMethod.buildMatchAndInvocation(builder, resultVariable);
+ method.buildMatchAndInvocation(builder, resultVariable);
- model.addEventHandler(eventHandlerMethod.eventType);
+ model.addEventHandler(method.eventType);
}
builder.loadVariable(resultVariable).returnResult();
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ComponentParameterTests.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ComponentParameterTests.groovy?rev=1154797&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ComponentParameterTests.groovy (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ComponentParameterTests.groovy Sun Aug 7 23:31:15 2011
@@ -0,0 +1,35 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.integration.app1
+
+import org.apache.tapestry5.test.SeleniumTestCase
+import org.testng.annotations.Test
+
+/**
+ *
+ * @since 5.3
+ */
+class ComponentParameterTests extends SeleniumTestCase
+{
+ @Test
+ void event_handler_method_for_missing_component_is_error()
+ {
+ openLinks "Unmatched Component Id in Event Method Demo"
+
+ assertTextPresent "Method org.apache.tapestry5.integration.app1.pages.EventMethodUnmatchedComponentId.onActionFromBaz() references component id 'Baz' which does not exist.",
+ "Component EventMethodUnmatchedComponentId does not contain embedded component 'Baz'."
+
+ }
+}