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;
+ }
+}