Author: hlship Date: Fri Mar 30 08:25:06 2007 New Revision: 524122 URL: http://svn.apache.org/viewvc?view=rev&rev=524122 Log: TAPESTRY-1368: The @ApplicationState annotation should be capable of enhancing a boolean field to indicate whether the state object already exists
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/ApplicationState.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategy.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStatePersistenceStrategy.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategyTest.java tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/StateHolder.java Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/ApplicationState.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/ApplicationState.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/ApplicationState.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/ApplicationState.java Fri Mar 30 08:25:06 2007 @@ -26,10 +26,18 @@ /** * 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 te companion + * boolean field ("_asoExists"). */ @Target(FIELD) @Documented @Retention(RUNTIME) -public @interface ApplicationState { +public @interface ApplicationState +{ } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateManagerImpl.java Fri Mar 30 08:25:06 2007 @@ -53,13 +53,18 @@ { _strategy.set(_asoClass, aso); } + + boolean exists() + { + return _strategy.exists(_asoClass); + } }; /** * The map will be extended periodically as new ASOs, not in the configuration, are encountered. - * Thus is is thread safe. + * Thut is is thread safe. */ - private final Map<Class, ApplicationStateAdapter> _classToAdapter; + private final Map<Class, ApplicationStateAdapter> _classToAdapter = newConcurrentMap(); private final ApplicationStatePersistenceStrategySource _source; @@ -67,7 +72,6 @@ public ApplicationStateManagerImpl(Map<Class, ApplicationStateContribution> configuration, ApplicationStatePersistenceStrategySource source) { - _classToAdapter = newConcurrentMap(); _source = source; for (Class asoClass : configuration.keySet()) @@ -88,22 +92,21 @@ private <T> ApplicationStateAdapter<T> newAdapter(final Class<T> asoClass, String strategyName, ApplicationStateCreator<T> creator) { - if (creator == null) - creator = new ApplicationStateCreator<T>() + if (creator == null) creator = new ApplicationStateCreator<T>() + { + public T create() { - public T create() + try { - try - { - return asoClass.newInstance(); - } - catch (Exception ex) - { - throw new RuntimeException(ex); - } + return asoClass.newInstance(); } + catch (Exception ex) + { + throw new RuntimeException(ex); + } + } - }; + }; ApplicationStatePersistenceStrategy strategy = _source.get(strategyName); @@ -134,6 +137,11 @@ public <T> void set(Class<T> asoClass, T aso) { getAdapter(asoClass).set(aso); + } + + public <T> boolean exists(Class<T> asoClass) + { + return getAdapter(asoClass).exists(); } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ApplicationStateWorker.java Fri Mar 30 08:25:06 2007 @@ -14,6 +14,8 @@ package org.apache.tapestry.internal.services; +import static java.lang.String.format; + import java.lang.reflect.Modifier; import java.util.List; @@ -43,8 +45,7 @@ { List<String> names = transformation.findFieldsWithAnnotation(ApplicationState.class); - if (names.isEmpty()) - return; + if (names.isEmpty()) return; String managerFieldName = transformation.addInjectedField( ApplicationStateManager.class, @@ -67,21 +68,46 @@ } - String typeField = transformation.addInjectedField( + String typeFieldName = transformation.addInjectedField( Class.class, fieldName + "_type", fieldClass); - replaceRead(transformation, fieldName, fieldType, managerFieldName, typeField); + replaceRead(transformation, fieldName, fieldType, managerFieldName, typeFieldName); - replaceWrite(transformation, fieldName, fieldType, managerFieldName, typeField); + replaceWrite(transformation, fieldName, fieldType, managerFieldName, typeFieldName); transformation.removeField(fieldName); + + String booleanFieldName = fieldName + "Exists"; + + if (transformation.isField(booleanFieldName) + && transformation.getFieldType(booleanFieldName).equals("boolean")) + { + replaceFlagRead(transformation, booleanFieldName, typeFieldName, managerFieldName); + } } } + private void replaceFlagRead(ClassTransformation transformation, String booleanFieldName, + String typeFieldName, String managerFieldName) + { + String readMethodName = transformation.newMemberName("read", booleanFieldName); + + MethodSignature sig = new MethodSignature(Modifier.PRIVATE, "boolean", readMethodName, + null, null); + + String body = format("return %s.exists(%s);", managerFieldName, typeFieldName); + + transformation.addMethod(sig, body); + + transformation.replaceReadAccess(booleanFieldName, readMethodName); + transformation.makeReadOnly(booleanFieldName); + transformation.removeField(booleanFieldName); + } + private void replaceWrite(ClassTransformation transformation, String fieldName, - String fieldType, String managerFieldName, String typeField) + String fieldType, String managerFieldName, String typeFieldName) { String writeMethodName = transformation.newMemberName("write", fieldName); @@ -89,7 +115,7 @@ writeMethodName, new String[] { fieldType }, null); - String body = String.format("%s.set(%s, $1);", managerFieldName, typeField); + String body = format("%s.set(%s, $1);", managerFieldName, typeFieldName); transformation.addMethod(writeSignature, body); @@ -97,7 +123,7 @@ } private void replaceRead(ClassTransformation transformation, String fieldName, - String fieldType, String managerFieldName, String typeField) + String fieldType, String managerFieldName, String typeFieldName) { String readMethodName = transformation.newMemberName("read", fieldName); @@ -105,11 +131,7 @@ MethodSignature readMethodSignature = new MethodSignature(Modifier.PRIVATE, fieldType, readMethodName, null, null); - String body = String.format( - "return (%s) %s.get(%s);", - fieldType, - managerFieldName, - typeField); + String body = format("return (%s) %s.get(%s);", fieldType, managerFieldName, typeFieldName); transformation.addMethod(readMethodSignature, body); Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java Fri Mar 30 08:25:06 2007 @@ -952,6 +952,22 @@ return type.getName(); } + public boolean isField(String fieldName) + { + failIfFrozen(); + + try + { + CtField field = _ctClass.getDeclaredField(fieldName); + + return isInstanceField(field); + } + catch (NotFoundException ex) + { + return false; + } + } + public int getFieldModifiers(String fieldName) { failIfFrozen(); Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategy.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategy.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategy.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategy.java Fri Mar 30 08:25:06 2007 @@ -71,4 +71,13 @@ getSession().setAttribute(key, aso); } + public <T> boolean exists(Class<T> asoClass) + { + String key = buildKey(asoClass); + + Session session = _sessionHolder.getSession(false); + + return session != null && session.getAttribute(key) != null; + } + } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStateManager.java Fri Mar 30 08:25:06 2007 @@ -35,6 +35,15 @@ <T> T get(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 + * @return true if ASO exists, false if null + */ + <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. * Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStatePersistenceStrategy.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStatePersistenceStrategy.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStatePersistenceStrategy.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ApplicationStatePersistenceStrategy.java Fri Mar 30 08:25:06 2007 @@ -35,4 +35,7 @@ * instance to store, or null to delete existing */ <T> void set(Class<T> asoClass, T aso); + + /** Returns true if the ASO already exists, false if null. */ + <T> boolean exists(Class<T> asoClass); } Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ClassTransformation.java Fri Mar 30 08:25:06 2007 @@ -184,6 +184,14 @@ String getFieldType(String fieldName); /** + * Returns true if the indicated name is a private instance field. + * + * @param fieldName + * @return true if field exists + */ + boolean isField(String fieldName); + + /** * Defines a new declared field for the class. The suggestedName may be modified to ensure * uniqueness. * Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Fri Mar 30 08:25:06 2007 @@ -944,4 +944,9 @@ { expect(annotation.value()).andReturn(value).atLeastOnce(); } + + protected final <T> void train_exists(ApplicationStatePersistenceStrategy strategy, Class<T> asoClass, boolean exists) + { + expect(strategy.exists(asoClass)).andReturn(exists); + } } Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/appstate.apt Fri Mar 30 08:25:06 2007 @@ -40,6 +40,22 @@ Assigning a value to an ASO field will store that value. Assigning null to an ASO field will remove the ASO (reading the field subsequently will force a new ASO instance to be created). +Check for Creation + + Scalable web applications do not create the server-side session needlessly. If you can avoid creating the session, especially on first + access to your web application, you will be able to handle an order of magnatude more users. So, if you can avoid creating the ASO, you should do so. + + But how to avoid creating it? Simply checkng ("_myState != null") will force the creation of the ASO and the session to store it in. + + Instead, create a second field: + ++---+ + private boolean _myStateExists; ++---+ + + This companion field is used to see if the ASO already exists. It is not annotated; it is located by name ("Exists" is appended to the name of the field + storing the ASO). It must be type boolean and must be a private instance variable. + Persistence Strategies Each ASO is managed according to a persistence strategy. The default persistence strategy, "session", stores the ASOs inside the session. Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateManagerImplTest.java Fri Mar 30 08:25:06 2007 @@ -63,6 +63,58 @@ @SuppressWarnings("unchecked") @Test + public void check_exists_when_null() + { + String strategyName = "ethereal"; + ApplicationStatePersistenceStrategy strategy = newApplicationStatePersistenceStrategy(); + ApplicationStatePersistenceStrategySource source = newApplicationStatePersistenceStrategySource(); + Class asoClass = ReadOnlyBean.class; + ApplicationStateCreator<ReadOnlyBean> creator = newApplicationStateCreator(); + + 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); + + assertFalse(manager.exists(asoClass)); + + verify(); + } + + @SuppressWarnings("unchecked") + @Test + public void check_exists_when_true() + { + String strategyName = "ethereal"; + ApplicationStatePersistenceStrategy strategy = newApplicationStatePersistenceStrategy(); + ApplicationStatePersistenceStrategySource source = newApplicationStatePersistenceStrategySource(); + Class asoClass = ReadOnlyBean.class; + ApplicationStateCreator<ReadOnlyBean> creator = newApplicationStateCreator(); + + Map<Class, ApplicationStateContribution> configuration = Collections.singletonMap( + asoClass, + new ApplicationStateContribution(strategyName, creator)); + + train_get(source, strategyName, strategy); + train_exists(strategy, asoClass, true); + + replay(); + + ApplicationStateManager manager = new ApplicationStateManagerImpl(configuration, source); + + assertTrue(manager.exists(asoClass)); + + verify(); + } + + @SuppressWarnings("unchecked") + @Test public void set_configured_aso() { String strategyName = "ethereal"; Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ApplicationStateWorkerTest.java Fri Mar 30 08:25:06 2007 @@ -100,6 +100,16 @@ Object component = instantiator.newInstance(resources); + // Test the companion flag field + + expect(manager.exists(asoClass)).andReturn(true); + + replay(); + + assertEquals(_access.get(component, "beanExists"), true); + + verify(); + // Test read property (get from ASM) Object aso = new ReadOnlyBean(); Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java Fri Mar 30 08:25:06 2007 @@ -283,6 +283,21 @@ } @Test + public void get_field_exists() throws Exception + { + Log log = newLog(); + + replay(); + + ClassTransformation ct = createClassTransformation(CheckFieldType.class, log); + + assertTrue(ct.isField("_privateField")); + assertFalse(ct.isField("_doesNotExist")); + + verify(); + } + + @Test public void find_fields_of_type_excludes_claimed_fields() throws Exception { Log log = newLog(); Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategyTest.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategyTest.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategyTest.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/SessionApplicationStatePersistenceStrategyTest.java Fri Mar 30 08:25:06 2007 @@ -26,7 +26,7 @@ @Test public void get_aso_already_exists() { - SessionHolder holder = newMock(SessionHolder.class); + SessionHolder holder = newSessionHolder(); Session session = newSession(); Class asoClass = ReadOnlyBean.class; Object aso = new ReadOnlyBean(); @@ -48,15 +48,44 @@ @SuppressWarnings("unchecked") @Test + public void check_exists_does_not_create_session() + { + SessionHolder holder = newSessionHolder(); + Class asoClass = ReadOnlyBean.class; + + train_getSession(holder, false, null); + + replay(); + + ApplicationStatePersistenceStrategy strategy = new SessionApplicationStatePersistenceStrategy( + holder); + + assertFalse(strategy.exists(asoClass)); + + verify(); + } + + private SessionHolder newSessionHolder() + { + return newMock(SessionHolder.class); + } + + @SuppressWarnings("unchecked") + @Test public void get_aso_needs_to_be_created() { - SessionHolder holder = newMock(SessionHolder.class); + SessionHolder holder = newSessionHolder(); Session session = newSession(); Class asoClass = ReadOnlyBean.class; Object aso = new ReadOnlyBean(); String key = "aso:" + asoClass.getName(); ApplicationStateCreator creator = newApplicationStateCreator(); + // First for exists() + train_getSession(holder, false, session); + train_getAttribute(session, key, null); + + // Second for get() train_getSession(holder, true, session); train_getAttribute(session, key, null); @@ -64,13 +93,21 @@ session.setAttribute(key, aso); + // Then for exists() after + train_getSession(holder, false, session); + train_getAttribute(session, key, aso); + replay(); ApplicationStatePersistenceStrategy strategy = new SessionApplicationStatePersistenceStrategy( holder); + assertFalse(strategy.exists(asoClass)); + assertSame(strategy.get(asoClass, creator), aso); + assertTrue(strategy.exists(asoClass)); + verify(); } @@ -78,7 +115,7 @@ @Test public void set_aso() { - SessionHolder holder = newMock(SessionHolder.class); + SessionHolder holder = newSessionHolder(); Session session = newSession(); Class asoClass = ReadOnlyBean.class; Object aso = new ReadOnlyBean(); Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/StateHolder.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/StateHolder.java?view=diff&rev=524122&r1=524121&r2=524122 ============================================================================== --- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/StateHolder.java (original) +++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/StateHolder.java Fri Mar 30 08:25:06 2007 @@ -21,6 +21,8 @@ @ApplicationState private ReadOnlyBean _bean; + private boolean _beanExists; + public ReadOnlyBean getBean() { return _bean; @@ -29,6 +31,11 @@ public void setBean(ReadOnlyBean bean) { _bean = bean; + } + + public boolean getBeanExists() + { + return _beanExists; } }