From commitsbrandon51@example.net Sat Sep 02 00:44:30 2006 Return-Path: <commitsbrandon51@example.net> Delivered-To: brandon51@example.net Received: (qmail 82257 invoked from network); 2 Sep 2006 00:44:30 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 2 Sep 2006 00:44:30 -0000 Received: (qmail 25334 invoked by uid 500); 2 Sep 2006 00:44:29 -0000 Delivered-To: brandon51@example.net Received: (qmail 25314 invoked by uid 500); 2 Sep 2006 00:44:29 -0000 Mailing-List: contact brandon51@example.net; run by ezmlm Precedence: bulk List-Help: <mailto:brandon51@example.net> List-Unsubscribe: <mailto:brandon51@example.net> List-Post: <mailto:brandon51@example.net> List-Id: <commits.tapestry.apache.org> Reply-To: brandon51@example.net Delivered-To: mailing list brandon51@example.net Received: (qmail 25305 invoked by uid 99); 2 Sep 2006 00:44:29 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 17:44:29 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [83.161.120.155] (HELO eris.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 17:44:26 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 1ACD91A981D; Fri, 1 Sep 2006 17:44:06 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r439507 [2/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/aspect/org/apache/tapestry/internal/aspects/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/ioc/... Date: Sat, 02 Sep 2006 00:43:50 -0000 To: brandon51@example.net From: brandon51@example.net X-Mailer: svnmailer-1.0.8 Message-Id: <brandon51@example.net> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java Fri Sep 1 17:43:45 2006 @@ -1,3 +1,17 @@ +// Copyright 2006 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.tapestry.internal.model; import org.apache.commons.logging.Log; @@ -34,6 +48,31 @@ assertEquals(pm.getName(), parameterName); assertEquals(true, pm.isRequired()); + + verify(); + } + + @Test + public void add_duplicate_parameter() + { + Resource r = newResource(); + Log log = newLog(); + + replay(); + + MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r); + + model.addParameter("fred", true); + + try + { + model.addParameter("fred", true); + unreachable(); + } + catch (IllegalArgumentException ex) + { + assertEquals(ex.getMessage(), "Parameter 'fred' of component org.example.components.Foo is already defined."); + } verify(); } Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java Fri Sep 1 17:43:45 2006 @@ -43,7 +43,7 @@ String description = "descrip"; String expression = "full expression"; - trainNewBinding(factory, description, component, expression, l, b); + train_newBinding(factory, description, component, expression, l, b); replay(); @@ -72,7 +72,7 @@ String description = "descrip"; String expression = "javascript:not-a-known-prefix"; - trainNewBinding(factory, description, component, expression, l, b); + train_newBinding(factory, description, component, expression, l, b); replay(); @@ -101,7 +101,7 @@ String description = "descrip"; // The "prop:" prefix is stripped off ... - trainNewBinding(factory, description, component, "myproperty", l, b); + train_newBinding(factory, description, component, "myproperty", l, b); replay(); 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -42,7 +42,7 @@ List<MethodSignature> sigs = newList(); - trainFindMethodsWithAnnotation(tf, sigs); + train_findMethodsWithAnnotation(tf, sigs); replay(); @@ -64,11 +64,12 @@ sigs.add(new MethodSignature("aMethod")); - trainFindMethodsWithAnnotation(tf, sigs); + train_findMethodsWithAnnotation(tf, sigs); - String expectedBody = join("{", " if ($2.isAborted()) return;", " aMethod();", "}"); - - tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody); + train_extendMethod( + tf, + TransformConstants.BEFORE_RENDER_SIGNATURE, + "{if ($2.isAborted()) return; aMethod(); }"); replay(); @@ -91,11 +92,12 @@ sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "aMethod", new String[] { MarkupWriter.class.getName() }, null)); - trainFindMethodsWithAnnotation(tf, sigs); - - String expectedBody = join("{", " if ($2.isAborted()) return;", " aMethod($1);", "}"); + train_findMethodsWithAnnotation(tf, sigs); - tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody); + train_extendMethod( + tf, + TransformConstants.BEFORE_RENDER_SIGNATURE, + "{ if ($2.isAborted()) return; aMethod($1); }"); replay(); @@ -118,16 +120,14 @@ sigs.add(new MethodSignature(Modifier.PROTECTED, "boolean", "aMethod", null, null)); - trainFindMethodsWithAnnotation(tf, sigs); + train_findMethodsWithAnnotation(tf, sigs); - String expectedBody = join( - "{", - " if ($2.isAborted()) return;", - " $2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");", - " if ($2.isAborted()) return;", - "}"); - - tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody); + train_extendMethod( + tf, + TransformConstants.BEFORE_RENDER_SIGNATURE, + "{ if ($2.isAborted()) return; ", + "$2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");", + "if ($2.isAborted()) return; }"); replay(); @@ -151,17 +151,15 @@ sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "bMethod", new String[] { MarkupWriter.class.getName() }, null)); - trainFindMethodsWithAnnotation(tf, sigs); - - String expectedBody = join( - "{", - " if ($2.isAborted()) return;", - " $2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");", - " if ($2.isAborted()) return;", - " bMethod($1);", - "}"); + train_findMethodsWithAnnotation(tf, sigs); - tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody); + train_extendMethod( + tf, + TransformConstants.BEFORE_RENDER_SIGNATURE, + "{ if ($2.isAborted()) return;", + "$2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");", + "if ($2.isAborted()) return;", + "bMethod($1); }"); replay(); @@ -171,14 +169,6 @@ worker.transform(tf, model); verify(); - - } - - protected final void trainFindMethodsWithAnnotation(ClassTransformation tf, - List<MethodSignature> sigs) - { - tf.findMethodsWithAnnotation(BeforeRender.class); - setReturnValue(sigs); } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java Fri Sep 1 17:43:45 2006 @@ -50,7 +50,7 @@ TemplateParser parser = newTemplateParser(); ComponentTemplate template = newComponentTemplate(); - trainParseTemplate(parser, r, template); + train_parseTemplate(parser, r, template); replay(); @@ -67,13 +67,6 @@ verify(); } - protected final void trainParseTemplate(TemplateParser parser, Resource resource, - ComponentTemplate template) - { - parser.parseTemplate(resource); - setReturnValue(template); - } - /** Tests resource invalidation. */ @Test public void invalidation() throws Exception @@ -94,7 +87,7 @@ ComponentTemplate template = newComponentTemplate(); InvalidationListener listener = newMock(InvalidationListener.class); - trainParseTemplate(parser, localized, template); + train_parseTemplate(parser, localized, template); replay(); @@ -130,7 +123,7 @@ // Check that the cache really is cleared. - trainParseTemplate(parser, localized, template); + train_parseTemplate(parser, localized, template); replay(); @@ -139,11 +132,6 @@ verify(); } - protected final TemplateParser newTemplateParser() - { - return newMock(TemplateParser.class); - } - /** Checks that localization to the same resource works (w/ caching). */ @Test public void localization_to_same() @@ -153,7 +141,7 @@ TemplateParser parser = newTemplateParser(); ComponentTemplate template = newComponentTemplate(); - trainParseTemplate(parser, r, template); + train_parseTemplate(parser, r, template); replay(); Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java?rev=439507&view=auto ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java Fri Sep 1 17:43:45 2006 @@ -0,0 +1,49 @@ +// Copyright 2006 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.tapestry.internal.services; + +import org.apache.tapestry.internal.annotations.SuppressNullCheck; + +/** + * @author Howard M. Lewis Ship + */ +@SuppressNullCheck +public class FieldAccessBean +{ + private String _foo; + + private String _bar; + + public String getBar() + { + return _bar; + } + + public void setBar(String bar) + { + _bar = bar; + } + + public String getFoo() + { + return _foo; + } + + public void setFoo(String foo) + { + _foo = foo; + } + +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java Fri Sep 1 17:43:45 2006 @@ -73,7 +73,7 @@ Map<String, Object> configuration = newMap(); configuration.put("myrunnable", r); - trainGetContributionsForMode(manager, "papyrus", configuration); + train_getContributionsForMode(manager, "papyrus", configuration); replay(); @@ -104,7 +104,7 @@ Map<String, Object> configuration = newMap(); configuration.put("myrunnable", r); - trainGetContributionsForMode(manager, "clay", configuration); + train_getContributionsForMode(manager, "clay", configuration); replay(); @@ -138,7 +138,7 @@ configuration.put("barney", this); configuration.put("wilma", this); - trainGetContributionsForMode(manager, "clay", configuration); + train_getContributionsForMode(manager, "clay", configuration); replay(); @@ -174,7 +174,7 @@ Map<String, Object> configuration = newMap(); configuration.put("myrunnable", r); - trainGetContributionsForMode(manager, "papyrus", configuration); + train_getContributionsForMode(manager, "papyrus", configuration); replay(); @@ -204,7 +204,7 @@ } - protected final void trainGetContributionsForMode(InfrastructureManager manager, String mode, + protected final void train_getContributionsForMode(InfrastructureManager manager, String mode, Map<String, Object> configuration) { manager.getContributionsForMode(mode); 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -31,6 +31,7 @@ import org.apache.tapestry.annotations.ComponentClass; import org.apache.tapestry.annotations.Retain; import org.apache.tapestry.internal.InternalComponentResources; +import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl; import org.apache.tapestry.internal.test.InternalBaseTestCase; import org.apache.tapestry.internal.transform.pages.AbstractFoo; import org.apache.tapestry.internal.transform.pages.BarImpl; @@ -39,6 +40,7 @@ import org.apache.tapestry.internal.transform.pages.ClaimedFields; import org.apache.tapestry.internal.transform.pages.ParentClass; import org.apache.tapestry.internal.transform.pages.TargetObject; +import org.apache.tapestry.ioc.services.PropertyAccess; import org.apache.tapestry.runtime.ComponentLifecycle; import org.apache.tapestry.runtime.ResourceAware; import org.apache.tapestry.services.ClassTransformation; @@ -58,6 +60,8 @@ @Test(sequential = true) public class InternalClassTransformationImplTest extends InternalBaseTestCase { + private static final String STRING_CLASS_NAME = "java.lang.String"; + private ClassPool _classPool; private final ClassLoader _contextClassLoader = currentThread().getContextClassLoader(); @@ -411,6 +415,97 @@ assertNull(getters.getString()); assertNull(getters.getObjectArray()); assertNull(getters.getIntArray()); + } + + /** + * Tests the basic functionality of overriding read and write; also tests the case for multiple + * field read/field write substitions. + */ + @Test + public void override_field_read_and_write() throws Exception + { + InternalComponentResources resources = newInternalComponentResources(); + + replay(); + + ClassLoader childLoader = newLoader(); + + CtClass targetObjectCtClass = findCtClass(FieldAccessBean.class); + + InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass); + + replaceAccessToField(ct, "foo"); + replaceAccessToField(ct, "bar"); + + // Stuff ... + + ct.finish(); + + Class transformed = _classPool.toClass(targetObjectCtClass, childLoader); + + Object target = ct.createInstantiator(transformed).newInstance(resources); + + // target is no longer assignable to FieldAccessBean; its a new class from a new class + // loader. So we use reflective access, which doesn't care about such things. + + PropertyAccess access = new PropertyAccessImpl(); + + checkReplacedFieldAccess(access, target, "foo"); + checkReplacedFieldAccess(access, target, "bar"); + + verify(); + } + + private void checkReplacedFieldAccess(PropertyAccess access, Object target, String propertyName) + { + + try + { + access.get(target, propertyName); + unreachable(); + } + catch (RuntimeException ex) + { + // PropertyAccess adds a wrapper exception + assertEquals(ex.getCause().getMessage(), "read " + propertyName); + } + + try + { + access.set(target, propertyName, "new value"); + unreachable(); + } + catch (RuntimeException ex) + { + // PropertyAccess adds a wrapper exception + assertEquals(ex.getCause().getMessage(), "write " + propertyName); + } + } + + private void replaceAccessToField(InternalClassTransformation ct, String baseName) + { + String fieldName = "_" + baseName; + String readMethodName = "_read_" + baseName; + + MethodSignature readMethodSignature = new MethodSignature(Modifier.PRIVATE, + STRING_CLASS_NAME, readMethodName, null, null); + + ct.addMethod(readMethodSignature, String.format( + "throw new RuntimeException(\"read %s\");", + baseName)); + + ct.replaceReadAccess(fieldName, readMethodName); + + String writeMethodName = "_write_" + baseName; + + MethodSignature writeMethodSignature = new MethodSignature(Modifier.PRIVATE, "void", + writeMethodName, new String[] + { STRING_CLASS_NAME }, null); + ct.addMethod(writeMethodSignature, String.format( + "throw new RuntimeException(\"write %s\");", + baseName)); + + ct.replaceWriteAccess(fieldName, writeMethodName); } @Test Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java Fri Sep 1 17:43:45 2006 @@ -37,7 +37,7 @@ PageLoader loader = newPageLoader(); Page page = newPage(); - trainLoadPage(loader, PAGE_NAME, _locale, page); + train_loadPage(loader, PAGE_NAME, _locale, page); replay(); @@ -56,9 +56,9 @@ Page page2 = newPage(); page1.detached(); - trainGetName(page1, PAGE_NAME); + train_getName(page1, PAGE_NAME); - trainLoadPage(loader, PAGE_NAME, _locale, page2); + train_loadPage(loader, PAGE_NAME, _locale, page2); replay(); @@ -84,11 +84,11 @@ page1.detached(); - trainGetName(page1, PAGE_NAME); + train_getName(page1, PAGE_NAME); page2.detached(); - trainGetName(page2, PAGE_NAME); + train_getName(page2, PAGE_NAME); replay(); Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java?rev=439507&view=auto ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java Fri Sep 1 17:43:45 2006 @@ -0,0 +1,236 @@ +// Copyright 2006 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.tapestry.internal.services; + +import java.lang.reflect.Modifier; + +import org.apache.tapestry.annotations.Parameter; +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.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * @author Howard M. Lewis Ship + */ +public class ParameterWorkerTest extends InternalBaseTestCase +{ + private static String f(String format, Object... args) + { + return String.format(format, args); + } + + @Test + public void standard_cacheable_parameter() + { + runWorkerCached("_foo", "foo", "", "java.lang.String", "java.lang.String"); + } + + @Test + public void annotation_name_overrides_default_from_field_name() + { + runWorkerCached("_foo", "zippy", "zippy", "java.util.Map", "java.util.Map"); + } + + @Test(dataProvider = "primitiveTypes") + public void primitive_types(String fieldType, String expectedWrapperType) + { + runWorkerCached("_primitive", "primitive", "", fieldType, expectedWrapperType); + } + + @DataProvider(name = "primitiveTypes") + public Object[][] primitiveTypes() + { + return new Object[][] + { + { "boolean", "java.lang.Boolean" }, + { "short", "java.lang.Short" }, + { "int", "java.lang.Integer" }, + { "byte", "java.lang.Byte" }, + { "char", "java.lang.Character" }, + { "long", "java.lang.Long" }, + { "float", "java.lang.Float" }, + { "double", "java.lang.Double" } }; + } + + private void runWorkerCached(String fieldName, String parameterName, String annotatedName, + String fieldType, String wrapperType) + { + ClassTransformation transformation = newClassTransformation(); + MutableComponentModel model = newMutableComponentModel(); + Parameter parameter = newMock(Parameter.class); + + train_findFieldsWithAnnotation(transformation, Parameter.class, fieldName); + train_getFieldAnnotation(transformation, fieldName, Parameter.class, parameter); + train_name(parameter, annotatedName); + train_required(parameter, true); + + model.addParameter(parameterName, true); + + train_getFieldType(transformation, fieldName, fieldType); + train_cache(parameter, true); + train_addField(transformation, Modifier.PRIVATE, "boolean", fieldName + "_cached", "$cache"); + train_getResourcesFieldName(transformation, "$res"); + + train_addField( + transformation, + Modifier.PRIVATE, + "boolean", + fieldName + "_invariant", + "$invariant"); + + // codeEq() lets us care less about whitespace + + train_extendMethod( + transformation, + TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, + String.format("$invariant = $res.isInvariant(\"%s\");", parameterName)); + + train_extendMethod( + transformation, + TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, + String.format("if (! $invariant) { %s = null; $cache = false; }", fieldName)); + + train_newMemberName(transformation, "_read_parameter_" + parameterName, "$read"); + + train_addMethod(transformation, new MethodSignature(Modifier.PRIVATE, fieldType, "$read", + null, null), f("{ if ($cache) return %s;", fieldName), f( + "%s result = ($r) ((%s) $res.readParameter(\"%s\", $type));", + fieldType, + wrapperType, + parameterName), f( + "if ($invariant || $res.isRendering()) { %s = result; $cache = true; }", + fieldName), "return result; }"); + + transformation.replaceReadAccess(fieldName, "$read"); + + train_newMemberName(transformation, "_update_parameter_" + parameterName, "$write"); + + train_addMethod( + transformation, + new MethodSignature(Modifier.PRIVATE, "void", "$write", new String[] + { fieldType, }, null), + f("{ $res.writeParameter(\"%s\", ($w)$1);", parameterName), + f("if ($res.isRendering()) { %s = $1; $cache = true; } }", fieldName)); + + transformation.replaceWriteAccess(fieldName, "$write"); + + transformation.claimField(fieldName, parameter); + + replay(); + + new ParameterWorker().transform(transformation, model); + + verify(); + } + + @Test + public void non_cached_parameter() + { + runWorkerNonCached("_foo", "foo", "", "java.lang.String", "java.lang.String"); + } + + private void runWorkerNonCached(String fieldName, String parameterName, String annotatedName, + String fieldType, String wrapperType) + { + ClassTransformation transformation = newClassTransformation(); + MutableComponentModel model = newMutableComponentModel(); + Parameter parameter = newMock(Parameter.class); + + train_findFieldsWithAnnotation(transformation, Parameter.class, fieldName); + train_getFieldAnnotation(transformation, fieldName, Parameter.class, parameter); + train_name(parameter, annotatedName); + train_required(parameter, true); + + model.addParameter(parameterName, true); + + train_getFieldType(transformation, fieldName, fieldType); + + train_cache(parameter, false); // First difference + + train_addField(transformation, Modifier.PRIVATE, "boolean", fieldName + "_cached", "$cache"); + train_getResourcesFieldName(transformation, "$res"); + + train_addField( + transformation, + Modifier.PRIVATE, + "boolean", + fieldName + "_invariant", + "$invariant"); + + // codeEq() lets us care less about whitespace + + train_extendMethod( + transformation, + TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, + String.format("$invariant = $res.isInvariant(\"%s\");", parameterName)); + + train_extendMethod( + transformation, + TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, + String.format("if (! $invariant) { %s = null; $cache = false; }", fieldName)); + + train_newMemberName(transformation, "_read_parameter_" + parameterName, "$read"); + + // Second difference: + + train_addMethod( + transformation, + new MethodSignature(Modifier.PRIVATE, fieldType, "$read", null, null), + f("{ if ($cache) return %s;", fieldName), + f( + "%s result = ($r) ((%s) $res.readParameter(\"%s\", $type));", + fieldType, + wrapperType, + parameterName), + f("if ($invariant) { %s = result; $cache = true; }", fieldName), + "return result; }"); + + transformation.replaceReadAccess(fieldName, "$read"); + + train_newMemberName(transformation, "_update_parameter_" + parameterName, "$write"); + + // Last difference: + + train_addMethod(transformation, new MethodSignature(Modifier.PRIVATE, "void", "$write", + new String[] + { fieldType, }, null), f("{ $res.writeParameter(\"%s\", ($w)$1); }", parameterName)); + + transformation.replaceWriteAccess(fieldName, "$write"); + + transformation.claimField(fieldName, parameter); + + replay(); + + new ParameterWorker().transform(transformation, model); + + verify(); + } + + private final void train_required(Parameter parameter, boolean required) + { + parameter.required(); + setReturnValue(required); + } + + private void train_cache(Parameter parameter, boolean cache) + { + parameter.cache(); + setReturnValue(cache); + } +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java Fri Sep 1 17:43:45 2006 @@ -32,7 +32,7 @@ ClassTransformation ct = newClassTransformation(); MutableComponentModel model = newMutableComponentModel(); - trainFindFieldsWithAnnotation(ct, Retain.class); + train_findFieldsWithAnnotation(ct, Retain.class); replay(); @@ -50,9 +50,9 @@ MutableComponentModel model = newMutableComponentModel(); Retain annotation = newMock(Retain.class); - trainFindFieldsWithAnnotation(ct, Retain.class, "fred"); + train_findFieldsWithAnnotation(ct, Retain.class, "fred"); - trainGetFieldAnnotation(ct, "fred", Retain.class, annotation); + train_getFieldAnnotation(ct, "fred", Retain.class, annotation); ct.claimField("fred", annotation); Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java Fri Sep 1 17:43:45 2006 @@ -36,7 +36,7 @@ ClassTransformation ct = newClassTransformation(); MutableComponentModel model = newMutableComponentModel(); - trainFindUnclaimedFields(ct); + train_findUnclaimedFields(ct); replay(); @@ -51,7 +51,7 @@ ClassTransformation ct = newClassTransformation(); MutableComponentModel model = newMutableComponentModel(); - trainFindUnclaimedFields(ct, "_fred"); + train_findUnclaimedFields(ct, "_fred"); ct.getFieldType("_fred"); setReturnValue("foo.Bar"); 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Fri Sep 1 17:43:45 2006 @@ -1,3 +1,17 @@ +// Copyright 2006 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.tapestry.internal.structure; import org.apache.tapestry.Binding; @@ -89,9 +103,27 @@ verify(); } - protected final ComponentModel newComponentModel() + @Test + public void write_binding() { - return newMock(ComponentModel.class); + Page page = newPage(); + ComponentLifecycle component = newComponentLifecycle(); + Instantiator ins = newInstantiator(component); + ComponentModel model = newComponentModel(); + + Binding binding = newBinding(); + + binding.set(23); + + replay(); + + ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, model); + + cpe.addParameter("barney", binding); + + cpe.writeParameter("barney", 23); + + verify(); } private Instantiator newInstantiator(ComponentLifecycle component) Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java?rev=439507&view=auto ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java Fri Sep 1 17:43:45 2006 @@ -0,0 +1,72 @@ +// Copyright 2006 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.tapestry.internal.test; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * @author Howard M. Lewis Ship + */ +public class CodeEqTest extends Assert +{ + @Test(dataProvider = "stripValues") + public void strip(String input, String expected) + { + assertEquals(CodeEq.strip(input), expected); + } + + @DataProvider(name = "stripValues") + public Object[][] stripValues() + { + return new Object[][] + { + { "foo", "foo" }, + { " foo\n", "foo" }, + { " foo \nbar\n\n \tbaz", "foo bar baz" }, + { "{\n bar();\n baz();\n if (gnip())\n {\n gnop();\n }\n}\n", + "{bar(); baz(); if (gnip()){gnop();}}" } }; + } + + @Test + public void to_string() + { + CodeEq eq = new CodeEq("{ foo(); bar(); baz(); }"); + + StringBuffer buffer = new StringBuffer(); + + eq.appendTo(buffer); + + assertEquals(buffer.toString(), "codeEq({foo(); bar(); baz();})"); + } + + @Test(dataProvider = "matchValues") + public void matches(String pattern, String parameter, boolean matches) + { + CodeEq ceq = new CodeEq(pattern); + + assertEquals(ceq.matches(parameter), matches); + } + + @DataProvider(name = "matchValues") + public Object[][] matchValues() + { + return new Object[][] + { + { "{ foo(); }", "{\n foo();\n}", true }, + { " foo();", "foo ();", false }, }; + } +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html Fri Sep 1 17:43:45 2006 @@ -5,4 +5,8 @@ <t:comp id="hello" type="HelloWorld"/> </t:comp> </p> + <p> + Here's some output from the Output component: + <t:comp id="output" type="Output" value="Yep, we have basic parameters working."/> + </p> </t:comp> From commitsbrandon51@example.net Sat Sep 02 00:44:32 2006 Return-Path: <commitsbrandon51@example.net> Delivered-To: brandon51@example.net Received: (qmail 82283 invoked from network); 2 Sep 2006 00:44:32 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 2 Sep 2006 00:44:32 -0000 Received: (qmail 25949 invoked by uid 500); 2 Sep 2006 00:44:32 -0000 Delivered-To: brandon51@example.net Received: (qmail 25646 invoked by uid 500); 2 Sep 2006 00:44:31 -0000 Mailing-List: contact brandon51@example.net; run by ezmlm Precedence: bulk List-Help: <mailto:brandon51@example.net> List-Unsubscribe: <mailto:brandon51@example.net> List-Post: <mailto:brandon51@example.net> List-Id: <commits.tapestry.apache.org> Reply-To: brandon51@example.net Delivered-To: mailing list brandon51@example.net Received: (qmail 25637 invoked by uid 99); 2 Sep 2006 00:44:30 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 17:44:30 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [83.161.120.155] (HELO eris.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 17:44:26 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id A41961A981A; Fri, 1 Sep 2006 17:44:05 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r439507 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/aspect/org/apache/tapestry/internal/aspects/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/ioc/... Date: Sat, 02 Sep 2006 00:43:50 -0000 To: brandon51@example.net From: brandon51@example.net X-Mailer: svnmailer-1.0.8 Message-Id: <brandon51@example.net> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: hlship Date: Fri Sep 1 17:43:45 2006 New Revision: 439507 URL: http://svn.apache.org/viewvc?rev=439507&view=rev Log: Change the naming of EasyMock trainer methods to start with "train_" (allowing the next character to be lower case, to match the name of the method being trained). Finish initial pass at the ParameterWorker and its corresponding test. Create the CodeEq EasyMock arguments matcher, used for comparing expected vs. actual Javassist method bodies without being overly concerned about whitespace. Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ModelMessages.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MethodCompileException.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/CodeEq.java tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/model/ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/model/ModelStrings.properties tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Output.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java Removed: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/FieldEncapsulation.java Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/CatchNullParameters.aj tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAdapterImpl.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/model/ParameterModelImpl.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/ParameterWorker.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/ComponentPageElementImpl.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.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/test/BaseTestCase.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TestBase.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/Start.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ContributionDefImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/InterceptorStackBuilderTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ModuleImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/OneShortServiceCreatorTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceBuilderMethodInvokerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/ServiceDecoratorImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/SingletonServiceLifecycleTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/MasterObjectProvideTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceLoggerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceObjectProviderTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.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/ComponentTemplateSourceImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.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/PagePoolImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/CatchNullParameters.aj URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/CatchNullParameters.aj?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/CatchNullParameters.aj (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/aspect/org/apache/tapestry/internal/aspects/CatchNullParameters.aj Fri Sep 1 17:43:45 2006 @@ -31,12 +31,12 @@ !within(@SuppressNullCheck Object+); /** - * Look for non-private methods and constructors that do NOT have the SuppressNullCheck + * Look for public methods (instance and static) and constructors that do NOT have the SuppressNullCheck * annotation. */ pointcut executionNotSuppressed() : - execution(!@SuppressNullCheck !private * *(..)) || - execution(!@SuppressNullCheck !private new(..)); + execution(!@SuppressNullCheck public * *(..)) || + execution(!@SuppressNullCheck public new(..)); /** * Exclude methods (and constructors) with no parameters. Also, exclude equals() since it has to Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java Fri Sep 1 17:43:45 2006 @@ -1,3 +1,17 @@ +// Copyright 2006 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.tapestry.annotations; import java.lang.annotation.Documented; Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java Fri Sep 1 17:43:45 2006 @@ -41,6 +41,18 @@ <T> T readParameter(String parameterName, Class<T> expectedType); /** + * Updates a parameter. It is an error to update a parameter which is not bound. The parameter + * {@link org.apache.tapestry.Binding binding} may also not support updates. + * + * @param <T> + * @param parameterName + * of parameter to update + * @param parameterValue + * new value (which may be null) + */ + <T> void writeParameter(String parameterName, T parameterValue); + + /** * Returns true if the named parameter's {@link org.apache.tapestry.Binding} is invariant, false * if otherwise, or if the parameter is not bound. Invariant bindings are cached more * aggresively than variant bindings. Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAdapterImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAdapterImpl.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAdapterImpl.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/PropertyAdapterImpl.java Fri Sep 1 17:43:45 2006 @@ -99,7 +99,7 @@ fail = ex; } - throw new RuntimeException(ServiceMessages.readFailure(_name, instance, fail)); + throw new RuntimeException(ServiceMessages.readFailure(_name, instance, fail), fail); } public void set(Object instance, Object value) @@ -126,7 +126,7 @@ fail = ex; } - throw new RuntimeException(ServiceMessages.writeFailure(_name, instance, fail)); + throw new RuntimeException(ServiceMessages.writeFailure(_name, instance, fail), fail); } } Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ModelMessages.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ModelMessages.java?rev=439507&view=auto ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ModelMessages.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ModelMessages.java Fri Sep 1 17:43:45 2006 @@ -0,0 +1,33 @@ +// Copyright 2006 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.tapestry.internal.model; + +import org.apache.tapestry.Messages; +import org.apache.tapestry.internal.MessagesImpl; +import org.apache.tapestry.internal.annotations.Utility; + +/** + * @author Howard M. Lewis Ship + */ +@Utility +class ModelMessages +{ + private final static Messages MESSAGES = MessagesImpl.forClass(ModelMessages.class); + + static String duplicateParameter(String parameterName, String componentName) + { + return MESSAGES.format("duplicate-parameter", parameterName, componentName); + } +} 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Fri Sep 1 17:43:45 2006 @@ -49,6 +49,12 @@ _baseResource = baseResource; } + @Override + public String toString() + { + return String.format("ComponentModel[%s]", _componentClassName); + } + public Log getLog() { return _log; @@ -73,7 +79,9 @@ else { if (_parameters.containsKey(name)) - throw new IllegalArgumentException(); + throw new IllegalArgumentException(ModelMessages.duplicateParameter( + name, + _componentClassName)); } Defense.notBlank(name, "name"); Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/ParameterModelImpl.java Fri Sep 1 17:43:45 2006 @@ -1,3 +1,17 @@ +// Copyright 2006 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.tapestry.internal.model; import org.apache.tapestry.model.ParameterModel; 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -24,6 +24,7 @@ import javassist.CannotCompileException; import javassist.ClassPool; +import javassist.CtBehavior; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; @@ -32,6 +33,8 @@ import javassist.CtNewConstructor; import javassist.CtNewMethod; import javassist.NotFoundException; +import javassist.expr.ExprEditor; +import javassist.expr.FieldAccess; import org.apache.tapestry.ComponentResources; import org.apache.tapestry.internal.InternalComponentResources; @@ -63,12 +66,8 @@ private final ClassPool _classPool; - // private Set<CtMethod> _addedMethods = newSet(); - private final IdAllocator _idAllocator; - // private final Map<CtField, FieldEncapsulation> _encapsulations = newMap(); - /** Map from a field to the annotation objects for that field. */ private Map<String, List<Annotation>> _fieldAnnotations = newMap(); @@ -77,7 +76,7 @@ private Set<String> _addedFieldNames = newSet(); - private Set<CtMethod> _addedMethods = newSet(); + private Set<CtBehavior> _addedMethods = newSet(); // Cache of class annotations @@ -89,18 +88,23 @@ private Map<CtMethod, MethodSignature> _methodSignatures = newMap(); + // Key is field name, value is expression used to replace read access + + private Map<String, String> _fieldReadTransforms; + + // Key is field name, value is expression used to replace read access + private Map<String, String> _fieldWriteTransforms; + /** Contains the assembled Javassist code for the class' default constructor. */ private StringBuilder _constructor = new StringBuilder(); private final List<ConstructorArg> _constructorArgs; - // All field/method names will have this value as a prefix - private final String _resourcesFieldName; private final StringBuilder _description = new StringBuilder(); - private final Formatter _formatter = new Formatter(_description); + private Formatter _formatter = new Formatter(_description); /** * This is a constructor for the root class, the class that directly contains the ComponentClass @@ -164,6 +168,26 @@ } + private void freeze() + { + _frozen = true; + + // Free up stuff we don't need after freezing. + // Everything else should be final. + + _fieldAnnotations = null; + _claimedFields = null; + _addedFieldNames = null; + _addedMethods = null; + _classAnnotations = null; + _methodAnnotations = null; + _methodSignatures = null; + _fieldReadTransforms = null; + _fieldWriteTransforms = null; + _constructor = null; + _formatter = null; + } + public String getResourcesFieldName() { return _resourcesFieldName; @@ -446,15 +470,23 @@ // TODO: Check for duplicate method add + method.setModifiers(signature.getModifiers()); + try { - method.setModifiers(signature.getModifiers()); method.setBody(methodBody); method.setExceptionTypes(exceptions); _ctClass.addMethod(method); } - catch (Exception ex) + catch (CannotCompileException ex) + { + throw new MethodCompileException(ServicesMessages.methodCompileError( + signature, + methodBody, + ex), methodBody, ex); + } + catch (NotFoundException ex) { throw new RuntimeException(ex); } @@ -759,6 +791,7 @@ catch (NotFoundException ex) { throw new RuntimeException(ex); + } } @@ -818,7 +851,7 @@ _constructorArgs.add(new ConstructorArg(ctType, value)); - _constructor.append(format("%s = $%d;\n", fieldName, _constructorArgs.size())); + _constructor.append(format(" %s = $%d;\n", fieldName, _constructorArgs.size())); return fieldName; } @@ -832,6 +865,15 @@ { failIfFrozen(); + performFieldTransformations(); + + addConstructor(); + + freeze(); + } + + private void addConstructor() + { int count = _constructorArgs.size(); CtClass[] types = new CtClass[count]; @@ -861,7 +903,6 @@ for (int i = 0; i < count; i++) { - if (i > 0) _description.append(", "); @@ -869,18 +910,6 @@ } _formatter.format(")\n%s\n\n", constructorBody); - - _frozen = true; - - // Free up stuff we don't need after freezing. - - // _addedMethods = null; - _claimedFields = null; - _addedFieldNames = null; - _fieldAnnotations = null; - _constructor = null; - _methodAnnotations = null; - _methodSignatures = null; } public Instantiator createInstantiator(Class componentClass) @@ -937,6 +966,8 @@ public List<Annotation> getClassAnnotations() { + failIfFrozen(); + if (_classAnnotations == null) assembleClassAnnotations(); @@ -1001,6 +1032,81 @@ builder.append("]"); return builder.toString(); + } + + public void replaceReadAccess(String fieldName, String methodName) + { + String body = String.format("$_ = %s();", methodName); + + if (_fieldReadTransforms == null) + _fieldReadTransforms = newMap(); + + // TODO: Collisions? + + _fieldReadTransforms.put(fieldName, body); + + _formatter.format("replace read %s: %s();\n\n", fieldName, methodName); + } + + public void replaceWriteAccess(String fieldName, String methodName) + { + String body = String.format("%s($1);", methodName); + + if (_fieldWriteTransforms == null) + _fieldWriteTransforms = newMap(); + + // TODO: Collisions? + + _fieldWriteTransforms.put(fieldName, body); + + _formatter.format("replace write %s: %s();\n\n", fieldName, methodName); + } + + private void performFieldTransformations() + { + // If no field transformations have been requested, then we can save ourselves some + // trouble! + if (_fieldReadTransforms == null && _fieldWriteTransforms == null) + return; + + // Provide empty maps here, to make the code in the inner class a tad + // easier. + + if (_fieldReadTransforms == null) + _fieldReadTransforms = newMap(); + + if (_fieldWriteTransforms == null) + _fieldWriteTransforms = newMap(); + + ExprEditor editor = new ExprEditor() + { + @Override + public void edit(FieldAccess access) throws CannotCompileException + { + // Ignore any methods to were added as part of the transformation. + // If we reference the field there, we really mean the field. + + if (_addedMethods.contains(access.where())) + return; + + Map<String, String> transformMap = access.isReader() ? _fieldReadTransforms + : _fieldWriteTransforms; + + String body = transformMap.get(access.getFieldName()); + + if (body != null) + access.replace(body); + } + }; + + try + { + _ctClass.instrument(editor); + } + catch (CannotCompileException ex) + { + throw new RuntimeException(ex); + } } } Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MethodCompileException.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MethodCompileException.java?rev=439507&view=auto ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MethodCompileException.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MethodCompileException.java Fri Sep 1 17:43:45 2006 @@ -0,0 +1,40 @@ +// Copyright 2006 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.tapestry.internal.services; + +/** + * Exception thrown when a method body fails to compile; this will allow the method body to be + * displayed to the user on the request failure page. + * + * @author Howard M. Lewis Ship + */ +public class MethodCompileException extends RuntimeException +{ + private static final long serialVersionUID = -2803586049370974986L; + + private final String _methodBody; + + public MethodCompileException(String message, String methodBody, Throwable cause) + { + super(message, cause); + + _methodBody = methodBody; + } + + public String getMethodBody() + { + return _methodBody; + } +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java Fri Sep 1 17:43:45 2006 @@ -1,7 +1,22 @@ +// Copyright 2006 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.tapestry.internal.services; import java.lang.reflect.Modifier; import java.util.List; +import java.util.Map; import org.apache.tapestry.annotations.Parameter; import org.apache.tapestry.internal.ioc.IOCUtilities; @@ -9,17 +24,33 @@ import org.apache.tapestry.model.MutableComponentModel; 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.util.BodyBuilder; +import static org.apache.tapestry.util.CollectionFactory.newMap; + /** * Responsible for identifying parameters via the {@link org.apache.tapestry.annotations.Parameter} - * annotation on component fields. + * annotation on component fields. This is one of the most complex of the transformations. * * @author Howard M. Lewis Ship */ public class ParameterWorker implements ComponentClassTransformWorker { + private static final Map<String, String> PRIMITIVE_TO_WRAPPER = newMap(); + + static + { + PRIMITIVE_TO_WRAPPER.put("boolean", "java.lang.Boolean"); + PRIMITIVE_TO_WRAPPER.put("char", "java.lang.Character"); + PRIMITIVE_TO_WRAPPER.put("byte", "java.lang.Byte"); + PRIMITIVE_TO_WRAPPER.put("short", "java.lang.Short"); + PRIMITIVE_TO_WRAPPER.put("int", "java.lang.Integer"); + PRIMITIVE_TO_WRAPPER.put("long", "java.lang.Long"); + PRIMITIVE_TO_WRAPPER.put("float", "java.lang.Float"); + PRIMITIVE_TO_WRAPPER.put("double", "java.lang.Double"); + } public void transform(ClassTransformation transformation, MutableComponentModel model) { @@ -27,42 +58,72 @@ for (String name : fieldNames) { - Parameter annotation = transformation.getFieldAnnotation(name, Parameter.class); + convertFieldIntoParameter(name, transformation, model); + } + } - model.addParameter(name, annotation.required()); + private void convertFieldIntoParameter(String name, ClassTransformation transformation, + MutableComponentModel model) + { + Parameter annotation = transformation.getFieldAnnotation(name, Parameter.class); - String parameterName = getParameterName(name, annotation.name()); + String parameterName = getParameterName(name, annotation.name()); - String type = transformation.getFieldType(name); + model.addParameter(parameterName, annotation.required()); - String cachedFieldName = transformation.addField(Modifier.PRIVATE, "boolean", name - + "_cached"); + String type = transformation.getFieldType(name); - String invariantFieldName = addParameterSetup( - name, - parameterName, - cachedFieldName, - transformation); - } + boolean cache = annotation.cache(); + + String cachedFieldName = transformation.addField(Modifier.PRIVATE, "boolean", name + + "_cached"); + + String resourcesFieldName = transformation.getResourcesFieldName(); + + String invariantFieldName = addParameterSetup( + name, + parameterName, + cachedFieldName, + resourcesFieldName, + transformation); + + addReaderMethod( + name, + cachedFieldName, + invariantFieldName, + cache, + parameterName, + type, + resourcesFieldName, + transformation); + + addWriterMethod( + name, + cachedFieldName, + cache, + parameterName, + type, + resourcesFieldName, + transformation); + + transformation.claimField(name, annotation); } /** Returns the name of a field that stores whether the parameter binding is invariant. */ private String addParameterSetup(String fieldName, String parameterName, - String cachedFieldName, ClassTransformation transformation) + String cachedFieldName, String resourcesFieldName, ClassTransformation transformation) { String name = transformation .addField(Modifier.PRIVATE, "boolean", fieldName + "_invariant"); - String resourcesFieldName = transformation.getResourcesFieldName(); - String body = String.format( "%s = %s.isInvariant(\"%s\");", name, resourcesFieldName, parameterName); - transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE, body); + transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, body); // Now, when the page detaches, ensure that any variant parameters are // are returned to default value. @@ -84,22 +145,67 @@ return name; } - private void addCachedReader(String fieldName, String cachedFieldName, - String invariantFieldName, boolean cache, String parameterName, String fieldType, + private void addWriterMethod(String fieldName, String cachedFieldName, boolean cache, + String parameterName, String fieldType, String resourcesFieldName, ClassTransformation transformation) { BodyBuilder builder = new BodyBuilder(); builder.begin(); + // Always start by updating the parameter; this will implicitly check for + // read-only or unbound parameters. $1 is the single parameter + // to the method. + + builder.addln("%s.writeParameter(\"%s\", ($w)$1);", resourcesFieldName, parameterName); + + // The method won't get this far if it is readonly or invariant. + // If caching, then stuff the value into the instance variable for later + // access by the read method. If not caching, there's no point, since we're + // just going to read the binding again as needed. + + if (cache) + { + builder.addln("if (%s.isRendering())", resourcesFieldName); + builder.begin(); + builder.addln("%s = $1;", fieldName); + builder.addln("%s = true;", cachedFieldName); + builder.end(); + } + + builder.end(); + + String methodName = transformation.newMemberName("_update_parameter_" + parameterName); + + MethodSignature signature = new MethodSignature(Modifier.PRIVATE, "void", methodName, + new String[] + { fieldType }, null); + + transformation.addMethod(signature, builder.toString()); + + transformation.replaceWriteAccess(fieldName, methodName); + } + + /** Adds a private method that will be the replacement for read-access to the field. */ + private void addReaderMethod(String fieldName, String cachedFieldName, + String invariantFieldName, boolean cache, String parameterName, String fieldType, + String resourcesFieldName, ClassTransformation transformation) + { + BodyBuilder builder = new BodyBuilder(); + builder.begin(); + builder.addln("if (%s) return %s;", cachedFieldName, fieldName); - // TODO: Handle primitive types + String cast = PRIMITIVE_TO_WRAPPER.containsKey(fieldType) ? PRIMITIVE_TO_WRAPPER + .get(fieldType) : fieldType; - String resourcesFieldName = transformation.getResourcesFieldName(); + // The ($r) cast will convert the result to the method return type; generally + // this does nothing. but for primitive types, it will unwrap + // the wrapper type back to a primitive. builder.addln( - "%s result = (%1$s) %s.getParameter(\"%s\", %1$s.class);", + "%s result = ($r) ((%s) %s.readParameter(\"%s\", $type));", fieldType, + cast, resourcesFieldName, parameterName); @@ -119,6 +225,16 @@ builder.end(); builder.addln("return result;"); + builder.end(); + + String methodName = transformation.newMemberName("_read_parameter_" + parameterName); + + MethodSignature signature = new MethodSignature(Modifier.PRIVATE, fieldType, methodName, + null, null); + + transformation.addMethod(signature, builder.toString()); + + transformation.replaceReadAccess(fieldName, methodName); } private String getParameterName(String fieldName, String annotatedName) 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -117,9 +117,14 @@ { return MESSAGES.format("content-inside-body-not-allowed", location); } - + static String mayNotNestElementsInsideBody(String elementName) { return MESSAGES.format("may-not-nest-elements-inside-body", elementName); + } + + static String methodCompileError(MethodSignature signature, String methodBody, Throwable cause) + { + return MESSAGES.format("method-compile-error", signature, methodBody, cause); } } 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -68,6 +68,8 @@ private Map<String, Binding> _bindings; + private boolean _rendering; + /** Constructor for the root component of a page. */ public ComponentPageElementImpl(Page page, Instantiator instantiator, ComponentModel model) { @@ -88,7 +90,6 @@ * @param container * component immediately containing this component * @param id - * unique id (within the container) for this component * @param instantiator * used to create the new component instance * @param model @@ -211,6 +212,8 @@ @SuppressNullCheck public void render(MarkupWriter writer, RenderQueue queue) { + _rendering = true; + LifecycleEvent<Boolean> event = newEvent(true); _component.beforeRender(writer, event); @@ -303,6 +306,12 @@ queue.push(this); queue.push(_beforeRender); } + else + { + _rendering = false; + + _component.cleanupAfterRender(); + } } @Override @@ -396,9 +405,25 @@ // TODO: If binding is null ... - // TODO: Type coercion when writing value into binding + // TODO: Type coercion to expected type return expectedType.cast(b.get()); + } + + public <T> void writeParameter(String parameterName, T parameterValue) + { + Binding b = getBinding(parameterName); + + // TODO: If binding is null ... + + // TODO: Type coercion when writing value into binding + + b.set(parameterValue); + } + + public boolean isRendering() + { + return _rendering; } } Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/CodeEq.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/CodeEq.java?rev=439507&view=auto ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/CodeEq.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/CodeEq.java Fri Sep 1 17:43:45 2006 @@ -0,0 +1,65 @@ +// Copyright 2006 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.tapestry.internal.test; + +import org.easymock.IArgumentMatcher; + +import static org.easymock.EasyMock.reportMatcher; + +/** + * Special version of string equality used to compare two snippets of code. This is somewhat + * simpleminded (it certainly doesn't understand about literal strings in quotes). It works by + * eliminating unecessary whitespace around curly braces, then reducing all whitespace to a single + * space. + * + * @author Howard M. Lewis Ship + */ +public class CodeEq implements IArgumentMatcher +{ + private String _code; + + public CodeEq(String input) + { + _code = strip(input); + } + + public boolean matches(Object argument) + { + String string = (String) argument; + String stripped = strip(string); + + return _code.equals(stripped); + } + + public void appendTo(StringBuffer buffer) + { + buffer.append("codeEq("); + buffer.append(_code); + buffer.append(")"); + } + + public static String codeEq(String input) + { + reportMatcher(new CodeEq(input)); + + return null; + } + + static String strip(String input) + { + return input.trim().replaceAll("\\s*\\{\\s*", "{").replaceAll("\\s*\\}\\s*", "}") + .replaceAll("\\s+", " "); + } +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Fri Sep 1 17:43:45 2006 @@ -17,6 +17,7 @@ import java.util.List; import java.util.Locale; +import org.apache.tapestry.Resource; import org.apache.tapestry.internal.InternalComponentResources; import org.apache.tapestry.internal.annotations.SuppressNullCheck; import org.apache.tapestry.internal.ioc.InternalRegistry; @@ -25,6 +26,7 @@ import org.apache.tapestry.internal.services.ComponentInstantiatorSource; import org.apache.tapestry.internal.services.PageLoader; import org.apache.tapestry.internal.services.PagePool; +import org.apache.tapestry.internal.services.TemplateParser; import org.apache.tapestry.internal.structure.Page; import org.apache.tapestry.ioc.ObjectProvider; import org.apache.tapestry.ioc.Registry; @@ -36,8 +38,9 @@ import org.apache.tapestry.runtime.ComponentLifecycle; import org.apache.tapestry.runtime.RenderQueue; import org.apache.tapestry.test.BaseTestCase; -import org.apache.tapestry.util.CollectionFactory; -import org.easymock.EasyMock; + +import static org.apache.tapestry.util.CollectionFactory.newList; +import static org.easymock.EasyMock.isA; /** * Contains additional factory and training methods related to internal interfaces. @@ -58,7 +61,7 @@ return newMock(ComponentTemplate.class); } - protected final <T> void trainGetService(InternalRegistry registry, String serviceId, + protected final <T> void train_getService(InternalRegistry registry, String serviceId, Class<T> serviceInterface, Module module, T service) { registry.getService(serviceId, serviceInterface, module); @@ -66,24 +69,24 @@ } - protected final void trainGetLifecycle(InternalRegistry registry, String name, + protected final void train_getLifecycle(InternalRegistry registry, String name, ServiceLifecycle lifecycle) { registry.getServiceLifecycle(name); setReturnValue(lifecycle); } - protected final void trainFindDecoratorsForService(Module module, String serviceId, + protected final void train_findDecoratorsForService(Module module, String serviceId, List<ServiceDecorator> decorators) { module.findDecoratorsForService(serviceId); setReturnValue(decorators); } - protected void trainFindDecoratorsForService(InternalRegistry registry) + protected final void train_findDecoratorsForService(InternalRegistry registry) { - registry.findDecoratorsForService(EasyMock.isA(ServiceDef.class)); - setReturnValue(CollectionFactory.newList()); + registry.findDecoratorsForService(isA(ServiceDef.class)); + setReturnValue(newList()); } protected final InternalRegistry newInternalRegistry() @@ -104,7 +107,8 @@ return newMock(ObjectProvider.class); } - protected final <T> void trainProvide(ObjectProvider provider, String expression, Class<T> objectType, ServiceLocator locator, T object) + protected final <T> void train_provide(ObjectProvider provider, String expression, + Class<T> objectType, ServiceLocator locator, T object) { provider.provide(expression, objectType, locator); setReturnValue(object); @@ -135,13 +139,13 @@ return newMock(PageLoader.class); } - protected final void trainLoadPage(PageLoader loader, String pageName, Locale locale, Page page) + protected final void train_loadPage(PageLoader loader, String pageName, Locale locale, Page page) { loader.loadPage(pageName, locale); setReturnValue(page); } - protected final void trainGetName(Page page, String name) + protected final void train_getName(Page page, String name) { page.getName(); setReturnValue(name); @@ -155,5 +159,16 @@ protected RenderQueue newRenderQueue() { return newMock(RenderQueue.class); + } + + protected final void train_parseTemplate(TemplateParser parser, Resource resource, ComponentTemplate template) + { + parser.parseTemplate(resource); + setReturnValue(template); + } + + protected final TemplateParser newTemplateParser() + { + return newMock(TemplateParser.class); } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ParameterModel.java Fri Sep 1 17:43:45 2006 @@ -1,3 +1,17 @@ +// Copyright 2006 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.tapestry.model; /** 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -200,4 +200,18 @@ /** Adds a new method to the transformed class. */ void addMethod(MethodSignature signature, String methodBody); + + /** + * Replaces all read-references to the specified field with invocations of the specified method + * name. Replacements do not occur in methods added via + * {@link #addMethod(MethodSignature, String)}. + */ + void replaceReadAccess(String fieldName, String methodName); + + /** + * Replaces all write accesses to the specified field with invocations of the specified method + * name. The method should take a single parameter of the same type as the field. Replacements + * do not occur in methods added via {@link #addMethod(MethodSignature, String)}. + */ + void replaceWriteAccess(String fieldName, String methodName); } 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?rev=439507&r1=439506&r2=439507&view=diff ============================================================================== --- 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 Sep 1 17:43:45 2006 @@ -31,6 +31,8 @@ import org.apache.tapestry.ComponentResources; import org.apache.tapestry.Location; import org.apache.tapestry.Resource; +import org.apache.tapestry.annotations.BeforeRender; +import org.apache.tapestry.annotations.Parameter; import org.apache.tapestry.internal.annotations.SuppressNullCheck; import org.apache.tapestry.ioc.Configuration; import org.apache.tapestry.ioc.LogSource; @@ -45,12 +47,16 @@ import org.apache.tapestry.ioc.def.DecoratorDef; import org.apache.tapestry.ioc.def.ModuleDef; import org.apache.tapestry.ioc.def.ServiceDef; +import org.apache.tapestry.model.ComponentModel; import org.apache.tapestry.model.MutableComponentModel; import org.apache.tapestry.services.BindingFactory; import org.apache.tapestry.services.ClassTransformation; import org.apache.tapestry.services.ComponentClassResolver; +import org.apache.tapestry.services.MethodSignature; import static java.lang.Thread.sleep; +import static org.apache.tapestry.internal.test.CodeEq.codeEq; +import static org.easymock.EasyMock.eq; /** * Base test case that adds a number of convienience factory and training methods to @@ -61,20 +67,20 @@ @SuppressNullCheck public abstract class BaseTestCase extends TestBase { - protected final void trainFindFieldsWithAnnotation(ClassTransformation transformation, + protected final void train_findFieldsWithAnnotation(ClassTransformation transformation, Class<? extends Annotation> annotationClass, String... fieldNames) { - trainFindFieldsWithAnnotation(transformation, annotationClass, Arrays.asList(fieldNames)); + train_findFieldsWithAnnotation(transformation, annotationClass, Arrays.asList(fieldNames)); } - protected final void trainFindFieldsWithAnnotation(ClassTransformation transformation, + protected final void train_findFieldsWithAnnotation(ClassTransformation transformation, Class<? extends Annotation> annotationClass, List<String> fieldNames) { transformation.findFieldsWithAnnotation(annotationClass); setReturnValue(fieldNames); } - protected final <T extends Annotation> void trainGetFieldAnnotation( + protected final <T extends Annotation> void train_getFieldAnnotation( ClassTransformation transformation, String fieldName, Class<T> annotationClass, T annotation) { @@ -92,14 +98,14 @@ return newMock(ClassTransformation.class); } - protected final void trainAddInjectedField(ClassTransformation ct, Class type, + protected final void train_addInjectedField(ClassTransformation ct, Class type, String suggestedName, Object value, String fieldName) { ct.addInjectedField(type, suggestedName, value); setReturnValue(fieldName); } - protected final void trainFindUnclaimedFields(ClassTransformation transformation, + protected final void train_findUnclaimedFields(ClassTransformation transformation, String... fieldNames) { transformation.findUnclaimedFields(); @@ -163,13 +169,13 @@ return newMock(Resource.class); } - protected final void trainGetServiceInterface(ServiceDef def, Class serviceInterface) + protected final void train_getServiceInterface(ServiceDef def, Class serviceInterface) { def.getServiceInterface(); setReturnValue(serviceInterface); } - protected final void trainGetServiceId(ServiceDef def, String serviceId) + protected final void train_getServiceId(ServiceDef def, String serviceId) { def.getServiceId(); setReturnValue(serviceId); @@ -185,28 +191,28 @@ return newMock(ServiceDef.class); } - protected final void trainGetServiceLog(ServiceResources resources, Log log) + protected final void train_getServiceLog(ServiceResources resources, Log log) { resources.getServiceLog(); setReturnValue(log); } - protected final <T> void trainGetService(ServiceLocator locator, String serviceId, + protected final <T> void train_getService(ServiceLocator locator, String serviceId, Class<T> serviceInterface, T service) { locator.getService(serviceId, serviceInterface); setReturnValue(service); } - protected final <T> void trainGetService(ServiceLocator locator, Class<T> serviceInterface, + protected final <T> void train_getService(ServiceLocator locator, Class<T> serviceInterface, T service) { locator.getService(serviceInterface); setReturnValue(service); } - protected final void trainCreateService(ObjectCreator creator, Object service) + protected final void train_greateService(ObjectCreator creator, Object service) { creator.createObject(); setReturnValue(service); @@ -217,19 +223,20 @@ return newMock(ObjectCreator.class); } - protected final void trainGetServiceInterface(ServiceResources resources, Class serviceInterface) + protected final void train_getServiceInterface(ServiceResources resources, + Class serviceInterface) { resources.getServiceInterface(); setReturnValue(serviceInterface); } - protected final void trainGetServiceId(ServiceResources resources, String serviceId) + protected final void train_getServiceId(ServiceResources resources, String serviceId) { resources.getServiceId(); setReturnValue(serviceId); } - protected final void trainCreateInterceptor(ServiceDecorator decorator, Object coreObject, + protected final void train_createInterceptor(ServiceDecorator decorator, Object coreObject, Object interceptor) { decorator.createInterceptor(coreObject); @@ -241,7 +248,7 @@ return newMock(ServiceDecorator.class); } - protected final void trainGetLog(LogSource source, String serviceId, Log log) + protected final void train_getLog(LogSource source, String serviceId, Log log) { source.getLog(serviceId); setReturnValue(log); @@ -303,7 +310,7 @@ return newMock(ServiceBuilderResources.class); } - protected final void trainGetModuleId(ModuleDef def, String moduleId) + protected final void train_getModuleId(ModuleDef def, String moduleId) { def.getModuleId(); setReturnValue(moduleId); @@ -314,7 +321,7 @@ return newMock(ModuleDef.class); } - protected final void trainMatches(DecoratorDef decoratorDef, ServiceDef serviceDef, + protected final void train_matches(DecoratorDef decoratorDef, ServiceDef serviceDef, boolean matches) { decoratorDef.matches(serviceDef); @@ -356,7 +363,8 @@ return newMock(ComponentClassResolver.class); } - protected final void trainNewBinding(BindingFactory factory, String description, ComponentResources component, String expression, Location l, Binding b) + protected final void train_newBinding(BindingFactory factory, String description, + ComponentResources component, String expression, Location l, Binding b) { factory.newBinding(description, component, expression, l); setReturnValue(b); @@ -375,5 +383,63 @@ protected final BindingFactory newBindingFactory() { return newMock(BindingFactory.class); + } + + protected final ComponentModel newComponentModel() + { + return newMock(ComponentModel.class); + } + + protected final void train_addMethod(ClassTransformation transformation, + MethodSignature signature, String... body) + { + transformation.addMethod(eq(signature), codeEq(join(body))); + } + + protected final void train_newMemberName(ClassTransformation transformation, String suggested, + String name) + { + transformation.newMemberName(suggested); + setReturnValue(name); + } + + protected final void train_extendMethod(ClassTransformation transformation, + MethodSignature signature, String... body) + { + transformation.extendMethod(eq(signature), codeEq(join(body))); + } + + protected final void train_getResourcesFieldName(ClassTransformation transformation, String name) + { + transformation.getResourcesFieldName(); + setReturnValue(name); + } + + protected final void train_addField(ClassTransformation transformation, int modifiers, + String type, String suggestedName, String actualName) + { + transformation.addField(modifiers, type, suggestedName); + setReturnValue(actualName); + } + + protected final void train_getFieldType(ClassTransformation transformation, String
{'source': 'Apache Software Foundation Public Mail Archives'}