Return-Path: Delivered-To: apmail-tapestry-commits-archive@locus.apache.org Received: (qmail 17960 invoked from network); 5 Sep 2006 18:15:22 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 5 Sep 2006 18:15:22 -0000 Received: (qmail 9232 invoked by uid 500); 5 Sep 2006 18:15:21 -0000 Delivered-To: apmail-tapestry-commits-archive@tapestry.apache.org Received: (qmail 9216 invoked by uid 500); 5 Sep 2006 18:15:20 -0000 Mailing-List: contact commits-help@tapestry.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@tapestry.apache.org Delivered-To: mailing list commits@tapestry.apache.org Received: (qmail 9207 invoked by uid 99); 5 Sep 2006 18:15:20 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Sep 2006 11:15:20 -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 [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Sep 2006 11:15:17 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 3FAEC1A981A; Tue, 5 Sep 2006 11:14:56 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r440425 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/bindings/ main/java/org/apache/tapestry/internal/ioc/services/ main/java/org/apache/tapestry/interna... Date: Tue, 05 Sep 2006 18:14:55 -0000 To: commits@tapestry.apache.org From: hlship@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20060905181456.3FAEC1A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: hlship Date: Tue Sep 5 11:14:53 2006 New Revision: 440425 URL: http://svn.apache.org/viewvc?view=rev&rev=440425 Log: Add initial support for the @Inject annotation. Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Inject.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectionProvider.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/WriteWebRequest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectWorkerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformer.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.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/InternalModule.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/services/ClassTransformation.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.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/services/ReadOnlyBean.java Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Inject.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Inject.java?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Inject.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Inject.java Tue Sep 5 11:14:53 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.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Allows injection of various objects into a component class. + * + * @author Howard M. Lewis Ship + * @see org.apache.tapestry.internal.services.InjectionProvider + */ +@Target(FIELD) +@Documented +@Retention(RUNTIME) +public @interface Inject { + + /** + * Identifies the value to be injected, when the type by itself is insufficient. Omitted in many + * cases. + */ + String value() default ""; +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BasePropBinding.java Tue Sep 5 11:14:53 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.bindings; import org.apache.tapestry.Location; Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java Tue Sep 5 11:14:53 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.bindings; import java.lang.reflect.Constructor; Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ClassFactoryClassPool.java Tue Sep 5 11:14:53 2006 @@ -56,9 +56,9 @@ /** * Convienience method for adding to the ClassPath for a particular class loader. *

- * TODO: This code assumes that ClassLoaders are structured as a "line" not a proper "tree". That - * is, if the ClassLoader hiearchy actually does have branches, rather than a straight line from - * root to leaf, it may not work. + * TODO: This code assumes that ClassLoaders are structured as a "line" not a proper "tree". + * That is, if the ClassLoader hiearchy actually does have branches, rather than a straight line + * from root to leaf, it may not work. * * @param loader * the class loader to add (derived from a loaded class, and may be null for some @@ -87,6 +87,11 @@ } _loader = loader; + } + + public ClassLoader getLoader() + { + return _loader; } /** Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformer.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformer.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformer.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformer.java Tue Sep 5 11:14:53 2006 @@ -29,8 +29,14 @@ { /** * Performs a transformation on the class, accessing the class from the class pool. + * + * @param ctClass + * compile time class to be transformed + * @param classLoader + * class loader used to resolve references to other classes (both transformed and + * not) */ - void transformComponentClass(CtClass ctClass); + void transformComponentClass(CtClass ctClass, ClassLoader classLoader); /** Creates a new instantiator instance. */ Instantiator createInstantiator(Class componentClass); Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassTransformerImpl.java Tue Sep 5 11:14:53 2006 @@ -75,7 +75,7 @@ } @Concurrent.Write - public void transformComponentClass(CtClass ctClass) + public void transformComponentClass(CtClass ctClass, ClassLoader classLoader) { String classname = ctClass.getName(); @@ -99,8 +99,8 @@ // TODO: Check that the name is not already in the map. InternalClassTransformation transformation = parentTransformation == null ? new InternalClassTransformationImpl( - ctClass) - : new InternalClassTransformationImpl(ctClass, parentTransformation); + ctClass, classLoader) + : new InternalClassTransformationImpl(ctClass, parentTransformation, classLoader); // Not all classes in the packages are components. That's not just sloppy coding by // application developers, it also represents inner classes (including anonymous classes). Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java Tue Sep 5 11:14:53 2006 @@ -160,7 +160,7 @@ // Do the transformations here - _transformer.transformComponentClass(ctClass); + _transformer.transformComponentClass(ctClass, _loader); diag = "END"; } Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectWorker.java Tue Sep 5 11:14:53 2006 @@ -0,0 +1,95 @@ +// 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.annotations.Inject; +import org.apache.tapestry.internal.ioc.IOCUtilities; +import org.apache.tapestry.ioc.ObjectProvider; +import org.apache.tapestry.ioc.ServiceLocator; +import org.apache.tapestry.model.MutableComponentModel; +import org.apache.tapestry.services.ClassTransformation; +import org.apache.tapestry.services.ComponentClassTransformWorker; + +/** + * Worker for the {@link org.apache.tapestry.annotations.Inject} annotation. + * + * @author Howard M. Lewis Ship + */ +public class InjectWorker implements ComponentClassTransformWorker +{ + private final ObjectProvider _objectProvider; + + private final ServiceLocator _locator; + + // Really, a chain of command + + private final InjectionProvider _injectionProvider; + + public InjectWorker(ObjectProvider objectProvider, ServiceLocator locator, + InjectionProvider injectionProvider) + { + _objectProvider = objectProvider; + _locator = locator; + _injectionProvider = injectionProvider; + } + + public void transform(ClassTransformation transformation, MutableComponentModel model) + { + for (String fieldName : transformation.findFieldsWithAnnotation(Inject.class)) + { + Inject annotation = transformation.getFieldAnnotation(fieldName, Inject.class); + + String value = annotation.value(); + + if (IOCUtilities.isBlank(value)) + injectAnnonymous(fieldName, transformation, model); + else + injectNamed(fieldName, value, transformation, model); + + transformation.claimField(fieldName, annotation); + } + + } + + @SuppressWarnings("unchecked") + private void injectNamed(String fieldName, String value, ClassTransformation transformation, + MutableComponentModel model) + { + String fieldType = transformation.getFieldType(fieldName); + + Class type = transformation.toClass(fieldType); + + Object inject = _objectProvider.provide(value, type, _locator); + + transformation.injectField(fieldName, inject); + } + + private void injectAnnonymous(String fieldName, ClassTransformation transformation, + MutableComponentModel model) + { + String fieldType = transformation.getFieldType(fieldName); + + boolean result = _injectionProvider.provideInjection( + fieldName, + fieldType, + _locator, + transformation, + model); + + if (!result) + throw new RuntimeException(ServicesMessages.noInjectionFound(transformation + .getClassName(), fieldName, fieldType)); + } +} Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectionProvider.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectionProvider.java?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectionProvider.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InjectionProvider.java Tue Sep 5 11:14:53 2006 @@ -0,0 +1,53 @@ +// 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.ioc.ServiceLocator; +import org.apache.tapestry.model.MutableComponentModel; +import org.apache.tapestry.services.ClassTransformation; + +/** + * Provides some form of injection when the value for an + * {@link org.apache.tapestry.annotations.Inject} annotation is blank. In this case, the provider is + * responsible for determining the value to be injected from the field name and field type. + *

+ * This interface will be used as part of a + * {@link org.apache.tapestry.ioc.services.ChainBuilder chain of command}. + * + * @author Howard M. Lewis Ship + */ +public interface InjectionProvider +{ + /** + * Peform the injection, if possible. Most often, this will result in a call to + * {@link ClassTransformation#injectField(String, Object)}. The caller is responsible for + * invoking {@link ClassTransformation#claimField(String, Object)}. + * + * @param fieldName + * the name of the field requesting injection + * @param fieldType + * the type of the field (as a string) + * @param locator + * allows services to be located + * @param transformation + * allows the code for the class to be transformed + * @param componentModel + * defines the relevant aspects of the component + * @return true if an injection has been made (terminates the command chain), false to continue + * down the chain + */ + boolean provideInjection(String fieldName, String fieldType, ServiceLocator locator, + ClassTransformation transformation, MutableComponentModel componentModel); +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java Tue Sep 5 11:14:53 2006 @@ -21,8 +21,8 @@ import org.apache.tapestry.util.IdAllocator; /** - * Extends {@link org.apache.tapestry.services.ClassTransformation} with additional methods that - * may only be used internally by Tapestry. + * Extends {@link org.apache.tapestry.services.ClassTransformation} with additional methods that may + * only be used internally by Tapestry. * * @author Howard M. Lewis Ship */ @@ -35,9 +35,9 @@ String getResourcesFieldName(); /** - * Invoked after all {@link ComponentClassTransformWorker}s have had their chance to work over the - * class. This performs any final operations for the class transformation, which includes coming - * up with the final constructor method for the class. + * Invoked after all {@link ComponentClassTransformWorker}s have had their chance to work over + * the class. This performs any final operations for the class transformation, which includes + * coming up with the final constructor method for the class. */ void finish(); Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- 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 Tue Sep 5 11:14:53 2006 @@ -42,6 +42,7 @@ import org.apache.tapestry.internal.util.InternalUtils; import org.apache.tapestry.runtime.ComponentLifecycle; import org.apache.tapestry.services.MethodSignature; +import org.apache.tapestry.services.TransformUtils; import org.apache.tapestry.util.CollectionFactory; import org.apache.tapestry.util.IdAllocator; @@ -64,7 +65,7 @@ private final CtClass _ctClass; - private final ClassPool _classPool; + private ClassPool _classPool; private final IdAllocator _idAllocator; @@ -106,14 +107,17 @@ private Formatter _formatter = new Formatter(_description); + private ClassLoader _loader; + /** * This is a constructor for the root class, the class that directly contains the ComponentClass * annotation. */ - public InternalClassTransformationImpl(CtClass ctClass) + public InternalClassTransformationImpl(CtClass ctClass, ClassLoader loader) { _ctClass = ctClass; _classPool = _ctClass.getClassPool(); + _loader = loader; _idAllocator = new IdAllocator(); @@ -135,10 +139,12 @@ } public InternalClassTransformationImpl(CtClass ctClass, - InternalClassTransformation parentTransformation) + InternalClassTransformation parentTransformation, ClassLoader loader) { _ctClass = ctClass; _classPool = _ctClass.getClassPool(); + _loader = loader; + _resourcesFieldName = parentTransformation.getResourcesFieldName(); _idAllocator = parentTransformation.getIdAllocator(); @@ -186,6 +192,9 @@ _fieldWriteTransforms = null; _constructor = null; _formatter = null; + _loader = null; + // _ctClass = null; -- needed by toString() + _classPool = null; } public String getResourcesFieldName() @@ -661,6 +670,8 @@ public List findFieldsWithAnnotation(Class annotationClass) { + failIfFrozen(); + List result = newList(); for (CtField field : _ctClass.getDeclaredFields()) @@ -693,6 +704,8 @@ public List findMethodsWithAnnotation( Class annotationClass) { + failIfFrozen(); + List result = newList(); for (CtMethod method : _ctClass.getDeclaredMethods()) @@ -781,13 +794,20 @@ public String getFieldType(String fieldName) { + failIfFrozen(); + + CtClass type = getFieldCtType(fieldName); + + return type.getName(); + } + + private CtClass getFieldCtType(String fieldName) + { try { CtField field = _ctClass.getDeclaredField(fieldName); - CtClass type = field.getType(); - - return type.getName(); + return field.getType(); } catch (NotFoundException ex) { @@ -849,11 +869,41 @@ String fieldName = addField(Modifier.PROTECTED, type.getName(), suggestedName); - _constructorArgs.add(new ConstructorArg(ctType, value)); + addInjectToConstructor(fieldName, ctType, value); + + return fieldName; + } + + /** + * Adds a parameter to the constructor for the class; the parameter is used to initialize the + * value for a field. + * + * @param fieldName + * name of field to inject + * @param fieldType + * Javassist type of the field (and corresponding parameter) + * @param value + * the value to be injected (which will in unusual cases be null) + */ + private void addInjectToConstructor(String fieldName, CtClass fieldType, Object value) + { + _constructorArgs.add(new ConstructorArg(fieldType, value)); _constructor.append(format(" %s = $%d;\n", fieldName, _constructorArgs.size())); + } - return fieldName; + @SuppressNullCheck + public void injectField(String fieldName, Object value) + { + notNull(fieldName, "fieldName"); + + failIfFrozen(); + + CtClass type = getFieldCtType(fieldName); + + addInjectToConstructor(fieldName, type, value); + + makeReadOnly(fieldName); } private CtClass convertNameToCtType(String type) throws NotFoundException @@ -1128,4 +1178,28 @@ throw new RuntimeException(ex); } } + + public Class toClass(String type) + { + failIfFrozen(); + + // No reason why this can't be allowed to work after freezing. + + String finalType = TransformUtils.getWrapperType(type); + + try + { + return Class.forName(finalType, true, _loader); + } + catch (ClassNotFoundException ex) + { + throw new RuntimeException(ex); + } + } + + public String getClassName() + { + return _ctClass.getName(); + } + } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Tue Sep 5 11:14:53 2006 @@ -14,19 +14,11 @@ package org.apache.tapestry.internal.services; -import java.lang.annotation.Annotation; - import org.apache.commons.logging.Log; -import org.apache.tapestry.annotations.BeforeRenderBody; -import org.apache.tapestry.annotations.BeginRender; -import org.apache.tapestry.annotations.CleanupRender; -import org.apache.tapestry.annotations.AfterRender; -import org.apache.tapestry.annotations.SetupRender; import org.apache.tapestry.events.InvalidationEvent; import org.apache.tapestry.events.InvalidationListener; import org.apache.tapestry.internal.InternalConstants; import org.apache.tapestry.internal.bindings.PropBindingFactory; -import org.apache.tapestry.ioc.IOCUtilities; import org.apache.tapestry.ioc.LogSource; import org.apache.tapestry.ioc.OrderedConfiguration; import org.apache.tapestry.ioc.annotations.Contribute; @@ -46,8 +38,6 @@ import org.apache.tapestry.services.ComponentClassResolver; import org.apache.tapestry.services.ComponentClassTransformWorker; import org.apache.tapestry.services.MarkupWriterFactory; -import org.apache.tapestry.services.MethodSignature; -import org.apache.tapestry.services.TransformConstants; import org.apache.tapestry.services.WebContext; import org.apache.tapestry.services.WebRequestFilter; @@ -167,49 +157,6 @@ public UpdateListenerHub buildUpdateListenerHub() { return new UpdateListenerHubImpl(); - } - - /** - * Adds a number of standard workers: - *

    - *
  • Retain -- allows fields to retain their values between requests
  • - *
  • Parameter
  • -- identifies parameters based on the Parameter annotation - *
  • UnclaimedField
  • -- identifies unclaimed fields and resets them to null/0/false at - * the end of the request - *
  • SetupRender, BeginRender, etc. -- correspond to component render phases and annotations
  • - *
- * - * @param configuration - */ - @Contribute("tapestry.ComponentClassTransformWorker") - public void contributeInternalWorkers( - OrderedConfiguration configuration) - { - // TODO: Proper scheduling of all of this. - - configuration.add("Parameter", new ParameterWorker()); - - // Workers for the component rendering state machine methods; this is in typical - // execution order. - - add(configuration, TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class); - add(configuration, TransformConstants.BEGIN_RENDER_SIGNATURE, BeginRender.class); - add(configuration, TransformConstants.BEFORE_RENDER_BODY_SIGNATURE, BeforeRenderBody.class); - add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class); - add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class); - - configuration.add("Retain", new RetainWorker()); - configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*.*"); - } - - private void add(OrderedConfiguration configuration, - MethodSignature signature, Class annotationClass) - { - // make the name match the annotation class name. - - String name = IOCUtilities.toSimpleId(annotationClass.getName()); - - configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass)); } /** Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- 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 Tue Sep 5 11:14:53 2006 @@ -138,4 +138,9 @@ { return MESSAGES.format("read-only-field", className, fieldName); } + + static String noInjectionFound(String className, String fieldName, String fieldType) + { + return MESSAGES.format("no-injection-found", className, fieldName, fieldType); + } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- 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 Tue Sep 5 11:14:53 2006 @@ -42,6 +42,12 @@ { /** + * Returns the name of the class being transformed. + */ + + String getClassName(); + + /** * Returns the name of a new member (field or method). Ensures that the resulting name does not * conflict with any existing member (declared by the underlying class, or inherited from a base * class). @@ -167,6 +173,16 @@ String addInjectedField(Class type, String suggestedName, Object value); /** + * Converts the field into a read only field whose value is the provided value. + * + * @param fieldName + * name of field to convert + * @param value + * the value provided by the field + */ + void injectField(String fieldName, Object value); + + /** * Transforms the class to implement the indicated interface. If the class (or its super class) * does not already implement the interface, then the interface is added, and default * implementations of any methods of the interface are added. @@ -224,4 +240,11 @@ * {@link #extendMethod(MethodSignature, String)}. */ void replaceWriteAccess(String fieldName, String methodName); + + /** + * Converts a type name into a corresponding class (possibly, a transformed class). Primitive + * type names are returned as wrapper types. + */ + + Class toClass(String type); } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Tue Sep 5 11:14:53 2006 @@ -15,6 +15,7 @@ package org.apache.tapestry.services; import java.io.IOException; +import java.lang.annotation.Annotation; import java.util.Collection; import java.util.List; import java.util.Map; @@ -25,6 +26,11 @@ import org.apache.commons.logging.Log; import org.apache.tapestry.MarkupWriter; +import org.apache.tapestry.annotations.AfterRender; +import org.apache.tapestry.annotations.BeforeRenderBody; +import org.apache.tapestry.annotations.BeginRender; +import org.apache.tapestry.annotations.CleanupRender; +import org.apache.tapestry.annotations.SetupRender; import org.apache.tapestry.internal.InternalConstants; import org.apache.tapestry.internal.annotations.SuppressNullCheck; import org.apache.tapestry.internal.bindings.LiteralBindingFactory; @@ -33,19 +39,26 @@ import org.apache.tapestry.internal.services.ComponentClassFactoryImpl; import org.apache.tapestry.internal.services.ComponentClassResolverImpl; import org.apache.tapestry.internal.services.ComponentInstantiatorSource; +import org.apache.tapestry.internal.services.ComponentLifecycleMethodWorker; import org.apache.tapestry.internal.services.HTMLDispatcher; import org.apache.tapestry.internal.services.InfrastructureImpl; import org.apache.tapestry.internal.services.InfrastructureManagerImpl; +import org.apache.tapestry.internal.services.InjectWorker; +import org.apache.tapestry.internal.services.InjectionProvider; import org.apache.tapestry.internal.services.InternalModule; import org.apache.tapestry.internal.services.MarkupWriterImpl; import org.apache.tapestry.internal.services.PageResponseRenderer; +import org.apache.tapestry.internal.services.ParameterWorker; import org.apache.tapestry.internal.services.RequestGlobalsImpl; import org.apache.tapestry.internal.services.RequestPageCache; +import org.apache.tapestry.internal.services.RetainWorker; import org.apache.tapestry.internal.services.StaticFilesFilter; +import org.apache.tapestry.internal.services.UnclaimedFieldWorker; import org.apache.tapestry.internal.services.WebContextImpl; import org.apache.tapestry.internal.services.WebRequestImpl; import org.apache.tapestry.internal.services.WebResponseImpl; import org.apache.tapestry.ioc.Configuration; +import org.apache.tapestry.ioc.IOCUtilities; import org.apache.tapestry.ioc.MappedConfiguration; import org.apache.tapestry.ioc.ObjectProvider; import org.apache.tapestry.ioc.OrderedConfiguration; @@ -340,7 +353,7 @@ @InjectService("Infrastructure") Infrastructure infrastructure) { - configuration.add("service", infrastructure.getObjectProvider()); + configuration.add("infrastructure", infrastructure.getObjectProvider()); } public void contributeMasterDispatcher(OrderedConfiguration configuration, @@ -380,5 +393,63 @@ ComponentInstantiatorSource source) { return new ComponentClassFactoryImpl(log, source); + } + + /** + * A chain of command for providing values for {@link org.apache.tapestry.annotations.Inject}-ed + * fields in component classes. The service's configuration can be extended to allow for + * different automatic injections (based on some combination of field type and field name). + */ + + public InjectionProvider buildInjectionProvider(List configuration) + { + return _chainBuilder.build(InjectionProvider.class, configuration); + } + + /** + * Adds a number of standard workers: + *
    + *
  • Retain -- allows fields to retain their values between requests
  • + *
  • Parameter
  • -- identifies parameters based on the Parameter annotation + *
  • UnclaimedField
  • -- identifies unclaimed fields and resets them to null/0/false at + * the end of the request + *
  • SetupRender, BeginRender, etc. -- correspond to component render phases and annotations
  • + *
+ * + * @param configuration + */ + @Contribute("tapestry.ComponentClassTransformWorker") + public void contributeTransformWorkers( + OrderedConfiguration configuration, + ServiceLocator locator, @InjectService("tapestry.ioc.MasterObjectProvider") + ObjectProvider objectProvider, @InjectService("InjectionProvider") + InjectionProvider injectionProvider) + { + // TODO: Proper scheduling of all of this. + + configuration.add("Inject", new InjectWorker(objectProvider, locator, injectionProvider)); + configuration.add("Parameter", new ParameterWorker()); + + // Workers for the component rendering state machine methods; this is in typical + // execution order. + + add(configuration, TransformConstants.SETUP_RENDER_SIGNATURE, SetupRender.class); + add(configuration, TransformConstants.BEGIN_RENDER_SIGNATURE, BeginRender.class); + add(configuration, TransformConstants.BEFORE_RENDER_BODY_SIGNATURE, BeforeRenderBody.class); + add(configuration, TransformConstants.AFTER_RENDER_SIGNATURE, AfterRender.class); + add(configuration, TransformConstants.CLEANUP_RENDER_SIGNATURE, CleanupRender.class); + + configuration.add("Retain", new RetainWorker()); + configuration.add("UnclaimedField", new UnclaimedFieldWorker(), "after:*.*"); + } + + private void add(OrderedConfiguration configuration, + MethodSignature signature, Class annotationClass) + { + // make the name match the annotation class name. + + String name = IOCUtilities.toSimpleId(annotationClass.getName()); + + configuration.add(name, new ComponentLifecycleMethodWorker(signature, annotationClass)); } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- 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 Tue Sep 5 11:14:53 2006 @@ -34,6 +34,7 @@ import org.apache.tapestry.annotations.SetupRender; import org.apache.tapestry.annotations.Parameter; import org.apache.tapestry.internal.annotations.SuppressNullCheck; +import org.apache.tapestry.internal.services.InjectionProvider; import org.apache.tapestry.ioc.Configuration; import org.apache.tapestry.ioc.LogSource; import org.apache.tapestry.ioc.MappedConfiguration; @@ -53,6 +54,7 @@ import org.apache.tapestry.services.ClassTransformation; import org.apache.tapestry.services.ComponentClassResolver; import org.apache.tapestry.services.MethodSignature; +import org.apache.tapestry.services.WebRequest; import static java.lang.Thread.sleep; import static org.apache.tapestry.internal.test.CodeEq.codeEq; @@ -441,5 +443,22 @@ { tf.findMethodsWithAnnotation(SetupRender.class); setReturnValue(sigs); + } + + protected final WebRequest newWebRequest() + { + return newMock(WebRequest.class); + } + + protected final void train_provideInjection(InjectionProvider provider, String fieldName, String fieldType, ServiceLocator locator, ClassTransformation transformation, MutableComponentModel model, boolean result) + { + provider.provideInjection(fieldName, fieldType, locator, transformation, model); + setReturnValue(result); + } + + protected final void train_toClass(ClassTransformation transformation, String type, Class classForType) + { + transformation.toClass(type); + setReturnValue(classForType); } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Tue Sep 5 11:14:53 2006 @@ -34,4 +34,6 @@ may-not-nest-elements-inside-body=Element '%s' is nested within a Tapestry body element, which is not allowed. method-compile-error=Error compiling method %s (%s): %s render-queue-error=Render queue error in %s: %s -read-only-field=Field %s.%s is read-only. \ No newline at end of file +read-only-field=Field %s.%s is read-only. +no-injection-found=Could not find a suitable object to inject into %s.%s (type %s). \ + Use the value attribute of the @Inject annotation to identify exactly what should be injected into this field. \ No newline at end of file Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Tue Sep 5 11:14:53 2006 @@ -2,26 +2,23 @@ Tapestry 5 Integration Application 1 - -

This page is static.

-

- Tapestry 5 Integration Application 1: - -

    - Start Page - Loop Page +

    Tapestry 5 Integration Application 1:

    - - -

    - Feast your eyes: -

    - +

    Feast your eyes:

    Component Render States - \ No newline at end of file + Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml Tue Sep 5 11:14:53 2006 @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> + Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Tue Sep 5 11:14:53 2006 @@ -116,6 +116,19 @@ // Selenium is nice enough to remove the elements and excess whitespace. assertTrue(body.contains("Ho! Ho! Ho!")); + + _selenium.open(BASE_URL); + + _selenium.click("link=Inject Page"); + _selenium.waitForPageToLoad(PAGE_LOAD_TIMEOUT); + + body = _selenium.getBodyText(); + + // This is the output from the proxy for the WebRequest service, which is what's injected + // into and output by, the component. + + assertTrue(body + .contains("")); } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Loop.java Tue Sep 5 11:14:53 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.integration.app1.components; import org.apache.tapestry.annotations.ComponentClass; Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/WriteWebRequest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/WriteWebRequest.java?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/WriteWebRequest.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/WriteWebRequest.java Tue Sep 5 11:14:53 2006 @@ -0,0 +1,39 @@ +// 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.integration.app1.components; + +import org.apache.tapestry.MarkupWriter; +import org.apache.tapestry.annotations.BeginRender; +import org.apache.tapestry.annotations.ComponentClass; +import org.apache.tapestry.annotations.Inject; +import org.apache.tapestry.services.WebRequest; + +/** + * This will go away once we implement output expressions in templates. + * + * @author Howard M. Lewis Ship + */ +@ComponentClass +public class WriteWebRequest +{ + @Inject("infrastructure:request") + private WebRequest _request; + + @BeginRender + void writeRequest(MarkupWriter writer) + { + writer.write(_request.toString()); + } +} Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/InjectPage.java Tue Sep 5 11:14:53 2006 @@ -0,0 +1,23 @@ +// 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.integration.app1.pages; + +import org.apache.tapestry.annotations.ComponentClass; + +@ComponentClass +public class InjectPage +{ + +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/MerryChristmas.java Tue Sep 5 11:14:53 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.integration.app1.pages; import org.apache.tapestry.annotations.ComponentClass; Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/DefaultComponentLifecyle.java Tue Sep 5 11:14:53 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.bindings; import org.apache.tapestry.ComponentResources; Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java Tue Sep 5 11:14:53 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.bindings; import org.apache.tapestry.Binding; Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/TargetBean.java Tue Sep 5 11:14:53 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.bindings; public class TargetBean extends DefaultComponentLifecyle Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectWorkerTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectWorkerTest.java?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectWorkerTest.java (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InjectWorkerTest.java Tue Sep 5 11:14:53 2006 @@ -0,0 +1,150 @@ +// 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.annotations.Inject; +import org.apache.tapestry.internal.test.InternalBaseTestCase; +import org.apache.tapestry.ioc.ObjectProvider; +import org.apache.tapestry.ioc.ServiceLocator; +import org.apache.tapestry.model.MutableComponentModel; +import org.apache.tapestry.services.ClassTransformation; +import org.apache.tapestry.services.WebRequest; +import org.testng.annotations.Test; + +/** + * @author Howard M. Lewis Ship + */ +public class InjectWorkerTest extends InternalBaseTestCase +{ + + private static final String WEBREQUEST_CLASS_NAME = WebRequest.class.getName(); + + @Test + public void annotation_has_value() + { + ObjectProvider provider = newObjectProvider(); + ServiceLocator locator = newServiceLocator(); + InjectionProvider ip = newMock(InjectionProvider.class); + Inject annotation = newMock(Inject.class); + ClassTransformation ct = newClassTransformation(); + MutableComponentModel model = newMutableComponentModel(); + WebRequest injected = newWebRequest(); + + train_findFieldsWithAnnotation(ct, Inject.class, "myfield"); + train_getFieldAnnotation(ct, "myfield", Inject.class, annotation); + + train_value(annotation, "foo:Bar"); + + train_getFieldType(ct, "myfield", WEBREQUEST_CLASS_NAME); + train_toClass(ct, WEBREQUEST_CLASS_NAME, WebRequest.class); + + train_provide(provider, "foo:Bar", WebRequest.class, locator, injected); + + ct.injectField("myfield", injected); + + ct.claimField("myfield", annotation); + + replay(); + + InjectWorker worker = new InjectWorker(provider, locator, ip); + + worker.transform(ct, model); + + verify(); + } + + @Test + public void no_value_for_annotation() + { + ObjectProvider provider = newObjectProvider(); + ServiceLocator locator = newServiceLocator(); + InjectionProvider ip = newMock(InjectionProvider.class); + Inject annotation = newMock(Inject.class); + ClassTransformation ct = newClassTransformation(); + MutableComponentModel model = newMutableComponentModel(); + + train_findFieldsWithAnnotation(ct, Inject.class, "myfield"); + train_getFieldAnnotation(ct, "myfield", Inject.class, annotation); + + train_value(annotation, ""); + + train_getFieldType(ct, "myfield", WEBREQUEST_CLASS_NAME); + + train_provideInjection(ip, "myfield", WEBREQUEST_CLASS_NAME, locator, ct, model, true); + + ct.claimField("myfield", annotation); + + replay(); + + InjectWorker worker = new InjectWorker(provider, locator, ip); + + worker.transform(ct, model); + + verify(); + } + + @Test + public void anonymous_injection_not_provided() + { + ObjectProvider provider = newObjectProvider(); + ServiceLocator locator = newServiceLocator(); + InjectionProvider ip = newMock(InjectionProvider.class); + Inject annotation = newMock(Inject.class); + ClassTransformation ct = newClassTransformation(); + MutableComponentModel model = newMutableComponentModel(); + + train_findFieldsWithAnnotation(ct, Inject.class, "myfield"); + train_getFieldAnnotation(ct, "myfield", Inject.class, annotation); + + train_value(annotation, ""); + + train_getFieldType(ct, "myfield", WEBREQUEST_CLASS_NAME); + + train_provideInjection(ip, "myfield", WEBREQUEST_CLASS_NAME, locator, ct, model, false); + + train_getClassName(ct, "foo.Baz"); + + replay(); + + InjectWorker worker = new InjectWorker(provider, locator, ip); + + try + { + worker.transform(ct, model); + unreachable(); + } + catch (RuntimeException ex) + { + assertEquals(ex.getMessage(), ServicesMessages.noInjectionFound( + "foo.Baz", + "myfield", + WEBREQUEST_CLASS_NAME)); + } + + verify(); + } + + protected void train_getClassName(ClassTransformation transformation, String className) + { + transformation.getClassName(); + setReturnValue(className); + } + + private void train_value(Inject annotation, String value) + { + annotation.value(); + setReturnValue(value); + } +} Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- 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 Tue Sep 5 11:14:53 2006 @@ -19,6 +19,7 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; +import java.util.Map; import javassist.ClassPool; import javassist.CtClass; @@ -111,7 +112,7 @@ throws NotFoundException { CtClass ctClass = findCtClass(targetClass); - return new InternalClassTransformationImpl(ctClass); + return new InternalClassTransformationImpl(ctClass, _contextClassLoader); } @Test @@ -316,7 +317,7 @@ } @Test - public void inject_field() throws Exception + public void add_injected_field() throws Exception { InternalComponentResources resources = newInternalComponentResources(); @@ -324,7 +325,11 @@ CtClass targetObjectCtClass = findCtClass(TargetObject.class); - InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass); + InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass, + _contextClassLoader); + + // Default behavior is to add an injected field for the InternalComponentResources object, + // so we'll just check that. ct.finish(); @@ -344,7 +349,8 @@ CtClass ctClass = findCtClass(BasicComponent.class); - InternalClassTransformation ct = new InternalClassTransformationImpl(ctClass); + InternalClassTransformation ct = new InternalClassTransformationImpl(ctClass, + _contextClassLoader); _classPool.toClass(ctClass, childLoader); @@ -383,7 +389,8 @@ CtClass targetObjectCtClass = findCtClass(TargetObject.class); - InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass); + InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass, + _contextClassLoader); ct.addImplementedInterface(FooInterface.class); ct.addImplementedInterface(GetterMethodsInterface.class); @@ -428,7 +435,8 @@ CtClass targetObjectCtClass = findCtClass(ReadOnlyBean.class); - InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass); + InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass, + _contextClassLoader); ct.makeReadOnly("_value"); @@ -457,6 +465,49 @@ verify(); } + @Test + public void inject_field() throws Exception + { + InternalComponentResources resources = newInternalComponentResources(); + + replay(); + + ClassLoader childLoader = newLoader(); + + CtClass targetObjectCtClass = findCtClass(ReadOnlyBean.class); + + InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass, + _contextClassLoader); + + ct.injectField("_value", "Tapestry"); + + ct.finish(); + + Class transformed = _classPool.toClass(targetObjectCtClass, childLoader); + + Object target = ct.createInstantiator(transformed).newInstance(resources); + + PropertyAccess access = new PropertyAccessImpl(); + + assertEquals(access.get(target, "value"), "Tapestry"); + + try + { + access.set(target, "value", "anything"); + unreachable(); + } + catch (RuntimeException ex) + { + // The PropertyAccess layer adds a wrapper exception around the real one. + + assertEquals( + ex.getCause().getMessage(), + "Field org.apache.tapestry.internal.services.ReadOnlyBean._value is read-only."); + } + + verify(); + } + /** * Tests the basic functionality of overriding read and write; also tests the case for multiple * field read/field write substitions. @@ -472,7 +523,8 @@ CtClass targetObjectCtClass = findCtClass(FieldAccessBean.class); - InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass); + InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass, + _contextClassLoader); replaceAccessToField(ct, "foo"); replaceAccessToField(ct, "bar"); @@ -568,5 +620,21 @@ // Check up on no match. assertTrue(ct.findFieldsWithAnnotation(Deprecated.class).isEmpty()); + } + + @Test + public void to_class_with_primitive_type() throws Exception + { + ClassTransformation ct = createClassTransformation(AnnotatedPage.class); + + assertSame(ct.toClass("float"), Float.class); + } + + @Test + public void to_class_with_object_type() throws Exception + { + ClassTransformation ct = createClassTransformation(AnnotatedPage.class); + + assertSame(ct.toClass("java.util.Map"), Map.class); } } Modified: 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?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java Tue Sep 5 11:14:53 2006 @@ -33,6 +33,8 @@ */ public class ParameterWorkerTest extends InternalBaseTestCase { + private final ClassLoader _contextClassLoader = Thread.currentThread().getContextClassLoader(); + private PropertyAccess _access = new PropertyAccessImpl(); @AfterClass @@ -342,7 +344,8 @@ loader.delegateLoadingOf("org.apache.tapestry."); CtClass ctClass = pool.get(ParameterComponent.class.getName()); - InternalClassTransformation transformation = new InternalClassTransformationImpl(ctClass); + InternalClassTransformation transformation = new InternalClassTransformationImpl(ctClass, + _contextClassLoader); MutableComponentModel model = newMutableComponentModel(); Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ReadOnlyBean.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ReadOnlyBean.java?view=diff&rev=440425&r1=440424&r2=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ReadOnlyBean.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ReadOnlyBean.java Tue Sep 5 11:14:53 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.services; import org.apache.tapestry.internal.annotations.SuppressNullCheck; Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html?view=auto&rev=440425 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html (added) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/InjectPage.html Tue Sep 5 11:14:53 2006 @@ -0,0 +1,4 @@ + +

    Demonstrates the use of the @Inject annotation.

    +

    WebRequest:

    +