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
- * [EMAIL PROTECTED] ApplicationStateManager}.
+ * Marker annotation for a field that is an <em>application state object</em>
as controlled by the [EMAIL PROTECTED]
+ * 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 [EMAIL PROTECTED] ApplicationState} annotation and converts
read and write access on such
- * fields into calls to the [EMAIL PROTECTED] ApplicationStateManager}.
+ * Looks for the [EMAIL PROTECTED] ApplicationState} annotation and converts
read and write access on such fields into calls to the
+ * [EMAIL PROTECTED] 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;
+ }
+}