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 2006/09/02 19:03:36 UTC
svn commit: r439617 - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/internal/ioc/services/
main/java/org/apache/tapestry/internal/services/
main/java/org/apache/tapestry/internal/structure/
main/java/org/apache/tapestry/...
Author: hlship
Date: Sat Sep 2 10:03:34 2006
New Revision: 439617
URL: http://svn.apache.org/viewvc?rev=439617&view=rev
Log:
Change the LoggingDecorator to not endlessly re-log the exact same exception as the stack unwinds (when an exception is thrown).
Split a few methods of ComponentLifecycle into their own interface, PageLifecycleListener.
Add new tests for ParameterWorker, and fix some bugs (and make some improvements).
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionTracker.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/PageLifecycleListener.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterComponent.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceLogger.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/ParameterWorker.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.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/services/TransformConstants.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceLoggerTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/PageImplTest.java
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImpl.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImpl.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,38 @@
+// Copyright 2006 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.ioc.services;
+
+import java.util.Set;
+
+import org.apache.tapestry.ioc.services.ExceptionTracker;
+
+import static org.apache.tapestry.util.CollectionFactory.newSet;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ExceptionTrackerImpl implements ExceptionTracker
+{
+ private final Set<Throwable> _exceptions = newSet();
+
+ public boolean exceptionLogged(Throwable exception)
+ {
+ boolean result = _exceptions.contains(exception);
+
+ _exceptions.add(exception);
+
+ return result;
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImpl.java Sat Sep 2 10:03:34 2006
@@ -21,6 +21,7 @@
import org.apache.commons.logging.Log;
import org.apache.tapestry.ioc.services.ClassFab;
import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.ExceptionTracker;
import org.apache.tapestry.ioc.services.LoggingDecorator;
import org.apache.tapestry.ioc.services.MethodIterator;
import org.apache.tapestry.ioc.services.MethodSignature;
@@ -36,16 +37,19 @@
{
private final ClassFactory _classFactory;
- public LoggingDecoratorImpl(ClassFactory classFactory)
+ private final ExceptionTracker _exceptionTracker;
+
+ public LoggingDecoratorImpl(ClassFactory classFactory, ExceptionTracker exceptionTracker)
{
_classFactory = classFactory;
+ _exceptionTracker = exceptionTracker;
}
public <T> T build(Class<T> serviceInterface, T delegate, String serviceId, Log serviceLog)
{
Class interceptorClass = createInterceptorClass(serviceInterface, serviceId);
- ServiceLogger logger = new ServiceLogger(serviceLog);
+ ServiceLogger logger = new ServiceLogger(serviceLog, _exceptionTracker);
Constructor cc = interceptorClass.getConstructors()[0];
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceLogger.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceLogger.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceLogger.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/services/ServiceLogger.java Sat Sep 2 10:03:34 2006
@@ -20,6 +20,7 @@
import org.apache.commons.logging.Log;
import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+import org.apache.tapestry.ioc.services.ExceptionTracker;
import org.apache.tapestry.util.Defense;
/**
@@ -32,15 +33,18 @@
{
private final Log _log;
+ private final ExceptionTracker _exceptionTracker;
+
private static final String ENTER = "ENTER";
private static final String EXIT = " EXIT";
private static final String FAIL = " FAIL";
- public ServiceLogger(Log log)
+ public ServiceLogger(Log log, ExceptionTracker exceptionTracker)
{
_log = log;
+ _exceptionTracker = exceptionTracker;
}
/** Returns true if the debugging is enabled for the underlying Log. */
@@ -169,6 +173,11 @@
/** Invoked when method invocation instead throws an exception. */
public void fail(String name, Throwable t)
{
- _log.debug(format("[%s] %s -- %s", FAIL, name, t.getClass().getName()), t);
+ if (_log.isDebugEnabled())
+ {
+ _log.debug(
+ format("[%s] %s -- %s", FAIL, name, t.getClass().getName()),
+ _exceptionTracker.exceptionLogged(t) ? null : t);
+ }
}
}
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?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- 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 Sat Sep 2 10:03:34 2006
@@ -535,6 +535,7 @@
addMethodToDescription("extend", methodSignature, methodBody);
+ _addedMethods.add(method);
}
private void addMethodToDescription(String operation, MethodSignature methodSignature,
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java Sat Sep 2 10:03:34 2006
@@ -16,7 +16,6 @@
import java.lang.reflect.Modifier;
import java.util.List;
-import java.util.Map;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.internal.ioc.IOCUtilities;
@@ -26,10 +25,9 @@
import org.apache.tapestry.services.ComponentClassTransformWorker;
import org.apache.tapestry.services.MethodSignature;
import org.apache.tapestry.services.TransformConstants;
+import org.apache.tapestry.services.TransformUtils;
import org.apache.tapestry.util.BodyBuilder;
-import static org.apache.tapestry.util.CollectionFactory.newMap;
-
/**
* Responsible for identifying parameters via the {@link org.apache.tapestry.annotations.Parameter}
* annotation on component fields. This is one of the most complex of the transformations.
@@ -38,20 +36,6 @@
*/
public class ParameterWorker implements ComponentClassTransformWorker
{
- private static final Map<String, String> PRIMITIVE_TO_WRAPPER = newMap();
-
- static
- {
- PRIMITIVE_TO_WRAPPER.put("boolean", "java.lang.Boolean");
- PRIMITIVE_TO_WRAPPER.put("char", "java.lang.Character");
- PRIMITIVE_TO_WRAPPER.put("byte", "java.lang.Byte");
- PRIMITIVE_TO_WRAPPER.put("short", "java.lang.Short");
- PRIMITIVE_TO_WRAPPER.put("int", "java.lang.Integer");
- PRIMITIVE_TO_WRAPPER.put("long", "java.lang.Long");
- PRIMITIVE_TO_WRAPPER.put("float", "java.lang.Float");
- PRIMITIVE_TO_WRAPPER.put("double", "java.lang.Double");
- }
-
public void transform(ClassTransformation transformation, MutableComponentModel model)
{
List<String> fieldNames = transformation.findFieldsWithAnnotation(Parameter.class);
@@ -84,6 +68,8 @@
name,
parameterName,
cachedFieldName,
+ cache,
+ type,
resourcesFieldName,
transformation);
@@ -112,7 +98,8 @@
/** Returns the name of a field that stores whether the parameter binding is invariant. */
private String addParameterSetup(String fieldName, String parameterName,
- String cachedFieldName, String resourcesFieldName, ClassTransformation transformation)
+ String cachedFieldName, boolean cache, String fieldType, String resourcesFieldName,
+ ClassTransformation transformation)
{
String name = transformation
.addField(Modifier.PRIVATE, "boolean", fieldName + "_invariant");
@@ -125,22 +112,24 @@
transformation.extendMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE, body);
- // Now, when the page detaches, ensure that any variant parameters are
- // are returned to default value.
+ // Now, when the component completes rendering, ensure that any variant parameters are
+ // are returned to default value. This isn't necessary when the parameter is not cached,
+ // because (unless the binding is invariant), there's no value to get rid of (and if it is
+ // invariant, there's no need to get rid of it).
- BodyBuilder builder = new BodyBuilder();
- builder.addln("if (! %s)", name);
- builder.begin();
-
- // TODO: Handle primitives
+ if (cache)
+ {
+ BodyBuilder builder = new BodyBuilder();
+ builder.addln("if (! %s)", name);
+ builder.begin();
- builder.addln("%s = null;", fieldName);
- builder.addln("%s = false;", cachedFieldName);
- builder.end();
+ builder.addln("%s = %s;", fieldName, TransformUtils.getDefaultValue(fieldType));
+ builder.addln("%s = false;", cachedFieldName);
+ builder.end();
- transformation.extendMethod(
- TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
- builder.toString());
+ transformation.extendMethod(TransformConstants.CLEANUP_AFTER_RENDER_SIGNATURE, builder
+ .toString());
+ }
return name;
}
@@ -195,8 +184,7 @@
builder.addln("if (%s) return %s;", cachedFieldName, fieldName);
- String cast = PRIMITIVE_TO_WRAPPER.containsKey(fieldType) ? PRIMITIVE_TO_WRAPPER
- .get(fieldType) : fieldType;
+ String cast = TransformUtils.getWrapperType(fieldType);
// The ($r) cast will convert the result to the method return type; generally
// this does nothing. but for primitive types, it will unwrap
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Sat Sep 2 10:03:34 2006
@@ -25,6 +25,7 @@
import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.runtime.ComponentLifecycle;
import org.apache.tapestry.runtime.LifecycleEvent;
+import org.apache.tapestry.runtime.PageLifecycleListener;
import org.apache.tapestry.runtime.RenderCommand;
import org.apache.tapestry.runtime.RenderQueue;
@@ -42,7 +43,7 @@
*
* @author Howard M. Lewis Ship
*/
-public class ComponentPageElementImpl implements ComponentPageElement
+public class ComponentPageElementImpl implements ComponentPageElement, PageLifecycleListener
{
private final Page _page;
@@ -325,6 +326,14 @@
/** Pushes AfterRender and BeforeRender phase commands onto the queue. */
public void render(MarkupWriter writer, RenderQueue queue)
{
+ // Here's the problem: if an exception gets thrown during rendering, then
+ // some components may never see their AfterRender phase cleanup occur, leaving
+ // the page as a whole in an undesirable state. I suppose
+ // that the pageDidDetach() would be another place to clean things up, but perhaps
+ // RenderQueue needs to catch exceptions and invoke commands that related to cleanup?
+ // Or have a way to determine if the page is "dirty" and should not go back into the
+ // pool?
+
queue.push(_afterRender);
queue.push(_beforeRender);
}
@@ -424,6 +433,21 @@
public boolean isRendering()
{
return _rendering;
+ }
+
+ public void containingPageDidAttach()
+ {
+ _component.containingPageDidAttach();
+ }
+
+ public void containingPageDidDetach()
+ {
+ _component.containingPageDidDetach();
+ }
+
+ public void containingPageDidLoad()
+ {
+ _component.containingPageDidLoad();
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/Page.java Sat Sep 2 10:03:34 2006
@@ -17,7 +17,7 @@
import java.util.Locale;
import org.apache.commons.logging.Log;
-import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.apache.tapestry.runtime.PageLifecycleListener;
/**
* Represents a unique page within the application.
@@ -56,7 +56,7 @@
* Inform page that it is being detached from the current request. This occurs just before the
* page is returned to the page pool.
*
- * @see ComponentLifecycle#containingPageDidDetach()
+ * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidDetach()
*/
void detached();
@@ -71,17 +71,15 @@
/**
* Inform the page that it is now completely loaded.
*
- * @see ComponentLifecycle#containingPageDidLoad()
+ * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()
*/
void loaded();
/**
- * Adds a component, identified via the {@link org.apache.tapestry.runtime.ComponentLifecycle}
- * interface it implements, to the page. The component will receive various lifecycle
- * notifications.
+ * Adds a listener that is notified of large scale page events.
*/
- void addComponentLifecycle(ComponentLifecycle component);
+ void addLifecycleListener(PageLifecycleListener listener);
/** Returns the log of the root element. */
Log getLog();
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/PageImpl.java Sat Sep 2 10:03:34 2006
@@ -18,7 +18,7 @@
import java.util.Locale;
import org.apache.commons.logging.Log;
-import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.apache.tapestry.runtime.PageLifecycleListener;
import static org.apache.tapestry.util.CollectionFactory.newList;
@@ -31,7 +31,7 @@
private ComponentPageElement _rootElement;
- private final List<ComponentLifecycle> _components = newList();
+ private final List<PageLifecycleListener> _listeners = newList();
public PageImpl(String name, Locale locale)
{
@@ -59,26 +59,27 @@
return _rootElement;
}
- public void addComponentLifecycle(ComponentLifecycle component)
+ public void addLifecycleListener(PageLifecycleListener listener)
{
- _components.add(component);
+ _listeners.add(listener);
}
public void detached()
{
- for (ComponentLifecycle c : _components)
- c.containingPageDidDetach();
+ for (PageLifecycleListener listener : _listeners)
+ listener.containingPageDidDetach();
}
public void loaded()
{
- for (ComponentLifecycle c : _components)
- c.containingPageDidLoad();
+ for (PageLifecycleListener listener : _listeners)
+ listener.containingPageDidLoad();
}
public void attached()
{
- // TODO: Define methods on ComponentLifecycle to invoke
+ for (PageLifecycleListener listener : _listeners)
+ listener.containingPageDidAttach();
}
public Log getLog()
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionTracker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionTracker.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionTracker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/ExceptionTracker.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,36 @@
+// Copyright 2006 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.ioc.services;
+
+/**
+ * Used by {@link org.apache.tapestry.ioc.services.LoggingDecorator} to track which exceptions have
+ * been logged during the current request (the ExceptionTracker is perthread). This keeps redundant
+ * information from appearing in the console output.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public interface ExceptionTracker
+{
+ /**
+ * Returns true if the indicated exception has already been logged (it is assumed that the
+ * exception will be logged if this method returns false). The exception is recorded for later
+ * checks.
+ *
+ * @param exception
+ * to check
+ * @return false if the exception has not been previously checked, true otherwise
+ */
+ boolean exceptionLogged(Throwable exception);
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java Sat Sep 2 10:03:34 2006
@@ -18,6 +18,7 @@
import org.apache.tapestry.internal.ioc.services.ChainBuilderImpl;
import org.apache.tapestry.internal.ioc.services.DefaultImplementationBuilderImpl;
+import org.apache.tapestry.internal.ioc.services.ExceptionTrackerImpl;
import org.apache.tapestry.internal.ioc.services.LoggingDecoratorImpl;
import org.apache.tapestry.internal.ioc.services.MasterObjectProvider;
import org.apache.tapestry.internal.ioc.services.PerThreadServiceLifecycle;
@@ -30,6 +31,7 @@
import org.apache.tapestry.ioc.ServiceLifecycle;
import org.apache.tapestry.ioc.annotations.Id;
import org.apache.tapestry.ioc.annotations.InjectService;
+import org.apache.tapestry.ioc.annotations.Lifecycle;
/**
* Defines the base set of services for the Tapestry IOC container.
@@ -51,9 +53,10 @@
* The LoggingDecorator service is used to decorate a service implementation so that it logs
* method entry and exit (at level debug).
*/
- public LoggingDecorator buildLoggingDecorator()
+ public LoggingDecorator buildLoggingDecorator(@InjectService("ExceptionTracker")
+ ExceptionTracker exceptionTracker)
{
- return new LoggingDecoratorImpl(_classFactory);
+ return new LoggingDecoratorImpl(_classFactory, exceptionTracker);
}
/**
@@ -146,5 +149,12 @@
MappedConfiguration<String, ObjectProvider> configuration)
{
configuration.add("service", new ServiceObjectProvider());
+ }
+
+ /** Used by the {@link org.apache.tapestry.ioc.services.LoggingDecorator} service. */
+ @Lifecycle("perthread")
+ public ExceptionTracker buildExceptionTracker()
+ {
+ return new ExceptionTrackerImpl();
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/ComponentLifecycle.java Sat Sep 2 10:03:34 2006
@@ -26,24 +26,13 @@
*
* @author Howard M. Lewis Ship
*/
-public interface ComponentLifecycle extends ResourceAware
+public interface ComponentLifecycle extends ResourceAware, PageLifecycleListener
{
- /**
- * Invoked when the page finishes loading. This occurs once all components are loaded and all
- * parameters have been set.
- */
- void containingPageDidLoad();
-
- /**
- * Invoked when the page is detached, allowing components a chance to clear out any temporary or
- * client specific state.
- */
- void containingPageDidDetach();
/**
* Lifecycle method invoked at the end of the
* {@link org.apache.tapestry.annotations.AfterRender} render phase. There is no annotation for
- * this method, it is part of AfterRender, but is always invoked. It's specific use to to allow
+ * this method, it is part of AfterRender, but is always invoked. Its specific use is to allow
* components to clean up cached parameter values.
*/
void cleanupAfterRender();
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/PageLifecycleListener.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/PageLifecycleListener.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/PageLifecycleListener.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/PageLifecycleListener.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,37 @@
+// Copyright 2006 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.runtime;
+
+public interface PageLifecycleListener
+{
+ /**
+ * Invoked when the page finishes loading. This occurs once all components are loaded and all
+ * parameters have been set.
+ */
+ void containingPageDidLoad();
+
+ /**
+ * Invoked when the page is detached, allowing components a chance to clear out any temporary or
+ * client specific state.
+ */
+ void containingPageDidDetach();
+
+ /**
+ * Invoked when a page is first attached to the current request, giving components a chance to
+ * initialize for the current request.
+ */
+
+ void containingPageDidAttach();
+}
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?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- 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 Sat Sep 2 10:03:34 2006
@@ -204,14 +204,15 @@
/**
* Replaces all read-references to the specified field with invocations of the specified method
* name. Replacements do not occur in methods added via
- * {@link #addMethod(MethodSignature, String)}.
+ * {@link #addMethod(MethodSignature, String)} or {@link #extendMethod(MethodSignature, String)}.
*/
void replaceReadAccess(String fieldName, String methodName);
/**
* Replaces all write accesses to the specified field with invocations of the specified method
* name. The method should take a single parameter of the same type as the field. Replacements
- * do not occur in methods added via {@link #addMethod(MethodSignature, String)}.
+ * do not occur in methods added via {@link #addMethod(MethodSignature, String)} or
+ * {@link #extendMethod(MethodSignature, String)}.
*/
void replaceWriteAccess(String fieldName, String methodName);
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformConstants.java Sat Sep 2 10:03:34 2006
@@ -34,7 +34,10 @@
private static final String[] LIFECYCLE_METHOD_PARAMETER_TYPES =
{ MarkupWriter.class.getName(), LifecycleEvent.class.getName() };
- /** Signature for {@link org.apache.tapestry.runtime.ComponentLifecycle#containingPageDidLoad()}. */
+ /**
+ * Signature for
+ * {@link org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()}.
+ */
public static final MethodSignature CONTAINING_PAGE_DID_LOAD_SIGNATURE = new MethodSignature(
"containingPageDidLoad");
@@ -44,7 +47,7 @@
/**
* Signature for
- * {@link org.apache.tapestry.runtime.ComponentLifecycle#containingPageDidDetach()}.
+ * {@link org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidDetach()}.
*/
public static final MethodSignature CONTAINING_PAGE_DID_DETACH_SIGNATURE = new MethodSignature(
"containingPageDidDetach");
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TransformUtils.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,97 @@
+// Copyright 2006 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.services;
+
+import java.util.Map;
+
+import org.apache.tapestry.internal.annotations.Utility;
+import org.apache.tapestry.util.CollectionFactory;
+
+/**
+ * Support code for generating code (used when transforming component classes).
+ *
+ * @author Howard M. Lewis Ship
+ */
+@Utility
+public final class TransformUtils
+{
+ private static final Map<String, PrimitiveTypeInfo> _primitives = CollectionFactory.newMap();
+
+ static class PrimitiveTypeInfo
+ {
+ private String _wrapperType;
+
+ private String _defaultValue;
+
+ public PrimitiveTypeInfo(String wrapperType, String defaultValue)
+ {
+ _wrapperType = wrapperType;
+ _defaultValue = defaultValue;
+ }
+
+ public String getDefaultValue()
+ {
+ return _defaultValue;
+ }
+
+ public String getWrapperType()
+ {
+ return _wrapperType;
+ }
+ }
+
+ static
+ {
+ add("boolean", "java.lang.Boolean", "false");
+ add("byte", "java.lang.Byte", "0");
+ add("char", "java.lang.Character", "0");
+ add("short", "java.lang.Short", "0");
+ add("int", "java.lang.Integer", "0");
+ add("long", "java.lang.Long", "0L");
+ add("float", "java.lang.Float", "0.0f");
+ add("double", "java.lang.Double", "0.0d");
+ }
+
+ private static void add(String primitiveType, String wrapperType, String defaultValue)
+ {
+ _primitives.put(primitiveType, new PrimitiveTypeInfo(wrapperType, defaultValue));
+ }
+
+ /**
+ * Returns the wrapper type for a given input type. For primitive types, returns the wrapper
+ * type. For other types, returns the type itself.
+ *
+ * @param type
+ * primitive type name, or fully qualified class name
+ * @return
+ */
+ public static String getWrapperType(String type)
+ {
+ PrimitiveTypeInfo info = _primitives.get(type);
+
+ return info == null ? type : info.getWrapperType();
+ }
+
+ /**
+ * Returns the default value for a type. This is the string "null" for most types, or a literal
+ * value for primtive types.
+ */
+ public static String getDefaultValue(String type)
+ {
+ PrimitiveTypeInfo info = _primitives.get(type);
+
+ return info == null ? "null" : info.getDefaultValue();
+ }
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImplTest.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ExceptionTrackerImplTest.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,40 @@
+// Copyright 2006 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.ioc.services;
+
+import org.apache.tapestry.ioc.services.ExceptionTracker;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ExceptionTrackerImplTest extends Assert
+{
+ @Test
+ public void check_exception_tracking()
+ {
+ Throwable t1 = new RuntimeException();
+ Throwable t2 = new RuntimeException();
+
+ ExceptionTracker et = new ExceptionTrackerImpl();
+
+ for (int i = 0; i < 3; i++)
+ {
+ assertEquals(et.exceptionLogged(t1), i != 0);
+ assertEquals(et.exceptionLogged(t2), i != 0);
+ }
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImplTest.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/LoggingDecoratorImplTest.java Sat Sep 2 10:03:34 2006
@@ -65,9 +65,8 @@
replay();
- LoggingDecorator ld = new LoggingDecoratorImpl(new ClassFactoryImpl());
- Runnable interceptor = ld
- .build(Runnable.class, delegate, "foo.Bar", log);
+ LoggingDecorator ld = newLoggingDecorator();
+ Runnable interceptor = ld.build(Runnable.class, delegate, "foo.Bar", log);
interceptor.run();
@@ -78,6 +77,11 @@
verify();
}
+ private LoggingDecoratorImpl newLoggingDecorator()
+ {
+ return new LoggingDecoratorImpl(new ClassFactoryImpl(), new ExceptionTrackerImpl());
+ }
+
@Test
public void method_throws_runtime_exception()
{
@@ -91,13 +95,14 @@
delegate.run();
setThrowable(t);
+ train_isDebugEnabled(log, true);
+
log.debug("[ FAIL] run -- " + t.getClass().getName(), t);
replay();
- LoggingDecorator ld = new LoggingDecoratorImpl(new ClassFactoryImpl());
- Runnable interceptor = ld
- .build(Runnable.class, delegate, "foo.Bar", log);
+ LoggingDecorator ld = newLoggingDecorator();
+ Runnable interceptor = ld.build(Runnable.class, delegate, "foo.Bar", log);
try
{
@@ -125,16 +130,14 @@
delegate.parse();
setThrowable(t);
+ train_isDebugEnabled(log, true);
+
log.debug("[ FAIL] parse -- " + t.getClass().getName(), t);
replay();
- LoggingDecorator ld = new LoggingDecoratorImpl(new ClassFactoryImpl());
- ExceptionService interceptor = ld.build(
- ExceptionService.class,
- delegate,
- "foo.Bar",
- log);
+ LoggingDecorator ld = newLoggingDecorator();
+ ExceptionService interceptor = ld.build(ExceptionService.class, delegate, "foo.Bar", log);
try
{
@@ -168,12 +171,8 @@
replay();
- LoggingDecorator ld = new LoggingDecoratorImpl(new ClassFactoryImpl());
- UpcaseService interceptor = ld.build(
- UpcaseService.class,
- delegate,
- "foo.Bar",
- log);
+ LoggingDecorator ld = newLoggingDecorator();
+ UpcaseService interceptor = ld.build(UpcaseService.class, delegate, "foo.Bar", log);
assertEquals(interceptor.upcase("barney"), "BARNEY");
@@ -199,12 +198,8 @@
replay();
- LoggingDecorator ld = new LoggingDecoratorImpl(new ClassFactoryImpl());
- AdderService interceptor = ld.build(
- AdderService.class,
- delegate,
- "foo.Bar",
- log);
+ LoggingDecorator ld = newLoggingDecorator();
+ AdderService interceptor = ld.build(AdderService.class, delegate, "foo.Bar", log);
assertEquals(interceptor.add(6, 13), 19);
@@ -231,12 +226,8 @@
replay();
- LoggingDecorator ld = new LoggingDecoratorImpl(new ClassFactoryImpl());
- ToStringService interceptor = ld.build(
- ToStringService.class,
- delegate,
- "foo.Bar",
- log);
+ LoggingDecorator ld = newLoggingDecorator();
+ ToStringService interceptor = ld.build(ToStringService.class, delegate, "foo.Bar", log);
assertEquals(interceptor.toString(), "FROM DELEGATE");
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceLoggerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceLoggerTest.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceLoggerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/ServiceLoggerTest.java Sat Sep 2 10:03:34 2006
@@ -17,6 +17,7 @@
import java.util.Arrays;
import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.services.ExceptionTracker;
import org.apache.tapestry.test.BaseTestCase;
import org.testng.annotations.Test;
@@ -28,26 +29,33 @@
private void try_entry(String methodName, String expected, Object... arguments)
{
Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
log.debug("[ENTER] " + expected);
replay();
- new ServiceLogger(log).entry(methodName, arguments);
+ new ServiceLogger(log, tracker).entry(methodName, arguments);
verify();
}
+ protected final ExceptionTracker newExceptionTracker()
+ {
+ return newMock(ExceptionTracker.class);
+ }
+
private void try_exit(String methodName, String expected, Object result)
{
Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
log.debug("[ EXIT] " + expected);
replay();
- new ServiceLogger(log).exit(methodName, result);
+ new ServiceLogger(log, tracker).exit(methodName, result);
verify();
}
@@ -76,43 +84,95 @@
public void void_exit_test()
{
Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
log.debug("[ EXIT] wilma");
replay();
- new ServiceLogger(log).voidExit("wilma");
+ new ServiceLogger(log, tracker).voidExit("wilma");
verify();
}
@Test
- public void fail_test()
+ public void fail_test_exception_not_already_logged()
{
Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
RuntimeException t = new RuntimeException("Ouch!");
+ train_isDebugEnabled(log, true);
+
+ train_exceptionLogged(tracker, t, false);
+
log.debug("[ FAIL] wilma -- " + t.getClass().getName(), t);
replay();
- new ServiceLogger(log).fail("wilma", t);
+ new ServiceLogger(log, tracker).fail("wilma", t);
+
+ verify();
+ }
+
+ @Test
+ public void fail_test_exception_previously_logged()
+ {
+ Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
+
+ RuntimeException t = new RuntimeException("Ouch!");
+
+ train_isDebugEnabled(log, true);
+
+ train_exceptionLogged(tracker, t, true);
+
+ log.debug("[ FAIL] wilma -- " + t.getClass().getName(), null);
+
+ replay();
+
+ new ServiceLogger(log, tracker).fail("wilma", t);
+
+ verify();
+ }
+
+ @Test
+ public void fail_debug_not_enabled()
+ {
+ Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
+
+ RuntimeException t = new RuntimeException("Ouch!");
+
+ train_isDebugEnabled(log, false);
+
+ replay();
+
+ new ServiceLogger(log, tracker).fail("wilma", t);
verify();
}
+ private void train_exceptionLogged(ExceptionTracker tracker, Throwable exception, boolean logged)
+ {
+ tracker.exceptionLogged(exception);
+ setReturnValue(logged);
+
+ }
+
@Test
public void debug_enabled()
{
Log log = newLog();
+ ExceptionTracker tracker = newExceptionTracker();
train_isDebugEnabled(log, true);
train_isDebugEnabled(log, false);
replay();
- ServiceLogger logger = new ServiceLogger(log);
+ ServiceLogger logger = new ServiceLogger(log, tracker);
assertTrue(logger.isDebugEnabled());
assertFalse(logger.isDebugEnabled());
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterComponent.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterComponent.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterComponent.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,95 @@
+// Copyright 2006 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.services;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+
+/**
+ * Used by {@link org.apache.tapestry.internal.services.ParameterWorkerTest}.
+ *
+ * @author Howard M. Lewis Ship
+ */
+@ComponentClass
+@SuppressNullCheck
+public class ParameterComponent
+{
+ @Parameter
+ private String _object;
+
+ @Parameter(cache = false, name = "uncached")
+ private String _uncachedObject;
+
+ @Parameter(required = true)
+ private int _primitive;
+
+ @Parameter
+ private String _invariantObject;
+
+ @Parameter
+ private long _invariantPrimitive;
+
+ public String getObject()
+ {
+ return _object;
+ }
+
+ public void setObject(String object)
+ {
+ _object = object;
+ }
+
+ public int getPrimitive()
+ {
+ return _primitive;
+ }
+
+ public void setPrimitive(int primitive)
+ {
+ _primitive = primitive;
+ }
+
+ public String getUncachedObject()
+ {
+ return _uncachedObject;
+ }
+
+ public void setUncachedObject(String uncachedObject)
+ {
+ _uncachedObject = uncachedObject;
+ }
+
+ public String getInvariantObject()
+ {
+ return _invariantObject;
+ }
+
+ public void setInvariantObject(String invariantObject)
+ {
+ _invariantObject = invariantObject;
+ }
+
+ public long getInvariantPrimitive()
+ {
+ return _invariantPrimitive;
+ }
+
+ public void setInvariantPrimitive(long invariantPrimitive)
+ {
+ _invariantPrimitive = invariantPrimitive;
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java Sat Sep 2 10:03:34 2006
@@ -14,15 +14,18 @@
package org.apache.tapestry.internal.services;
-import java.lang.reflect.Modifier;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.Loader;
+import javassist.LoaderClassPath;
-import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.InternalComponentResources;
+import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.services.PropertyAccess;
import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.services.ClassTransformation;
-import org.apache.tapestry.services.MethodSignature;
-import org.apache.tapestry.services.TransformConstants;
-import org.testng.annotations.DataProvider;
+import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
/**
@@ -30,207 +33,360 @@
*/
public class ParameterWorkerTest extends InternalBaseTestCase
{
- private static String f(String format, Object... args)
+ private PropertyAccess _access = new PropertyAccessImpl();
+
+ @AfterClass
+ public void cleanup()
{
- return String.format(format, args);
+ _access = null;
}
@Test
- public void standard_cacheable_parameter()
+ public void page_load_behavior() throws Exception
{
- runWorkerCached("_foo", "foo", "", "java.lang.String", "java.lang.String");
+ InternalComponentResources resources = newInternalComponentResources();
+
+ assertNotNull(setupForIntegrationTest(resources));
}
@Test
- public void annotation_name_overrides_default_from_field_name()
+ public void invariant_object_retained_after_detach() throws Exception
{
- runWorkerCached("_foo", "zippy", "zippy", "java.util.Map", "java.util.Map");
+ InternalComponentResources resources = newInternalComponentResources();
+
+ ComponentLifecycle component = setupForIntegrationTest(resources);
+
+ // On first invocation, the resources are queried.
+
+ String value = "To be in Tapestry in the spring time ...";
+
+ train_readParameter(resources, "invariantObject", String.class, value);
+
+ replay();
+
+ assertSame(_access.get(component, "invariantObject"), value);
+
+ verify();
+
+ // No further training needed here.
+
+ replay();
+
+ // Still cached ...
+
+ assertSame(_access.get(component, "invariantObject"), value);
+
+ component.cleanupAfterRender();
+
+ // Still cached ...
+
+ assertSame(_access.get(component, "invariantObject"), value);
+
+ component.containingPageDidDetach();
+
+ // Still cached ...
+
+ assertSame(_access.get(component, "invariantObject"), value);
+
+ verify();
}
- @Test(dataProvider = "primitiveTypes")
- public void primitive_types(String fieldType, String expectedWrapperType)
+ @Test
+ public void invariant_primitive_retained_after_detach() throws Exception
{
- runWorkerCached("_primitive", "primitive", "", fieldType, expectedWrapperType);
+ InternalComponentResources resources = newInternalComponentResources();
+
+ ComponentLifecycle component = setupForIntegrationTest(resources);
+
+ // On first invocation, the resources are queried.
+
+ long value = 123456;
+
+ train_readParameter(resources, "invariantPrimitive", long.class, value);
+
+ replay();
+
+ assertEquals(_access.get(component, "invariantPrimitive"), value);
+
+ verify();
+
+ // No further training needed here.
+
+ replay();
+
+ // Still cached ...
+
+ assertEquals(_access.get(component, "invariantPrimitive"), value);
+
+ component.cleanupAfterRender();
+
+ // Still cached ...
+
+ assertEquals(_access.get(component, "invariantPrimitive"), value);
+
+ verify();
}
- @DataProvider(name = "primitiveTypes")
- public Object[][] primitiveTypes()
+ @Test
+ public void cached_object_read() throws Exception
{
- return new Object[][]
- {
- { "boolean", "java.lang.Boolean" },
- { "short", "java.lang.Short" },
- { "int", "java.lang.Integer" },
- { "byte", "java.lang.Byte" },
- { "char", "java.lang.Character" },
- { "long", "java.lang.Long" },
- { "float", "java.lang.Float" },
- { "double", "java.lang.Double" } };
+ InternalComponentResources resources = newInternalComponentResources();
+
+ ComponentLifecycle component = setupForIntegrationTest(resources);
+
+ train_readParameter(resources, "object", String.class, "first");
+ train_isRendering(resources, false);
+
+ replay();
+
+ assertEquals(_access.get(component, "object"), "first");
+
+ verify();
+
+ // Keeps re-reading the parameter when not rendering.
+
+ train_readParameter(resources, "object", String.class, "second");
+ train_isRendering(resources, false);
+
+ replay();
+
+ assertEquals(_access.get(component, "object"), "second");
+
+ verify();
+
+ // Now, when rendering is active, the value is cached
+
+ train_readParameter(resources, "object", String.class, "third");
+ train_isRendering(resources, true);
+
+ replay();
+
+ assertEquals(_access.get(component, "object"), "third");
+
+ // Does not cause readParameter() to be invoked:
+
+ assertEquals(_access.get(component, "object"), "third");
+
+ verify();
+
+ train_readParameter(resources, "object", String.class, "fourth");
+ train_isRendering(resources, false);
+
+ replay();
+
+ component.cleanupAfterRender();
+
+ assertEquals(_access.get(component, "object"), "fourth");
+
+ verify();
}
- private void runWorkerCached(String fieldName, String parameterName, String annotatedName,
- String fieldType, String wrapperType)
+ @Test
+ public void cached_object_write() throws Exception
{
- ClassTransformation transformation = newClassTransformation();
- MutableComponentModel model = newMutableComponentModel();
- Parameter parameter = newMock(Parameter.class);
+ InternalComponentResources resources = newInternalComponentResources();
- train_findFieldsWithAnnotation(transformation, Parameter.class, fieldName);
- train_getFieldAnnotation(transformation, fieldName, Parameter.class, parameter);
- train_name(parameter, annotatedName);
- train_required(parameter, true);
-
- model.addParameter(parameterName, true);
-
- train_getFieldType(transformation, fieldName, fieldType);
- train_cache(parameter, true);
- train_addField(transformation, Modifier.PRIVATE, "boolean", fieldName + "_cached", "$cache");
- train_getResourcesFieldName(transformation, "$res");
-
- train_addField(
- transformation,
- Modifier.PRIVATE,
- "boolean",
- fieldName + "_invariant",
- "$invariant");
-
- // codeEq() lets us care less about whitespace
-
- train_extendMethod(
- transformation,
- TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
- String.format("$invariant = $res.isInvariant(\"%s\");", parameterName));
-
- train_extendMethod(
- transformation,
- TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
- String.format("if (! $invariant) { %s = null; $cache = false; }", fieldName));
-
- train_newMemberName(transformation, "_read_parameter_" + parameterName, "$read");
-
- train_addMethod(transformation, new MethodSignature(Modifier.PRIVATE, fieldType, "$read",
- null, null), f("{ if ($cache) return %s;", fieldName), f(
- "%s result = ($r) ((%s) $res.readParameter(\"%s\", $type));",
- fieldType,
- wrapperType,
- parameterName), f(
- "if ($invariant || $res.isRendering()) { %s = result; $cache = true; }",
- fieldName), "return result; }");
-
- transformation.replaceReadAccess(fieldName, "$read");
-
- train_newMemberName(transformation, "_update_parameter_" + parameterName, "$write");
-
- train_addMethod(
- transformation,
- new MethodSignature(Modifier.PRIVATE, "void", "$write", new String[]
- { fieldType, }, null),
- f("{ $res.writeParameter(\"%s\", ($w)$1);", parameterName),
- f("if ($res.isRendering()) { %s = $1; $cache = true; } }", fieldName));
+ ComponentLifecycle component = setupForIntegrationTest(resources);
- transformation.replaceWriteAccess(fieldName, "$write");
+ resources.writeParameter("object", "first");
+ train_isRendering(resources, false);
- transformation.claimField(fieldName, parameter);
+ train_readParameter(resources, "object", String.class, "second");
+ train_isRendering(resources, false);
replay();
- new ParameterWorker().transform(transformation, model);
+ _access.set(component, "object", "first");
+ assertEquals(_access.get(component, "object"), "second");
+
+ verify();
+
+ // Now try during rendering ...
+
+ resources.writeParameter("object", "third");
+ train_isRendering(resources, true);
+
+ replay();
+
+ _access.set(component, "object", "third");
+ assertEquals(_access.get(component, "object"), "third");
+
+ verify();
+
+ // And the cached value is lost after rendering is complete.
+
+ train_readParameter(resources, "object", String.class, "fourth");
+ train_isRendering(resources, false);
+
+ replay();
+
+ component.cleanupAfterRender();
+
+ assertEquals(_access.get(component, "object"), "fourth");
verify();
}
@Test
- public void non_cached_parameter()
+ public void cached_primitive_write() throws Exception
{
- runWorkerNonCached("_foo", "foo", "", "java.lang.String", "java.lang.String");
+ InternalComponentResources resources = newInternalComponentResources();
+
+ ComponentLifecycle component = setupForIntegrationTest(resources);
+
+ resources.writeParameter("primitive", 321);
+ train_isRendering(resources, false);
+
+ train_readParameter(resources, "primitive", int.class, 123);
+ train_isRendering(resources, false);
+
+ replay();
+
+ _access.set(component, "primitive", 321);
+ assertEquals(_access.get(component, "primitive"), 123);
+
+ verify();
+
+ // Now try during rendering ...
+
+ resources.writeParameter("primitive", 567);
+ train_isRendering(resources, true);
+
+ replay();
+
+ _access.set(component, "primitive", 567);
+ assertEquals(_access.get(component, "primitive"), 567);
+
+ verify();
+
+ // And the cached value is lost after rendering is complete.
+
+ train_readParameter(resources, "primitive", int.class, 890);
+ train_isRendering(resources, false);
+
+ replay();
+
+ component.cleanupAfterRender();
+
+ assertEquals(_access.get(component, "primitive"), 890);
+
+ verify();
}
- private void runWorkerNonCached(String fieldName, String parameterName, String annotatedName,
- String fieldType, String wrapperType)
+ @Test
+ public void uncached_object_read() throws Exception
{
- ClassTransformation transformation = newClassTransformation();
- MutableComponentModel model = newMutableComponentModel();
- Parameter parameter = newMock(Parameter.class);
+ InternalComponentResources resources = newInternalComponentResources();
- train_findFieldsWithAnnotation(transformation, Parameter.class, fieldName);
- train_getFieldAnnotation(transformation, fieldName, Parameter.class, parameter);
- train_name(parameter, annotatedName);
- train_required(parameter, true);
+ ComponentLifecycle component = setupForIntegrationTest(resources);
- model.addParameter(parameterName, true);
+ // Notice no check for isRendering() since that is irrelevant to uncached parameters.
+ // Also note difference between field name and parameter name, due to Parameter.name() being
+ // specified.
- train_getFieldType(transformation, fieldName, fieldType);
+ train_readParameter(resources, "uncached", String.class, "first");
+ train_readParameter(resources, "uncached", String.class, "second");
- train_cache(parameter, false); // First difference
+ replay();
- train_addField(transformation, Modifier.PRIVATE, "boolean", fieldName + "_cached", "$cache");
- train_getResourcesFieldName(transformation, "$res");
+ assertEquals(_access.get(component, "uncachedObject"), "first");
+ assertEquals(_access.get(component, "uncachedObject"), "second");
- train_addField(
- transformation,
- Modifier.PRIVATE,
- "boolean",
- fieldName + "_invariant",
- "$invariant");
+ verify();
+ }
- // codeEq() lets us care less about whitespace
+ @Test
+ public void uncached_object_write() throws Exception
+ {
+ InternalComponentResources resources = newInternalComponentResources();
- train_extendMethod(
- transformation,
- TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
- String.format("$invariant = $res.isInvariant(\"%s\");", parameterName));
+ ComponentLifecycle component = setupForIntegrationTest(resources);
- train_extendMethod(
- transformation,
- TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
- String.format("if (! $invariant) { %s = null; $cache = false; }", fieldName));
+ // Notice no check for isRendering() since that is irrelevant to uncached parameters.
+ // Also note difference between field name and parameter name, due to Parameter.name() being
+ // specified.
- train_newMemberName(transformation, "_read_parameter_" + parameterName, "$read");
+ resources.writeParameter("uncached", "first");
+ train_readParameter(resources, "uncached", String.class, "second");
- // Second difference:
+ replay();
- train_addMethod(
- transformation,
- new MethodSignature(Modifier.PRIVATE, fieldType, "$read", null, null),
- f("{ if ($cache) return %s;", fieldName),
- f(
- "%s result = ($r) ((%s) $res.readParameter(\"%s\", $type));",
- fieldType,
- wrapperType,
- parameterName),
- f("if ($invariant) { %s = result; $cache = true; }", fieldName),
- "return result; }");
+ _access.set(component, "uncachedObject", "first");
+ assertEquals(_access.get(component, "uncachedObject"), "second");
- transformation.replaceReadAccess(fieldName, "$read");
+ verify();
+ }
- train_newMemberName(transformation, "_update_parameter_" + parameterName, "$write");
+ protected final void train_isRendering(InternalComponentResources resources, boolean rendering)
+ {
+ resources.isRendering();
+ setReturnValue(rendering);
+ }
- // Last difference:
+ protected final <T> void train_readParameter(InternalComponentResources resources,
+ String parameterName, Class<T> expectedType, T value)
+ {
+ resources.readParameter(parameterName, expectedType);
+ setReturnValue(value);
+ }
- train_addMethod(transformation, new MethodSignature(Modifier.PRIVATE, "void", "$write",
- new String[]
- { fieldType, }, null), f("{ $res.writeParameter(\"%s\", ($w)$1); }", parameterName));
+ private ComponentLifecycle setupForIntegrationTest(InternalComponentResources resources)
+ throws Exception
+ {
+ ClassPool pool = new ClassPool();
+ ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+ pool.appendClassPath(new LoaderClassPath(contextLoader));
+
+ Loader loader = new Loader(contextLoader, pool);
+
+ loader.delegateLoadingOf("org.apache.tapestry.");
- transformation.replaceWriteAccess(fieldName, "$write");
+ CtClass ctClass = pool.get(ParameterComponent.class.getName());
+ InternalClassTransformation transformation = new InternalClassTransformationImpl(ctClass);
+
+ MutableComponentModel model = newMutableComponentModel();
- transformation.claimField(fieldName, parameter);
+ model.addParameter("invariantObject", false);
+ model.addParameter("invariantPrimitive", false);
+ model.addParameter("object", false);
+ model.addParameter("primitive", true);
+ model.addParameter("uncached", false);
replay();
new ParameterWorker().transform(transformation, model);
verify();
- }
- private final void train_required(Parameter parameter, boolean required)
- {
- parameter.required();
- setReturnValue(required);
+ transformation.finish();
+
+ // System.out.println("Transformation: " + transformation);
+
+ Class transformedClass = pool.toClass(ctClass, loader);
+
+ Instantiator instantiator = transformation.createInstantiator(transformedClass);
+
+ train_isInvariant(resources, "invariantObject", true);
+ train_isInvariant(resources, "invariantPrimitive", true);
+ train_isInvariant(resources, "object", false);
+ train_isInvariant(resources, "primitive", false);
+ train_isInvariant(resources, "uncached", false);
+
+ replay();
+
+ ComponentLifecycle component = instantiator.newInstance(resources);
+
+ component.containingPageDidLoad();
+
+ verify();
+
+ return component;
}
- private void train_cache(Parameter parameter, boolean cache)
+ protected final void train_isInvariant(InternalComponentResources resources,
+ String parameterName, boolean invariant)
{
- parameter.cache();
- setReturnValue(cache);
+ resources.isInvariant(parameterName);
+ setReturnValue(invariant);
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/PageImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/PageImplTest.java?rev=439617&r1=439616&r2=439617&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/PageImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/PageImplTest.java Sat Sep 2 10:03:34 2006
@@ -17,7 +17,7 @@
import java.util.Locale;
import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.apache.tapestry.runtime.PageLifecycleListener;
import org.testng.annotations.Test;
/**
@@ -52,18 +52,18 @@
@Test
public void detach_notification()
{
- ComponentLifecycle cl1 = newComponentLifecycle();
- ComponentLifecycle cl2 = newComponentLifecycle();
+ PageLifecycleListener listener1 = newPageLifecycle();
+ PageLifecycleListener listener2 = newPageLifecycle();
- cl1.containingPageDidDetach();
- cl2.containingPageDidDetach();
+ listener1.containingPageDidDetach();
+ listener2.containingPageDidDetach();
replay();
Page page = new PageImpl(PAGE_NAME, _locale);
- page.addComponentLifecycle(cl1);
- page.addComponentLifecycle(cl2);
+ page.addLifecycleListener(listener1);
+ page.addLifecycleListener(listener2);
page.detached();
@@ -71,20 +71,47 @@
}
@Test
+ public void attach_notification()
+ {
+
+ PageLifecycleListener listener1 = newPageLifecycle();
+ PageLifecycleListener listener2 = newPageLifecycle();
+
+ listener1.containingPageDidAttach();
+ listener2.containingPageDidAttach();
+
+ replay();
+
+ Page page = new PageImpl(PAGE_NAME, _locale);
+
+ page.addLifecycleListener(listener1);
+ page.addLifecycleListener(listener2);
+
+ page.attached();
+
+ verify();
+ }
+
+ private PageLifecycleListener newPageLifecycle()
+ {
+ return newMock(PageLifecycleListener.class);
+ }
+
+ @Test
public void load_notification()
{
- ComponentLifecycle cl1 = newComponentLifecycle();
- ComponentLifecycle cl2 = newComponentLifecycle();
+ PageLifecycleListener listener1 = newPageLifecycle();
+ PageLifecycleListener listener2 = newPageLifecycle();
- cl1.containingPageDidLoad();
- cl2.containingPageDidLoad();
+ listener1.containingPageDidLoad();
+ listener2.containingPageDidLoad();
replay();
Page page = new PageImpl(PAGE_NAME, _locale);
- page.addComponentLifecycle(cl1);
- page.addComponentLifecycle(cl2);
+ page.addLifecycleListener(listener1);
+ page.addLifecycleListener(listener2);
page.loaded();
Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java?rev=439617&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/services/TransformUtilsTest.java Sat Sep 2 10:03:34 2006
@@ -0,0 +1,41 @@
+// Copyright 2006 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.services;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import static org.apache.tapestry.services.TransformUtils.getDefaultValue;
+import static org.apache.tapestry.services.TransformUtils.getWrapperType;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class TransformUtilsTest extends Assert
+{
+ @Test
+ public void wrapper_type()
+ {
+ assertEquals(getWrapperType("char"), "java.lang.Character");
+ assertEquals(getWrapperType("java.util.Map"), "java.util.Map");
+ }
+
+ @Test
+ public void default_value()
+ {
+ assertEquals(getDefaultValue("long"), "0L");
+ assertEquals(getDefaultValue("java.util.Map"), "null");
+ }
+}