You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by jk...@apache.org on 2007/02/19 01:04:26 UTC
svn commit: r509035 [1/2] - in /tapestry/tapestry4/trunk: ./
tapestry-annotations/src/descriptor/META-INF/
tapestry-annotations/src/java/org/apache/tapestry/annotations/
tapestry-annotations/src/test/org/apache/tapestry/annotations/
tapestry-examples/T...
Author: jkuhnert
Date: Sun Feb 18 16:04:24 2007
New Revision: 509035
URL: http://svn.apache.org/viewvc?view=rev&rev=509035
Log:
Fixed annoyance with persistent property state changes not being detected unless you explicitly set them on a
page property. Only goes one level deep but now uses cglib enhancements to detect property ~object~ changes as well.
(plus some additional rules to make sure it doesn't conflict with existing bytecode enhancement libraries like
hibernate / javax.persistence / etc .. )
Added:
tapestry/tapestry4/trunk/tapestry-annotations/src/java/org/apache/tapestry/annotations/ComponentPropertyProxyWorker.java
tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/Entity.java
tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SimpleBean.java
tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SubSimpleBean.java
tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/TestComponentPropertyProxyWorker.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectChangeObserverWorker.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibPropertyChangeInterceptor.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibProxiedPropertyChangeObserverImpl.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/LazyProxyDelegate.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/ObservableMethodFilter.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/PropertyChangeObserver.java
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/record/SimpleState.java
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/record/TestPropertyChangeObserver.java
Modified:
tapestry/tapestry4/trunk/pom.xml
tapestry/tapestry4/trunk/tapestry-annotations/src/descriptor/META-INF/hivemodule.xml
tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java
tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/BasicComponent.java
tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/Redirect.html
tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/localization/Change.html
tapestry/tapestry4/trunk/tapestry-framework/pom.xml
tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.enhance.xml
tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.persist.xml
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/AbstractPage.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/IPage.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/engine/IPageRecorder.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/DispatchToInjectWorker.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhanceUtils.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectRenderWorker.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/SpecifiedPropertyWorker.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ChangeObserver.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ObservedChangeEvent.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/PageRecorderImpl.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/PersistentPropertyData.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/SessionPropertyPersistenceStrategy.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/RequestLocaleManagerImpl.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/spec/IPropertySpecification.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/spec/PropertySpecification.java
tapestry/tapestry4/trunk/tapestry-framework/src/scripts/TestDefaultParameterValues.xml
tapestry/tapestry4/trunk/tapestry-framework/src/test-data/context27/Home.html
tapestry/tapestry4/trunk/tapestry-framework/src/test-data/context27/WEB-INF/Home.page
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/enhance/TestSpecifiedPropertyWorker.java
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/junit/mock/TestMockApplications.java
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/record/PageFixture.java
Modified: tapestry/tapestry4/trunk/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/pom.xml?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/pom.xml (original)
+++ tapestry/tapestry4/trunk/pom.xml Sun Feb 18 16:04:24 2007
@@ -123,6 +123,12 @@
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ <version>2.1_3</version>
+ <scope>compile</scope>
+ </dependency>
<!-- Really, a transitive dependency of hivemind. -->
<dependency>
<groupId>oro</groupId>
@@ -270,7 +276,7 @@
</systemProperties>
<parallel>true</parallel>
<threadCount>4</threadCount>
- <excludedGroups>integration</excludedGroups>
+ <excludedGroups>integration</excludedGroups>
</configuration>
</plugin>
<plugin>
@@ -297,6 +303,12 @@
</executions>
</plugin>
<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.0.2-SNAPSHOT</version>
+ <inherited>true</inherited>
+ </plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0-alpha-1-SNAPSHOT</version>
Modified: tapestry/tapestry4/trunk/tapestry-annotations/src/descriptor/META-INF/hivemodule.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/descriptor/META-INF/hivemodule.xml?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/descriptor/META-INF/hivemodule.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/descriptor/META-INF/hivemodule.xml Sun Feb 18 16:04:24 2007
@@ -1,205 +1,241 @@
<?xml version="1.0"?>
<!--
- Copyright 2005 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.
+ Copyright 2005 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.
-->
<module id="tapestry.annotation" version="4.0.0" package="org.apache.tapestry.annotations">
-
- JDK 1.5 annotation support for Tapestry, allowing classes (including base classes) to provide details normally
- specified in the XML component or page specification.
-
- <service-point id="AnnotationEnhancementWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
-
- Bridge from ordinary specification-based enhancements, to annotation-driven enhancements.
-
- <invoke-factory>
- <construct class="AnnotationEnhancementWorker">
- <set-configuration property="methodWorkers" configuration-id="MethodWorkers"/>
- <set-configuration property="classWorkers" configuration-id="ClassWorkers"/>
- <set-configuration property="secondaryAnnotationWorkers" configuration-id="SecondaryAnnotationWorkers"/>
- </construct>
- </invoke-factory>
-
- </service-point>
-
- <service-point id="ComponentHousekeepingWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
-
- Perform additional housekeeping relating to injected components, i.e. ensure bindings are set
- for copyOf components.
-
- <invoke-factory>
- <construct class="ComponentHousekeepingWorker">
- </construct>
- </invoke-factory>
- </service-point>
-
- <!-- Only contribute when in JDK 1.5 and java.lang.Annotation exists -->
-
- <contribution configuration-id="tapestry.enhance.EnhancementWorkers" if="class java.lang.annotation.Annotation">
- <!-- Needs to come first because some enhancements modify
- the component specification, affecting what occurs in later commands. -->
- <command id="annotation-worker" object="service:AnnotationEnhancementWorker" before="*"/>
- <command id="component-housekeeping-worker" object="service:ComponentHousekeepingWorker" after="annotation-worker"/>
- <command id="inject-asset-annotation" object="service:InjectAssetAnnotationWorker" after="tapestry.enhance.inject-asset"/>
- </contribution>
-
- <configuration-point id="ClassWorkers">
-
- Maps from a specific Annotation class, to a particular ClassAnnotationEnhancementWorker (typically,
- a service).
- <schema>
- <element name="worker" key-attribute="annotation">
-
- <attribute name="annotation" translator="class">
- The name of an Annotation class which triggers the enhancement worker's behavior.
- </attribute>
-
- <attribute name="object" translator="object">
-
- An object that implements the ClassAnnotationEnhancementWorker interface.
- </attribute>
-
- <rules>
- <push-attribute attribute="object"/>
- <invoke-parent method="addElement"/>
- </rules>
-
- </element>
- </schema>
-
- </configuration-point>
-
- <contribution configuration-id="ClassWorkers">
- <worker annotation="ComponentClass" object="instance:ComponentClassAnnotationWorker"/>
- <worker annotation="Meta" object="instance:MetaAnnotationWorker"/>
- </contribution>
-
- <configuration-point id="MethodWorkers">
-
- Maps from a specific Annotation class, to a particular MethodAnnotationEnhancementWorker (typically,
- a service).
- <schema>
- <element name="worker" key-attribute="annotation">
-
- <attribute name="annotation" translator="class">
- The name of an Annotation class which triggers the enhancement worker's behavior.
- </attribute>
-
- <attribute name="object" translator="object">
-
- An object that implements the MethodAnnotationEnhancementWorker interface.
- </attribute>
-
- <rules>
- <push-attribute attribute="object"/>
- <invoke-parent method="addElement"/>
- </rules>
-
- </element>
- </schema>
-
- </configuration-point>
-
- <contribution configuration-id="MethodWorkers">
-
- <!-- These instantiate the corresponding enhancement worker, and delegate to it. -->
- <worker annotation="InjectObject" object="service:InjectObjectAnnotationWorker"/>
- <worker annotation="InjectComponent" object="instance:InjectComponentAnnotationWorker"/>
- <worker annotation="Message" object="instance:MessageAnnotationWorker"/>
-
- <!-- These update the component specification with new sub-elements. Later, the
- existing enhancement workers perform the work, as if the sub-elements were
- specified in the XML. This is actually a lot easier and just as powerful, and
- the delegating style will probably go pretty soon. -->
-
- <worker annotation="InjectState" object="instance:InjectStateAnnotationWorker"/>
- <worker annotation="InjectStateFlag" object="instance:InjectStateFlagAnnotationWorker"/>
- <worker annotation="Persist" object="instance:PersistAnnotationWorker"/>
- <worker annotation="Bean" object="instance:BeanAnnotationWorker"/>
- <worker annotation="Asset" object="instance:AssetAnnotationWorker"/>
- <worker annotation="Parameter" object="instance:ParameterAnnotationWorker"/>
- <worker annotation="InjectPage" object="instance:InjectPageAnnotationWorker"/>
- <worker annotation="Component" object="service:ComponentAnnotationWorker"/>
- <worker annotation="InjectMeta" object="instance:InjectMetaAnnotationWorker"/>
- <worker annotation="InjectScript" object="instance:InjectScriptAnnotationWorker"/>
- </contribution>
-
- <service-point id="ComponentAnnotationWorker" interface="MethodAnnotationEnhancementWorker">
- <invoke-factory>
- <construct class="ComponentAnnotationWorker" />
- </invoke-factory>
- </service-point>
-
- <service-point id="InjectAssetAnnotationWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
-
- Injects IAsset assets based on previously defined asset alias names. (such as in a .page or .jwc spec )
-
- <invoke-factory>
- <construct class="InjectAssetAnnotationWorker"/>
- </invoke-factory>
-
- </service-point>
-
- <service-point id="InjectObjectAnnotationWorker" interface="MethodAnnotationEnhancementWorker">
-
- Injects HiveMind objects, based on the InjectObject annotation.
-
- <invoke-factory>
- <construct class="InjectObjectAnnotationWorker">
- <set-service property="provider" service-id="tapestry.InjectedValueProvider"/>
- </construct>
- </invoke-factory>
-
- </service-point>
-
- <service-point id="EventListenerAnnotationWorker" interface="EventListenerAnnotationWorker">
-
- Handles EventListener annotations.
-
- <invoke-factory>
- <construct class="EventListenerAnnotationWorker">
- <set-service property="invoker" service-id="tapestry.event.EventInvoker"/>
- </construct>
- </invoke-factory>
-
- </service-point>
-
- <configuration-point id="SecondaryAnnotationWorkers">
-
- Configures a list of secondary annotation workers.
- <schema>
- <element name="worker">
-
- <attribute name="object" translator="object" required="true">
-
- An object that implements the SecondaryAnnotationEnhancementWorker interface.
- </attribute>
-
- <rules>
- <push-attribute attribute="object"/>
- <invoke-parent method="addElement"/>
- </rules>
+
+ JDK 1.5 annotation support for Tapestry, allowing classes (including base classes) to provide details normally
+ specified in the XML component or page specification.
+
+ <service-point id="AnnotationEnhancementWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
+
+ Bridge from ordinary specification-based enhancements, to annotation-driven enhancements.
+
+ <invoke-factory>
+ <construct class="AnnotationEnhancementWorker">
+ <set-configuration property="methodWorkers" configuration-id="MethodWorkers" />
+ <set-configuration property="classWorkers" configuration-id="ClassWorkers" />
+ <set-configuration property="secondaryAnnotationWorkers" configuration-id="SecondaryAnnotationWorkers" />
+ </construct>
+ </invoke-factory>
+
+ </service-point>
+
+ <service-point id="ComponentHousekeepingWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
+
+ Perform additional housekeeping relating to injected components, i.e. ensure bindings are set for copyOf
+ components.
+
+ <invoke-factory>
+ <construct class="ComponentHousekeepingWorker"></construct>
+ </invoke-factory>
+ </service-point>
+
+ <service-point id="ComponentPropertyProxyWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
+
+ Checks for proxy capabilities of specified properties.
- </element>
- </schema>
+ <invoke-factory>
+ <construct class="ComponentPropertyProxyWorker">
+ <set-configuration property="excludedPackages" configuration-id="ExcludedProxyAnnotations" />
+ </construct>
+ </invoke-factory>
+ </service-point>
+
+ <!-- Only contribute when in JDK 1.5 and java.lang.Annotation exists -->
+
+ <contribution configuration-id="tapestry.enhance.EnhancementWorkers" if="class java.lang.annotation.Annotation">
+ <!-- Needs to come first because some enhancements modify
+ the component specification, affecting what occurs in later commands. -->
+ <command id="annotation-worker" object="service:AnnotationEnhancementWorker" before="*" />
+
+ <command id="component-housekeeping-worker" object="service:ComponentHousekeepingWorker" after="annotation-worker" />
+ <command id="component-propertyproxy-worker" object="service:ComponentPropertyProxyWorker" before="tapestry.enhance.specified-property" />
+ <command id="inject-asset-annotation" object="service:InjectAssetAnnotationWorker" after="tapestry.enhance.inject-asset" />
+ </contribution>
+
+ <configuration-point id="ExcludedProxyAnnotations">
- </configuration-point>
-
- <contribution configuration-id="SecondaryAnnotationWorkers">
- <worker object="instance:InitialValueAnnotationWorker"/>
- <worker object="service:EventListenerAnnotationWorker"/>
- </contribution>
-
+ Definition of simple string match configurations that will cause any annotation class name
+ matching any of the definitions in this configuration point to not be eligable for cglib proxying
+ enhancements later on. This is done to prevent issues with popular persistence frameworks like
+ Hibernate.
+
+ <schema>
+ <element name="exclude">
+ <attribute name="match" required="true" unique="true" >
+ The string to use in matching containment within the string returned from Annotation.annotationType().getName().
+ </attribute>
+ <rules>
+ <push-attribute attribute="match" />
+ <invoke-parent method="addElement" />
+ </rules>
+ </element>
+ </schema>
+ </configuration-point>
+
+ <contribution configuration-id="ExcludedProxyAnnotations">
+ <exclude match="org.hibernate" />
+ <exclude match="javax.persistence" />
+ <exclude match="Entity" />
+ </contribution>
+
+ <configuration-point id="ClassWorkers">
+
+ Maps from a specific Annotation class, to a particular ClassAnnotationEnhancementWorker (typically, a service).
+ <schema>
+ <element name="worker" key-attribute="annotation">
+
+ <attribute name="annotation" translator="class">
+ The name of an Annotation class which triggers the enhancement worker's behavior.
+ </attribute>
+
+ <attribute name="object" translator="object">
+
+ An object that implements the ClassAnnotationEnhancementWorker interface.
+ </attribute>
+
+ <rules>
+ <push-attribute attribute="object" />
+ <invoke-parent method="addElement" />
+ </rules>
+
+ </element>
+ </schema>
+
+ </configuration-point>
+
+ <contribution configuration-id="ClassWorkers">
+ <worker annotation="ComponentClass" object="instance:ComponentClassAnnotationWorker" />
+ <worker annotation="Meta" object="instance:MetaAnnotationWorker" />
+ </contribution>
+
+ <configuration-point id="MethodWorkers">
+
+ Maps from a specific Annotation class, to a particular MethodAnnotationEnhancementWorker (typically, a service).
+ <schema>
+ <element name="worker" key-attribute="annotation">
+
+ <attribute name="annotation" translator="class">
+ The name of an Annotation class which triggers the enhancement worker's behavior.
+ </attribute>
+
+ <attribute name="object" translator="object">
+
+ An object that implements the MethodAnnotationEnhancementWorker interface.
+ </attribute>
+
+ <rules>
+ <push-attribute attribute="object" />
+ <invoke-parent method="addElement" />
+ </rules>
+
+ </element>
+ </schema>
+
+ </configuration-point>
+
+ <contribution configuration-id="MethodWorkers">
+
+ <!-- These instantiate the corresponding enhancement worker, and delegate to it. -->
+ <worker annotation="InjectObject" object="service:InjectObjectAnnotationWorker" />
+ <worker annotation="InjectComponent" object="instance:InjectComponentAnnotationWorker" />
+ <worker annotation="Message" object="instance:MessageAnnotationWorker" />
+
+ <!-- These update the component specification with new sub-elements. Later, the
+ existing enhancement workers perform the work, as if the sub-elements were
+ specified in the XML. This is actually a lot easier and just as powerful, and
+ the delegating style will probably go pretty soon. -->
+
+ <worker annotation="InjectState" object="instance:InjectStateAnnotationWorker" />
+ <worker annotation="InjectStateFlag" object="instance:InjectStateFlagAnnotationWorker" />
+ <worker annotation="Persist" object="instance:PersistAnnotationWorker" />
+ <worker annotation="Bean" object="instance:BeanAnnotationWorker" />
+ <worker annotation="Asset" object="instance:AssetAnnotationWorker" />
+ <worker annotation="Parameter" object="instance:ParameterAnnotationWorker" />
+ <worker annotation="InjectPage" object="instance:InjectPageAnnotationWorker" />
+ <worker annotation="Component" object="service:ComponentAnnotationWorker" />
+ <worker annotation="InjectMeta" object="instance:InjectMetaAnnotationWorker" />
+ <worker annotation="InjectScript" object="instance:InjectScriptAnnotationWorker" />
+ </contribution>
+
+ <service-point id="ComponentAnnotationWorker" interface="MethodAnnotationEnhancementWorker">
+ <invoke-factory>
+ <construct class="ComponentAnnotationWorker" />
+ </invoke-factory>
+ </service-point>
+
+ <service-point id="InjectAssetAnnotationWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
+
+ Injects IAsset assets based on previously defined asset alias names. (such as in a .page or .jwc spec )
+
+ <invoke-factory>
+ <construct class="InjectAssetAnnotationWorker" />
+ </invoke-factory>
+
+ </service-point>
+
+ <service-point id="InjectObjectAnnotationWorker" interface="MethodAnnotationEnhancementWorker">
+
+ Injects HiveMind objects, based on the InjectObject annotation.
+
+ <invoke-factory>
+ <construct class="InjectObjectAnnotationWorker">
+ <set-service property="provider" service-id="tapestry.InjectedValueProvider" />
+ </construct>
+ </invoke-factory>
+
+ </service-point>
+
+ <service-point id="EventListenerAnnotationWorker" interface="EventListenerAnnotationWorker">
+
+ Handles EventListener annotations.
+
+ <invoke-factory>
+ <construct class="EventListenerAnnotationWorker">
+ <set-service property="invoker" service-id="tapestry.event.EventInvoker" />
+ </construct>
+ </invoke-factory>
+
+ </service-point>
+
+ <configuration-point id="SecondaryAnnotationWorkers">
+
+ Configures a list of secondary annotation workers.
+ <schema>
+ <element name="worker">
+
+ <attribute name="object" translator="object" required="true">
+
+ An object that implements the SecondaryAnnotationEnhancementWorker interface.
+ </attribute>
+
+ <rules>
+ <push-attribute attribute="object" />
+ <invoke-parent method="addElement" />
+ </rules>
+
+ </element>
+ </schema>
+
+ </configuration-point>
+
+ <contribution configuration-id="SecondaryAnnotationWorkers">
+ <worker object="instance:InitialValueAnnotationWorker" />
+ <worker object="service:EventListenerAnnotationWorker" />
+ </contribution>
+
</module>
Added: tapestry/tapestry4/trunk/tapestry-annotations/src/java/org/apache/tapestry/annotations/ComponentPropertyProxyWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/java/org/apache/tapestry/annotations/ComponentPropertyProxyWorker.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/java/org/apache/tapestry/annotations/ComponentPropertyProxyWorker.java (added)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/java/org/apache/tapestry/annotations/ComponentPropertyProxyWorker.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,92 @@
+// Copyright 2004, 2005 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.Annotation;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tapestry.enhance.EnhanceUtils;
+import org.apache.tapestry.enhance.EnhancementOperation;
+import org.apache.tapestry.enhance.EnhancementWorker;
+import org.apache.tapestry.spec.IComponentSpecification;
+import org.apache.tapestry.spec.IPropertySpecification;
+
+
+/**
+ * Performs runtime checks on persistent properties to ensure that objects being
+ * managed by competing bytecode enhancement libraries (such as Hibernate) aren't
+ * proxied.
+ */
+public class ComponentPropertyProxyWorker implements EnhancementWorker
+{
+
+ private List<String> _excludedPackages;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
+ {
+ Iterator i = spec.getPropertySpecificationNames().iterator();
+
+ while(i.hasNext())
+ {
+ String name = (String) i.next();
+ IPropertySpecification ps = spec.getPropertySpecification(name);
+
+ checkProxy(op, ps);
+ }
+ }
+
+ void checkProxy(EnhancementOperation op, IPropertySpecification ps)
+ {
+ ps.setProxyChecked(true);
+
+ if (!ps.isPersistent())
+ return;
+
+ Class propertyType = EnhanceUtils.extractPropertyType(op, ps.getName(), ps.getType());
+ if (propertyType == null)
+ return;
+
+ if (!EnhanceUtils.canProxyPropertyType(propertyType))
+ return;
+
+ Annotation[] annotations = propertyType.getAnnotations();
+
+ for (int i = 0; i < annotations.length; i++) {
+ if (isExcluded(annotations[i]))
+ return;
+ }
+
+ ps.setCanProxy(true);
+ }
+
+ boolean isExcluded(Annotation annotation)
+ {
+ for (String match : _excludedPackages) {
+
+ if (annotation.annotationType().getName().indexOf(match) > -1)
+ return true;
+ }
+
+ return false;
+ }
+
+ public void setExcludedPackages(List packages)
+ {
+ _excludedPackages = packages;
+ }
+}
Modified: tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java (original)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/AnnotatedPage.java Sun Feb 18 16:04:24 2007
@@ -165,4 +165,10 @@
@InitialValue("literal:5")
public abstract int getDefaultPageSize();
+
+ @Persist
+ public abstract SimpleBean getBean();
+
+ @Persist
+ public abstract SubSimpleBean getSubBean();
}
Modified: tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/BasicComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/BasicComponent.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/BasicComponent.java (original)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/BasicComponent.java Sun Feb 18 16:04:24 2007
@@ -23,5 +23,4 @@
@ComponentClass
public class BasicComponent
{
-
}
Added: tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/Entity.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/Entity.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/Entity.java (added)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/Entity.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,34 @@
+// Copyright 2004, 2005 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.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines a basic annotation with a name matching that of most persistence frameworks.
+ */
+@Target( { ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface Entity
+{
+
+
+}
Added: tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SimpleBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SimpleBean.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SimpleBean.java (added)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SimpleBean.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,26 @@
+// Copyright 2004, 2005 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;
+
+
+/**
+ * Used to test proxy ignore rules.
+ */
+@Entity
+public class SimpleBean
+{
+ public SimpleBean()
+ {
+ }
+}
Added: tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SubSimpleBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SubSimpleBean.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SubSimpleBean.java (added)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/SubSimpleBean.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,23 @@
+// Copyright 2004, 2005 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;
+
+
+/**
+ * Test of annotation inheritance.
+ */
+public class SubSimpleBean extends SimpleBean
+{
+
+}
Added: tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/TestComponentPropertyProxyWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/TestComponentPropertyProxyWorker.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/TestComponentPropertyProxyWorker.java (added)
+++ tapestry/tapestry4/trunk/tapestry-annotations/src/test/org/apache/tapestry/annotations/TestComponentPropertyProxyWorker.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,108 @@
+// Copyright 2004, 2005 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 static org.easymock.EasyMock.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.hivemind.Location;
+import org.apache.tapestry.enhance.EnhancementOperation;
+import org.apache.tapestry.spec.ComponentSpecification;
+import org.apache.tapestry.spec.IComponentSpecification;
+import org.apache.tapestry.spec.IPropertySpecification;
+import org.apache.tapestry.spec.PropertySpecification;
+import org.testng.annotations.Test;
+
+
+/**
+ * Tests functionality of {@link ComponentPropertyProxyWorker}.
+ */
+@Test
+public class TestComponentPropertyProxyWorker extends BaseAnnotationTestCase
+{
+
+ void addProperty(EnhancementOperation op, IComponentSpecification spec, Location l,
+ String propertyName, Class type)
+ {
+ IPropertySpecification pspec = new PropertySpecification();
+
+ pspec.setName(propertyName);
+ pspec.setPersistence("session");
+ pspec.setLocation(l);
+ pspec.setType(type.getName());
+
+ spec.addPropertySpecification(pspec);
+
+ expect(op.convertTypeName(type.getName())).andReturn(type);
+ op.validateProperty(propertyName, type);
+ }
+
+ public void test_Excluded()
+ {
+ Location l = newLocation();
+ EnhancementOperation op = newOp();
+ IComponentSpecification spec = new ComponentSpecification();
+
+ addProperty(op, spec, l, "bean", SimpleBean.class);
+
+ ComponentPropertyProxyWorker worker = new ComponentPropertyProxyWorker();
+
+ List exclude = new ArrayList();
+ exclude.add("Entity");
+ worker.setExcludedPackages(exclude);
+
+ replay();
+
+ worker.performEnhancement(op, spec);
+
+ verify();
+
+ IPropertySpecification prop = spec.getPropertySpecification("bean");
+
+ assert prop != null;
+ assert prop.isPersistent();
+ assert prop.isProxyChecked();
+ assert !prop.canProxy();
+ }
+
+ public void test_SubClass_Excluded()
+ {
+ Location l = newLocation();
+ EnhancementOperation op = newOp();
+ IComponentSpecification spec = new ComponentSpecification();
+
+ addProperty(op, spec, l, "subBean", SubSimpleBean.class);
+
+ ComponentPropertyProxyWorker worker = new ComponentPropertyProxyWorker();
+
+ List exclude = new ArrayList();
+ exclude.add("Entity");
+ worker.setExcludedPackages(exclude);
+
+ replay();
+
+ worker.performEnhancement(op, spec);
+
+ verify();
+
+ IPropertySpecification prop = spec.getPropertySpecification("subBean");
+
+ assert prop != null;
+ assert prop.isPersistent();
+ assert prop.isProxyChecked();
+ assert !prop.canProxy();
+ }
+}
Modified: tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java (original)
+++ tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java Sun Feb 18 16:04:24 2007
@@ -53,7 +53,7 @@
@InjectObject("service:timetracker.dao.ProjectDao")
public abstract GenericDao<E> getProjectDao();
- @Persist("session")
+ @Persist
public abstract E getSelectedProject();
public abstract Project getCurrentProject();
Modified: tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/Redirect.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/Redirect.html?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/Redirect.html (original)
+++ tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/Redirect.html Sun Feb 18 16:04:24 2007
@@ -19,7 +19,7 @@
public void redirectExternal()
throws RequestCycleException
{
- throw new RedirectException("http://jakarta.apache.org/tapestry");
+ throw new RedirectException("http://tapestry.apache.org");
}
</pre>
</span>
Modified: tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/localization/Change.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/localization/Change.html?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/localization/Change.html (original)
+++ tapestry/tapestry4/trunk/tapestry-examples/Workbench/src/context/localization/Change.html Sun Feb 18 16:04:24 2007
@@ -4,4 +4,4 @@
<p><a jwcid="back"><img jwcid="chooseAgainImage"/></a>
-</span>
\ No newline at end of file
+</span>
Modified: tapestry/tapestry4/trunk/tapestry-framework/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/pom.xml?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/pom.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/pom.xml Sun Feb 18 16:04:24 2007
@@ -22,6 +22,10 @@
<scope>compile</scope>
</dependency>
<dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ </dependency>
+ <dependency>
<groupId>hivemind</groupId>
<artifactId>hivemind</artifactId>
</dependency>
@@ -274,7 +278,7 @@
</dependency>
</dependencies>
</plugin>
-
+
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
@@ -288,7 +292,7 @@
</excludes>
</configuration>
</plugin>
-
+
</plugins>
</build>
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.enhance.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.enhance.xml?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.enhance.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.enhance.xml Sun Feb 18 16:04:24 2007
@@ -84,6 +84,7 @@
<command id="inject-event-invoker" object="service:InjectEventInvokerWorker" before="abstract-property"/>
<command id="inject-render-worker" object="service:InjectRenderWorker" before="abstract-property"/>
<command id="specified-property" object="service:SpecifiedPropertyWorker" before="abstract-property"/>
+ <command id="inject-propertychange-worker" object="service:InjectChangeObserverWorker" before="abstract-property" />
<command id="parameter" object="service:ParameterPropertyWorker" before="abstract-property"/>
<command id="dispatch-inject" object="service:DispatchToInjectWorker" before="abstract-property"/>
<command id="inject-component" object="service:InjectComponentWorker" before="abstract-property"/>
@@ -110,7 +111,6 @@
<command id="page-validate-listener" object="service:InjectPageValidateListenerWorker" after="abstract-property"/>
<command id="page-begin-render-listener" object="service:InjectPageBeginRenderListenerWorker" after="abstract-property"/>
<command id="page-end-render-listener" object="service:InjectPageEndRenderListenerWorker" after="abstract-property"/>
-
</contribution>
@@ -314,6 +314,18 @@
<invoke-factory>
<construct class="InjectAssetWorker"/>
+ </invoke-factory>
+
+ </service-point>
+
+ <service-point id="InjectChangeObserverWorker" interface="EnhancementWorker">
+
+ Injects the PropertyChangeObserver service into page instances.
+
+ <invoke-factory>
+ <construct class="InjectChangeObserverWorker" >
+ <set-service property="propertyChangeObserver" service-id="tapestry.persist.PropertyChangeObserver" />
+ </construct>
</invoke-factory>
</service-point>
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.persist.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.persist.xml?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.persist.xml (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.persist.xml Sun Feb 18 16:04:24 2007
@@ -135,4 +135,15 @@
<strategy name="client:page" object="service:PageClientPropertyPersistenceStrategy"/>
<strategy name="client:app" object="service:AppClientPropertyPersistenceStrategy"/>
</contribution>
-</module>
\ No newline at end of file
+
+ <service-point id="PropertyChangeObserver" interface="PropertyChangeObserver">
+
+ Used to observe changes to persistent page properties.
+
+ <invoke-factory>
+ <construct class="CglibProxiedPropertyChangeObserverImpl" />
+ </invoke-factory>
+
+ </service-point>
+
+</module>
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/AbstractPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/AbstractPage.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/AbstractPage.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/AbstractPage.java Sun Feb 18 16:04:24 2007
@@ -50,7 +50,7 @@
*/
private ChangeObserver _changeObserver;
-
+
/**
* The {@link IEngine}the page is currently attached to.
*/
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/IPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/IPage.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/IPage.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/IPage.java Sun Feb 18 16:04:24 2007
@@ -23,6 +23,7 @@
import org.apache.tapestry.event.PageDetachListener;
import org.apache.tapestry.event.PageEndRenderListener;
import org.apache.tapestry.event.PageValidateListener;
+import org.apache.tapestry.record.PropertyChangeObserver;
import org.apache.tapestry.services.ResponseBuilder;
import org.apache.tapestry.util.ContentType;
@@ -63,7 +64,15 @@
*/
ChangeObserver getChangeObserver();
-
+
+ /**
+ * Returns the injected property change service responsible for monitoring changes to
+ * individual object properties being persisted.
+ *
+ * @return The injected property change service.
+ */
+ PropertyChangeObserver getPropertyChangeObserver();
+
/**
* Returns the <code>Locale</code> of the page. The locale may be used to determine what
* template is used by the page and the components contained by the page.
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/engine/IPageRecorder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/engine/IPageRecorder.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/engine/IPageRecorder.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/engine/IPageRecorder.java Sun Feb 18 16:04:24 2007
@@ -38,7 +38,7 @@
*/
void commit();
-
+
/**
* Rolls back the page to the currently persisted state.
* <p>
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/DispatchToInjectWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/DispatchToInjectWorker.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/DispatchToInjectWorker.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/DispatchToInjectWorker.java Sun Feb 18 16:04:24 2007
@@ -50,13 +50,11 @@
{
try
{
- InjectEnhancementWorker worker = (InjectEnhancementWorker) _injectWorkers.get(spec
- .getType());
+ InjectEnhancementWorker worker = (InjectEnhancementWorker) _injectWorkers.get(spec.getType());
if (worker == null)
{
- _errorLog.error(EnhanceMessages.unknownInjectType(spec.getProperty(), spec
- .getType()), spec.getLocation(), null);
+ _errorLog.error(EnhanceMessages.unknownInjectType(spec.getProperty(), spec.getType()), spec.getLocation(), null);
return;
}
@@ -65,8 +63,8 @@
}
catch (Exception ex)
{
- _errorLog.error(EnhanceMessages.errorAddingProperty(spec.getProperty(), op
- .getBaseClass(), ex), spec.getLocation(), ex);
+ _errorLog.error(EnhanceMessages.errorAddingProperty(spec.getProperty(), op.getBaseClass(), ex),
+ spec.getLocation(), ex);
}
}
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhanceUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhanceUtils.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhanceUtils.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhanceUtils.java Sun Feb 18 16:04:24 2007
@@ -18,6 +18,9 @@
import java.util.HashMap;
import java.util.Map;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.Factory;
+
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.Location;
import org.apache.hivemind.service.ClassFabUtils;
@@ -48,7 +51,7 @@
public static final MethodSignature CLEANUP_AFTER_RENDER_SIGNATURE = new MethodSignature(
void.class, "cleanupAfterRender", new Class[]
{ IRequestCycle.class }, null);
-
+
/**
* Used to unwrap primitive types inside the accessor method. In each case, the binding is in a
* variable named "binding", and {0} will be the actual type of the property. The Map is keyed
@@ -91,12 +94,9 @@
String propertyName, Class propertyType, Location location)
{
String methodName = op.getAccessorMethodName(propertyName);
-
- op.addMethod(
- Modifier.PUBLIC,
- new MethodSignature(propertyType, methodName, null, null),
- "return " + fieldName + ";",
- location);
+
+ op.addMethod( Modifier.PUBLIC, new MethodSignature(propertyType, methodName, null, null),
+ "return " + fieldName + ";", location);
}
public static void createSimpleMutator(EnhancementOperation op, String fieldName,
@@ -104,8 +104,8 @@
{
String methodName = createMutatorMethodName(propertyName);
- op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, methodName, new Class[]
- { propertyType }, null), fieldName + " = $1;", location);
+ op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, methodName,
+ new Class[] { propertyType }, null), fieldName + " = $1;", location);
}
/**
@@ -129,13 +129,13 @@
{
Defense.notNull(op, "op");
Defense.notNull(propertyName, "propertyName");
-
+
if (definedTypeName != null)
{
Class propertyType = op.convertTypeName(definedTypeName);
-
+
op.validateProperty(propertyName, propertyType);
-
+
return propertyType;
}
@@ -228,8 +228,7 @@
* the type of value to be extracted from the binding.
*/
- public static String createUnwrapExpression(EnhancementOperation op, String bindingName,
- Class valueType)
+ public static String createUnwrapExpression(EnhancementOperation op, String bindingName, Class valueType)
{
Defense.notNull(op, "op");
Defense.notNull(bindingName, "bindingName");
@@ -263,7 +262,7 @@
return buffer.toString();
}
-
+
/**
* Verifies that a property type can be assigned a particular type of value.
*
@@ -298,5 +297,52 @@
requiredType));
return propertyType;
+ }
+
+ /**
+ * Determines whether or not the specified class type is elligable for proxying. This generally
+ * means it needs a default constructor, can't be final / primitive / array.
+ *
+ * @param type
+ * The class to check for proxying elligibility.
+ * @return True if the type can be proxied, false otherwise.
+ */
+ public static boolean canProxyPropertyType(Class type)
+ {
+ // if it's already enhanced it must be by someone else
+
+ if (Enhancer.isEnhanced(type) || Factory.class.isAssignableFrom(type))
+ return false;
+
+ if (type.isInterface())
+ return true;
+
+ if (!hasEmptyConstructor(type))
+ return false;
+
+ if (type.isArray() || type.isPrimitive() || Modifier.isFinal(type.getModifiers()) || Object.class == type)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Checks if the specified class type has an empty constructor.
+ *
+ * @param type
+ * The class to check, can't be null.
+ *
+ * @return True if a no args constructor exists.
+ */
+ public static boolean hasEmptyConstructor(Class type)
+ {
+ Defense.notNull(type, "type");
+
+ try {
+
+ return type.getConstructor(null) != null;
+ } catch (Throwable t) {
+ return false;
+ }
}
}
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java Sun Feb 18 16:04:24 2007
@@ -96,8 +96,7 @@
* prevent naming conflicts.
*/
- String addInjectedField(String fieldName, Class fieldType,
- Object value);
+ String addInjectedField(String fieldName, Class fieldType, Object value);
/**
* Converts a type name (an object class name, a primtive name, or an array)
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java Sun Feb 18 16:04:24 2007
@@ -235,7 +235,8 @@
String name = pd.getName();
- if (!_properties.containsKey(name)) _properties.put(name, pd);
+ if (!_properties.containsKey(name))
+ _properties.put(name, pd);
}
}
@@ -244,8 +245,7 @@
Defense.notNull(propertyName, "propertyName");
if (_claimedProperties.contains(propertyName))
- throw new ApplicationRuntimeException(EnhanceMessages
- .claimedProperty(propertyName));
+ throw new ApplicationRuntimeException(EnhanceMessages.claimedProperty(propertyName));
_claimedProperties.add(propertyName);
}
@@ -260,7 +260,8 @@
PropertyDescriptor pd = getPropertyDescriptor(propertyName);
- if (pd == null) return false;
+ if (pd == null)
+ return false;
return pd.getWriteMethod() == null ? true : false;
}
@@ -272,8 +273,7 @@
PropertyDescriptor pd = getPropertyDescriptor(propertyName);
if (pd != null && pd.getWriteMethod() != null)
- throw new ApplicationRuntimeException(EnhanceMessages
- .readonlyProperty(propertyName, pd.getWriteMethod()));
+ throw new ApplicationRuntimeException(EnhanceMessages.readonlyProperty(propertyName, pd.getWriteMethod()));
}
public void addField(String name, Class type)
@@ -281,8 +281,7 @@
_classFab.addField(name, type);
}
- public String addInjectedField(String fieldName, Class fieldType,
- Object value)
+ public String addInjectedField(String fieldName, Class fieldType, Object value)
{
Defense.notNull(fieldName, "fieldName");
Defense.notNull(fieldType, "fieldType");
@@ -292,7 +291,8 @@
// See if this object has been previously added.
- if (existing != null) return existing;
+ if (existing != null)
+ return existing;
// TODO: Should be ensure that the name is unique?
@@ -310,8 +310,7 @@
int parameterIndex = addConstructorParameter(fieldType, value);
- constructorBuilder().addln("{0} = ${1};", uniqueName,
- Integer.toString(parameterIndex));
+ constructorBuilder().addln("{0} = ${1};", uniqueName, Integer.toString(parameterIndex));
// Remember the mapping from the value to the field name.
@@ -352,15 +351,15 @@
PropertyDescriptor pd = getPropertyDescriptor(name);
- if (pd == null) return;
+ if (pd == null)
+ return;
Class propertyType = pd.getPropertyType();
- if (propertyType.equals(expectedType)) return;
+ if (propertyType.equals(expectedType))
+ return;
- throw new ApplicationRuntimeException(EnhanceMessages
- .propertyTypeMismatch(_baseClass, name, propertyType,
- expectedType));
+ throw new ApplicationRuntimeException(EnhanceMessages.propertyTypeMismatch(_baseClass, name, propertyType, expectedType));
}
PropertyDescriptor getPropertyDescriptor(String name)
@@ -389,8 +388,7 @@
Location existing = (Location) _methods.get(sig);
if (existing != null)
- throw new ApplicationRuntimeException(EnhanceMessages
- .methodConflict(sig, existing), location, null);
+ throw new ApplicationRuntimeException(EnhanceMessages.methodConflict(sig, existing), location, null);
_methods.put(sig, location);
@@ -408,7 +406,8 @@
String result = (String) _finalFields.get(clazz);
- if (result == null) result = addClassReference(clazz);
+ if (result == null)
+ result = addClassReference(clazz);
return result;
}
@@ -476,8 +475,7 @@
}
catch (Throwable t)
{
- throw new ApplicationRuntimeException(EnhanceMessages
- .classEnhancementFailure(_baseClass, t), _classFab, null, t);
+ throw new ApplicationRuntimeException(EnhanceMessages.classEnhancementFailure(_baseClass, t), _classFab, null, t);
}
}
@@ -489,14 +487,13 @@
{
_constructorBuilder.end();
- Class[] types = (Class[]) _constructorTypes
- .toArray(new Class[_constructorTypes.size()]);
+ Class[] types = (Class[]) _constructorTypes.toArray(new Class[_constructorTypes.size()]);
- _classFab.addConstructor(types, null, _constructorBuilder
- .toString());
+ _classFab.addConstructor(types, null, _constructorBuilder.toString());
}
- if (_log != null) _log.debug("Creating class:\n\n" + _classFab);
+ if (_log != null && _log.isDebugEnabled())
+ _log.debug("Creating class:\n\n" + _classFab);
}
private void finalizeIncompleteMethods()
@@ -539,8 +536,7 @@
{
addInterfaceIfNeeded(interfaceClass);
- BodyBuilder builder = (BodyBuilder) _incompleteMethods
- .get(methodSignature);
+ BodyBuilder builder = (BodyBuilder) _incompleteMethods.get(methodSignature);
if (builder == null)
{
@@ -554,7 +550,8 @@
private void addInterfaceIfNeeded(Class interfaceClass)
{
- if (implementsInterface(interfaceClass)) return;
+ if (implementsInterface(interfaceClass))
+ return;
_classFab.addInterface(interfaceClass);
_addedInterfaces.add(interfaceClass);
@@ -562,14 +559,16 @@
public boolean implementsInterface(Class interfaceClass)
{
- if (interfaceClass.isAssignableFrom(_baseClass)) return true;
+ if (interfaceClass.isAssignableFrom(_baseClass))
+ return true;
Iterator i = _addedInterfaces.iterator();
while(i.hasNext())
{
Class addedInterface = (Class) i.next();
- if (interfaceClass.isAssignableFrom(addedInterface)) return true;
+ if (interfaceClass.isAssignableFrom(addedInterface))
+ return true;
}
return false;
@@ -650,9 +649,11 @@
String name = pd.getName();
- if (_claimedProperties.contains(name)) continue;
+ if (_claimedProperties.contains(name))
+ continue;
- if (isAbstractProperty(pd)) result.add(name);
+ if (isAbstractProperty(pd))
+ result.add(name);
}
return result;
Added: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectChangeObserverWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectChangeObserverWorker.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectChangeObserverWorker.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectChangeObserverWorker.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,75 @@
+// Copyright 2004, 2005 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.enhance;
+
+import org.apache.hivemind.ErrorLog;
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.record.PropertyChangeObserver;
+import org.apache.tapestry.spec.IComponentSpecification;
+
+
+/**
+ * Responsible for injecting the {@link PropertyChangeObserver} service into each page
+ * instance.
+ */
+public class InjectChangeObserverWorker implements EnhancementWorker
+{
+ static final String PROPERTY_NAME = "propertyChangeObserver";
+
+ private ErrorLog _errorLog;
+
+ private PropertyChangeObserver _observer;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
+ {
+ if (!spec.isPageSpecification())
+ return;
+
+ try
+ {
+ injectChangeObserver(op, spec);
+ }
+ catch (Exception ex)
+ {
+ _errorLog.error(EnhanceMessages.errorAddingProperty(PROPERTY_NAME, op.getBaseClass(), ex),
+ spec.getLocation(), ex);
+ }
+ }
+
+ public void injectChangeObserver(EnhancementOperation op, IComponentSpecification spec)
+ {
+ Defense.notNull(op, "op");
+ Defense.notNull(spec, "spec");
+
+ op.claimReadonlyProperty(PROPERTY_NAME);
+
+ String fieldName = op.addInjectedField("_$" + PROPERTY_NAME, PropertyChangeObserver.class, _observer);
+
+ EnhanceUtils.createSimpleAccessor(op, fieldName, PROPERTY_NAME,
+ PropertyChangeObserver.class, spec.getLocation());
+ }
+
+ public void setErrorLog(ErrorLog errorLog)
+ {
+ _errorLog = errorLog;
+ }
+
+ public void setPropertyChangeObserver(PropertyChangeObserver observer)
+ {
+ _observer = observer;
+ }
+}
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectRenderWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectRenderWorker.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectRenderWorker.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/InjectRenderWorker.java Sun Feb 18 16:04:24 2007
@@ -43,9 +43,8 @@
}
catch (Exception ex)
{
- _errorLog.error(EnhanceMessages.errorAddingProperty(
- PROPERTY_NAME, op.getBaseClass(), ex), spec
- .getLocation(), ex);
+ _errorLog.error(EnhanceMessages.errorAddingProperty(PROPERTY_NAME, op.getBaseClass(), ex),
+ spec.getLocation(), ex);
}
}
@@ -56,9 +55,7 @@
op.claimReadonlyProperty(PROPERTY_NAME);
- String fieldName = op.addInjectedField("_$"
- + PROPERTY_NAME, ComponentRenderWorker.class,
- _renderWorker);
+ String fieldName = op.addInjectedField("_$" + PROPERTY_NAME, ComponentRenderWorker.class, _renderWorker);
EnhanceUtils.createSimpleAccessor(op, fieldName,
PROPERTY_NAME, ComponentRenderWorker.class,
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/SpecifiedPropertyWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/SpecifiedPropertyWorker.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/SpecifiedPropertyWorker.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/enhance/SpecifiedPropertyWorker.java Sun Feb 18 16:04:24 2007
@@ -20,6 +20,7 @@
import org.apache.hivemind.ErrorLog;
import org.apache.hivemind.Location;
import org.apache.hivemind.service.BodyBuilder;
+import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.util.Defense;
import org.apache.tapestry.IBinding;
@@ -31,7 +32,8 @@
/**
* Responsible for adding properties to a class corresponding to specified
- * properties in the component's specification.
+ * properties in the component's specification - which may come from .jwc / .page specifications
+ * or annotated abstract methods.
*
* @author Howard M. Lewis Ship
* @since 4.0
@@ -43,7 +45,7 @@
private ErrorLog _errorLog;
private BindingSource _bindingSource;
-
+
/**
* Iterates over the specified properties, creating an enhanced property for
* each (a field, an accessor, a mutator). Persistent properties will invoke
@@ -83,17 +85,15 @@
boolean persistent = ps.isPersistent();
String initialValue = ps.getInitialValue();
Location location = ps.getLocation();
-
- addProperty(op, propertyName, specifiedType, persistent, initialValue,
- location);
+
+ addProperty(op, propertyName, specifiedType, persistent, initialValue, location, ps);
}
- public void addProperty(EnhancementOperation op, String propertyName,
- String specifiedType, boolean persistent, String initialValue,
- Location location)
+ public void addProperty(EnhancementOperation op, String propertyName, String specifiedType,
+ boolean persistent, String initialValue, Location location, IPropertySpecification ps)
{
Class propertyType = EnhanceUtils.extractPropertyType(op, propertyName, specifiedType);
-
+
op.claimProperty(propertyName);
String field = "_$" + propertyName;
@@ -104,83 +104,86 @@
// if they exist. 4.0 is less picky ... it blindly adds new methods,
// possibly
// overwriting methods in the base component class.
-
- EnhanceUtils.createSimpleAccessor(op, field, propertyName,
- propertyType, location);
-
- addMutator(op, propertyName, propertyType, field, persistent, location);
-
+
+ EnhanceUtils.createSimpleAccessor(op, field, propertyName, propertyType, location);
+
+ boolean canProxy = false;
+ if (ps.isProxyChecked())
+ canProxy = ps.canProxy();
+ else
+ canProxy = persistent && EnhanceUtils.canProxyPropertyType(propertyType);
+
+ addMutator(op, propertyName, propertyType, field, persistent, canProxy, location);
+
if (initialValue == null)
addReinitializer(op, propertyType, field);
- else addInitialValue(op, propertyName, propertyType, field,
- initialValue, location);
+ else
+ addInitialValue(op, propertyName, propertyType, field, initialValue, persistent, canProxy, location);
}
- private void addReinitializer(EnhancementOperation op, Class propertyType,
- String fieldName)
+ private void addReinitializer(EnhancementOperation op, Class propertyType, String fieldName)
{
String defaultFieldName = fieldName + "$default";
-
+
op.addField(defaultFieldName, propertyType);
-
+
// On finishLoad(), store the current value into the default field.
- op.extendMethodImplementation(IComponent.class,
- EnhanceUtils.FINISH_LOAD_SIGNATURE, defaultFieldName + " = "
- + fieldName + ";");
+ op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE,
+ defaultFieldName + " = " + fieldName + ";");
// On pageDetach(), restore the attribute to its default value.
-
+
op.extendMethodImplementation(PageDetachListener.class,
- EnhanceUtils.PAGE_DETACHED_SIGNATURE, fieldName + " = "
- + defaultFieldName + ";");
+ EnhanceUtils.PAGE_DETACHED_SIGNATURE, fieldName + " = " + defaultFieldName + ";");
}
- private void addInitialValue(EnhancementOperation op, String propertyName,
- Class propertyType, String fieldName, String initialValue,
- Location location)
+ private void addInitialValue(EnhancementOperation op, String propertyName, Class propertyType,
+ String fieldName, String initialValue, boolean persistent, boolean canProxy, Location location)
{
- String description = EnhanceMessages
- .initialValueForProperty(propertyName);
-
- InitialValueBindingCreator creator = new InitialValueBindingCreator(
- _bindingSource, description, initialValue, location);
+ String description = EnhanceMessages.initialValueForProperty(propertyName);
- String creatorField = op.addInjectedField(fieldName
- + "$initialValueBindingCreator",
- InitialValueBindingCreator.class, creator);
+ InitialValueBindingCreator creator =
+ new InitialValueBindingCreator(_bindingSource, description, initialValue, location);
+
+ String creatorField = op.addInjectedField(fieldName + "$initialValueBindingCreator", InitialValueBindingCreator.class, creator);
String bindingField = fieldName + "$initialValueBinding";
op.addField(bindingField, IBinding.class);
BodyBuilder builder = new BodyBuilder();
+
+ builder.addln("{0} = {1}.createBinding(this);", bindingField, creatorField);
- builder.addln("{0} = {1}.createBinding(this);", bindingField,
- creatorField);
-
- op.extendMethodImplementation(IComponent.class,
- EnhanceUtils.FINISH_LOAD_SIGNATURE, builder.toString());
+ op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, builder.toString());
builder.clear();
-
- builder.addln("{0} = {1};", fieldName, EnhanceUtils
- .createUnwrapExpression(op, bindingField, propertyType));
-
+
+ builder.addln("{0} = {1};", fieldName, EnhanceUtils.createUnwrapExpression(op, bindingField, propertyType));
+
+ // add proxy observers if we can
+
+ if (canProxy) {
+
+ builder.add(fieldName + " = (" + ClassFabUtils.getJavaClassName(propertyType) + ") getPage().getPropertyChangeObserver().observePropertyChanges(this, ("
+ + ClassFabUtils.getJavaClassName(propertyType) + ") " + fieldName + ",");
+ builder.addQuoted(propertyName);
+ builder.addln(");");
+ }
+
String code = builder.toString();
-
+
// In finishLoad() and pageDetach(), de-reference the binding to get the
// value
// for the property.
- op.extendMethodImplementation(IComponent.class,
- EnhanceUtils.FINISH_LOAD_SIGNATURE, code);
- op.extendMethodImplementation(PageDetachListener.class,
- EnhanceUtils.PAGE_DETACHED_SIGNATURE, code);
-
+ op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, code);
+
+ op.extendMethodImplementation(PageDetachListener.class, EnhanceUtils.PAGE_DETACHED_SIGNATURE, code);
}
private void addMutator(EnhancementOperation op, String propertyName,
- Class propertyType, String fieldName, boolean persistent,
+ Class propertyType, String fieldName, boolean persistent, boolean canProxy,
Location location)
{
String methodName = EnhanceUtils.createMutatorMethodName(propertyName);
@@ -188,20 +191,30 @@
BodyBuilder body = new BodyBuilder();
body.begin();
-
- if (persistent)
- {
+
+ if (persistent) {
+
body.add("org.apache.tapestry.Tapestry#fireObservedChange(this, ");
body.addQuoted(propertyName);
body.addln(", ($w) $1);");
}
-
- body.addln(fieldName + " = $1;");
-
+
+ if (canProxy) {
+
+ // set the field to the proxied type
+
+ body.add(fieldName + " = (" + ClassFabUtils.getJavaClassName(propertyType) + ") getPage().getPropertyChangeObserver().observePropertyChanges(this, ($w) $1,");
+ body.addQuoted(propertyName);
+ body.addln(");");
+
+ } else {
+
+ body.addln(fieldName + " = $1;");
+ }
+
body.end();
- MethodSignature sig = new MethodSignature(void.class, methodName,
- new Class[] { propertyType }, null);
+ MethodSignature sig = new MethodSignature(void.class, methodName, new Class[] { propertyType }, null);
op.addMethod(Modifier.PUBLIC, sig, body.toString(), location);
}
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ChangeObserver.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ChangeObserver.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ChangeObserver.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ChangeObserver.java Sun Feb 18 16:04:24 2007
@@ -33,4 +33,11 @@
**/
void observeChange(ObservedChangeEvent event);
+
+ /**
+ * Checks if the current state changes have already been committed.
+ *
+ * @return True if state changes are locked, false otherwise.
+ */
+ boolean isLocked();
}
Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ObservedChangeEvent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ObservedChangeEvent.java?view=diff&rev=509035&r1=509034&r2=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ObservedChangeEvent.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/event/ObservedChangeEvent.java Sun Feb 18 16:04:24 2007
@@ -54,8 +54,7 @@
* serializable
*/
- public ObservedChangeEvent(IComponent component, String propertyName,
- Object newValue)
+ public ObservedChangeEvent(IComponent component, String propertyName, Object newValue)
{
super(component);
Added: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibPropertyChangeInterceptor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibPropertyChangeInterceptor.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibPropertyChangeInterceptor.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibPropertyChangeInterceptor.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,71 @@
+// Copyright 2004, 2005 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.record;
+
+import java.lang.reflect.Method;
+
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.Tapestry;
+
+
+/**
+ * Class responsible for watching changes on a specific property instance attached to a component.
+ *
+ * Used by the default {@link PropertyChangeObserver} service.
+ */
+public class CglibPropertyChangeInterceptor implements MethodInterceptor
+{
+ private Object _property;
+
+ private transient IComponent _component;
+ private String _propertyName;
+
+ /**
+ * Creates a new property change observer for the specified component / property.
+ *
+ * @param component
+ * The component that owns this property.
+ * @param property
+ * The actual property object, may be null.
+ * @param propertyName
+ * The name of the property.
+ */
+ public CglibPropertyChangeInterceptor(IComponent component, Object property, String propertyName)
+ {
+ _property = property;
+ _component = component;
+ _propertyName = propertyName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
+ throws Throwable
+ {
+ if (_component.getPage().getChangeObserver() != null
+ && !_component.getPage().getChangeObserver().isLocked()) {
+
+ Tapestry.fireObservedChange(_component, _propertyName, _property);
+ }
+
+ // invoke the method being called either way
+
+ return proxy.invoke(_property, args);
+ }
+
+}
Added: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibProxiedPropertyChangeObserverImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibProxiedPropertyChangeObserverImpl.java?view=auto&rev=509035
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibProxiedPropertyChangeObserverImpl.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/record/CglibProxiedPropertyChangeObserverImpl.java Sun Feb 18 16:04:24 2007
@@ -0,0 +1,97 @@
+// Copyright 2004, 2005 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.record;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.Factory;
+
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.enhance.EnhanceUtils;
+
+
+/**
+ * Default implementation of {@link PropertyChangeObserver} that creates a bytecode enhanced
+ * proxy instance of {@link CglibPropertyChangeInterceptor} to notify Tapestry of changes
+ * made to the first level public properties available on the observed object.
+ */
+public class CglibProxiedPropertyChangeObserverImpl implements PropertyChangeObserver
+{
+
+ /**
+ * Holds a mapping of previously enhanced property class proxy {@link Factory} objects
+ * keyed off of {@link IComponent#getIdPath()} + <code>propertyName</code>.
+ */
+ private Map _enhancedMap = new WeakHashMap();
+
+ /**
+ * Holds previously reflected {@link Class#getName()} values on any property instances
+ * that don't have default constructors, which we can't enhance.
+ */
+ private Map _badMap = new WeakHashMap();
+
+ public CglibProxiedPropertyChangeObserverImpl()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object observePropertyChanges(IComponent component, Object property, String propertyName)
+ {
+ Defense.notNull(component, "component");
+
+ // can't proxy a null object
+ if (property == null)
+ return null;
+
+ // if it's already proxied just return it
+
+ if (Enhancer.isEnhanced(property.getClass()))
+ return property;
+
+ // possibly already did the expensive reflection on this type
+
+ if (_badMap.get(property.getClass().getName()) != null)
+ return property;
+
+ Factory f = (Factory) _enhancedMap.get(component.getIdPath() + propertyName);
+
+ if (f == null) {
+
+ // some classes can't have their constructors detected until now..
+
+ if (!EnhanceUtils.hasEmptyConstructor(property.getClass())) {
+
+ _badMap.put(property.getClass().getName(), Boolean.TRUE);
+ return property;
+ }
+
+ Object ret = Enhancer.create(property.getClass(), property.getClass().getInterfaces(),
+ new ObservableMethodFilter(),
+ new Callback[] { new LazyProxyDelegate(property), new CglibPropertyChangeInterceptor(component, property, propertyName)});
+
+ f = (Factory)ret;
+ _enhancedMap.put(component.getIdPath() + propertyName, f);
+
+ return ret;
+ }
+
+ return f.newInstance(new Callback[] { new LazyProxyDelegate(property), new CglibPropertyChangeInterceptor(component, property, propertyName)});
+ }
+}