You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/01/20 23:47:01 UTC

svn commit: r613698 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/services/ test/java/org/apache/tapestry/internal/services/ t...

Author: hlship
Date: Sun Jan 20 14:47:00 2008
New Revision: 613698

URL: http://svn.apache.org/viewvc?rev=613698&view=rev
Log:
TAPESTRY-1991: It should be easier to access an Application State Object without forcing its creation

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/transform/MaybeStateHolder.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/annotations/ApplicationState.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/annotations/ApplicationState.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/annotations/ApplicationState.java?rev=613698&r1=613697&r2=613698&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/annotations/ApplicationState.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/annotations/ApplicationState.java Sun Jan 20 14:47:00 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -23,20 +23,23 @@
 import java.lang.annotation.Target;
 
 /**
- * Marker annotation for a field that is an <em>application state object</em> as controlled by the
- * {@link ApplicationStateManager}.
+ * Marker annotation for a field that is an <em>application state object</em> as controlled by the {@link
+ * ApplicationStateManager}.
  * <p/>
- * An ASO file may have a companion field, of type boolean, used to see if the ASO has been created yet.
- * If another field exists with the same name, suffixed with "Exists" (i.e., "_aso" for the ASO
- * field, and "_asoExists" for the companion field) and the type of that field is boolean, then access
- * to the field will determine whether the ASO has already been created. This is necessary because
- * even a null check ("_aso != null") will force the ASO to be created. Instead, check the companion
- * boolean field ("_asoExists").
+ * An ASO file may have a companion field, of type boolean, used to see if the ASO has been created yet. If another
+ * field exists with the same name, suffixed with "Exists" (i.e., "_aso" for the ASO field, and "_asoExists" for the
+ * companion field) and the type of that field is boolean, then access to the field will determine whether the ASO has
+ * already been created. This is necessary because even a null check ("_aso != null") will force the ASO to be created.
+ * Instead, check the companion boolean field ("_asoExists").
  */
 @Target(FIELD)
 @Documented
 @Retention(RUNTIME)
 public @interface ApplicationState
 {
-
+    /**
+     * If true (the default), then referencing an field marked with the annotation will create the ASO.  If false, then
+     * accessing the field will not create the ASO, it will only allow access to it if it already exists.
+     */
+    boolean create() default true;
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java?rev=613698&r1=613697&r2=613698&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java Sun Jan 20 14:47:00 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -56,8 +56,8 @@
     }
 
     /**
-     * The map will be extended periodically as new ASOs, not in the configuration, are encountered.
-     * Thut is is thread safe.
+     * The map will be extended periodically as new ASOs, not in the configuration, are encountered. Thut is is thread
+     * safe.
      */
     private final Map<Class, ApplicationStateAdapter> _classToAdapter = newConcurrentMap();
 
@@ -125,6 +125,13 @@
     public <T> T get(Class<T> asoClass)
     {
         return getAdapter(asoClass).getOrCreate();
+    }
+
+    public <T> T getIfExists(Class<T> asoClass)
+    {
+        ApplicationStateAdapter<T> adapter = getAdapter(asoClass);
+
+        return adapter.exists() ? adapter.getOrCreate() : null;
     }
 
     public <T> void set(Class<T> asoClass, T aso)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java?rev=613698&r1=613697&r2=613698&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java Sun Jan 20 14:47:00 2008
@@ -26,8 +26,8 @@
 import java.util.List;
 
 /**
- * Looks for the {@link ApplicationState} annotation and converts read and write access on such
- * fields into calls to the {@link ApplicationStateManager}.
+ * Looks for the {@link ApplicationState} annotation and converts read and write access on such fields into calls to the
+ * {@link ApplicationStateManager}.
  */
 public class ApplicationStateWorker implements ComponentClassTransformWorker
 {
@@ -53,25 +53,29 @@
 
         for (String fieldName : names)
         {
-            String fieldType = transformation.getFieldType(fieldName);
+            processField(fieldName, managerFieldName, transformation);
+        }
+    }
+
+    private void processField(String fieldName, String managerFieldName, ClassTransformation transformation)
+    {
+        String fieldType = transformation.getFieldType(fieldName);
 
-            Class fieldClass = _componentClassCache.forName(fieldType);
+        Class fieldClass = _componentClassCache.forName(fieldType);
 
-            String typeFieldName = transformation.addInjectedField(Class.class, fieldName + "_type", fieldClass);
+        String typeFieldName = transformation.addInjectedField(Class.class, fieldName + "_type", fieldClass);
 
-            replaceRead(transformation, fieldName, fieldType, managerFieldName, typeFieldName);
+        replaceRead(transformation, fieldName, fieldType, managerFieldName, typeFieldName);
 
-            replaceWrite(transformation, fieldName, fieldType, managerFieldName, typeFieldName);
+        replaceWrite(transformation, fieldName, fieldType, managerFieldName, typeFieldName);
 
-            transformation.removeField(fieldName);
+        transformation.removeField(fieldName);
 
-            String booleanFieldName = fieldName + "Exists";
+        String booleanFieldName = fieldName + "Exists";
 
-            if (transformation.isField(booleanFieldName) && transformation.getFieldType(booleanFieldName).equals(
-                    "boolean"))
-            {
-                replaceFlagRead(transformation, booleanFieldName, typeFieldName, managerFieldName);
-            }
+        if (transformation.isField(booleanFieldName) && transformation.getFieldType(booleanFieldName).equals("boolean"))
+        {
+            replaceFlagRead(transformation, booleanFieldName, typeFieldName, managerFieldName);
         }
     }
 
@@ -111,13 +115,17 @@
     private void replaceRead(ClassTransformation transformation, String fieldName, String fieldType,
                              String managerFieldName, String typeFieldName)
     {
+        ApplicationState annotation = transformation.getFieldAnnotation(fieldName, ApplicationState.class);
+
 
         String readMethodName = transformation.newMemberName("read", fieldName);
 
         TransformMethodSignature readMethodSignature = new TransformMethodSignature(Modifier.PRIVATE, fieldType,
                                                                                     readMethodName, null, null);
 
-        String body = format("return (%s) %s.get(%s);", fieldType, managerFieldName, typeFieldName);
+        String methodName = annotation.create() ? "get" : "getIfExists";
+
+        String body = format("return (%s) %s.%s(%s);", fieldType, managerFieldName, methodName, typeFieldName);
 
         transformation.addMethod(readMethodSignature, body);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java?rev=613698&r1=613697&r2=613698&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java Sun Jan 20 14:47:00 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -15,17 +15,16 @@
 package org.apache.tapestry.services;
 
 /**
- * Responsible for managing <em>application state objects</em>, objects which persist between
- * requests, but are not tied to any individual page or component. ASOs are also created on demand.
- * ASOs are typically stored in the session, so that they are specific to a particular client.
+ * Responsible for managing <em>application state objects</em>, objects which persist between requests, but are not tied
+ * to any individual page or component. ASOs are also created on demand. ASOs are typically stored in the session, so
+ * that they are specific to a particular client.
  */
 public interface ApplicationStateManager
 {
     /**
-     * For a given class, find the ASO for the class, creating it if necessary. The manager has a
-     * configuration that determines how an instance is stored and created as needed. A requested
-     * ASO not in the configuration is assumed to be created via a no-args constructor, and stored
-     * in the session.
+     * For a given class, find the ASO for the class, creating it if necessary. The manager has a configuration that
+     * determines how an instance is stored and created as needed. A requested ASO not in the configuration is assumed
+     * to be created via a no-args constructor, and stored in the session.
      *
      * @param <T>
      * @param asoClass identifies the ASO to access or create
@@ -34,6 +33,16 @@
     <T> T get(Class<T> asoClass);
 
     /**
+     * For a given class, find the ASO for the class. The manager has a configuration that determines how an instance is
+     * stored.
+     *
+     * @param <T>
+     * @param asoClass identifies the ASO to access or create
+     * @return the ASO instance or null if it does not already exist
+     */
+    <T> T getIfExists(Class<T> asoClass);
+
+    /**
      * Returns true if the ASO already exists, false if it has not yet been created.
      *
      * @param asoClass used to select the ASO
@@ -42,8 +51,8 @@
     <T> boolean exists(Class<T> asoClass);
 
     /**
-     * Stores a new ASO, replacing the existing ASO (if any). Storing the value null will delete the
-     * ASO so that it may be re-created later.
+     * Stores a new ASO, replacing the existing ASO (if any). Storing the value null will delete the ASO so that it may
+     * be re-created later.
      *
      * @param <T>
      * @param asoClass the type of ASO

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java?rev=613698&r1=613697&r2=613698&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java Sun Jan 20 14:47:00 2008
@@ -179,4 +179,58 @@
 
         verify();
     }
+
+    @Test
+    public void get_if_exists_and_it_doesnt()
+    {
+        String strategyName = "ethereal";
+        ApplicationStatePersistenceStrategy strategy = mockApplicationStatePersistenceStrategy();
+        ApplicationStatePersistenceStrategySource source = mockApplicationStatePersistenceStrategySource();
+        Class asoClass = ReadOnlyBean.class;
+        ApplicationStateCreator<ReadOnlyBean> creator = mockApplicationStateCreator();
+
+        Map<Class, ApplicationStateContribution> configuration = Collections.singletonMap(asoClass,
+                                                                                          new ApplicationStateContribution(
+                                                                                                  strategyName,
+                                                                                                  creator));
+
+        train_get(source, strategyName, strategy);
+        train_exists(strategy, asoClass, false);
+
+        replay();
+
+        ApplicationStateManager manager = new ApplicationStateManagerImpl(configuration, source);
+
+        assertNull(manager.getIfExists(asoClass));
+
+        verify();
+    }
+
+    @Test
+    public void get_if_exists_when_it_does_exist()
+    {
+        String strategyName = "ethereal";
+        ApplicationStatePersistenceStrategy strategy = mockApplicationStatePersistenceStrategy();
+        ApplicationStatePersistenceStrategySource source = mockApplicationStatePersistenceStrategySource();
+        Class asoClass = ReadOnlyBean.class;
+        ApplicationStateCreator<ReadOnlyBean> creator = mockApplicationStateCreator();
+        ReadOnlyBean aso = new ReadOnlyBean();
+
+        Map<Class, ApplicationStateContribution> configuration = Collections.singletonMap(asoClass,
+                                                                                          new ApplicationStateContribution(
+                                                                                                  strategyName,
+                                                                                                  creator));
+
+        train_get(source, strategyName, strategy);
+        train_exists(strategy, asoClass, true);
+        train_get(strategy, asoClass, creator, aso);
+
+        replay();
+
+        ApplicationStateManager manager = new ApplicationStateManagerImpl(configuration, source);
+
+        assertSame(manager.getIfExists(asoClass), aso);
+
+        verify();
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java?rev=613698&r1=613697&r2=613698&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java Sun Jan 20 14:47:00 2008
@@ -21,6 +21,7 @@
 import org.apache.tapestry.annotations.ApplicationState;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.internal.transform.MaybeStateHolder;
 import org.apache.tapestry.internal.transform.StateHolder;
 import org.apache.tapestry.ioc.internal.services.ClassFactoryClassPool;
 import org.apache.tapestry.ioc.internal.services.ClassFactoryImpl;
@@ -170,5 +171,61 @@
         verify();
     }
 
+
+    @Test
+    public void read_field_with_create_disabled() throws Exception
+    {
+        ApplicationStateManager manager = mockApplicationStateManager();
+        Logger logger = mockLogger();
+        MutableComponentModel model = mockMutableComponentModel();
+        InternalComponentResources resources = mockInternalComponentResources();
+        ComponentClassCache cache = mockComponentClassCache();
+
+        Class asoClass = SimpleASO.class;
+
+        CtClass ctClass = findCtClass(MaybeStateHolder.class);
+
+        InternalClassTransformation transformation = new InternalClassTransformationImpl(ctClass, _classFactory, logger,
+                                                                                         null);
+        train_forName(cache, asoClass);
+
+        replay();
+
+        new ApplicationStateWorker(manager, cache).transform(transformation, model);
+
+        verify();
+
+        transformation.finish();
+
+        Instantiator instantiator = transformation.createInstantiator();
+
+        Object component = instantiator.newInstance(resources);
+
+        // Test read property
+
+        train_getIfExists(manager, asoClass, null);
+
+        replay();
+
+        assertNull(_access.get(component, "bean"));
+
+        verify();
+
+
+        Object aso = new SimpleASO();
+
+        train_getIfExists(manager, asoClass, aso);
+
+        replay();
+
+        assertSame(_access.get(component, "bean"), aso);
+
+        verify();
+    }
+
+    protected final void train_getIfExists(ApplicationStateManager manager, Class asoClass, Object aso)
+    {
+        expect(manager.getIfExists(asoClass)).andReturn(aso);
+    }
 
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/transform/MaybeStateHolder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/transform/MaybeStateHolder.java?rev=613698&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/transform/MaybeStateHolder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/transform/MaybeStateHolder.java Sun Jan 20 14:47:00 2008
@@ -0,0 +1,30 @@
+// Copyright 2008 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.transform;
+
+import org.apache.tapestry.annotations.ApplicationState;
+import org.apache.tapestry.internal.services.SimpleASO;
+
+public class MaybeStateHolder
+{
+    @ApplicationState(create = false)
+    private SimpleASO _bean;
+
+
+    public SimpleASO getBean()
+    {
+        return _bean;
+    }
+}