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/11/17 20:51:40 UTC
svn commit: r476282 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src:
main/java/org/apache/tapestry/corelib/components/
main/java/org/apache/tapestry/internal/services/
main/java/org/apache/tapestry/services/
test/java/org/apache/tapestry/interna...
Author: hlship
Date: Fri Nov 17 11:51:39 2006
New Revision: 476282
URL: http://svn.apache.org/viewvc?view=rev&rev=476282
Log:
Add an explicit, configurable setup and cleanup phase to page response rendering.
Implement the Heartbeat environmental service.
Modify the Loop copmonent to begin and end a heartbeat around each iteration.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HeartbeatImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/DefaultPageRenderCommand.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Heartbeat.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/HeartbeatImplTest.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java?view=diff&rev=476282&r1=476281&r2=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java Fri Nov 17 11:51:39 2006
@@ -14,13 +14,15 @@
package org.apache.tapestry.corelib.components;
-import java.util.Iterator;
-
-import org.apache.tapestry.annotations.AfterRender;
-import org.apache.tapestry.annotations.BeginRender;
-import org.apache.tapestry.annotations.ComponentClass;
-import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.annotations.SetupRender;
+import java.util.Iterator;
+
+import org.apache.tapestry.annotations.AfterRender;
+import org.apache.tapestry.annotations.BeginRender;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Environmental;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.annotations.SetupRender;
+import org.apache.tapestry.services.Heartbeat;
/**
* Basic looping class; loops over a number of items (provided by its source parameter), rendering
@@ -60,7 +62,10 @@
private int _index;
private Iterator<?> _iterator;
-
+
+ @Environmental
+ private Heartbeat _heartbeat;
+
@SetupRender
boolean setup()
{
@@ -75,16 +80,22 @@
return _iterator.hasNext();
}
-
+
+ /** Begins a new heartbeat. */
@BeginRender
void begin()
{
- _value = _iterator.next();
+ _value = _iterator.next();
+
+ _heartbeat.begin();
}
-
+
+ /** Ends the current heartbeat. */
@AfterRender
boolean after()
- {
+ {
+ _heartbeat.end();
+
_index++;
return _iterator.hasNext();
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java?view=diff&rev=476282&r1=476281&r2=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java Fri Nov 17 11:51:39 2006
@@ -12,69 +12,67 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.services;
-
-import static org.apache.tapestry.util.CollectionFactory.newLinkedList;
-
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.apache.tapestry.services.Environment;
-import org.apache.tapestry.util.CollectionFactory;
-
-/**
- * A non-threadsafe implementation (expects to use the "perthread" service lifecyle.
- *
- *
- */
-public class EnvironmentImpl implements Environment
-{
- // My generics mojo breaks down when we talk about the key and the value being related
- // types.
-
- private final Map<Class, LinkedList> _stacks = CollectionFactory.newMap();
-
- @SuppressWarnings("unchecked")
- private <T> LinkedList<T> stackFor(Class<T> type)
- {
- LinkedList<T> result = _stacks.get(type);
-
- if (result == null)
- {
- result = newLinkedList();
- _stacks.put(type, result);
- }
-
- return result;
- }
-
- public <T> T peek(Class<T> type)
- {
- LinkedList<T> stack = stackFor(type);
-
- return stack.isEmpty() ? null : stack.getFirst();
- }
-
- public <T> T pop(Class<T> type)
- {
- LinkedList<T> stack = stackFor(type);
-
- return stack.removeFirst();
- }
-
- public <T> T push(Class<T> type, T instance)
- {
- LinkedList<T> stack = stackFor(type);
-
- T result = stack.isEmpty() ? null : stack.getFirst();
-
- stack.addFirst(instance);
-
- return result;
- }
-
- public void clear()
- {
- _stacks.clear();
- }
-}
+package org.apache.tapestry.internal.services;
+
+import static org.apache.tapestry.util.CollectionFactory.newLinkedList;
+
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.util.CollectionFactory;
+
+/**
+ * A non-threadsafe implementation (expects to use the "perthread" service lifecyle.
+ */
+public class EnvironmentImpl implements Environment
+{
+ // My generics mojo breaks down when we talk about the key and the value being related
+ // types.
+
+ private final Map<Class, LinkedList> _stacks = CollectionFactory.newMap();
+
+ @SuppressWarnings("unchecked")
+ private <T> LinkedList<T> stackFor(Class<T> type)
+ {
+ LinkedList<T> result = _stacks.get(type);
+
+ if (result == null)
+ {
+ result = newLinkedList();
+ _stacks.put(type, result);
+ }
+
+ return result;
+ }
+
+ public <T> T peek(Class<T> type)
+ {
+ LinkedList<T> stack = stackFor(type);
+
+ return stack.isEmpty() ? null : stack.getFirst();
+ }
+
+ public <T> T pop(Class<T> type)
+ {
+ LinkedList<T> stack = stackFor(type);
+
+ return stack.removeFirst();
+ }
+
+ public <T> T push(Class<T> type, T instance)
+ {
+ LinkedList<T> stack = stackFor(type);
+
+ T result = stack.isEmpty() ? null : stack.getFirst();
+
+ stack.addFirst(instance);
+
+ return result;
+ }
+
+ public void clear()
+ {
+ _stacks.clear();
+ }
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HeartbeatImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HeartbeatImpl.java?view=auto&rev=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HeartbeatImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/HeartbeatImpl.java Fri Nov 17 11:51:39 2006
@@ -0,0 +1,53 @@
+// 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 static org.apache.tapestry.util.CollectionFactory.newLinkedList;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.tapestry.services.Heartbeat;
+import org.apache.tapestry.util.CollectionFactory;
+import org.apache.tapestry.util.Defense;
+
+public class HeartbeatImpl implements Heartbeat
+{
+ private final LinkedList<List<Runnable>> _stack = newLinkedList();
+
+ public void begin()
+ {
+ List<Runnable> beat = CollectionFactory.newList();
+
+ _stack.addFirst(beat);
+ }
+
+ public void defer(Runnable command)
+ {
+ Defense.notNull(command, "command");
+
+ _stack.getFirst().add(command);
+
+ }
+
+ public void end()
+ {
+ List<Runnable> beat = _stack.removeFirst();
+
+ for (Runnable r : beat)
+ r.run();
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=476282&r1=476281&r2=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Fri Nov 17 11:51:39 2006
@@ -12,473 +12,471 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.services;
-
-import static org.apache.tapestry.util.CollectionFactory.newMap;
-
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.Binding;
-import org.apache.tapestry.ComponentResources;
-import org.apache.tapestry.Location;
-import org.apache.tapestry.events.InvalidationListener;
-import org.apache.tapestry.internal.InternalConstants;
-import org.apache.tapestry.internal.bindings.LiteralBinding;
-import org.apache.tapestry.internal.bindings.PropBindingFactory;
-import org.apache.tapestry.ioc.LogSource;
-import org.apache.tapestry.ioc.OrderedConfiguration;
-import org.apache.tapestry.ioc.annotations.Contribute;
-import org.apache.tapestry.ioc.annotations.Id;
-import org.apache.tapestry.ioc.annotations.Inject;
-import org.apache.tapestry.ioc.annotations.InjectService;
-import org.apache.tapestry.ioc.annotations.Lifecycle;
-import org.apache.tapestry.ioc.annotations.Match;
-import org.apache.tapestry.ioc.annotations.Order;
-import org.apache.tapestry.ioc.services.ChainBuilder;
-import org.apache.tapestry.ioc.services.ClassFactory;
-import org.apache.tapestry.ioc.services.LoggingDecorator;
-import org.apache.tapestry.ioc.services.PropertyAccess;
-import org.apache.tapestry.ioc.services.ThreadCleanupHub;
-import org.apache.tapestry.ioc.services.TypeCoercer;
-import org.apache.tapestry.services.ApplicationInitializer;
-import org.apache.tapestry.services.ApplicationInitializerFilter;
-import org.apache.tapestry.services.BindingFactory;
-import org.apache.tapestry.services.BindingSource;
-import org.apache.tapestry.services.ComponentClassResolver;
-import org.apache.tapestry.services.ComponentClassTransformWorker;
-import org.apache.tapestry.services.MarkupWriterFactory;
-import org.apache.tapestry.services.PersistentFieldManager;
-import org.apache.tapestry.services.PersistentFieldStrategy;
-import org.apache.tapestry.services.RequestExceptionHandler;
-import org.apache.tapestry.services.WebContext;
-import org.apache.tapestry.services.WebRequest;
-import org.apache.tapestry.services.WebRequestFilter;
-import org.apache.tapestry.services.WebResponse;
-import org.apache.tapestry.util.IntegerRange;
-
-/**
- *
- */
-@Id("tapestry.internal")
-public final class InternalModule
-{
- private final ComponentInstantiatorSource _componentInstantiatorSource;
-
- private final ComponentTemplateSource _componentTemplateSource;
-
- private final UpdateListenerHub _updateListenerHub;
-
- private final ThreadCleanupHub _threadCleanupHub;
-
- private final ComponentClassResolver _componentClassResolver;
-
- private final ChainBuilder _chainBuilder;
-
- private final WebRequest _request;
-
- private final WebResponse _response;
-
- public InternalModule(@InjectService("ComponentInstantiatorSource")
- ComponentInstantiatorSource componentInstantiatorSource, @InjectService("UpdateListenerHub")
- UpdateListenerHub updateListenerHub, @InjectService("tapestry.ioc.ThreadCleanupHub")
- ThreadCleanupHub threadCleanupHub, @InjectService("ComponentTemplateSource")
- ComponentTemplateSource componentTemplateSource,
- @InjectService("tapestry.ComponentClassResolver")
- ComponentClassResolver componentClassResolver,
- @InjectService("tapestry.ioc.ChainBuilder")
- ChainBuilder chainBuilder, @Inject("infrastructure:request")
- WebRequest request, @Inject("infrastructure:response")
- WebResponse response)
- {
- _componentInstantiatorSource = componentInstantiatorSource;
- _updateListenerHub = updateListenerHub;
- _threadCleanupHub = threadCleanupHub;
- _componentTemplateSource = componentTemplateSource;
- _componentClassResolver = componentClassResolver;
- _chainBuilder = chainBuilder;
- _request = request;
- _response = response;
- }
-
- public ComponentClassTransformer buildComponentClassTransformer(
- @InjectService("tapestry.ComponentClassTransformWorker")
- ComponentClassTransformWorker workerChain, @InjectService("tapestry.ioc.LogSource")
- LogSource logSource)
- {
- ComponentClassTransformerImpl transformer = new ComponentClassTransformerImpl(workerChain,
- logSource);
-
- _componentInstantiatorSource.addInvalidationListener(transformer);
-
- return transformer;
- }
-
- public ComponentInstantiatorSource buildComponentInstantiatorSource(
- @InjectService("tapestry.ioc.ClassFactory")
- ClassFactory classFactory, @InjectService("ComponentClassTransformer")
- ComponentClassTransformer transformer, Log log)
- {
- ComponentInstantiatorSourceImpl source = new ComponentInstantiatorSourceImpl(classFactory
- .getClassLoader(), transformer, log);
-
- _updateListenerHub.addUpdateListener(source);
-
- return source;
- }
-
- public ComponentTemplateSource buildComponentTemplateSource(@InjectService("TemplateParser")
- TemplateParser parser)
- {
- ComponentTemplateSourceImpl service = new ComponentTemplateSourceImpl(parser);
-
- _updateListenerHub.addUpdateListener(service);
-
- return service;
- }
-
- @Lifecycle("perthread")
- public static TemplateParser buildTemplateParser(Log log)
- {
- return new TemplateParserImpl(log);
- }
-
- public PageElementFactory buildPageElementFactory(@Inject("infrastructure:typeCoercer")
- TypeCoercer typeCoercer, @InjectService("tapestry.BindingSource")
- BindingSource bindingSource)
- {
- return new PageElementFactoryImpl(_componentInstantiatorSource, _componentClassResolver,
- typeCoercer, bindingSource);
- }
-
- public PageLoader buildPageLoader(@InjectService("PageElementFactory")
- PageElementFactory pageElementFactory, @InjectService("tapestry.BindingSource")
- BindingSource bindingSource, @InjectService("LinkFactory")
- LinkFactory linkFactory, @Inject("infrastructure:persistentFieldManager")
- PersistentFieldManager persistentFieldManager)
- {
- PageLoaderImpl service = new PageLoaderImpl(_componentTemplateSource, pageElementFactory,
- bindingSource, linkFactory, persistentFieldManager);
-
- // Recieve invalidations when the class loader is discarded (due to a component class
- // change).
- // The notification is forwarded to the page loader's listeners.
-
- _componentInstantiatorSource.addInvalidationListener(service);
-
- return service;
- }
-
- public PagePool buildPagePool(Log log, @InjectService("PageLoader")
- PageLoader pageLoader)
- {
- PagePoolImpl service = new PagePoolImpl(log, pageLoader);
-
- // This covers invalidations due to changes to classes
-
- pageLoader.addInvalidationListener(service);
-
- // ... and this covers invalidations due to changes to templates
-
- _componentTemplateSource.addInvalidationListener(service);
-
- return service;
- }
-
- /**
- * The UpdateListenerHub provides events that other services use to check for invalidations.
- * Such services usually are {@link org.apache.tapestry.internal.event.InvalidationEventHub}s,
- * and fire invalidation events to their listeners.
- */
- public static UpdateListenerHub buildUpdateListenerHub()
- {
- return new UpdateListenerHubImpl();
- }
-
- /**
- * All public services in the tapestry module, and in any sub-module of tapestry will get
- * logging. This doesn't include the tapesry.ioc module since services of that module can not be
- * decorated.
- */
- @Match(
- { "tapestry.*", "tapestry.*.*" })
- @Order("before:*.*")
- public static <T> T decorateWithLogging(Class<T> serviceInterface, T delegate,
- String serviceId, Log log, @InjectService("tapestry.ioc.LoggingDecorator")
- LoggingDecorator loggingDecorator)
- {
- return loggingDecorator.build(serviceInterface, delegate, serviceId, log);
- }
-
- @Lifecycle("perthread")
- public RequestPageCache buildRequestPageCache(@InjectService("PagePool")
- PagePool pagePool)
- {
- RequestPageCacheImpl service = new RequestPageCacheImpl(_componentClassResolver, pagePool);
-
- _threadCleanupHub.addThreadCleanupListener(service);
-
- return service;
- }
-
- public static PageResponseRenderer buildPageResponseRenderer(
- @InjectService("tapestry.MarkupWriterFactory")
- MarkupWriterFactory markupWriterFactory,
- @InjectService("tapestry.PageRenderInitializer")
- Runnable pageRenderInitializer)
- {
- return new PageResponseRendererImpl(markupWriterFactory, pageRenderInitializer);
- }
-
- /**
- * Adds a filter that checks for updates to classes and other resources. It is ordered
- * before:*.*.
- */
- @Contribute("tapestry.WebRequestHandler")
- public void contributeWebRequestFilters(OrderedConfiguration<WebRequestFilter> configuration)
- {
- configuration.add(
- "CheckForUpdates",
- new CheckForUpdatesFilter(_updateListenerHub),
- "before:*.*");
- }
-
- /**
- * Adds a filter that sets the application package (for class loading purposes). The filter is
- * ordered before:*.*".
- */
- @Contribute("tapestry.ApplicationInitializer")
- public void contributeApplicationInitializerFilters(
- OrderedConfiguration<ApplicationInitializerFilter> configuration,
- @InjectService("tapestry.ioc.PropertyAccess")
- final PropertyAccess propertyAccess, @Inject("infrastructure:typeCoercer")
- final TypeCoercer typeCoercer)
- {
- ApplicationInitializerFilter setApplicationPackage = new ApplicationInitializerFilter()
- {
- public void initializeApplication(WebContext context, ApplicationInitializer initializer)
- {
- String packageName = context
- .getInitParameter(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
-
- _componentClassResolver.setApplicationPackage(packageName);
-
- initializer.initializeApplication(context);
- }
- };
-
- configuration.add("SetApplicationPackage", setApplicationPackage, "before:*.*");
-
- final InvalidationListener listener = new InvalidationListener()
- {
- public void objectWasInvalidated()
- {
- propertyAccess.clearCache();
- typeCoercer.clearCache();
- }
- };
-
- ApplicationInitializerFilter clearCaches = new ApplicationInitializerFilter()
- {
- public void initializeApplication(WebContext context, ApplicationInitializer initializer)
- {
- // Snuck in here is the logic to clear the PropertyAccess service's cache whenever
- // the component class loader is invalidated.
-
- _componentInstantiatorSource.addInvalidationListener(listener);
-
- initializer.initializeApplication(context);
- }
- };
-
- configuration.add("ClearCachesOnInvalidation", clearCaches);
- }
-
- /**
- * Builds the PropBindingFactory as a chain of command. The terminator of the chain is
- * responsible for ordinary property names (and property paths). Contributions to the service
- * cover additional special cases, such as simple literal values.
- *
- * @param configuration
- * contributions of special factories for some constants, each contributed factory
- * may return a binding if applicable, or null otherwise
- * @param propertyAccess
- * @param classFactory
- * @return
- */
- public BindingFactory buildPropBindingFactory(List<BindingFactory> configuration,
- @InjectService("tapestry.ioc.PropertyAccess")
- PropertyAccess propertyAccess, @InjectService("tapestry.ComponentClassFactory")
- ClassFactory classFactory)
- {
- PropBindingFactory service = new PropBindingFactory(propertyAccess, classFactory);
-
- _componentInstantiatorSource.addInvalidationListener(service);
-
- configuration.add(service);
-
- return _chainBuilder.build(BindingFactory.class, configuration);
- }
-
- public void contributePropBindingFactory(OrderedConfiguration<BindingFactory> configuration)
- {
- BindingFactory keywordFactory = new BindingFactory()
- {
- private final Map<String, Object> _keywords = newMap();
-
- {
- _keywords.put("true", Boolean.TRUE);
- _keywords.put("false", Boolean.FALSE);
- _keywords.put("null", null);
- }
-
- public Binding newBinding(String description, ComponentResources component,
- String expression, Location location)
- {
- String key = expression.trim().toLowerCase();
-
- if (_keywords.containsKey(key))
- return new LiteralBinding(description, _keywords.get(key), location);
-
- return null;
- }
- };
-
- BindingFactory thisFactory = new BindingFactory()
- {
-
- public Binding newBinding(String description, ComponentResources component,
- String expression, Location location)
- {
- if ("this".equalsIgnoreCase(expression.trim()))
- return new LiteralBinding(description, component.getComponent(), location);
-
- return null;
- }
- };
-
- BindingFactory longFactory = new BindingFactory()
- {
- private final Pattern _pattern = Pattern.compile("^\\s*(-?\\d+)\\s*$");
-
- public Binding newBinding(String description, ComponentResources component,
- String expression, Location location)
- {
- Matcher matcher = _pattern.matcher(expression);
-
- if (matcher.matches())
- {
- String value = matcher.group(1);
-
- return new LiteralBinding(description, new Long(value), location);
- }
-
- return null;
- }
- };
-
- BindingFactory intRangeFactory = new BindingFactory()
- {
- private final Pattern _pattern = Pattern
- .compile("^\\s*(-?\\d+)\\s*\\.\\.\\s*(-?\\d+)\\s*$");
-
- public Binding newBinding(String description, ComponentResources component,
- String expression, Location location)
- {
- Matcher matcher = _pattern.matcher(expression);
-
- if (matcher.matches())
- {
- int start = Integer.parseInt(matcher.group(1));
- int finish = Integer.parseInt(matcher.group(2));
-
- IntegerRange range = new IntegerRange(start, finish);
-
- return new LiteralBinding(description, range, location);
- }
-
- return null;
- }
- };
-
- BindingFactory doubleFactory = new BindingFactory()
- {
- // So, either 1234. or 1234.56 or .78
- private final Pattern _pattern = Pattern
- .compile("^\\s*(\\-?((\\d+\\.)|(\\d*\\.\\d+)))\\s*$");
-
- public Binding newBinding(String description, ComponentResources component,
- String expression, Location location)
- {
- Matcher matcher = _pattern.matcher(expression);
-
- if (matcher.matches())
- {
- String value = matcher.group(1);
-
- return new LiteralBinding(description, new Double(value), location);
- }
-
- return null;
- }
- };
-
- BindingFactory stringFactory = new BindingFactory()
- {
- // This will match embedded single quotes as-is, no escaping necessary.
-
- private final Pattern _pattern = Pattern.compile("^\\s*'(.*)'\\s*$");
-
- public Binding newBinding(String description, ComponentResources component,
- String expression, Location location)
- {
- Matcher matcher = _pattern.matcher(expression);
-
- if (matcher.matches())
- {
- String value = matcher.group(1);
-
- return new LiteralBinding(description, value, location);
- }
-
- return null;
- }
- };
-
- // To be honest, order probably doesn't matter.
-
- configuration.add("Keyword", keywordFactory);
- configuration.add("This", thisFactory);
- configuration.add("Long", longFactory);
- configuration.add("IntRange", intRangeFactory);
- configuration.add("Double", doubleFactory);
- configuration.add("StringLiteral", stringFactory);
- }
-
- public RequestExceptionHandler buildDefaultRequestExceptionHandler(
- @InjectService("RequestPageCache")
- RequestPageCache pageCache, @InjectService("PageResponseRenderer")
- PageResponseRenderer renderer)
- {
- return new DefaultRequestExceptionHandler(pageCache, renderer, _response);
- }
-
- /** Service used to create links for components and pages. */
- public LinkFactory buildLinkFactory()
- {
- return new LinkFactoryImpl(_request, _response, _componentClassResolver);
- }
-
- /**
- * This exists as its own service just so that we can monitor it using logging.
- * <p>
- * TODO: Move this to TapestryModule?
- */
- public PersistentFieldStrategy buildSessionPersistentFieldStrategy()
- {
- return new SessionPersistentFieldStrategy(_request);
- }
-}
+package org.apache.tapestry.internal.services;
+
+import static org.apache.tapestry.util.CollectionFactory.newMap;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Location;
+import org.apache.tapestry.events.InvalidationListener;
+import org.apache.tapestry.internal.InternalConstants;
+import org.apache.tapestry.internal.bindings.LiteralBinding;
+import org.apache.tapestry.internal.bindings.PropBindingFactory;
+import org.apache.tapestry.ioc.LogSource;
+import org.apache.tapestry.ioc.OrderedConfiguration;
+import org.apache.tapestry.ioc.annotations.Contribute;
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.ioc.annotations.Inject;
+import org.apache.tapestry.ioc.annotations.InjectService;
+import org.apache.tapestry.ioc.annotations.Lifecycle;
+import org.apache.tapestry.ioc.annotations.Match;
+import org.apache.tapestry.ioc.annotations.Order;
+import org.apache.tapestry.ioc.services.ChainBuilder;
+import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.LoggingDecorator;
+import org.apache.tapestry.ioc.services.PropertyAccess;
+import org.apache.tapestry.ioc.services.ThreadCleanupHub;
+import org.apache.tapestry.ioc.services.TypeCoercer;
+import org.apache.tapestry.services.ApplicationInitializer;
+import org.apache.tapestry.services.ApplicationInitializerFilter;
+import org.apache.tapestry.services.BindingFactory;
+import org.apache.tapestry.services.BindingSource;
+import org.apache.tapestry.services.ComponentClassResolver;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.MarkupWriterFactory;
+import org.apache.tapestry.services.PageRenderInitializer;
+import org.apache.tapestry.services.PersistentFieldManager;
+import org.apache.tapestry.services.PersistentFieldStrategy;
+import org.apache.tapestry.services.RequestExceptionHandler;
+import org.apache.tapestry.services.WebContext;
+import org.apache.tapestry.services.WebRequest;
+import org.apache.tapestry.services.WebRequestFilter;
+import org.apache.tapestry.services.WebResponse;
+import org.apache.tapestry.util.IntegerRange;
+
+@Id("tapestry.internal")
+public final class InternalModule
+{
+ private final ComponentInstantiatorSource _componentInstantiatorSource;
+
+ private final ComponentTemplateSource _componentTemplateSource;
+
+ private final UpdateListenerHub _updateListenerHub;
+
+ private final ThreadCleanupHub _threadCleanupHub;
+
+ private final ComponentClassResolver _componentClassResolver;
+
+ private final ChainBuilder _chainBuilder;
+
+ private final WebRequest _request;
+
+ private final WebResponse _response;
+
+ public InternalModule(@InjectService("ComponentInstantiatorSource")
+ ComponentInstantiatorSource componentInstantiatorSource, @InjectService("UpdateListenerHub")
+ UpdateListenerHub updateListenerHub, @InjectService("tapestry.ioc.ThreadCleanupHub")
+ ThreadCleanupHub threadCleanupHub, @InjectService("ComponentTemplateSource")
+ ComponentTemplateSource componentTemplateSource,
+ @InjectService("tapestry.ComponentClassResolver")
+ ComponentClassResolver componentClassResolver,
+ @InjectService("tapestry.ioc.ChainBuilder")
+ ChainBuilder chainBuilder, @Inject("infrastructure:request")
+ WebRequest request, @Inject("infrastructure:response")
+ WebResponse response)
+ {
+ _componentInstantiatorSource = componentInstantiatorSource;
+ _updateListenerHub = updateListenerHub;
+ _threadCleanupHub = threadCleanupHub;
+ _componentTemplateSource = componentTemplateSource;
+ _componentClassResolver = componentClassResolver;
+ _chainBuilder = chainBuilder;
+ _request = request;
+ _response = response;
+ }
+
+ public ComponentClassTransformer buildComponentClassTransformer(
+ @InjectService("tapestry.ComponentClassTransformWorker")
+ ComponentClassTransformWorker workerChain, @InjectService("tapestry.ioc.LogSource")
+ LogSource logSource)
+ {
+ ComponentClassTransformerImpl transformer = new ComponentClassTransformerImpl(workerChain,
+ logSource);
+
+ _componentInstantiatorSource.addInvalidationListener(transformer);
+
+ return transformer;
+ }
+
+ public ComponentInstantiatorSource buildComponentInstantiatorSource(
+ @InjectService("tapestry.ioc.ClassFactory")
+ ClassFactory classFactory, @InjectService("ComponentClassTransformer")
+ ComponentClassTransformer transformer, Log log)
+ {
+ ComponentInstantiatorSourceImpl source = new ComponentInstantiatorSourceImpl(classFactory
+ .getClassLoader(), transformer, log);
+
+ _updateListenerHub.addUpdateListener(source);
+
+ return source;
+ }
+
+ public ComponentTemplateSource buildComponentTemplateSource(@InjectService("TemplateParser")
+ TemplateParser parser)
+ {
+ ComponentTemplateSourceImpl service = new ComponentTemplateSourceImpl(parser);
+
+ _updateListenerHub.addUpdateListener(service);
+
+ return service;
+ }
+
+ @Lifecycle("perthread")
+ public static TemplateParser buildTemplateParser(Log log)
+ {
+ return new TemplateParserImpl(log);
+ }
+
+ public PageElementFactory buildPageElementFactory(@Inject("infrastructure:typeCoercer")
+ TypeCoercer typeCoercer, @InjectService("tapestry.BindingSource")
+ BindingSource bindingSource)
+ {
+ return new PageElementFactoryImpl(_componentInstantiatorSource, _componentClassResolver,
+ typeCoercer, bindingSource);
+ }
+
+ public PageLoader buildPageLoader(@InjectService("PageElementFactory")
+ PageElementFactory pageElementFactory, @InjectService("tapestry.BindingSource")
+ BindingSource bindingSource, @InjectService("LinkFactory")
+ LinkFactory linkFactory, @Inject("infrastructure:persistentFieldManager")
+ PersistentFieldManager persistentFieldManager)
+ {
+ PageLoaderImpl service = new PageLoaderImpl(_componentTemplateSource, pageElementFactory,
+ bindingSource, linkFactory, persistentFieldManager);
+
+ // Recieve invalidations when the class loader is discarded (due to a component class
+ // change).
+ // The notification is forwarded to the page loader's listeners.
+
+ _componentInstantiatorSource.addInvalidationListener(service);
+
+ return service;
+ }
+
+ public PagePool buildPagePool(Log log, @InjectService("PageLoader")
+ PageLoader pageLoader)
+ {
+ PagePoolImpl service = new PagePoolImpl(log, pageLoader);
+
+ // This covers invalidations due to changes to classes
+
+ pageLoader.addInvalidationListener(service);
+
+ // ... and this covers invalidations due to changes to templates
+
+ _componentTemplateSource.addInvalidationListener(service);
+
+ return service;
+ }
+
+ /**
+ * The UpdateListenerHub provides events that other services use to check for invalidations.
+ * Such services usually are {@link org.apache.tapestry.internal.event.InvalidationEventHub}s,
+ * and fire invalidation events to their listeners.
+ */
+ public static UpdateListenerHub buildUpdateListenerHub()
+ {
+ return new UpdateListenerHubImpl();
+ }
+
+ /**
+ * All public services in the tapestry module, and in any sub-module of tapestry will get
+ * logging. This doesn't include the tapesry.ioc module since services of that module can not be
+ * decorated.
+ */
+ @Match(
+ { "tapestry.*", "tapestry.*.*" })
+ @Order("before:*.*")
+ public static <T> T decorateWithLogging(Class<T> serviceInterface, T delegate,
+ String serviceId, Log log, @InjectService("tapestry.ioc.LoggingDecorator")
+ LoggingDecorator loggingDecorator)
+ {
+ return loggingDecorator.build(serviceInterface, delegate, serviceId, log);
+ }
+
+ @Lifecycle("perthread")
+ public RequestPageCache buildRequestPageCache(@InjectService("PagePool")
+ PagePool pagePool)
+ {
+ RequestPageCacheImpl service = new RequestPageCacheImpl(_componentClassResolver, pagePool);
+
+ _threadCleanupHub.addThreadCleanupListener(service);
+
+ return service;
+ }
+
+ public static PageResponseRenderer buildPageResponseRenderer(
+ @InjectService("tapestry.MarkupWriterFactory")
+ MarkupWriterFactory markupWriterFactory,
+ @InjectService("tapestry.PageRenderInitializer")
+ PageRenderInitializer pageRenderInitializer)
+ {
+ return new PageResponseRendererImpl(markupWriterFactory, pageRenderInitializer);
+ }
+
+ /**
+ * Adds a filter that checks for updates to classes and other resources. It is ordered
+ * before:*.*.
+ */
+ @Contribute("tapestry.WebRequestHandler")
+ public void contributeWebRequestFilters(OrderedConfiguration<WebRequestFilter> configuration)
+ {
+ configuration.add(
+ "CheckForUpdates",
+ new CheckForUpdatesFilter(_updateListenerHub),
+ "before:*.*");
+ }
+
+ /**
+ * Adds a filter that sets the application package (for class loading purposes). The filter is
+ * ordered before:*.*".
+ */
+ @Contribute("tapestry.ApplicationInitializer")
+ public void contributeApplicationInitializerFilters(
+ OrderedConfiguration<ApplicationInitializerFilter> configuration,
+ @InjectService("tapestry.ioc.PropertyAccess")
+ final PropertyAccess propertyAccess, @Inject("infrastructure:typeCoercer")
+ final TypeCoercer typeCoercer)
+ {
+ ApplicationInitializerFilter setApplicationPackage = new ApplicationInitializerFilter()
+ {
+ public void initializeApplication(WebContext context, ApplicationInitializer initializer)
+ {
+ String packageName = context
+ .getInitParameter(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
+
+ _componentClassResolver.setApplicationPackage(packageName);
+
+ initializer.initializeApplication(context);
+ }
+ };
+
+ configuration.add("SetApplicationPackage", setApplicationPackage, "before:*.*");
+
+ final InvalidationListener listener = new InvalidationListener()
+ {
+ public void objectWasInvalidated()
+ {
+ propertyAccess.clearCache();
+ typeCoercer.clearCache();
+ }
+ };
+
+ ApplicationInitializerFilter clearCaches = new ApplicationInitializerFilter()
+ {
+ public void initializeApplication(WebContext context, ApplicationInitializer initializer)
+ {
+ // Snuck in here is the logic to clear the PropertyAccess service's cache whenever
+ // the component class loader is invalidated.
+
+ _componentInstantiatorSource.addInvalidationListener(listener);
+
+ initializer.initializeApplication(context);
+ }
+ };
+
+ configuration.add("ClearCachesOnInvalidation", clearCaches);
+ }
+
+ /**
+ * Builds the PropBindingFactory as a chain of command. The terminator of the chain is
+ * responsible for ordinary property names (and property paths). Contributions to the service
+ * cover additional special cases, such as simple literal values.
+ *
+ * @param configuration
+ * contributions of special factories for some constants, each contributed factory
+ * may return a binding if applicable, or null otherwise
+ * @param propertyAccess
+ * @param classFactory
+ * @return
+ */
+ public BindingFactory buildPropBindingFactory(List<BindingFactory> configuration,
+ @InjectService("tapestry.ioc.PropertyAccess")
+ PropertyAccess propertyAccess, @InjectService("tapestry.ComponentClassFactory")
+ ClassFactory classFactory)
+ {
+ PropBindingFactory service = new PropBindingFactory(propertyAccess, classFactory);
+
+ _componentInstantiatorSource.addInvalidationListener(service);
+
+ configuration.add(service);
+
+ return _chainBuilder.build(BindingFactory.class, configuration);
+ }
+
+ public void contributePropBindingFactory(OrderedConfiguration<BindingFactory> configuration)
+ {
+ BindingFactory keywordFactory = new BindingFactory()
+ {
+ private final Map<String, Object> _keywords = newMap();
+
+ {
+ _keywords.put("true", Boolean.TRUE);
+ _keywords.put("false", Boolean.FALSE);
+ _keywords.put("null", null);
+ }
+
+ public Binding newBinding(String description, ComponentResources component,
+ String expression, Location location)
+ {
+ String key = expression.trim().toLowerCase();
+
+ if (_keywords.containsKey(key))
+ return new LiteralBinding(description, _keywords.get(key), location);
+
+ return null;
+ }
+ };
+
+ BindingFactory thisFactory = new BindingFactory()
+ {
+
+ public Binding newBinding(String description, ComponentResources component,
+ String expression, Location location)
+ {
+ if ("this".equalsIgnoreCase(expression.trim()))
+ return new LiteralBinding(description, component.getComponent(), location);
+
+ return null;
+ }
+ };
+
+ BindingFactory longFactory = new BindingFactory()
+ {
+ private final Pattern _pattern = Pattern.compile("^\\s*(-?\\d+)\\s*$");
+
+ public Binding newBinding(String description, ComponentResources component,
+ String expression, Location location)
+ {
+ Matcher matcher = _pattern.matcher(expression);
+
+ if (matcher.matches())
+ {
+ String value = matcher.group(1);
+
+ return new LiteralBinding(description, new Long(value), location);
+ }
+
+ return null;
+ }
+ };
+
+ BindingFactory intRangeFactory = new BindingFactory()
+ {
+ private final Pattern _pattern = Pattern
+ .compile("^\\s*(-?\\d+)\\s*\\.\\.\\s*(-?\\d+)\\s*$");
+
+ public Binding newBinding(String description, ComponentResources component,
+ String expression, Location location)
+ {
+ Matcher matcher = _pattern.matcher(expression);
+
+ if (matcher.matches())
+ {
+ int start = Integer.parseInt(matcher.group(1));
+ int finish = Integer.parseInt(matcher.group(2));
+
+ IntegerRange range = new IntegerRange(start, finish);
+
+ return new LiteralBinding(description, range, location);
+ }
+
+ return null;
+ }
+ };
+
+ BindingFactory doubleFactory = new BindingFactory()
+ {
+ // So, either 1234. or 1234.56 or .78
+ private final Pattern _pattern = Pattern
+ .compile("^\\s*(\\-?((\\d+\\.)|(\\d*\\.\\d+)))\\s*$");
+
+ public Binding newBinding(String description, ComponentResources component,
+ String expression, Location location)
+ {
+ Matcher matcher = _pattern.matcher(expression);
+
+ if (matcher.matches())
+ {
+ String value = matcher.group(1);
+
+ return new LiteralBinding(description, new Double(value), location);
+ }
+
+ return null;
+ }
+ };
+
+ BindingFactory stringFactory = new BindingFactory()
+ {
+ // This will match embedded single quotes as-is, no escaping necessary.
+
+ private final Pattern _pattern = Pattern.compile("^\\s*'(.*)'\\s*$");
+
+ public Binding newBinding(String description, ComponentResources component,
+ String expression, Location location)
+ {
+ Matcher matcher = _pattern.matcher(expression);
+
+ if (matcher.matches())
+ {
+ String value = matcher.group(1);
+
+ return new LiteralBinding(description, value, location);
+ }
+
+ return null;
+ }
+ };
+
+ // To be honest, order probably doesn't matter.
+
+ configuration.add("Keyword", keywordFactory);
+ configuration.add("This", thisFactory);
+ configuration.add("Long", longFactory);
+ configuration.add("IntRange", intRangeFactory);
+ configuration.add("Double", doubleFactory);
+ configuration.add("StringLiteral", stringFactory);
+ }
+
+ public RequestExceptionHandler buildDefaultRequestExceptionHandler(
+ @InjectService("RequestPageCache")
+ RequestPageCache pageCache, @InjectService("PageResponseRenderer")
+ PageResponseRenderer renderer)
+ {
+ return new DefaultRequestExceptionHandler(pageCache, renderer, _response);
+ }
+
+ /** Service used to create links for components and pages. */
+ public LinkFactory buildLinkFactory()
+ {
+ return new LinkFactoryImpl(_request, _response, _componentClassResolver);
+ }
+
+ /**
+ * This exists as its own service just so that we can monitor it using logging.
+ * <p>
+ * TODO: Move this to TapestryModule?
+ */
+ public PersistentFieldStrategy buildSessionPersistentFieldStrategy()
+ {
+ return new SessionPersistentFieldStrategy(_request);
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java?view=diff&rev=476282&r1=476281&r2=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java Fri Nov 17 11:51:39 2006
@@ -12,51 +12,54 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.services;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.internal.structure.Page;
-import org.apache.tapestry.services.MarkupWriterFactory;
-import org.apache.tapestry.services.WebResponse;
-
-/**
- *
- */
-public class PageResponseRendererImpl implements PageResponseRenderer
-{
- private final Runnable _pageRenderInitializer;
-
- private final MarkupWriterFactory _markupWriterFactory;
-
- public PageResponseRendererImpl(MarkupWriterFactory markupWriterFactory,
- Runnable pageRenderInitializer)
- {
- _markupWriterFactory = markupWriterFactory;
- _pageRenderInitializer = pageRenderInitializer;
- }
-
- public void renderPageResponse(Page page, WebResponse response) throws IOException
- {
- _pageRenderInitializer.run();
-
- MarkupWriter writer = _markupWriterFactory.newMarkupWriter();
-
- RenderQueueImpl queue = new RenderQueueImpl(page.getLog());
-
- queue.push(page.getRootElement());
-
- // Run the queue until empty.
-
- queue.run(writer);
-
- PrintWriter pw = response.getPrintWriter();
-
- writer.toXML(pw);
-
- pw.flush();
- }
-
-}
+package org.apache.tapestry.internal.services;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.services.MarkupWriterFactory;
+import org.apache.tapestry.services.PageRenderInitializer;
+import org.apache.tapestry.services.WebResponse;
+
+public class PageResponseRendererImpl implements PageResponseRenderer
+{
+ private final PageRenderInitializer _pageRenderInitializer;
+
+ private final MarkupWriterFactory _markupWriterFactory;
+
+ public PageResponseRendererImpl(MarkupWriterFactory markupWriterFactory,
+ PageRenderInitializer pageRenderInitializer)
+ {
+ _markupWriterFactory = markupWriterFactory;
+ _pageRenderInitializer = pageRenderInitializer;
+ }
+
+ public void renderPageResponse(Page page, WebResponse response) throws IOException
+ {
+ _pageRenderInitializer.setup();
+
+ // Eventually we'll have to do work to figure out the correct markup type, content type,
+ // whatever. Right now its defaulting to plain HTML.
+
+ MarkupWriter writer = _markupWriterFactory.newMarkupWriter();
+
+ RenderQueueImpl queue = new RenderQueueImpl(page.getLog());
+
+ queue.push(page.getRootElement());
+
+ // Run the queue until empty.
+
+ queue.run(writer);
+
+ _pageRenderInitializer.cleanup();
+
+ PrintWriter pw = response.getPrintWriter();
+
+ writer.toXML(pw);
+
+ pw.flush();
+ }
+
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/DefaultPageRenderCommand.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/DefaultPageRenderCommand.java?view=auto&rev=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/DefaultPageRenderCommand.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/DefaultPageRenderCommand.java Fri Nov 17 11:51:39 2006
@@ -0,0 +1,32 @@
+// 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;
+
+/**
+ * Default implementation of {@link PageRenderCommand} that does nothing.
+ */
+public abstract class DefaultPageRenderCommand implements PageRenderCommand
+{
+ /** Does nothing. */
+ public void cleanup(Environment environment)
+ {
+ }
+
+ /** Does nothing. */
+ public void setup(Environment environment)
+ {
+ }
+
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Heartbeat.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Heartbeat.java?view=auto&rev=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Heartbeat.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Heartbeat.java Fri Nov 17 11:51:39 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.services;
+
+/**
+ * Allow for deferred execution of logic, useful when trying to get multiple components to
+ * coordinate behavior. A component may add a command to be executed "{@link #end() at the end of the heartbeat}".
+ * The classic example of this is a Label and the field it labels; since we don't know which order
+ * the two will render, we can't tell if the field's id is correct until after both have rendered.
+ */
+public interface Heartbeat
+{
+ /**
+ * Begins a new Heartbeat. Heartbeats nest. Every call to begin() should be matched by a call to
+ * {@link #end()}.
+ */
+ void begin();
+
+ /** Executes all commands since the most recent {@link #begin()}. */
+ void end();
+
+ /**
+ * Adds a new command to the current Heartbeat. The command will be executed by {@link #end()}.
+ *
+ * @param command
+ */
+ void defer(Runnable command);
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java?view=auto&rev=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java Fri Nov 17 11:51:39 2006
@@ -0,0 +1,30 @@
+// 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;
+
+/**
+ * Page render commands are invoked at the start of the page render cycle and at the end. This
+ * allows them to perform initial startup or final cleanup (or both).
+ *
+ * @see PageRenderInitializer
+ */
+public interface PageRenderCommand
+{
+ /** Invoked to perform an initial setup. */
+ void setup(Environment environment);
+
+ /** Invoked to peform final cleanup. */
+ void cleanup(Environment environment);
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java?view=auto&rev=476282
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java Fri Nov 17 11:51:39 2006
@@ -0,0 +1,34 @@
+// 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;
+
+/**
+ * Responsible for setup and cleanup of the rendering of a page. The implementation of this is based
+ * on an ordered list of {@link PageRenderCommand}s.
+ */
+public interface PageRenderInitializer
+{
+ /**
+ * Perform any initial setup, by invoking {@link PageRenderCommand#setup(Environment)}.
+ * Execution occurs in normal order.
+ */
+ void setup();
+
+ /**
+ * Peform any post-render cleanup, by invoking {@link PageRenderCommand#cleanup(Environment)}.
+ * Execution order is reversed.
+ */
+ void cleanup();
+}