Refactor and simplify concurrency support.
git-svn-id: https://svn.apache.org/repos/asf/tapestry/tapestry3/trunk@681513 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tapestry-framework/src/org/apache/tapestry/ApplicationServlet.java b/tapestry-framework/src/org/apache/tapestry/ApplicationServlet.java
index 1107a47..df5f266 100644
--- a/tapestry-framework/src/org/apache/tapestry/ApplicationServlet.java
+++ b/tapestry-framework/src/org/apache/tapestry/ApplicationServlet.java
@@ -14,7 +14,6 @@
package org.apache.tapestry;
-import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tapestry.engine.BaseEngine;
@@ -39,141 +38,108 @@
import java.util.Locale;
/**
- * Links a servlet container with a Tapestry application. The servlet has some
- * responsibilities related to bootstrapping the application (in terms of
- * logging, reading the {@link ApplicationSpecification specification}, etc.).
- * It is also responsible for creating or locating the {@link IEngine} and delegating
- * incoming requests to it.
- *
- * <p>The servlet init parameter
- * <code>org.apache.tapestry.specification-path</code>
- * should be set to the complete resource path (within the classpath)
- * to the application specification, i.e.,
- * <code>/com/foo/bar/MyApp.application</code>.
+ * Links a servlet container with a Tapestry application. The servlet has some responsibilities related to
+ * bootstrapping the application (in terms of logging, reading the {@link ApplicationSpecification specification},
+ * etc.). It is also responsible for creating or locating the {@link IEngine} and delegating incoming requests to it.
+ * <p/>
+ * <p>The servlet init parameter <code>org.apache.tapestry.specification-path</code> should be set to the complete
+ * resource path (within the classpath) to the application specification, i.e., <code>/com/foo/bar/MyApp.application</code>.
+ * <p/>
+ * <p>In some servlet containers (notably <a href="www.bea.com"/>WebLogic</a>) it is necessary to invoke {@link
+ * HttpSession#setAttribute(String,Object)} in order to force a persistent value to be replicated to the other servers
+ * in the cluster. Tapestry applications usually only have a single persistent value, the {@link IEngine engine}. For
+ * persistence to work in such an environment, the JVM system property <code>org.apache.tapestry.store-engine</code>
+ * must be set to <code>true</code>. This will force the application servlet to restore the engine into the {@link
+ * HttpSession} at the end of each request cycle.
+ * <p/>
+ * <p>As of release 1.0.1, it is no longer necessary for a {@link HttpSession} to be created on the first request cycle.
+ * Instead, the HttpSession is created as needed by the {@link IEngine} ... that is, when a visit object is created, or
+ * when persistent page state is required. Otherwise, for sessionless requests, an {@link IEngine} from a {@link Pool}
+ * is used. Additional work must be done so that the {@link IEngine} can change locale <em>without</em> forcing the
+ * creation of a session; this involves the servlet and the engine storing locale information in a {@link Cookie}.
*
- * <p>In some servlet containers (notably
- * <a href="www.bea.com"/>WebLogic</a>)
- * it is necessary to invoke {@link HttpSession#setAttribute(String,Object)}
- * in order to force a persistent value to be replicated to the other
- * servers in the cluster. Tapestry applications usually only have a single
- * persistent value, the {@link IEngine engine}. For persistence to
- * work in such an environment, the
- * JVM system property <code>org.apache.tapestry.store-engine</code>
- * must be set to <code>true</code>. This will force the application
- * servlet to restore the engine into the {@link HttpSession} at the
- * end of each request cycle.
- *
- * <p>As of release 1.0.1, it is no longer necessary for a {@link HttpSession}
- * to be created on the first request cycle. Instead, the HttpSession is created
- * as needed by the {@link IEngine} ... that is, when a visit object is created,
- * or when persistent page state is required. Otherwise, for sessionless requests,
- * an {@link IEngine} from a {@link Pool} is used. Additional work must be done
- * so that the {@link IEngine} can change locale <em>without</em> forcing
- * the creation of a session; this involves the servlet and the engine storing
- * locale information in a {@link Cookie}.
- *
- * @version $Id$
- * @author Howard Lewis Ship
- *
- **/
+ * @author Howard Lewis Ship
+ * @version $Id$
+ */
public class ApplicationServlet extends HttpServlet
{
private static final Log LOG = LogFactory.getLog(ApplicationServlet.class);
- /** @since 2.3 **/
+ /**
+ * @since 2.3 *
+ */
private static final String APP_SPEC_PATH_PARAM =
- "org.apache.tapestry.application-specification";
+ "org.apache.tapestry.application-specification";
/**
- * Name of the cookie written to the client web browser to
- * identify the locale.
- *
- **/
+ * Name of the cookie written to the client web browser to identify the locale.
+ */
private static final String LOCALE_COOKIE_NAME = "org.apache.tapestry.locale";
/**
- * A {@link Pool} used to store {@link IEngine engine}s that are not currently
- * in use. The key is on {@link Locale}.
- *
- **/
+ * A {@link Pool} used to store {@link IEngine engine}s that are not currently in use. The key is on {@link
+ * Locale}.
+ */
private Pool _enginePool = new Pool();
/**
- * The application specification, which is read once and kept in memory
- * thereafter.
- *
- **/
+ * The application specification, which is read once and kept in memory thereafter.
+ */
private IApplicationSpecification _specification;
/**
- * The name under which the {@link IEngine engine} is stored within the
- * {@link HttpSession}.
- *
- **/
+ * The name under which the {@link IEngine engine} is stored within the {@link HttpSession}.
+ */
private String _attributeName;
/**
- * The resolved class name used to instantiate the engine.
- *
- * @since 3.0
- *
- **/
+ * The resolved class name used to instantiate the engine.
+ *
+ * @since 3.0
+ */
private String _engineClassName;
/**
- * Used to search for configuration properties.
- *
- *
- * @since 3.0
- *
- **/
+ * Used to search for configuration properties.
+ *
+ * @since 3.0
+ */
private IPropertySource _propertySource;
/**
- * Global lock used to synchronize global thread access to commonly shared
- * services / data structures.
+ * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
+ *
+ * @since 1.0.6
*/
- private ReentrantLock _lock = new ReentrantLock();
-
- /**
- * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
- *
- * @since 1.0.6
- *
- **/
public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException
+ throws IOException, ServletException
{
doService(request, response);
}
/**
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
private IResourceResolver _resolver;
/**
- * Handles the GET and POST requests. Performs the following:
- * <ul>
- * <li>Construct a {@link RequestContext}
- * <li>Invoke {@link #getEngine(RequestContext)} to get or create the {@link IEngine}
- * <li>Invoke {@link IEngine#service(RequestContext)} on the application
- * </ul>
- **/
+ * Handles the GET and POST requests. Performs the following: <ul> <li>Construct a {@link RequestContext} <li>Invoke
+ * {@link #getEngine(RequestContext)} to get or create the {@link IEngine} <li>Invoke {@link
+ * IEngine#service(RequestContext)} on the application </ul>
+ */
protected void doService(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException
+ throws IOException, ServletException
{
RequestContext context = null;
@@ -189,7 +155,7 @@
if (engine == null)
throw new ServletException(
- Tapestry.getMessage("ApplicationServlet.could-not-locate-engine"));
+ Tapestry.getMessage("ApplicationServlet.could-not-locate-engine"));
boolean dirty = engine.service(context);
@@ -210,7 +176,7 @@
{
boolean forceStore =
- engine.isStateful() && (session.getAttribute(_attributeName) == null);
+ engine.isStateful() && (session.getAttribute(_attributeName) == null);
if (forceStore || dirty)
{
@@ -239,9 +205,9 @@
if (engine.isStateful())
{
LOG.error(
- Tapestry.format(
- "ApplicationServlet.engine-stateful-without-session",
- engine));
+ Tapestry.format(
+ "ApplicationServlet.engine-stateful-without-session",
+ engine));
return;
}
@@ -285,18 +251,17 @@
}
/**
- * Invoked by {@link #doService(HttpServletRequest, HttpServletResponse)} to create
- * the {@link RequestContext} for this request cycle. Some applications may need to
- * replace the default RequestContext with a subclass for particular behavior.
- *
- * @since 2.3
- *
- **/
+ * Invoked by {@link #doService(HttpServletRequest, HttpServletResponse)} to create the {@link RequestContext} for
+ * this request cycle. Some applications may need to replace the default RequestContext with a subclass for
+ * particular behavior.
+ *
+ * @since 2.3
+ */
protected RequestContext createRequestContext(
- HttpServletRequest request,
- HttpServletResponse response)
- throws IOException
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
{
return new RequestContext(this, request, response);
}
@@ -312,22 +277,18 @@
}
/**
- * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
- *
- *
- **/
+ * Invokes {@link #doService(HttpServletRequest, HttpServletResponse)}.
+ */
public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException
+ throws IOException, ServletException
{
doService(request, response);
}
/**
- * Returns the application specification, which is read
- * by the {@link #init(ServletConfig)} method.
- *
- **/
+ * Returns the application specification, which is read by the {@link #init(ServletConfig)} method.
+ */
public IApplicationSpecification getApplicationSpecification()
{
@@ -335,25 +296,10 @@
}
/**
- * Used internally to synchronize access to creation of shared services.
- *
- * @return The global shared lock.
+ * Retrieves the {@link IEngine engine} that will process this request. This comes from one of the following
+ * places: <ul> <li>The {@link HttpSession}, if the there is one. <li>From the pool of available engines <li>Freshly
+ * created </ul>
*/
- public ReentrantLock getLock()
- {
- return _lock;
- }
-
- /**
- * Retrieves the {@link IEngine engine} that will process this
- * request. This comes from one of the following places:
- * <ul>
- * <li>The {@link HttpSession}, if the there is one.
- * <li>From the pool of available engines
- * <li>Freshly created
- * </ul>
- *
- **/
protected IEngine getEngine(RequestContext context) throws ServletException
{
@@ -396,12 +342,9 @@
}
/**
- * Determines the {@link Locale} for the incoming request.
- * This is determined from the locale cookie or, if not set,
- * from the request itself. This may return null
- * if no locale is determined.
- *
- **/
+ * Determines the {@link Locale} for the incoming request. This is determined from the locale cookie or, if not set,
+ * from the request itself. This may return null if no locale is determined.
+ */
protected Locale getLocaleFromRequest(RequestContext context) throws ServletException
{
@@ -414,15 +357,13 @@
}
/**
- * Reads the application specification when the servlet is
- * first initialized. All {@link IEngine engine instances}
- * will have access to the specification via the servlet.
- *
- * @see #getApplicationSpecification()
- * @see #constructApplicationSpecification()
- * @see #createResourceResolver()
+ * Reads the application specification when the servlet is first initialized. All {@link IEngine engine instances}
+ * will have access to the specification via the servlet.
*
- **/
+ * @see #getApplicationSpecification()
+ * @see #constructApplicationSpecification()
+ * @see #createResourceResolver()
+ */
public void init(ServletConfig config) throws ServletException
{
@@ -436,17 +377,15 @@
}
/**
- * Invoked from {@link #init(ServletConfig)} to create a resource resolver
- * for the servlet (which will utlimately be shared and used through the
- * application).
- *
- * <p>This implementation constructs a {@link DefaultResourceResolver}, subclasses
- * may provide a different implementation.
- *
- * @see #getResourceResolver()
- * @since 2.3
- *
- **/
+ * Invoked from {@link #init(ServletConfig)} to create a resource resolver for the servlet (which will utlimately be
+ * shared and used through the application).
+ * <p/>
+ * <p>This implementation constructs a {@link DefaultResourceResolver}, subclasses may provide a different
+ * implementation.
+ *
+ * @see #getResourceResolver()
+ * @since 2.3
+ */
protected IResourceResolver createResourceResolver() throws ServletException
{
@@ -454,24 +393,18 @@
}
/**
- * Invoked from {@link #init(ServletConfig)} to read and construct
- * the {@link ApplicationSpecification} for this servlet.
- * Invokes {@link #getApplicationSpecificationPath()}, opens
- * the resource as a stream, then invokes
- * {@link #parseApplicationSpecification(IResourceLocation)}.
- *
- * <p>
- * This method exists to be overriden in
- * applications where the application specification cannot be
- * loaded from the classpath. Alternately, a subclass
- * could override this method, invoke this implementation,
- * and then add additional data to it (for example, an application
- * where some of the pages are defined in an external source
- * such as a database).
- *
- * @since 2.2
- *
- **/
+ * Invoked from {@link #init(ServletConfig)} to read and construct the {@link ApplicationSpecification} for this
+ * servlet. Invokes {@link #getApplicationSpecificationPath()}, opens the resource as a stream, then invokes {@link
+ * #parseApplicationSpecification(IResourceLocation)}.
+ * <p/>
+ * <p/>
+ * This method exists to be overriden in applications where the application specification cannot be loaded from the
+ * classpath. Alternately, a subclass could override this method, invoke this implementation, and then add
+ * additional data to it (for example, an application where some of the pages are defined in an external source such
+ * as a database).
+ *
+ * @since 2.2
+ */
protected IApplicationSpecification constructApplicationSpecification() throws ServletException
{
@@ -492,24 +425,16 @@
}
/**
- * Gets the location of the application specification, if there is one.
- *
- * <ul>
- * <li>Invokes {@link #getApplicationSpecificationPath()} to get the
- * location of the application specification on the classpath.
- * <li>If that return null, search for the application specification:
- * <ul>
- * <li><i>name</i>.application in /WEB-INF/<i>name</i>/
- * <li><i>name</i>.application in /WEB-INF/
- * </ul>
- * </ul>
- *
- * <p>Returns the location of the application specification, or null
- * if not found.
- *
- * @since 3.0
- *
- **/
+ * Gets the location of the application specification, if there is one.
+ * <p/>
+ * <ul> <li>Invokes {@link #getApplicationSpecificationPath()} to get the location of the application specification
+ * on the classpath. <li>If that return null, search for the application specification: <ul>
+ * <li><i>name</i>.application in /WEB-INF/<i>name</i>/ <li><i>name</i>.application in /WEB-INF/ </ul> </ul>
+ * <p/>
+ * <p>Returns the location of the application specification, or null if not found.
+ *
+ * @since 3.0
+ */
protected IResourceLocation getApplicationSpecificationLocation() throws ServletException
{
@@ -533,12 +458,10 @@
}
/**
- * Checks for the application specification relative to the specified
- * location.
- *
- * @since 3.0
- *
- **/
+ * Checks for the application specification relative to the specified location.
+ *
+ * @since 3.0
+ */
private IResourceLocation check(IResourceLocation location, String name)
{
@@ -557,21 +480,19 @@
}
/**
- * Invoked from {@link #constructApplicationSpecification()} when
- * the application doesn't have an explicit specification. A
- * simple specification is constructed and returned. This is useful
- * for minimal applications and prototypes.
- *
- * @since 3.0
- *
- **/
+ * Invoked from {@link #constructApplicationSpecification()} when the application doesn't have an explicit
+ * specification. A simple specification is constructed and returned. This is useful for minimal applications and
+ * prototypes.
+ *
+ * @since 3.0
+ */
protected IApplicationSpecification constructStandinSpecification()
{
ApplicationSpecification result = new ApplicationSpecification();
IResourceLocation virtualLocation =
- new ContextResourceLocation(getServletContext(), "/WEB-INF/");
+ new ContextResourceLocation(getServletContext(), "/WEB-INF/");
result.setSpecificationLocation(virtualLocation);
@@ -582,16 +503,14 @@
}
/**
- * Invoked from {@link #constructApplicationSpecification()} to
- * actually parse the stream (with content provided from the path)
- * and convert it into an {@link ApplicationSpecification}.
- *
- * @since 2.2
- *
- **/
+ * Invoked from {@link #constructApplicationSpecification()} to actually parse the stream (with content provided
+ * from the path) and convert it into an {@link ApplicationSpecification}.
+ *
+ * @since 2.2
+ */
protected IApplicationSpecification parseApplicationSpecification(IResourceLocation location)
- throws ServletException
+ throws ServletException
{
try
{
@@ -604,15 +523,14 @@
show(ex);
throw new ServletException(
- Tapestry.format("ApplicationServlet.could-not-parse-spec", location),
- ex);
+ Tapestry.format("ApplicationServlet.could-not-parse-spec", location),
+ ex);
}
}
/**
- * Closes the stream, ignoring any exceptions.
- *
- **/
+ * Closes the stream, ignoring any exceptions.
+ */
protected void close(InputStream stream)
{
@@ -628,18 +546,15 @@
}
/**
- * Reads the servlet init parameter
- * <code>org.apache.tapestry.application-specification</code>, which
- * is the location, on the classpath, of the application specification.
+ * Reads the servlet init parameter <code>org.apache.tapestry.application-specification</code>, which is the
+ * location, on the classpath, of the application specification.
+ * <p/>
+ * <p/>
+ * If the parameter is not set, this method returns null, and a search for the application specification within the
+ * servlet context will begin.
*
- * <p>
- * If the parameter is not set, this method returns null, and a search
- * for the application specification within the servlet context
- * will begin.
- *
- * @see #getApplicationSpecificationLocation()
- *
- **/
+ * @see #getApplicationSpecificationLocation()
+ */
protected String getApplicationSpecificationPath() throws ServletException
{
@@ -647,17 +562,13 @@
}
/**
- * Invoked by {@link #getEngine(RequestContext)} to create
- * the {@link IEngine} instance specific to the
- * application, if not already in the
- * {@link HttpSession}.
+ * Invoked by {@link #getEngine(RequestContext)} to create the {@link IEngine} instance specific to the application,
+ * if not already in the {@link HttpSession}.
+ * <p/>
+ * <p>The {@link IEngine} instance returned is stored into the {@link HttpSession}.
*
- * <p>The {@link IEngine} instance returned is stored into the
- * {@link HttpSession}.
- *
- * @see #getEngineClassName()
- *
- **/
+ * @see #getEngineClassName()
+ */
protected IEngine createEngine(RequestContext context) throws ServletException
{
@@ -684,19 +595,12 @@
}
/**
- *
- * Returns the name of the class to use when instantiating
- * an engine instance for this application.
- * If the application specification
- * provides a value, this is returned. Otherwise, a search for
- * the configuration property
- * <code>org.apache.tapestry.engine-class</code>
- * occurs (see {@link #searchConfiguration(String)}).
- *
- * <p>If the search is still unsuccessful, then
- * {@link org.apache.tapestry.engine.BaseEngine} is used.
- *
- **/
+ * Returns the name of the class to use when instantiating an engine instance for this application. If the
+ * application specification provides a value, this is returned. Otherwise, a search for the configuration property
+ * <code>org.apache.tapestry.engine-class</code> occurs (see {@link #searchConfiguration(String)}).
+ * <p/>
+ * <p>If the search is still unsuccessful, then {@link org.apache.tapestry.engine.BaseEngine} is used.
+ */
protected String getEngineClassName()
{
@@ -715,48 +619,30 @@
}
/**
- * Searches for a configuration property in:
- * <ul>
- * <li>The servlet's initial parameters
- * <li>The servlet context's initial parameters
- * <li>JVM system properties
- * </ul>
- *
- * @see #createPropertySource()
- * @since 3.0
- *
- **/
+ * Searches for a configuration property in: <ul> <li>The servlet's initial parameters <li>The servlet context's
+ * initial parameters <li>JVM system properties </ul>
+ *
+ * @see #createPropertySource()
+ * @since 3.0
+ */
protected String searchConfiguration(String propertyName)
{
- if (_propertySource == null)
+ synchronized (this)
{
- _lock.lock();
-
- try
- {
- if (_propertySource == null)
- {
- _propertySource = createPropertySource();
- }
- } finally
- {
- _lock.unlock();
- }
+ if (_propertySource == null)
+ _propertySource = createPropertySource();
}
return _propertySource.getPropertyValue(propertyName);
}
/**
- * Creates an instance of {@link IPropertySource} used for
- * searching of configuration values. Subclasses may override
- * this method if they want to change the normal locations
- * that properties are searched for within.
- *
- * @since 3.0
- *
- **/
+ * Creates an instance of {@link IPropertySource} used for searching of configuration values. Subclasses may
+ * override this method if they want to change the normal locations that properties are searched for within.
+ *
+ * @since 3.0
+ */
protected IPropertySource createPropertySource()
{
@@ -770,16 +656,14 @@
}
/**
- * Invoked from the {@link IEngine engine}, just prior to starting to
- * render a response, when the locale has changed. The servlet writes a
- * {@link Cookie} so that, on subsequent request cycles, an engine localized
- * to the selected locale is chosen.
+ * Invoked from the {@link IEngine engine}, just prior to starting to render a response, when the locale has
+ * changed. The servlet writes a {@link Cookie} so that, on subsequent request cycles, an engine localized to the
+ * selected locale is chosen.
+ * <p/>
+ * <p>At this time, the cookie is <em>not</em> persistent. That may change in subsequent releases.
*
- * <p>At this time, the cookie is <em>not</em> persistent. That may
- * change in subsequent releases.
- *
- * @since 1.0.1
- **/
+ * @since 1.0.1
+ */
public void writeLocaleCookie(Locale locale, IEngine engine, RequestContext cycle)
{
@@ -793,14 +677,11 @@
}
/**
- * Returns a resource resolver that can access classes and resources related
- * to the current web application context. Relies on
- * {@link java.lang.Thread#getContextClassLoader()}, which is set by
- * most modern servlet containers.
- *
- * @since 2.3
+ * Returns a resource resolver that can access classes and resources related to the current web application context.
+ * Relies on {@link java.lang.Thread#getContextClassLoader()}, which is set by most modern servlet containers.
*
- **/
+ * @since 2.3
+ */
public IResourceResolver getResourceResolver()
{
@@ -809,6 +690,7 @@
/**
* Ensures that shared janitor thread is terminated.
+ *
* @see javax.servlet.Servlet#destroy()
* @since 3.0.3
*/
diff --git a/tapestry-framework/src/org/apache/tapestry/BaseComponentTemplateLoader.java b/tapestry-framework/src/org/apache/tapestry/BaseComponentTemplateLoader.java
index 423b24b..f32fa33 100644
--- a/tapestry-framework/src/org/apache/tapestry/BaseComponentTemplateLoader.java
+++ b/tapestry-framework/src/org/apache/tapestry/BaseComponentTemplateLoader.java
@@ -20,7 +20,6 @@
import org.apache.tapestry.binding.ExpressionBinding;
import org.apache.tapestry.binding.StaticBinding;
import org.apache.tapestry.binding.StringBinding;
-import org.apache.tapestry.engine.ExpressionEvaluator;
import org.apache.tapestry.engine.IPageLoader;
import org.apache.tapestry.engine.IPageSource;
import org.apache.tapestry.engine.ITemplateSource;
@@ -34,16 +33,14 @@
import java.util.Set;
/**
- * Utility class instantiated by {@link org.apache.tapestry.BaseComponent} to
- * process the component's {@link org.apache.tapestry.parse.ComponentTemplate template},
- * which involves working through the nested structure of the template and hooking
- * the various static template blocks and components together using
- * {@link IComponent#addBody(IRender)} and
- * {@link org.apache.tapestry.BaseComponent#addOuter(IRender)}.
+ * Utility class instantiated by {@link org.apache.tapestry.BaseComponent} to process the component's {@link
+ * org.apache.tapestry.parse.ComponentTemplate template}, which involves working through the nested structure of the
+ * template and hooking the various static template blocks and components together using {@link
+ * IComponent#addBody(IRender)} and {@link org.apache.tapestry.BaseComponent#addOuter(IRender)}.
*
- * @author Howard Lewis Ship
- * @version $Id$
- * @since 3.0
+ * @author Howard Lewis Ship
+ * @version $Id$
+ * @since 3.0
*/
public class BaseComponentTemplateLoader
@@ -58,12 +55,10 @@
private IComponent[] _stack;
private int _stackx = 0;
private IComponent _activeComponent = null;
- private ExpressionEvaluator _evaluator;
private Set _seenIds = new HashSet();
/**
- * A class used with invisible localizations. Constructed
- * from a {@link TextToken}.
+ * A class used with invisible localizations. Constructed from a {@link TextToken}.
*/
private static class LocalizedStringRender implements IRender
@@ -130,11 +125,11 @@
}
public BaseComponentTemplateLoader(
- IRequestCycle requestCycle,
- IPageLoader pageLoader,
- BaseComponent loadComponent,
- ComponentTemplate template,
- IPageSource pageSource)
+ IRequestCycle requestCycle,
+ IPageLoader pageLoader,
+ BaseComponent loadComponent,
+ ComponentTemplate template,
+ IPageSource pageSource)
{
_requestCycle = requestCycle;
_pageLoader = pageLoader;
@@ -185,21 +180,20 @@
if (_stackx != 0)
throw new ApplicationRuntimeException(
- Tapestry.getMessage("BaseComponent.unbalance-open-tags"),
- _loadComponent,
- null,
- null);
+ Tapestry.getMessage("BaseComponent.unbalance-open-tags"),
+ _loadComponent,
+ null,
+ null);
checkAllComponentsReferenced();
}
/**
- * Adds the token (which implements {@link IRender})
- * to the active component (using {@link IComponent#addBody(IRender)}),
- * or to this component {@link BaseComponent#addOuter(IRender)}.
- *
- * <p>
- * A check is made that the active component allows a body.
+ * Adds the token (which implements {@link IRender}) to the active component (using {@link
+ * IComponent#addBody(IRender)}), or to this component {@link BaseComponent#addOuter(IRender)}.
+ * <p/>
+ * <p/>
+ * A check is made that the active component allows a body.
*/
private void process(TextToken token)
@@ -235,13 +229,13 @@
if (_seenIds.contains(id))
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.multiple-component-references",
- _loadComponent.getExtendedId(),
- id),
- _loadComponent,
- token.getLocation(),
- null);
+ Tapestry.format(
+ "BaseComponent.multiple-component-references",
+ _loadComponent.getExtendedId(),
+ id),
+ _loadComponent,
+ token.getLocation(),
+ null);
_seenIds.add(id);
@@ -274,25 +268,25 @@
if (cc != null)
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponentTemplateLoader.dupe-component-id",
- id,
+ Tapestry.format(
+ "BaseComponentTemplateLoader.dupe-component-id",
+ id,
+ location,
+ cc.getLocation()),
+ _loadComponent,
location,
- cc.getLocation()),
- _loadComponent,
- location,
- null);
+ null);
}
private IComponent createImplicitComponent(String id, String componentType, ILocation location)
{
IComponent result =
- _pageLoader.createImplicitComponent(
- _requestCycle,
- _loadComponent,
- id,
- componentType,
- location);
+ _pageLoader.createImplicitComponent(
+ _requestCycle,
+ _loadComponent,
+ id,
+ componentType,
+ location);
return result;
}
@@ -309,10 +303,10 @@
if (_stackx <= 0)
throw new ApplicationRuntimeException(
- Tapestry.getMessage("BaseComponent.unbalanced-close-tags"),
- _loadComponent,
- token.getLocation(),
- null);
+ Tapestry.getMessage("BaseComponent.unbalanced-close-tags"),
+ _loadComponent,
+ token.getLocation(),
+ null);
// Null and forget the top element on the stack.
@@ -332,7 +326,7 @@
}
/**
- * Adds bindings based on attributes in the template.
+ * Adds bindings based on attributes in the template.
*/
private void addTemplateBindings(IComponent component, OpenToken token)
@@ -356,32 +350,32 @@
if (type == AttributeType.OGNL_EXPRESSION)
{
addExpressionBinding(
- component,
- spec,
- name,
- attribute.getValue(),
- token.getLocation());
+ component,
+ spec,
+ name,
+ attribute.getValue(),
+ token.getLocation());
continue;
}
if (type == AttributeType.LOCALIZATION_KEY)
{
addStringBinding(
- component,
- spec,
- name,
- attribute.getValue(),
- token.getLocation());
+ component,
+ spec,
+ name,
+ attribute.getValue(),
+ token.getLocation());
continue;
}
if (type == AttributeType.LITERAL)
addStaticBinding(
- component,
- spec,
- name,
- attribute.getValue(),
- token.getLocation());
+ component,
+ spec,
+ name,
+ attribute.getValue(),
+ token.getLocation());
}
}
@@ -389,33 +383,30 @@
// there is no established binding for that parameter,
// add a static binding carrying the template tag
if (spec.getParameter(ITemplateSource.TEMPLATE_TAG_PARAMETER_NAME) != null
- && component.getBinding(ITemplateSource.TEMPLATE_TAG_PARAMETER_NAME) == null)
+ && component.getBinding(ITemplateSource.TEMPLATE_TAG_PARAMETER_NAME) == null)
{
addStaticBinding(
- component,
- spec,
- ITemplateSource.TEMPLATE_TAG_PARAMETER_NAME,
- token.getTag(),
- token.getLocation());
+ component,
+ spec,
+ ITemplateSource.TEMPLATE_TAG_PARAMETER_NAME,
+ token.getTag(),
+ token.getLocation());
}
}
/**
- * Adds an expression binding, checking for errors related
- * to reserved and informal parameters.
- *
- * <p>It is an error to specify expression
- * bindings in both the specification
- * and the template.
+ * Adds an expression binding, checking for errors related to reserved and informal parameters.
+ * <p/>
+ * <p>It is an error to specify expression bindings in both the specification and the template.
*/
private void addExpressionBinding(
- IComponent component,
- IComponentSpecification spec,
- String name,
- String expression,
- ILocation location)
+ IComponent component,
+ IComponentSpecification spec,
+ String name,
+ String expression,
+ ILocation location)
{
// If matches a formal parameter name, allow it to be set
@@ -427,68 +418,65 @@
{
if (component.getBinding(name) != null)
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.dupe-template-expression",
- name,
- component.getExtendedId(),
- _loadComponent.getExtendedId()),
- component,
- location,
- null);
+ Tapestry.format(
+ "BaseComponent.dupe-template-expression",
+ name,
+ component.getExtendedId(),
+ _loadComponent.getExtendedId()),
+ component,
+ location,
+ null);
}
else
{
if (!spec.getAllowInformalParameters())
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.template-expression-for-informal-parameter",
- name,
- component.getExtendedId(),
- _loadComponent.getExtendedId()),
- component,
- location,
- null);
+ Tapestry.format(
+ "BaseComponent.template-expression-for-informal-parameter",
+ name,
+ component.getExtendedId(),
+ _loadComponent.getExtendedId()),
+ component,
+ location,
+ null);
// If the name is reserved (matches a formal parameter
// or reserved name, caselessly), then skip it.
if (spec.isReservedParameterName(name))
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.template-expression-for-reserved-parameter",
- name,
- component.getExtendedId(),
- _loadComponent.getExtendedId()),
- component,
- location,
- null);
+ Tapestry.format(
+ "BaseComponent.template-expression-for-reserved-parameter",
+ name,
+ component.getExtendedId(),
+ _loadComponent.getExtendedId()),
+ component,
+ location,
+ null);
}
IBinding binding =
- new ExpressionBinding(
- _pageSource.getResourceResolver(),
- _loadComponent,
- expression,
- location);
+ new ExpressionBinding(
+ _pageSource.getResourceResolver(),
+ _loadComponent,
+ expression,
+ location);
component.setBinding(name, binding);
}
/**
- * Adds an expression binding, checking for errors related
- * to reserved and informal parameters.
- *
- * <p>It is an error to specify expression
- * bindings in both the specification
- * and the template.
- */
+ * Adds an expression binding, checking for errors related to reserved and informal parameters.
+ * <p/>
+ * <p>It is an error to specify expression bindings in both the specification and the template.
+ */
private void addStringBinding(
- IComponent component,
- IComponentSpecification spec,
- String name,
- String localizationKey,
- ILocation location)
+ IComponent component,
+ IComponentSpecification spec,
+ String name,
+ String localizationKey,
+ ILocation location)
{
// If matches a formal parameter name, allow it to be set
// unless there's already a binding.
@@ -499,41 +487,41 @@
{
if (component.getBinding(name) != null)
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.dupe-string",
- name,
- component.getExtendedId(),
- _loadComponent.getExtendedId()),
- component,
- location,
- null);
+ Tapestry.format(
+ "BaseComponent.dupe-string",
+ name,
+ component.getExtendedId(),
+ _loadComponent.getExtendedId()),
+ component,
+ location,
+ null);
}
else
{
if (!spec.getAllowInformalParameters())
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.template-expression-for-informal-parameter",
- name,
- component.getExtendedId(),
- _loadComponent.getExtendedId()),
- component,
- location,
- null);
+ Tapestry.format(
+ "BaseComponent.template-expression-for-informal-parameter",
+ name,
+ component.getExtendedId(),
+ _loadComponent.getExtendedId()),
+ component,
+ location,
+ null);
// If the name is reserved (matches a formal parameter
// or reserved name, caselessly), then skip it.
if (spec.isReservedParameterName(name))
throw new ApplicationRuntimeException(
- Tapestry.format(
- "BaseComponent.template-expression-for-reserved-parameter",
- name,
- component.getExtendedId(),
- _loadComponent.getExtendedId()),
- component,
- location,
- null);
+ Tapestry.format(
+ "BaseComponent.template-expression-for-reserved-parameter",
+ name,
+ component.getExtendedId(),
+ _loadComponent.getExtendedId()),
+ component,
+ location,
+ null);
}
IBinding binding = new StringBinding(_loadComponent, localizationKey, location);
@@ -542,20 +530,18 @@
}
/**
- * Adds a static binding, checking for errors related
- * to reserved and informal parameters.
- *
- * <p>
- * Static bindings that conflict with bindings in the
- * specification are quietly ignored.
+ * Adds a static binding, checking for errors related to reserved and informal parameters.
+ * <p/>
+ * <p/>
+ * Static bindings that conflict with bindings in the specification are quietly ignored.
*/
private void addStaticBinding(
- IComponent component,
- IComponentSpecification spec,
- String name,
- String staticValue,
- ILocation location)
+ IComponent component,
+ IComponentSpecification spec,
+ String name,
+ String staticValue,
+ ILocation location)
{
if (component.getBinding(name) != null)
@@ -609,12 +595,12 @@
int count = ids.size();
String key =
- (count == 1)
+ (count == 1)
? "BaseComponent.missing-component-spec-single"
: "BaseComponent.missing-component-spec-multi";
StringBuffer buffer =
- new StringBuffer(Tapestry.format(key, _loadComponent.getExtendedId()));
+ new StringBuffer(Tapestry.format(key, _loadComponent.getExtendedId()));
Iterator i = ids.iterator();
int j = 1;
@@ -623,15 +609,14 @@
{
if (j == 1)
buffer.append(' ');
+ else if (j == count)
+ {
+ buffer.append(' ');
+ buffer.append(Tapestry.getMessage("BaseComponent.and"));
+ buffer.append(' ');
+ }
else
- if (j == count)
- {
- buffer.append(' ');
- buffer.append(Tapestry.getMessage("BaseComponent.and"));
- buffer.append(' ');
- }
- else
- buffer.append(", ");
+ buffer.append(", ");
buffer.append(i.next());
@@ -646,9 +631,9 @@
protected ApplicationRuntimeException createBodylessComponentException(IComponent component)
{
return new ApplicationRuntimeException(
- Tapestry.getMessage("BaseComponentTemplateLoader.bodyless-component"),
- component,
- null,
- null);
+ Tapestry.getMessage("BaseComponentTemplateLoader.bodyless-component"),
+ component,
+ null,
+ null);
}
}
diff --git a/tapestry-framework/src/org/apache/tapestry/binding/ExpressionBinding.java b/tapestry-framework/src/org/apache/tapestry/binding/ExpressionBinding.java
index a4ab6f7..8629974 100644
--- a/tapestry-framework/src/org/apache/tapestry/binding/ExpressionBinding.java
+++ b/tapestry-framework/src/org/apache/tapestry/binding/ExpressionBinding.java
@@ -29,118 +29,87 @@
import java.util.Map;
/**
- * Implements a dynamic binding, based on getting and fetching
- * values using JavaBeans property access. This is built
- * upon the <a href="http://www.ognl.org">OGNL</a> library.
+ * Implements a dynamic binding, based on getting and fetching values using JavaBeans property access. This is built
+ * upon the <a href="http://www.ognl.org">OGNL</a> library.
+ * <p/>
+ * <p><b>Optimization of the Expression</b>
+ * <p/>
+ * <p>There's a lot of room for optimization here because we can count on some portions of the expression to be
+ * effectively static. Note that we type the root object as {@link IComponent}. We have some expectations that certain
+ * properties of the root (and properties reachable from the root) will be constant for the lifetime of the binding. For
+ * example, components never change thier page or container. This means that certain property prefixes can be
+ * optimized:
+ * <p/>
+ * <ul> <li>page <li>container <li>components.<i>name</i> </ul>
+ * <p/>
+ * <p>This means that once an ExpressionBinding has been triggered, the {@link #toString()} method may return different
+ * values for the root component and the expression than was originally set.
+ * <p/>
+ * <p><b>Identifying Invariants</b>
+ * <p/>
+ * <p>Most expressions are fully dynamic; they must be resolved each time they are accessed. This can be somewhat
+ * inefficient. Tapestry can identify certain paths as invariant:
+ * <p/>
+ * <ul> <li>A component within the page hierarchy <li>An {@link org.apache.tapestry.IAsset} from then assets map
+ * (property <code>assets</code>) <li>A {@link org.apache.tapestry.IActionListener} from the listener map (property
+ * <code>listeners</code>) <li>A bean with a {@link org.apache.tapestry.spec.BeanLifecycle#PAGE} lifecycle (property
+ * <code>beans</code>) <li>A binding (property <code>bindings</code>) </ul>
+ * <p/>
+ * <p/>
+ * These optimizations have some inherent dangers; they assume that the components have not overidden the specified
+ * properties; the last one (concerning helper beans) assumes that the component does inherit from {@link
+ * org.apache.tapestry.AbstractComponent}. If this becomes a problem in the future, it may be necessary to have the
+ * component itself involved in these determinations.
*
- * <p><b>Optimization of the Expression</b>
- *
- * <p>There's a lot of room for optimization here because we can
- * count on some portions of the expression to be
- * effectively static. Note that we type the root object as
- * {@link IComponent}. We have some expectations that
- * certain properties of the root (and properties reachable from the root)
- * will be constant for the lifetime of the binding. For example,
- * components never change thier page or container. This means
- * that certain property prefixes can be optimized:
- *
- * <ul>
- * <li>page
- * <li>container
- * <li>components.<i>name</i>
- * </ul>
- *
- * <p>This means that once an ExpressionBinding has been triggered,
- * the {@link #toString()} method may return different values for the root
- * component and the expression than was originally set.
- *
- * <p><b>Identifying Invariants</b>
- *
- * <p>Most expressions are fully dynamic; they must be
- * resolved each time they are accessed. This can be somewhat inefficient.
- * Tapestry can identify certain paths as invariant:
- *
- * <ul>
- * <li>A component within the page hierarchy
- * <li>An {@link org.apache.tapestry.IAsset} from then assets map (property <code>assets</code>)
- * <li>A {@link org.apache.tapestry.IActionListener}
- * from the listener map (property <code>listeners</code>)
- * <li>A bean with a {@link org.apache.tapestry.spec.BeanLifecycle#PAGE}
- * lifecycle (property <code>beans</code>)
- * <li>A binding (property <code>bindings</code>)
- * </ul>
- *
- * <p>
- * These optimizations have some inherent dangers; they assume that
- * the components have not overidden the specified properties;
- * the last one (concerning helper beans) assumes that the
- * component does inherit from {@link org.apache.tapestry.AbstractComponent}.
- * If this becomes a problem in the future, it may be necessary to
- * have the component itself involved in these determinations.
- *
- * @author Howard Lewis Ship
- * @version $Id$
- * @since 2.2
- *
- **/
+ * @author Howard Lewis Ship
+ * @version $Id$
+ * @since 2.2
+ */
public class ExpressionBinding extends AbstractBinding
{
/**
- * The root object against which the nested property name is evaluated.
- *
- **/
+ * The root object against which the nested property name is evaluated.
+ */
private IComponent _root;
/**
- * The OGNL expression, as a string.
- *
- **/
+ * The OGNL expression, as a string.
+ */
private String _expression;
/**
- * If true, then the binding is invariant, and cachedValue
- * is the ultimate value.
- *
- **/
+ * If true, then the binding is invariant, and cachedValue is the ultimate value.
+ */
private boolean _invariant = false;
/**
- * Stores the cached value for the binding, if invariant
- * is true.
- *
- **/
+ * Stores the cached value for the binding, if invariant is true.
+ */
private Object _cachedValue;
/**
- * Parsed OGNL expression.
- *
- **/
+ * Parsed OGNL expression.
+ */
private Node _parsedExpression;
/**
- * Flag set once the binding has initialized.
- * _cachedValue, _invariant and _final value
- * for _expression
- * are not valid until after initialization.
- *
- *
- **/
+ * Flag set once the binding has initialized. _cachedValue, _invariant and _final value for _expression are not
+ * valid until after initialization.
+ */
private boolean _initialized;
private IResourceResolver _resolver;
/**
- * The OGNL context for this binding. It is retained
- * for the lifespan of the binding once created.
- *
- **/
+ * The OGNL context for this binding. It is retained for the lifespan of the binding once created.
+ */
private Map _context;
@@ -156,17 +125,19 @@
private ExpressionAccessor _accessor;
/**
- * Used to detect previous failed attempts at writing values when compiling expressions so
- * that as many expressions as possible can be fully compiled into their java byte form when
- * all objects in the expression are available.
+ * Used to detect previous failed attempts at writing values when compiling expressions so that as many expressions
+ * as possible can be fully compiled into their java byte form when all objects in the expression are available.
*/
private boolean _writeFailed;
/**
- * Creates a {@link ExpressionBinding} from the root object
- * and an OGNL expression.
- *
- **/
+ * This is current set to false, to prevent any attempts at bytecode compilation of OGNL expressions.
+ */
+ private static final boolean EXPRESSION_EVALUATION_ENABLED = false;
+
+ /**
+ * Creates a {@link ExpressionBinding} from the root object and an OGNL expression.
+ */
public ExpressionBinding(
IResourceResolver resolver,
@@ -193,12 +164,10 @@
}
/**
- * Gets the value of the property path, with the assistance of a
- * OGNL.
+ * Gets the value of the property path, with the assistance of a OGNL.
*
- * @throws BindingException if an exception is thrown accessing the property.
- *
- **/
+ * @throws BindingException if an exception is thrown accessing the property.
+ */
public Object getObject()
{
@@ -214,7 +183,7 @@
{
try
{
- if (false && _evaluator.isCompileEnabled() && _accessor == null && !_writeFailed)
+ if (EXPRESSION_EVALUATION_ENABLED && _evaluator.isCompileEnabled() && _accessor == null && !_writeFailed)
{
_evaluator.compileExpression(_root, _parsedExpression, _expression);
_accessor = _parsedExpression.getAccessor();
@@ -238,14 +207,10 @@
}
/**
- * Creates an OGNL context used to get or set a value.
- * We may extend this in the future to set additional
- * context variables (such as page, request cycle and engine).
- * An optional type converter will be added to the OGNL context
- * if it is specified as an application extension with the name
- * {@link Tapestry#OGNL_TYPE_CONVERTER}.
- *
- **/
+ * Creates an OGNL context used to get or set a value. We may extend this in the future to set additional context
+ * variables (such as page, request cycle and engine). An optional type converter will be added to the OGNL context
+ * if it is specified as an application extension with the name {@link Tapestry#OGNL_TYPE_CONVERTER}.
+ */
private Map getOgnlContext()
{
@@ -273,11 +238,8 @@
}
/**
- * Returns true if the binding is expected to always
- * return the same value.
- *
- *
- **/
+ * Returns true if the binding is expected to always return the same value.
+ */
public boolean isInvariant()
{
@@ -307,10 +269,8 @@
}
/**
- * Sets up the helper object, but also optimizes the property path
- * and determines if the binding is invarant.
- *
- **/
+ * Sets up the helper object, but also optimizes the property path and determines if the binding is invarant.
+ */
private void initialize()
{
@@ -341,7 +301,6 @@
throw new BindingException(ex.getMessage(), this, ex);
}
-
// Split the expression into individual property names.
// We then optimize what we can from the expression. This will
// shorten the expression and, in some cases, eliminate
@@ -375,13 +334,11 @@
}
/**
- * Looks for common prefixes on the expression (provided pre-split) that
- * are recognized as references to other components.
+ * Looks for common prefixes on the expression (provided pre-split) that are recognized as references to other
+ * components.
*
- * @return the number of leading elements of the split expression that
- * have been removed.
- *
- **/
+ * @return the number of leading elements of the split expression that have been removed.
+ */
private int optimizeRootObject(String[] split)
{
@@ -437,10 +394,8 @@
}
/**
- * Reassembles the remainder of the split property path
- * from the start point.
- *
- **/
+ * Reassembles the remainder of the split property path from the start point.
+ */
private String reassemble(int start, String[] split)
{
@@ -466,9 +421,8 @@
}
/**
- * Checks to see if the binding can be converted to an invariant.
- *
- **/
+ * Checks to see if the binding can be converted to an invariant.
+ */
private void checkForInvariant(int start, String[] split)
{
@@ -547,12 +501,12 @@
}
/**
- * Updates the property for the binding to the given value.
+ * Updates the property for the binding to the given value.
*
- * @throws BindingException if the property can't be updated (typically
- * due to an security problem, or a missing mutator method).
- * @throws BindingException if the binding is invariant.
- **/
+ * @throws BindingException if the property can't be updated (typically due to an security problem, or a missing
+ * mutator method).
+ * @throws BindingException if the binding is invariant.
+ */
public void setObject(Object value)
{
@@ -566,7 +520,8 @@
if (_accessor != null)
{
_evaluator.write(_root, _accessor, value);
- } else if (false && _evaluator.isCompileEnabled() && _accessor == null)
+ }
+ else if (EXPRESSION_EVALUATION_ENABLED && _evaluator.isCompileEnabled() && _accessor == null)
{
//_evaluator.compileExpression(_root, _parsedExpression, _expression);
//_accessor = _parsedExpression.getAccessor();
@@ -578,7 +533,8 @@
{
_evaluator.compileExpression(_root, _parsedExpression, _expression);
_accessor = _parsedExpression.getAccessor();
- } catch (Throwable t)
+ }
+ catch (Throwable t)
{
// ignore re-read failures as they aren't supposed to be happening now anyways
// and a more user friendly version will be available if someone actually calls
@@ -589,7 +545,8 @@
_writeFailed = true;
}
}
- } else
+ }
+ else
{
_evaluator.writeCompiled(_root, _parsedExpression, value);
}
@@ -608,12 +565,10 @@
}
/**
- * Returns the a String representing the property path. This includes
- * the {@link IComponent#getExtendedId() extended id} of the root component
- * and the property path ... once the binding is used, these may change
- * due to optimization of the property path.
- *
- **/
+ * Returns the a String representing the property path. This includes the {@link IComponent#getExtendedId()
+ * extended id} of the root component and the property path ... once the binding is used, these may change due to
+ * optimization of the property path.
+ */
public String toString()
{
diff --git a/tapestry-framework/src/org/apache/tapestry/engine/AbstractEngine.java b/tapestry-framework/src/org/apache/tapestry/engine/AbstractEngine.java
index 158e355..4a29195 100644
--- a/tapestry-framework/src/org/apache/tapestry/engine/AbstractEngine.java
+++ b/tapestry-framework/src/org/apache/tapestry/engine/AbstractEngine.java
@@ -43,56 +43,36 @@
import java.util.*;
/**
- * Basis for building real Tapestry applications. Immediate subclasses
- * provide different strategies for managing page state and other resources
- * between request cycles.
+ * Basis for building real Tapestry applications. Immediate subclasses provide different strategies for managing page
+ * state and other resources between request cycles.
+ * <p/>
+ * Uses a shared instance of {@link ITemplateSource}, {@link ISpecificationSource}, {@link IScriptSource} and {@link
+ * IComponentMessagesSource} stored as attributes of the {@link ServletContext} (they will be shared by all sessions).
+ * <p/>
+ * <p>An application is designed to be very lightweight. Particularily, it should <b>never</b> hold references to any
+ * {@link IPage} or {@link org.apache.tapestry.IComponent} objects. The entire system is based upon being able to
+ * quickly rebuild the state of any page(s).
+ * <p/>
+ * <p>Where possible, instance variables should be transient. They can be restored inside {@link
+ * #setupForRequest(RequestContext)}.
+ * <p/>
+ * <p>In practice, a subclass (usually {@link BaseEngine}) is used without subclassing. Instead, a visit object is
+ * specified. To facilitate this, the application specification may include a property,
+ * <code>org.apache.tapestry.visit-class</code> which is the class name to instantiate when a visit object is first
+ * needed. See {@link #createVisit(IRequestCycle)} for more details.
+ * <p/>
+ * <p>Some of the classes' behavior is controlled by JVM system properties (typically only used during development):
+ * <p/>
+ * <table border=1> <tr> <th>Property</th> <th>Description</th> </tr> <tr> <td>org.apache.tapestry.enable-reset-service</td>
+ * <td>If true, enabled an additional service, reset, that allow page, specification and template caches to be cleared
+ * on demand. See {@link #isResetServiceEnabled()}. </td> </tr> <tr> <td>org.apache.tapestry.disable-caching</td> <td>If
+ * true, then the page, specification, template and script caches will be cleared after each request. This slows things
+ * down, but ensures that the latest versions of such files are used. Care should be taken that the source directories
+ * for the files preceeds any versions of the files available in JARs or WARs. </td> </tr> </table>
*
- * Uses a shared instance of
- * {@link ITemplateSource}, {@link ISpecificationSource},
- * {@link IScriptSource} and {@link IComponentMessagesSource}
- * stored as attributes of the {@link ServletContext}
- * (they will be shared by all sessions).
- *
- * <p>An application is designed to be very lightweight.
- * Particularily, it should <b>never</b> hold references to any
- * {@link IPage} or {@link org.apache.tapestry.IComponent} objects. The entire system is
- * based upon being able to quickly rebuild the state of any page(s).
- *
- * <p>Where possible, instance variables should be transient. They
- * can be restored inside {@link #setupForRequest(RequestContext)}.
- *
- * <p>In practice, a subclass (usually {@link BaseEngine})
- * is used without subclassing. Instead, a
- * visit object is specified. To facilitate this, the application specification
- * may include a property, <code>org.apache.tapestry.visit-class</code>
- * which is the class name to instantiate when a visit object is first needed. See
- * {@link #createVisit(IRequestCycle)} for more details.
- *
- * <p>Some of the classes' behavior is controlled by JVM system properties
- * (typically only used during development):
- *
- * <table border=1>
- * <tr> <th>Property</th> <th>Description</th> </tr>
- * <tr> <td>org.apache.tapestry.enable-reset-service</td>
- * <td>If true, enabled an additional service, reset, that
- * allow page, specification and template caches to be cleared on demand.
- * See {@link #isResetServiceEnabled()}. </td>
- * </tr>
- * <tr>
- * <td>org.apache.tapestry.disable-caching</td>
- * <td>If true, then the page, specification, template and script caches
- * will be cleared after each request. This slows things down,
- * but ensures that the latest versions of such files are used.
- * Care should be taken that the source directories for the files
- * preceeds any versions of the files available in JARs or WARs. </td>
- * </tr>
- * </table>
- *
- *
- * @author Howard Lewis Ship
- * @version $Id$
- *
- **/
+ * @author Howard Lewis Ship
+ * @version $Id$
+ */
public abstract class AbstractEngine
implements IEngine, IEngineServiceView, Externalizable, HttpSessionBindingListener
@@ -100,9 +80,8 @@
private static final Log LOG = LogFactory.getLog(AbstractEngine.class);
/**
- * @since 2.0.4
- *
- **/
+ * @since 2.0.4
+ */
private static final long serialVersionUID = 6884834397673817117L;
@@ -113,216 +92,177 @@
private transient boolean _stateful;
private transient ListenerMap _listeners;
- /** @since 2.2 **/
+ /**
+ * @since 2.2 *
+ */
private transient DataSqueezer _dataSqueezer;
/**
- * An object used to contain application-specific server side state.
- *
- **/
+ * An object used to contain application-specific server side state.
+ */
private Object _visit;
/**
- * The globally shared application object. Typically, this is created
- * when first needed, shared between sessions and engines, and
- * stored in the {@link ServletContext}.
+ * The globally shared application object. Typically, this is created when first needed, shared between sessions
+ * and engines, and stored in the {@link ServletContext}.
*
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
private transient Object _global;
/**
- * The base name for the servlet context key used to store
- * the application-defined Global object, if any.
+ * The base name for the servlet context key used to store the application-defined Global object, if any.
*
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
public static final String GLOBAL_NAME = "org.apache.tapestry.global";
/**
- * The name of the application property that will be used to
- * determine the encoding to use when generating the output
+ * The name of the application property that will be used to determine the encoding to use when generating the
+ * output
*
- * @since 3.0
- **/
+ * @since 3.0
+ */
public static final String OUTPUT_ENCODING_PROPERTY_NAME =
"org.apache.tapestry.output-encoding";
/**
- * The default encoding that will be used when generating the output.
- * It is used if no output encoding property has been specified.
+ * The default encoding that will be used when generating the output. It is used if no output encoding property has
+ * been specified.
*
- * @since 3.0
+ * @since 3.0
*/
public static final String DEFAULT_OUTPUT_ENCODING = "UTF-8";
/**
- * The curent locale for the engine, which may be changed at any time.
- *
- **/
+ * The curent locale for the engine, which may be changed at any time.
+ */
private Locale _locale;
/**
- * Set by {@link #setLocale(Locale)} when the locale is changed;
- * this allows the locale cookie to be updated.
- *
- **/
+ * Set by {@link #setLocale(Locale)} when the locale is changed; this allows the locale cookie to be updated.
+ */
private boolean _localeChanged;
/**
- * The specification for the application, which
- * lives in the {@link ServletContext}. If the
- * session (and application) moves to a different context (i.e.,
- * a different JVM), then
- * we want to reconnect to the specification in the new context.
- * A check is made on every request
- * cycle as needed.
- *
- **/
+ * The specification for the application, which lives in the {@link ServletContext}. If the session (and
+ * application) moves to a different context (i.e., a different JVM), then we want to reconnect to the specification
+ * in the new context. A check is made on every request cycle as needed.
+ */
protected transient IApplicationSpecification _specification;
/**
- * The source for template data. The template source is stored
- * in the {@link ServletContext} as a named attribute.
- * After de-serialization, the application can re-connect to
- * the template source (or create a new one).
- *
- **/
+ * The source for template data. The template source is stored in the {@link ServletContext} as a named attribute.
+ * After de-serialization, the application can re-connect to the template source (or create a new one).
+ */
protected transient ITemplateSource _templateSource;
/**
- * The source for component specifications, stored in the
- * {@link ServletContext} (like {@link #_templateSource}).
- *
- **/
+ * The source for component specifications, stored in the {@link ServletContext} (like {@link #_templateSource}).
+ */
protected transient ISpecificationSource _specificationSource;
/**
- * The source for parsed scripts, again, stored in the
- * {@link ServletContext}.
+ * The source for parsed scripts, again, stored in the {@link ServletContext}.
*
- * @since 1.0.2
- *
- **/
+ * @since 1.0.2
+ */
private transient IScriptSource _scriptSource;
/**
- * The name of the context attribute for the {@link IScriptSource} instance.
- * The application's name is appended.
+ * The name of the context attribute for the {@link IScriptSource} instance. The application's name is appended.
*
- * @since 1.0.2
- *
- **/
+ * @since 1.0.2
+ */
protected static final String SCRIPT_SOURCE_NAME = "org.apache.tapestry.ScriptSource";
/**
- * The name of the context attribute for the {@link IComponentMessagesSource}
- * instance. The application's name is appended.
+ * The name of the context attribute for the {@link IComponentMessagesSource} instance. The application's name is
+ * appended.
*
- * @since 2.0.4
- *
- **/
+ * @since 2.0.4
+ */
protected static final String STRINGS_SOURCE_NAME = "org.apache.tapestry.StringsSource";
private transient IComponentMessagesSource _stringsSource;
/**
- * The name of the application specification property used to specify the
- * class of the visit object.
- *
- **/
+ * The name of the application specification property used to specify the class of the visit object.
+ */
public static final String VISIT_CLASS_PROPERTY_NAME = "org.apache.tapestry.visit-class";
/**
- * Servlet context attribute name for the default {@link ITemplateSource}
- * instance. The application's name is appended.
- *
- **/
+ * Servlet context attribute name for the default {@link ITemplateSource} instance. The application's name is
+ * appended.
+ */
protected static final String TEMPLATE_SOURCE_NAME = "org.apache.tapestry.TemplateSource";
/**
- * Servlet context attribute name for the default {@link ISpecificationSource}
- * instance. The application's name is appended.
- *
- **/
+ * Servlet context attribute name for the default {@link ISpecificationSource} instance. The application's name is
+ * appended.
+ */
protected static final String SPECIFICATION_SOURCE_NAME =
"org.apache.tapestry.SpecificationSource";
/**
- * Servlet context attribute name for the {@link IPageSource}
- * instance. The application's name is appended.
- *
- **/
+ * Servlet context attribute name for the {@link IPageSource} instance. The application's name is appended.
+ */
protected static final String PAGE_SOURCE_NAME = "org.apache.tapestry.PageSource";
/**
- * Servlet context attribute name for a shared instance
- * of {@link DataSqueezer}. The instance is actually shared
- * between Tapestry applications within the same context
- * (which will have the same ClassLoader).
+ * Servlet context attribute name for a shared instance of {@link DataSqueezer}. The instance is actually shared
+ * between Tapestry applications within the same context (which will have the same ClassLoader).
*
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
protected static final String DATA_SQUEEZER_NAME = "org.apache.tapestry.DataSqueezer";
/**
- * Servlet context attribute name for a shared instance
- * of {@link ResourceChecksumSource}.
+ * Servlet context attribute name for a shared instance of {@link ResourceChecksumSource}.
+ *
* @since 3.0.3
*/
protected static final String RESOURCE_CHECKSUM_SOURCE_NAME =
"org.apache.tapestry.ResourceChecksumSource";
/**
- * The source for pages, which acts as a pool, but is capable of
- * creating pages as needed. Stored in the
- * {@link ServletContext}, like {@link #_templateSource}.
- *
- **/
+ * The source for pages, which acts as a pool, but is capable of creating pages as needed. Stored in the {@link
+ * ServletContext}, like {@link #_templateSource}.
+ */
private transient IPageSource _pageSource;
/**
- * If true (set from JVM system parameter
- * <code>org.apache.tapestry.enable-reset-service</code>)
- * then the reset service will be enabled, allowing
- * the cache of pages, specifications and template
- * to be cleared on demand.
- *
- **/
+ * If true (set from JVM system parameter <code>org.apache.tapestry.enable-reset-service</code>) then the reset
+ * service will be enabled, allowing the cache of pages, specifications and template to be cleared on demand.
+ */
private static final boolean _resetServiceEnabled =
Boolean.getBoolean("org.apache.tapestry.enable-reset-service");
/**
- * If true (set from the JVM system parameter
- * <code>org.apache.tapestry.disable-caching</code>)
- * then the cache of pages, specifications and template
- * will be cleared after each request.
- *
- **/
+ * If true (set from the JVM system parameter <code>org.apache.tapestry.disable-caching</code>) then the cache of
+ * pages, specifications and template will be cleared after each request.
+ */
private static final boolean _disableCaching =
Boolean.getBoolean("org.apache.tapestry.disable-caching");
@@ -330,65 +270,58 @@
private transient IResourceResolver _resolver;
/**
- * Constant used to store a {@link org.apache.tapestry.util.IPropertyHolder}
- * in the servlet context.
+ * Constant used to store a {@link org.apache.tapestry.util.IPropertyHolder} in the servlet context.
*
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
protected static final String PROPERTY_SOURCE_NAME = "org.apache.tapestry.PropertySource";
/**
- * A shared instance of {@link IPropertySource}
+ * A shared instance of {@link IPropertySource}
*
- * @since 3.0
- * @see #createPropertySource(RequestContext)
- *
- **/
+ * @see #createPropertySource(RequestContext)
+ * @since 3.0
+ */
private transient IPropertySource _propertySource;
/**
- * Map from service name to service instance.
+ * Map from service name to service instance.
*
- * @since 1.0.9
- *
- **/
+ * @since 1.0.9
+ */
private transient Map _serviceMap;
protected static final String SERVICE_MAP_NAME = "org.apache.tapestry.ServiceMap";
/**
- * A shared instance of {@link Pool}.
+ * A shared instance of {@link Pool}.
*
- * @since 3.0
- * @see #createPool(RequestContext)
- *
- **/
+ * @see #createPool(RequestContext)
+ * @since 3.0
+ */
private transient Pool _pool;
protected static final String POOL_NAME = "org.apache.tapestry.Pool";
/**
- * Name of a shared instance of {@link org.apache.tapestry.engine.IComponentClassEnhancer}
- * stored in the {@link ServletContext}.
+ * Name of a shared instance of {@link org.apache.tapestry.engine.IComponentClassEnhancer} stored in the {@link
+ * ServletContext}.
*
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
protected static final String ENHANCER_NAME = "org.apache.tapestry.ComponentClassEnhancer";
/**
- * A shared instance of {@link org.apache.tapestry.engine.IComponentClassEnhancer}.
+ * A shared instance of {@link org.apache.tapestry.engine.IComponentClassEnhancer}.
*
- * @since 3.0
- * @see #createComponentClassEnhancer(RequestContext)
- *
- **/
+ * @see #createComponentClassEnhancer(RequestContext)
+ * @since 3.0
+ */
private transient IComponentClassEnhancer _enhancer;
@@ -397,14 +330,11 @@
private transient IEnhancedClassFactory _classFactory;
/**
- * Set to true when there is a (potential)
- * change to the internal state of the engine, set
- * to false when the engine is stored into the
- * {@link HttpSession}.
+ * Set to true when there is a (potential) change to the internal state of the engine, set to false when the engine
+ * is stored into the {@link HttpSession}.
*
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
private transient boolean _dirty;
@@ -418,14 +348,15 @@
/**
* Used to obtain resource checksums for the asset service.
+ *
* @since 3.0.3
*/
private transient ResourceChecksumSource _resourceChecksumSource;
/**
- * The name of the context attribute for the {@link ExpressionEvaluator} instance.
- * The application's name is appended.
- **/
+ * The name of the context attribute for the {@link ExpressionEvaluator} instance. The application's name is
+ * appended.
+ */
protected static final String EXPRESSION_EVALUATOR_NAME = "org.apache.tapestry.engine.ExpressionEvaluator";
private transient ExpressionEvaluator _expressionEvaluator;
@@ -435,12 +366,11 @@
private transient String _outputEncoding;
/**
- * Sets the Exception page's exception property, then renders the Exception page.
- *
- * <p>If the render throws an exception, then copious output is sent to
- * <code>System.err</code> and a {@link ServletException} is thrown.
- *
- **/
+ * Sets the Exception page's exception property, then renders the Exception page.
+ * <p/>
+ * <p>If the render throws an exception, then copious output is sent to <code>System.err</code> and a {@link
+ * ServletException} is thrown.
+ */
protected void activateExceptionPage(
IRequestCycle cycle,
@@ -482,9 +412,8 @@
}
/**
- * Writes a detailed report of the exception to <code>System.err</code>.
- *
- **/
+ * Writes a detailed report of the exception to <code>System.err</code>.
+ */
public void reportException(String reportTitle, Throwable ex)
{
@@ -496,10 +425,10 @@
System.err.println(
"\n\n Session id: "
- + _sessionId
- + "\n Client address: "
- + _clientAddress
- + "\n\nExceptions:\n");
+ + _sessionId
+ + "\n Client address: "
+ + _clientAddress
+ + "\n\nExceptions:\n");
new ExceptionAnalyzer().reportException(ex, System.err);
@@ -508,22 +437,18 @@
}
/**
- * Invoked at the end of the request cycle to release any resources specific
- * to the request cycle.
- *
- **/
+ * Invoked at the end of the request cycle to release any resources specific to the request cycle.
+ */
protected abstract void cleanupAfterRequest(IRequestCycle cycle);
/**
- * Extends the description of the class generated by {@link #toString()}.
- * If a subclass adds additional instance variables that should be described
- * in the instance description, it may overide this method. This implementation
- * does nothing.
+ * Extends the description of the class generated by {@link #toString()}. If a subclass adds additional instance
+ * variables that should be described in the instance description, it may overide this method. This implementation
+ * does nothing.
*
- * @see #toString()
- *
- **/
+ * @see #toString()
+ */
protected void extendDescription(ToStringBuilder builder)
{
@@ -531,11 +456,9 @@
}
/**
- * Returns the locale for the engine. This is initially set
- * by the {@link ApplicationServlet} but may be updated
- * by the application.
- *
- **/
+ * Returns the locale for the engine. This is initially set by the {@link ApplicationServlet} but may be updated by
+ * the application.
+ */
public Locale getLocale()
{
@@ -543,20 +466,15 @@
}
/**
- * Overriden in subclasses that support monitoring. Should create and return
- * an instance of {@link IMonitor} that is appropriate for the request cycle described
- * by the {@link RequestContext}.
- *
+ * Overriden in subclasses that support monitoring. Should create and return an instance of {@link IMonitor} that
+ * is appropriate for the request cycle described by the {@link RequestContext}.
+ * <p/>
* <p>The monitor is used to create a {@link RequestCycle}.
- *
- * <p>This implementation uses a {@link IMonitorFactory}
- * to create the monitor instance. The factory
- * is provided as an application extension. If the application
- * extension does not exist, {@link DefaultMonitorFactory} is used.
- *
+ * <p/>
+ * <p>This implementation uses a {@link IMonitorFactory} to create the monitor instance. The factory is provided as
+ * an application extension. If the application extension does not exist, {@link DefaultMonitorFactory} is used.
+ * <p/>
* <p>As of release 3.0, this method should <em>not</em> return null.
- *
- *
*/
public IMonitor getMonitor(RequestContext context)
@@ -581,9 +499,9 @@
}
/**
- * Returns a service with the given name. Services are created by the
- * first call to {@link #setupForRequest(RequestContext)}.
- **/
+ * Returns a service with the given name. Services are created by the first call to {@link
+ * #setupForRequest(RequestContext)}.
+ */
public IEngineService getService(String name)
{
@@ -602,12 +520,11 @@
}
/**
- * Returns the context path, the prefix to apply to any URLs so that they
- * are recognized as belonging to the Servlet 2.2 context.
+ * Returns the context path, the prefix to apply to any URLs so that they are recognized as belonging to the Servlet
+ * 2.2 context.
*
- * @see org.apache.tapestry.asset.ContextAsset
- *
- **/
+ * @see org.apache.tapestry.asset.ContextAsset
+ */
public String getContextPath()
{
@@ -615,15 +532,12 @@
}
/**
- * Returns the specification, if available, or null otherwise.
- *
- * <p>To facilitate deployment across multiple servlet containers, the
- * application is serializable. However, the reference to the specification
- * is transient. When an application instance is deserialized, it reconnects
- * with the application specification by locating it in the {@link ServletContext}
- * or parsing it fresh.
- *
- **/
+ * Returns the specification, if available, or null otherwise.
+ * <p/>
+ * <p>To facilitate deployment across multiple servlet containers, the application is serializable. However, the
+ * reference to the specification is transient. When an application instance is deserialized, it reconnects with
+ * the application specification by locating it in the {@link ServletContext} or parsing it fresh.
+ */
public IApplicationSpecification getSpecification()
{
@@ -641,11 +555,11 @@
}
/**
- * Reads the state serialized by {@link #writeExternal(ObjectOutput)}.
- *
- * <p>This always set the stateful flag. By default, a deserialized
- * session is stateful (else, it would not have been serialized).
- **/
+ * Reads the state serialized by {@link #writeExternal(ObjectOutput)}.
+ * <p/>
+ * <p>This always set the stateful flag. By default, a deserialized session is stateful (else, it would not have
+ * been serialized).
+ */
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
@@ -658,14 +572,10 @@
}
/**
- * Writes the following properties:
- *
- * <ul>
- * <li>locale name ({@link Locale#toString()})
- * <li>visit
- * </ul>
- *
- **/
+ * Writes the following properties:
+ * <p/>
+ * <ul> <li>locale name ({@link Locale#toString()}) <li>visit </ul>
+ */
public void writeExternal(ObjectOutput out) throws IOException
{
@@ -674,10 +584,9 @@
}
/**
- * Invoked, typically, when an exception occurs while servicing the request.
- * This method resets the output, sets the new page and renders it.
- *
- **/
+ * Invoked, typically, when an exception occurs while servicing the request. This method resets the output, sets the
+ * new page and renders it.
+ */
protected void redirect(
String pageName,
@@ -753,13 +662,11 @@
}
/**
- * Invalidates the session, then redirects the client web browser to
- * the servlet's prefix, starting a new visit.
- *
- * <p>Subclasses should perform their own restart (if necessary, which is
- * rarely) before invoking this implementation.
- *
- **/
+ * Invalidates the session, then redirects the client web browser to the servlet's prefix, starting a new visit.
+ * <p/>
+ * <p>Subclasses should perform their own restart (if necessary, which is rarely) before invoking this
+ * implementation.
+ */
public void restart(IRequestCycle cycle) throws IOException
{
@@ -793,9 +700,8 @@
}
/**
- * Delegate method for the servlet. Services the request.
- *
- **/
+ * Delegate method for the servlet. Services the request.
+ */
public boolean service(RequestContext context) throws ServletException, IOException
{
@@ -959,14 +865,13 @@
}
/**
- * Handles {@link PageRedirectException} which involves
- * executing {@link IPage#validate(IRequestCycle)} on the target page
- * (of the exception), until either a loop is found, or a page
- * succesfully validates and can be activated.
+ * Handles {@link PageRedirectException} which involves executing {@link IPage#validate(IRequestCycle)} on the
+ * target page (of the exception), until either a loop is found, or a page succesfully validates and can be
+ * activated.
+ * <p/>
+ * <p>This should generally not be overriden in subclasses.
*
- * <p>This should generally not be overriden in subclasses.
- *
- * @since 3.0
+ * @since 3.0
*/
protected void handlePageRedirectException(
@@ -1029,13 +934,11 @@
}
/**
- * Invoked from {@link #service(RequestContext)} to create an instance of
- * {@link IRequestCycle} for the current request. This implementation creates
- * an returns an instance of {@link RequestCycle}.
+ * Invoked from {@link #service(RequestContext)} to create an instance of {@link IRequestCycle} for the current
+ * request. This implementation creates an returns an instance of {@link RequestCycle}.
*
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
protected IRequestCycle createRequestCycle(
RequestContext context,
@@ -1046,29 +949,20 @@
}
/**
- * Invoked by {@link #service(RequestContext)} if a {@link StaleLinkException}
- * is thrown by the {@link IEngineService service}. This implementation
- * sets the message property of the StaleLink page to the
- * message provided in the exception,
- * then invokes
- * {@link #redirect(String, IRequestCycle, ResponseOutputStream, ApplicationRuntimeException)}
- * to render the StaleLink page.
+ * Invoked by {@link #service(RequestContext)} if a {@link StaleLinkException} is thrown by the {@link
+ * IEngineService service}. This implementation sets the message property of the StaleLink page to the message
+ * provided in the exception, then invokes {@link #redirect(String, IRequestCycle, ResponseOutputStream,
+ * ApplicationRuntimeException)} to render the StaleLink page.
+ * <p/>
+ * <p>Subclasses may overide this method (without invoking this implementation). A common practice is to present an
+ * error message on the application's Home page.
+ * <p/>
+ * <p>Alternately, the application may provide its own version of the StaleLink page, overriding the framework's
+ * implementation (probably a good idea, because the default page hints at "application errors" and isn't
+ * localized). The overriding StaleLink implementation must implement a message property of type String.
*
- * <p>Subclasses may overide this method (without
- * invoking this implementation). A common practice
- * is to present an error message on the application's
- * Home page.
- *
- * <p>Alternately, the application may provide its own version of
- * the StaleLink page, overriding
- * the framework's implementation (probably a good idea, because the
- * default page hints at "application errors" and isn't localized).
- * The overriding StaleLink implementation must
- * implement a message property of type String.
- *
- * @since 0.2.10
- *
- **/
+ * @since 0.2.10
+ */
protected void handleStaleLinkException(
StaleLinkException ex,
@@ -1085,19 +979,15 @@
}
/**
- * Invoked by {@link #service(RequestContext)} if a {@link StaleSessionException}
- * is thrown by the {@link IEngineService service}. This implementation
- * invokes
- * {@link #redirect(String, IRequestCycle, ResponseOutputStream, ApplicationRuntimeException)}
- * to render the StaleSession page.
+ * Invoked by {@link #service(RequestContext)} if a {@link StaleSessionException} is thrown by the {@link
+ * IEngineService service}. This implementation invokes {@link #redirect(String, IRequestCycle,
+ * ResponseOutputStream, ApplicationRuntimeException)} to render the StaleSession page.
+ * <p/>
+ * <p>Subclasses may overide this method (without invoking this implementation). A common practice is to present an
+ * eror message on the application's Home page.
*
- * <p>Subclasses may overide this method (without
- * invoking this implementation). A common practice
- * is to present an eror message on the application's
- * Home page.
- *
- * @since 0.2.10
- **/
+ * @since 0.2.10
+ */
protected void handleStaleSessionException(
StaleSessionException ex,
@@ -1109,13 +999,11 @@
}
/**
- * Discards all cached pages, component specifications and templates.
- * Subclasses who override this method should invoke this implementation
- * as well.
+ * Discards all cached pages, component specifications and templates. Subclasses who override this method should
+ * invoke this implementation as well.
*
- * @since 1.0.1
- *
- **/
+ * @since 1.0.1
+ */
public void clearCachedData()
{
@@ -1133,9 +1021,8 @@
}
/**
- * Changes the locale for the engine.
- *
- **/
+ * Changes the locale for the engine.
+ */
public void setLocale(Locale value)
{
@@ -1154,44 +1041,30 @@
}
/**
- * Invoked from {@link #service(RequestContext)} to ensure that the engine's
- * instance variables are setup. This allows the application a chance to
- * restore transient variables that will not have survived deserialization.
- *
- * Determines the servlet prefix: this is the base URL used by
- * {@link IEngineService services} to build URLs. It consists
- * of two parts: the context path and the servlet path.
- *
- * <p>The servlet path is retrieved from {@link HttpServletRequest#getServletPath()}.
- *
- * <p>The context path is retrieved from {@link HttpServletRequest#getContextPath()}.
- *
- * <p>The global object is retrieved from {@link IEngine#getGlobal()} method.
- *
- * <p>The final path is available via the {@link #getServletPath()} method.
- *
- * <p>In addition, this method locates and/or creates the:
- * <ul>
- * <li>{@link IComponentClassEnhancer}
- * <li>{@link Pool}
- * <li>{@link ITemplateSource}
- * <li>{@link ISpecificationSource}
- * <li>{@link IPageSource}
- * <li>{@link IEngineService} {@link Map}
- * <ll>{@link IScriptSource}
- * <li>{@link IComponentMessagesSource}
- * <li>{@link IPropertySource}
- * </ul>
- *
- * <p>This order is important, because some of the later shared objects
- * depend on some of the earlier shared objects already having
- * been located or created
- * (especially {@link #getPool() pool}).
- *
- * <p>Subclasses should invoke this implementation first, then perform their
- * own setup.
- *
- **/
+ * Invoked from {@link #service(RequestContext)} to ensure that the engine's instance variables are setup. This
+ * allows the application a chance to restore transient variables that will not have survived deserialization.
+ * <p/>
+ * Determines the servlet prefix: this is the base URL used by {@link IEngineService services} to build URLs. It
+ * consists of two parts: the context path and the servlet path.
+ * <p/>
+ * <p>The servlet path is retrieved from {@link HttpServletRequest#getServletPath()}.
+ * <p/>
+ * <p>The context path is retrieved from {@link HttpServletRequest#getContextPath()}.
+ * <p/>
+ * <p>The global object is retrieved from {@link IEngine#getGlobal()} method.
+ * <p/>
+ * <p>The final path is available via the {@link #getServletPath()} method.
+ * <p/>
+ * <p>In addition, this method locates and/or creates the: <ul> <li>{@link IComponentClassEnhancer} <li>{@link Pool}
+ * <li>{@link ITemplateSource} <li>{@link ISpecificationSource} <li>{@link IPageSource} <li>{@link IEngineService}
+ * {@link Map} <ll>{@link IScriptSource} <li>{@link IComponentMessagesSource} <li>{@link IPropertySource} </ul>
+ * <p/>
+ * <p>This order is important, because some of the later shared objects depend on some of the earlier shared objects
+ * already having been located or created (especially {@link #getPool() pool}).
+ * <p/>
+ * <p>Subclasses should invoke this implementation first, then perform their own setup. They must also synchronize
+ * on the {@link org.apache.tapestry.request.RequestContext#getServlet() application servlet}.
+ */
protected void setupForRequest(RequestContext context)
{
@@ -1200,6 +1073,7 @@
HttpServletRequest request = context.getRequest();
HttpSession session = context.getSession();
+
if (session != null)
_sessionId = context.getSession().getId();
else
@@ -1243,386 +1117,216 @@
String servletName = context.getServlet().getServletName();
- if (_propertySource == null)
+ // Synchronize on the servlet to make sure that two different IEngine instances
+ // do not try ot create some of the common dependencies simulataneously. We enclose
+ // all the code that uses the ServletContext as a cache. This is the motivation for
+ // adding an IoC container to Tapestry 4.
+
+ // Note: by borrowing ConcurrentBarrier from Tapestry 5, we could perhaps optimize this
+ // a bit ... but in most cases, we'll "flit" into the synchronized block, see non-nulls
+ // for all the fields, and "flit" back out with virtually no chance of contention.
+
+ synchronized (servlet)
{
- String name = PROPERTY_SOURCE_NAME + ":" + servletName;
-
- _propertySource = (IPropertySource) servletContext.getAttribute(name);
-
if (_propertySource == null)
{
- try
+ String name = PROPERTY_SOURCE_NAME + ":" + servletName;
+
+ _propertySource = (IPropertySource) servletContext.getAttribute(name);
+
+ if (_propertySource == null)
{
- context.getServlet().getLock().lock();
+ _propertySource = createPropertySource(context);
- _propertySource = (IPropertySource) servletContext.getAttribute(name);
-
- if (_propertySource == null)
- {
- _propertySource = createPropertySource(context);
-
- servletContext.setAttribute(name, _propertySource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _propertySource);
}
}
- }
-
- if (_classFactory == null)
- {
- String name = CLASS_FACTORY_NAME + ":" + servletName;
-
- _classFactory = (IEnhancedClassFactory) servletContext.getAttribute(name);
if (_classFactory == null)
{
- try
+ String name = CLASS_FACTORY_NAME + ":" + servletName;
+
+ _classFactory = (IEnhancedClassFactory) servletContext.getAttribute(name);
+
+ if (_classFactory == null)
{
- context.getServlet().getLock().lock();
+ _classFactory = createClassFactory();
- _classFactory = (IEnhancedClassFactory) servletContext.getAttribute(name);
-
- if (_classFactory == null)
- {
- _classFactory = createClassFactory();
-
- servletContext.setAttribute(name, _classFactory);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _classFactory);
}
}
- }
-
- if (_enhancer == null)
- {
- String name = ENHANCER_NAME + ":" + servletName;
-
- _enhancer = (IComponentClassEnhancer) servletContext.getAttribute(name);
if (_enhancer == null)
{
- try
+ String name = ENHANCER_NAME + ":" + servletName;
+
+ _enhancer = (IComponentClassEnhancer) servletContext.getAttribute(name);
+
+ if (_enhancer == null)
{
- context.getServlet().getLock().lock();
+ _enhancer = createComponentClassEnhancer(context);
- _enhancer = (IComponentClassEnhancer) servletContext.getAttribute(name);
-
- if (_enhancer == null)
- {
- _enhancer = createComponentClassEnhancer(context);
-
- servletContext.setAttribute(name, _enhancer);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _enhancer);
}
}
- }
-
- if (_pool == null)
- {
- String name = POOL_NAME + ":" + servletName;
-
- _pool = (Pool) servletContext.getAttribute(name);
if (_pool == null)
{
- try
- {
- context.getServlet().getLock().lock();
+ String name = POOL_NAME + ":" + servletName;
- _pool = (Pool) servletContext.getAttribute(name);
+ _pool = (Pool) servletContext.getAttribute(name);
- if (_pool == null)
- {
- _pool = createPool(context);
+ _pool = createPool(context);
- servletContext.setAttribute(name, _pool);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
- }
}
- }
-
- if (_templateSource == null)
- {
- String name = TEMPLATE_SOURCE_NAME + ":" + servletName;
-
- _templateSource = (ITemplateSource) servletContext.getAttribute(name);
if (_templateSource == null)
{
- try
+ String name = TEMPLATE_SOURCE_NAME + ":" + servletName;
+
+ _templateSource = (ITemplateSource) servletContext.getAttribute(name);
+
+ if (_templateSource == null)
{
- context.getServlet().getLock().lock();
+ _templateSource = createTemplateSource(context);
- _templateSource = (ITemplateSource) servletContext.getAttribute(name);
-
- if (_templateSource == null)
- {
- _templateSource = createTemplateSource(context);
-
- servletContext.setAttribute(name, _templateSource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _templateSource);
}
}
- }
-
- if (_specificationSource == null)
- {
- String name = SPECIFICATION_SOURCE_NAME + ":" + servletName;
-
- _specificationSource = (ISpecificationSource) servletContext.getAttribute(name);
if (_specificationSource == null)
{
- try
+ String name = SPECIFICATION_SOURCE_NAME + ":" + servletName;
+
+ _specificationSource = (ISpecificationSource) servletContext.getAttribute(name);
+
+ if (_specificationSource == null)
{
- context.getServlet().getLock().lock();
+ _specificationSource = createSpecificationSource(context);
- _specificationSource = (ISpecificationSource) servletContext.getAttribute(name);
-
- if (_specificationSource == null)
- {
- _specificationSource = createSpecificationSource(context);
-
- servletContext.setAttribute(name, _specificationSource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _specificationSource);
}
}
- }
-
- if (_pageSource == null)
- {
- String name = PAGE_SOURCE_NAME + ":" + servletName;
-
- _pageSource = (IPageSource) servletContext.getAttribute(name);
if (_pageSource == null)
{
- try
+ String name = PAGE_SOURCE_NAME + ":" + servletName;
+
+ _pageSource = (IPageSource) servletContext.getAttribute(name);
+
+ if (_pageSource == null)
{
- context.getServlet().getLock().lock();
+ _pageSource = createPageSource(context);
- _pageSource = (IPageSource) servletContext.getAttribute(name);
-
- if (_pageSource == null)
- {
- _pageSource = createPageSource(context);
-
- servletContext.setAttribute(name, _pageSource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _pageSource);
}
}
- }
-
- if (_scriptSource == null)
- {
- String name = SCRIPT_SOURCE_NAME + ":" + servletName;
-
- _scriptSource = (IScriptSource) servletContext.getAttribute(name);
if (_scriptSource == null)
{
- try
+ String name = SCRIPT_SOURCE_NAME + ":" + servletName;
+
+ _scriptSource = (IScriptSource) servletContext.getAttribute(name);
+
+ if (_scriptSource == null)
{
- context.getServlet().getLock().lock();
+ _scriptSource = createScriptSource(context);
- _scriptSource = (IScriptSource) servletContext.getAttribute(name);
-
- if (_scriptSource == null)
- {
- _scriptSource = createScriptSource(context);
-
- servletContext.setAttribute(name, _scriptSource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _scriptSource);
}
}
- }
-
- if (_serviceMap == null)
- {
- String name = SERVICE_MAP_NAME + ":" + servletName;
-
- _serviceMap = (Map) servletContext.getAttribute(name);
if (_serviceMap == null)
{
- try
+ String name = SERVICE_MAP_NAME + ":" + servletName;
+
+ _serviceMap = (Map) servletContext.getAttribute(name);
+
+ if (_serviceMap == null)
{
- context.getServlet().getLock().lock();
+ _serviceMap = createServiceMap();
- _serviceMap = (Map) servletContext.getAttribute(name);
-
- if (_serviceMap == null)
- {
- _serviceMap = createServiceMap();
-
- servletContext.setAttribute(name, _serviceMap);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _serviceMap);
}
}
- }
-
- if (_stringsSource == null)
- {
- String name = STRINGS_SOURCE_NAME + ":" + servletName;
-
- _stringsSource = (IComponentMessagesSource) servletContext.getAttribute(name);
if (_stringsSource == null)
{
- try
+ String name = STRINGS_SOURCE_NAME + ":" + servletName;
+
+ _stringsSource = (IComponentMessagesSource) servletContext.getAttribute(name);
+
+ if (_stringsSource == null)
{
- context.getServlet().getLock().lock();
+ _stringsSource = createComponentStringsSource(context);
- _stringsSource = (IComponentMessagesSource) servletContext.getAttribute(name);
-
- if (_stringsSource == null)
- {
- _stringsSource = createComponentStringsSource(context);
-
- servletContext.setAttribute(name, _stringsSource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _stringsSource);
}
}
- }
-
- if (_dataSqueezer == null)
- {
- String name = DATA_SQUEEZER_NAME + ":" + servletName;
-
- _dataSqueezer = (DataSqueezer) servletContext.getAttribute(name);
if (_dataSqueezer == null)
{
- try
+ String name = DATA_SQUEEZER_NAME + ":" + servletName;
+
+ _dataSqueezer = (DataSqueezer) servletContext.getAttribute(name);
+
+ if (_dataSqueezer == null)
{
- context.getServlet().getLock().lock();
+ _dataSqueezer = createDataSqueezer();
- _dataSqueezer = (DataSqueezer) servletContext.getAttribute(name);
-
- if (_dataSqueezer == null)
- {
- _dataSqueezer = createDataSqueezer();
-
- servletContext.setAttribute(name, _dataSqueezer);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _dataSqueezer);
}
}
- }
-
- if (_global == null)
- {
- String name = GLOBAL_NAME + ":" + servletName;
-
- _global = servletContext.getAttribute(name);
if (_global == null)
{
- try
+ String name = GLOBAL_NAME + ":" + servletName;
+
+ _global = servletContext.getAttribute(name);
+
+ if (_global == null)
{
- context.getServlet().getLock().lock();
+ _global = createGlobal(context);
- _global = servletContext.getAttribute(name);
-
- if (_global == null)
- {
- _global = createGlobal(context);
-
- servletContext.setAttribute(name, _global);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _global);
}
}
- }
-
- if (_resourceChecksumSource == null)
- {
- String name = RESOURCE_CHECKSUM_SOURCE_NAME + ":" + servletName;
-
- _resourceChecksumSource = (ResourceChecksumSource) servletContext.getAttribute(name);
if (_resourceChecksumSource == null)
{
- try
+ String name = RESOURCE_CHECKSUM_SOURCE_NAME + ":" + servletName;
+
+ _resourceChecksumSource = (ResourceChecksumSource) servletContext.getAttribute(name);
+
+ if (_resourceChecksumSource == null)
{
- context.getServlet().getLock().lock();
+ _resourceChecksumSource = createResourceChecksumSource();
- _resourceChecksumSource = (ResourceChecksumSource) servletContext.getAttribute(name);
-
- if (_resourceChecksumSource == null)
- {
- _resourceChecksumSource = createResourceChecksumSource();
-
- servletContext.setAttribute(name, _resourceChecksumSource);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _resourceChecksumSource);
}
}
- }
-
- if (_expressionEvaluator == null)
- {
- String name = EXPRESSION_EVALUATOR_NAME + ":" + servletName;
-
- _expressionEvaluator = (ExpressionEvaluator) servletContext.getAttribute(name);
if (_expressionEvaluator == null)
{
- try
+ String name = EXPRESSION_EVALUATOR_NAME + ":" + servletName;
+
+ _expressionEvaluator = (ExpressionEvaluator) servletContext.getAttribute(name);
+
+ if (_expressionEvaluator == null)
{
- context.getServlet().getLock().lock();
+ _expressionEvaluator = createExpressionEvaluator();
- _expressionEvaluator = (ExpressionEvaluator) servletContext.getAttribute(name);
-
- if (_expressionEvaluator == null)
- {
- _expressionEvaluator = createExpressionEvaluator();
-
- servletContext.setAttribute(name, _expressionEvaluator);
- }
- } finally
- {
- context.getServlet().getLock().unlock();
+ servletContext.setAttribute(name, _expressionEvaluator);
}
}
+
+ // That's the end of reading to and from the servlet context, so we can leave the block
+ // synchronized against the servlet.
}
String encoding = request.getCharacterEncoding();
if (encoding == null)
+
{
encoding = getOutputEncoding();
try
@@ -1647,14 +1351,12 @@
}
/**
+ * Invoked from {@link #setupForRequest(RequestContext)} to provide a new instance of {@link
+ * IComponentMessagesSource}.
*
- * Invoked from {@link #setupForRequest(RequestContext)} to provide
- * a new instance of {@link IComponentMessagesSource}.
- *
- * @return an instance of {@link DefaultComponentMessagesSource}
- * @since 2.0.4
- *
- **/
+ * @return an instance of {@link DefaultComponentMessagesSource}
+ * @since 2.0.4
+ */
public IComponentMessagesSource createComponentStringsSource(RequestContext context)
{
@@ -1662,16 +1364,13 @@
}
/**
- * Invoked from {@link #setupForRequest(RequestContext)} to provide
- * an instance of {@link IScriptSource} that will be stored into
- * the {@link ServletContext}. Subclasses may override this method
- * to provide a different implementation.
+ * Invoked from {@link #setupForRequest(RequestContext)} to provide an instance of {@link IScriptSource} that will
+ * be stored into the {@link ServletContext}. Subclasses may override this method to provide a different
+ * implementation.
*
- *
- * @return an instance of {@link DefaultScriptSource}
- * @since 1.0.9
- *
- **/
+ * @return an instance of {@link DefaultScriptSource}
+ * @since 1.0.9
+ */
protected IScriptSource createScriptSource(RequestContext context)
{
@@ -1679,15 +1378,13 @@
}
/**
- * Invoked from {@link #setupForRequest(RequestContext)} to provide
- * an instance of {@link IPageSource} that will be stored into
- * the {@link ServletContext}. Subclasses may override this method
- * to provide a different implementation.
+ * Invoked from {@link #setupForRequest(RequestContext)} to provide an instance of {@link IPageSource} that will be
+ * stored into the {@link ServletContext}. Subclasses may override this method to provide a different
+ * implementation.
*
- * @return an instance of {@link PageSource}
- * @since 1.0.9
- *
- **/
+ * @return an instance of {@link PageSource}
+ * @since 1.0.9
+ */
protected IPageSource createPageSource(RequestContext context)
{
@@ -1695,14 +1392,13 @@
}
/**
- * Invoked from {@link #setupForRequest(RequestContext)} to provide
- * an instance of {@link ISpecificationSource} that will be stored into
- * the {@link ServletContext}. Subclasses may override this method
- * to provide a different implementation.
+ * Invoked from {@link #setupForRequest(RequestContext)} to provide an instance of {@link ISpecificationSource} that
+ * will be stored into the {@link ServletContext}. Subclasses may override this method to provide a different
+ * implementation.
*
- * @return an instance of {@link DefaultSpecificationSource}
- * @since 1.0.9
- **/
+ * @return an instance of {@link DefaultSpecificationSource}
+ * @since 1.0.9
+ */
protected ISpecificationSource createSpecificationSource(RequestContext context)
{
@@ -1710,15 +1406,13 @@
}
/**
- * Invoked from {@link #setupForRequest(RequestContext)} to provide
- * an instance of {@link ITemplateSource} that will be stored into
- * the {@link ServletContext}. Subclasses may override this method
- * to provide a different implementation.
+ * Invoked from {@link #setupForRequest(RequestContext)} to provide an instance of {@link ITemplateSource} that will
+ * be stored into the {@link ServletContext}. Subclasses may override this method to provide a different
+ * implementation.
*
- * @return an instance of {@link DefaultTemplateSource}
- * @since 1.0.9
- *
- **/
+ * @return an instance of {@link DefaultTemplateSource}
+ * @since 1.0.9
+ */
protected ITemplateSource createTemplateSource(RequestContext context)
{
@@ -1726,10 +1420,10 @@
}
/**
- * Invoked from {@link #setupForRequest(RequestContext)} to provide
- * an instance of {@link ResourceChecksumSource} that will be stored into
- * the {@link ServletContext}. Subclasses may override this method
- * to provide a different implementation.
+ * Invoked from {@link #setupForRequest(RequestContext)} to provide an instance of {@link ResourceChecksumSource}
+ * that will be stored into the {@link ServletContext}. Subclasses may override this method to provide a different
+ * implementation.
+ *
* @return an instance of {@link ResourceChecksumSourceImpl} that uses MD5 and Hex encoding.
* @since 3.0.3
*/
@@ -1737,7 +1431,7 @@
{
return new ResourceChecksumSourceImpl("MD5", new Hex());
}
-
+
protected ExpressionEvaluator createExpressionEvaluator()
{
_expressionCache = (ExpressionCacheImpl) createExpressionCache();
@@ -1751,9 +1445,8 @@
}
/**
- * Returns an object which can find resources and classes.
- *
- **/
+ * Returns an object which can find resources and classes.
+ */
public IResourceResolver getResourceResolver()
{
@@ -1766,13 +1459,11 @@
}
/**
- * Generates a description of the instance.
- * Invokes {@link #extendDescription(ToStringBuilder)}
- * to fill in details about the instance.
+ * Generates a description of the instance. Invokes {@link #extendDescription(ToStringBuilder)} to fill in details
+ * about the instance.
*
- * @see #extendDescription(ToStringBuilder)
- *
- **/
+ * @see #extendDescription(ToStringBuilder)
+ */
public String toString()
{
@@ -1781,8 +1472,8 @@
builder.append(
"name",
_specification == null
- ? Tapestry.getMessage("AbstractEngine.unknown-specification")
- : _specification.getName());
+ ? Tapestry.getMessage("AbstractEngine.unknown-specification")
+ : _specification.getName());
builder.append("dirty", _dirty);
builder.append("locale", _locale);
@@ -1795,9 +1486,8 @@
}
/**
- * Returns true if the reset service is curently enabled.
- *
- **/
+ * Returns true if the reset service is curently enabled.
+ */
public boolean isResetServiceEnabled()
{
@@ -1805,24 +1495,19 @@
}
/**
- * Implemented by subclasses to return the names of the active pages
- * (pages for which recorders exist). May return the empty list,
- * but should not return null.
- *
- **/
+ * Implemented by subclasses to return the names of the active pages (pages for which recorders exist). May return
+ * the empty list, but should not return null.
+ */
abstract public Collection getActivePageNames();
/**
- * Gets the visit object, if it has been created already.
- *
- * <p>
- * If the visit is non-null then
- * the {@link #isDirty()} flag is set (because
- * the engine can't tell what the caller will
- * <i>do</i> with the visit).
- *
- **/
+ * Gets the visit object, if it has been created already.
+ * <p/>
+ * <p/>
+ * If the visit is non-null then the {@link #isDirty()} flag is set (because the engine can't tell what the caller
+ * will <i>do</i> with the visit).
+ */
public Object getVisit()
{
@@ -1833,20 +1518,16 @@
}
/**
- * Gets the visit object, invoking {@link #createVisit(IRequestCycle)} to create
- * it lazily if needed. If cycle is null, the visit will not be lazily created.
- *
- * <p>
- * After creating the visit, but before returning,
- * the {@link HttpSession} will be created, and
- * {@link #setStateful()} will be invoked.
- *
- * <p>
- * Sets the {@link #isDirty()} flag, if the return value
- * is not null.
- *
- *
- **/
+ * Gets the visit object, invoking {@link #createVisit(IRequestCycle)} to create it lazily if needed. If cycle is
+ * null, the visit will not be lazily created.
+ * <p/>
+ * <p/>
+ * After creating the visit, but before returning, the {@link HttpSession} will be created, and {@link
+ * #setStateful()} will be invoked.
+ * <p/>
+ * <p/>
+ * Sets the {@link #isDirty()} flag, if the return value is not null.
+ */
public Object getVisit(IRequestCycle cycle)
{
@@ -1854,8 +1535,8 @@
{
_visit = createVisit(cycle);
- // Now that a visit object exists, we need to force the creation
- // of a HttpSession.
+// Now that a visit object exists, we need to force the creation
+// of a HttpSession.
cycle.getRequestContext().createSession();
@@ -1869,10 +1550,8 @@
}
/**
- * Updates the visit object and
- * sets the {@link #isDirty() dirty flag}.
- *
- **/
+ * Updates the visit object and sets the {@link #isDirty() dirty flag}.
+ */
public void setVisit(Object value)
{
@@ -1887,14 +1566,12 @@
}
/**
- * Invoked to lazily create a new visit object when it is first
- * referenced (by {@link #getVisit(IRequestCycle)}). This implementation works
- * by looking up the name of the class to instantiate
- * in the {@link #getPropertySource() configuration}.
- *
- * <p>Subclasses may want to overide this method if some other means
- * of instantiating a visit object is required.
- **/
+ * Invoked to lazily create a new visit object when it is first referenced (by {@link #getVisit(IRequestCycle)}).
+ * This implementation works by looking up the name of the class to instantiate in the {@link #getPropertySource()
+ * configuration}.
+ * <p/>
+ * <p>Subclasses may want to overide this method if some other means of instantiating a visit object is required.
+ */
protected Object createVisit(IRequestCycle cycle)
{
@@ -1924,18 +1601,13 @@
}
/**
- * Returns the global object for the application. The global object is created at the start
- * of the request ({@link #setupForRequest(RequestContext)} invokes
- * {@link #createGlobal(RequestContext)} if needed),
- * and is stored into the {@link ServletContext}. All instances of the engine for
- * the application share
- * the global object; however, the global object is explicitly <em>not</em>
- * replicated to other servers within
- * a cluster.
+ * Returns the global object for the application. The global object is created at the start of the request ({@link
+ * #setupForRequest(RequestContext)} invokes {@link #createGlobal(RequestContext)} if needed), and is stored into
+ * the {@link ServletContext}. All instances of the engine for the application share the global object; however,
+ * the global object is explicitly <em>not</em> replicated to other servers within a cluster.
*
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
public Object getGlobal()
{
@@ -1953,14 +1625,12 @@
}
/**
- * Invoked by subclasses to indicate that some state must now be stored
- * in the engine (and that the engine should now be stored in the
- * HttpSession). The caller is responsible for actually creating
- * the HttpSession (it will have access to the {@link RequestContext}).
+ * Invoked by subclasses to indicate that some state must now be stored in the engine (and that the engine should
+ * now be stored in the HttpSession). The caller is responsible for actually creating the HttpSession (it will have
+ * access to the {@link RequestContext}).
*
- * @since 1.0.2
- *
- **/
+ * @since 1.0.2
+ */
protected void setStateful()
{
@@ -1968,10 +1638,10 @@
}
/**
- * Allows subclasses to include listener methods easily.
+ * Allows subclasses to include listener methods easily.
*
* @since 1.0.2
- **/
+ */
public ListenerMap getListeners()
{
@@ -2061,15 +1731,13 @@
}
/**
- * Invoked when a {@link RedirectException} is thrown during the processing of a request.
+ * Invoked when a {@link RedirectException} is thrown during the processing of a request.
*
- * @throws ApplicationRuntimeException if an {@link IOException},
- * {@link ServletException} is thrown by the redirect, or if no
- * {@link RequestDispatcher} can be found for local resource.
- *
- * @since 2.2
- *
- **/
+ * @throws ApplicationRuntimeException if an {@link IOException}, {@link ServletException} is thrown by the
+ * redirect, or if no {@link RequestDispatcher} can be found for local
+ * resource.
+ * @since 2.2
+ */
protected void handleRedirectException(IRequestCycle cycle, RedirectException ex)
{
@@ -2084,12 +1752,11 @@
}
/**
- * Creates a Map of all the services available to the application.
- *
- * <p>Note: the Map returned is not synchronized, on the theory that returned
- * map is not further modified and therefore threadsafe.
- *
- **/
+ * Creates a Map of all the services available to the application.
+ * <p/>
+ * <p>Note: the Map returned is not synchronized, on the theory that returned map is not further modified and
+ * therefore threadsafe.
+ */
private Map createServiceMap()
{
@@ -2098,16 +1765,16 @@
ISpecificationSource source = getSpecificationSource();
- // Build the initial version of the result map,
- // where each value is the *name* of a class.
+// Build the initial version of the result map,
+// where each value is the *name* of a class.
Map result = new HashMap();
- // Do the framework first.
+// Do the framework first.
addServices(source.getFrameworkNamespace(), result);
- // And allow the application to override the framework.
+// And allow the application to override the framework.
addServices(source.getApplicationNamespace(), result);
@@ -2140,8 +1807,8 @@
className,
serviceName));
- // Replace the class name with an instance
- // of the named class.
+// Replace the class name with an instance
+// of the named class.
entry.setValue(service);
}
@@ -2178,14 +1845,11 @@
}
/**
- * Locates all services in the namespace and adds key/value
- * pairs to the map (name and class name). Then recursively
- * descendends into child namespaces to collect more
- * service names.
+ * Locates all services in the namespace and adds key/value pairs to the map (name and class name). Then
+ * recursively descendends into child namespaces to collect more service names.
*
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
private void addServices(INamespace namespace, Map map)
{
@@ -2211,9 +1875,8 @@
}
/**
- * @since 2.0.4
- *
- **/
+ * @since 2.0.4
+ */
public IComponentMessagesSource getComponentMessagesSource()
{
@@ -2221,9 +1884,8 @@
}
/**
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
public DataSqueezer getDataSqueezer()
{
@@ -2231,14 +1893,11 @@
}
/**
+ * Invoked from {@link #setupForRequest(RequestContext)} to create a {@link DataSqueezer} when needed (typically,
+ * just the very first time). This implementation returns a standard, new instance.
*
- * Invoked from {@link #setupForRequest(RequestContext)} to create
- * a {@link DataSqueezer} when needed (typically, just the very first time).
- * This implementation returns a standard, new instance.
- *
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
public DataSqueezer createDataSqueezer()
{
@@ -2246,27 +1905,22 @@
}
/**
- * Invoked from {@link #service(RequestContext)} to extract, from the URL,
- * the name of the service. The current implementation expects the first
- * pathInfo element to be the service name. At some point in the future,
- * the method of constructing and parsing URLs may be abstracted into
- * a developer-selected class.
+ * Invoked from {@link #service(RequestContext)} to extract, from the URL, the name of the service. The current
+ * implementation expects the first pathInfo element to be the service name. At some point in the future, the
+ * method of constructing and parsing URLs may be abstracted into a developer-selected class.
+ * <p/>
+ * <p>Subclasses may override this method if the application defines specific services with unusual URL encoding
+ * rules.
+ * <p/>
+ * <p>This implementation simply extracts the value for query parameter {@link Tapestry#SERVICE_QUERY_PARAMETER_NAME}
+ * and extracts the service name from that.
+ * <p/>
+ * <p/>
+ * For supporting the JSP tags, this method first checks for attribute {@link Tapestry#TAG_SUPPORT_SERVICE_ATTRIBUTE}.
+ * If non-null, then {@link Tapestry#TAGSUPPORT_SERVICE} is returned.
*
- * <p>Subclasses may override this method if the application defines
- * specific services with unusual URL encoding rules.
- *
- * <p>This implementation simply extracts the value for
- * query parameter {@link Tapestry#SERVICE_QUERY_PARAMETER_NAME}
- * and extracts the service name from that.
- *
- * <p>
- * For supporting the JSP tags, this method first
- * checks for attribute {@link Tapestry#TAG_SUPPORT_SERVICE_ATTRIBUTE}. If non-null,
- * then {@link Tapestry#TAGSUPPORT_SERVICE} is returned.
- *
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
protected String extractServiceName(RequestContext context)
{
@@ -2278,8 +1932,8 @@
if (serviceData == null)
return Tapestry.HOME_SERVICE;
- // The service name is anything before the first slash,
- // if there is one.
+// The service name is anything before the first slash,
+// if there is one.
int slashx = serviceData.indexOf('/');
@@ -2289,35 +1943,45 @@
return serviceData.substring(0, slashx);
}
- /** @since 2.3 **/
+ /**
+ * @since 2.3 *
+ */
public IPropertySource getPropertySource()
{
return _propertySource;
}
- /** @since 3.0.3 */
+ /**
+ * @since 3.0.3
+ */
public ResourceChecksumSource getResourceChecksumSource()
{
return _resourceChecksumSource;
}
- /** @since 3.0 **/
+ /**
+ * @since 3.0 *
+ */
protected String getExceptionPageName()
{
return EXCEPTION_PAGE;
}
- /** @since 3.0 **/
+ /**
+ * @since 3.0 *
+ */
protected String getStaleLinkPageName()
{
return STALE_LINK_PAGE;
}
- /** @since 3.0 **/
+ /**
+ * @since 3.0 *
+ */
protected String getStaleSessionPageName()
{
@@ -2325,36 +1989,26 @@
}
/**
- * Name of an application extension that can provide configuration properties.
+ * Name of an application extension that can provide configuration properties.
*
- * @see #createPropertySource(RequestContext)
- * @since 2.3
- *
- **/
+ * @see #createPropertySource(RequestContext)
+ * @since 2.3
+ */
private static final String EXTENSION_PROPERTY_SOURCE_NAME =
"org.apache.tapestry.property-source";
/**
- * Creates a shared property source that will be stored into
- * the servlet context.
- * Subclasses may override this method to build thier
- * own search path.
+ * Creates a shared property source that will be stored into the servlet context. Subclasses may override this
+ * method to build thier own search path.
+ * <p/>
+ * <p>If the application specification contains an extension named "org.apache.tapestry.property-source" it is
+ * inserted in the search path just before the property source for JVM System Properties. This is a simple hook at
+ * allow application-specific methods of obtaining configuration values (typically, from a database or from JMX, in
+ * some way). Alternately, subclasses may override this method to provide whatever search path is appropriate.
*
- * <p>If the application specification contains an extension
- * named "org.apache.tapestry.property-source" it is inserted
- * in the search path just before
- * the property source for JVM System Properties. This is a simple
- * hook at allow application-specific methods of obtaining
- * configuration values (typically, from a database or from JMX,
- * in some way). Alternately, subclasses may
- * override this method to provide whatever search path
- * is appropriate.
- *
- *
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
protected IPropertySource createPropertySource(RequestContext context)
{
@@ -2379,7 +2033,7 @@
result.addSource(SystemPropertiesPropertySource.getInstance());
- // Lastly, add a final source to handle "factory defaults".
+// Lastly, add a final source to handle "factory defaults".
ResourceBundle bundle =
ResourceBundle.getBundle("org.apache.tapestry.ConfigurationDefaults");
@@ -2390,15 +2044,12 @@
}
/**
- * Creates the shared Global object. This implementation looks for an configuration
- * property, <code>org.apache.tapestry.global-class</code>, and instantiates that class
- * using a no-arguments
- * constructor. If the property is not defined, a synchronized
- * {@link java.util.HashMap} is created.
+ * Creates the shared Global object. This implementation looks for an configuration property,
+ * <code>org.apache.tapestry.global-class</code>, and instantiates that class using a no-arguments constructor. If
+ * the property is not defined, a synchronized {@link java.util.HashMap} is created.
*
- * @since 2.3
- *
- **/
+ * @since 2.3
+ */
protected Object createGlobal(RequestContext context)
{
@@ -2422,16 +2073,13 @@
}
/**
- * Returns an new instance of {@link Pool}, with the standard
- * set of adaptors, plus {@link BSFManagerPoolableAdaptor} for
- * {@link BSFManager}.
+ * Returns an new instance of {@link Pool}, with the standard set of adaptors, plus {@link
+ * BSFManagerPoolableAdaptor} for {@link BSFManager}.
+ * <p/>
+ * <p>Subclasses may override this method to configure the Pool differently.
*
- * <p>Subclasses may override this
- * method to configure the Pool differently.
- *
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
protected Pool createPool(RequestContext context)
{
@@ -2442,7 +2090,9 @@
return result;
}
- /** @since 3.0 **/
+ /**
+ * @since 3.0 *
+ */
public Pool getPool()
{
@@ -2450,16 +2100,13 @@
}
/**
- *
- * Invoked from {@link #setupForRequest(RequestContext)}. Creates
- * a new instance of {@link DefaultComponentClassEnhancer}. Subclasses
- * may override to return a different object.
- *
- * <p>
- * Check the property <code>org.apache.tapestry.enhance.disable-abstract-method-validation</code>
- * and, if true, disables abstract method validation. This is used in some
- * errant JDK's (such as IBM's 1.3.1) that incorrectly report concrete methods from
- * abstract classes as abstract.
+ * Invoked from {@link #setupForRequest(RequestContext)}. Creates a new instance of {@link
+ * DefaultComponentClassEnhancer}. Subclasses may override to return a different object.
+ * <p/>
+ * <p/>
+ * Check the property <code>org.apache.tapestry.enhance.disable-abstract-method-validation</code> and, if true,
+ * disables abstract method validation. This is used in some errant JDK's (such as IBM's 1.3.1) that incorrectly
+ * report concrete methods from abstract classes as abstract.
*
* @since 3.0
*/
@@ -2470,7 +2117,7 @@
"true".equals(
_propertySource.getPropertyValue(
"org.apache.tapestry.enhance.disable-abstract-method-validation"));
-
+
return new DefaultComponentClassEnhancer(_resolver, disableValidation, _classFactory);
}
@@ -2478,8 +2125,10 @@
{
return new EnhancedClassFactory(_resolver);
}
-
- /** @since 3.0 **/
+
+ /**
+ * @since 3.0 *
+ */
public IComponentClassEnhancer getComponentClassEnhancer()
{
@@ -2487,14 +2136,11 @@
}
/**
- * Returns true if the engine has (potentially) changed
- * state since the last time it was stored
- * into the {@link javax.servlet.http.HttpSession}. Various
- * events set this property to true.
+ * Returns true if the engine has (potentially) changed state since the last time it was stored into the {@link
+ * javax.servlet.http.HttpSession}. Various events set this property to true.
*
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
public boolean isDirty()
{
@@ -2502,14 +2148,11 @@
}
/**
- * Invoked to set the dirty flag, indicating that the
- * engine should be stored into the
- * {@link javax.servlet.http.HttpSession}.
+ * Invoked to set the dirty flag, indicating that the engine should be stored into the {@link
+ * javax.servlet.http.HttpSession}.
*
- *
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
protected void markDirty()
{
@@ -2520,14 +2163,10 @@
}
/**
+ * Clears the dirty flag when a engine is stored into the {@link HttpSession}.
*
- * Clears the dirty flag when a engine is stored into the
- * {@link HttpSession}.
- *
- *
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
public void valueBound(HttpSessionBindingEvent arg0)
{
@@ -2537,47 +2176,40 @@
}
/**
- * Does nothing.
+ * Does nothing.
*
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
public void valueUnbound(HttpSessionBindingEvent arg0)
{
}
/**
+ * The encoding to be used if none has been defined using the output encoding property. Override this method to
+ * change the default.
*
- * The encoding to be used if none has been defined using the output encoding property.
- * Override this method to change the default.
- *
- * @return the default output encoding
- * @since 3.0
- *
- **/
+ * @return the default output encoding
+ * @since 3.0
+ */
protected String getDefaultOutputEncoding()
{
return DEFAULT_OUTPUT_ENCODING;
}
/**
+ * Returns the encoding to be used to generate the servlet responses and accept the servlet requests.
+ * <p/>
+ * The encoding is defined using the org.apache.tapestry.output-encoding and is UTF-8 by default
*
- * Returns the encoding to be used to generate the servlet responses and
- * accept the servlet requests.
- *
- * The encoding is defined using the org.apache.tapestry.output-encoding
- * and is UTF-8 by default
- *
- * @since 3.0
- * @see org.apache.tapestry.IEngine#getOutputEncoding()
- *
- **/
+ * @see org.apache.tapestry.IEngine#getOutputEncoding()
+ * @since 3.0
+ */
public String getOutputEncoding()
{
if (_outputEncoding != null)
return _outputEncoding;
-
+
IPropertySource source = getPropertySource();
String encoding = source.getPropertyValue(OUTPUT_ENCODING_PROPERTY_NAME);
diff --git a/tapestry-framework/src/org/apache/tapestry/engine/BaseEngine.java b/tapestry-framework/src/org/apache/tapestry/engine/BaseEngine.java
index 412bc0c..46ac179 100644
--- a/tapestry-framework/src/org/apache/tapestry/engine/BaseEngine.java
+++ b/tapestry-framework/src/org/apache/tapestry/engine/BaseEngine.java
@@ -26,33 +26,26 @@
import java.util.*;
/**
- * Concrete implementation of {@link org.apache.tapestry.IEngine} used for ordinary
- * applications. All page state information is maintained in
- * the {@link javax.servlet.http.HttpSession} using
- * instances of {@link org.apache.tapestry.record.SessionPageRecorder}.
+ * Concrete implementation of {@link org.apache.tapestry.IEngine} used for ordinary applications. All page state
+ * information is maintained in the {@link javax.servlet.http.HttpSession} using instances of {@link
+ * org.apache.tapestry.record.SessionPageRecorder}.
*
- * @author Howard Lewis Ship
- * @version $Id$
- *
- **/
+ * @author Howard Lewis Ship
+ * @version $Id$
+ */
public class BaseEngine extends AbstractEngine
{
private static final long serialVersionUID = -7051050643746333380L;
- private final static int MAP_SIZE = 3;
-
private transient Map _recorders;
private transient Set _activePageNames;
/**
- * Removes all page recorders that contain no changes, or
- * are marked for discard. Subclasses
- * should invoke this implementation in addition to providing
- * thier own.
- *
- **/
+ * Removes all page recorders that contain no changes, or are marked for discard. Subclasses should invoke this
+ * implementation in addition to providing thier own.
+ */
protected void cleanupAfterRequest(IRequestCycle cycle)
{
@@ -105,11 +98,8 @@
}
/**
- * Returns an unmodifiable {@link Collection} of the page names for which
- * {@link IPageRecorder} instances exist.
- *
- *
- **/
+ * Returns an unmodifiable {@link Collection} of the page names for which {@link IPageRecorder} instances exist.
+ */
public Collection getActivePageNames()
{
@@ -170,10 +160,8 @@
}
/**
- * Reconstructs the list of active page names
- * written by {@link #writeExternal(ObjectOutput)}.
- *
- **/
+ * Reconstructs the list of active page names written by {@link #writeExternal(ObjectOutput)}.
+ */
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
@@ -194,11 +182,9 @@
}
/**
- * Writes the engine's persistent state; this is simply the list of active page
- * names. For efficiency, this is written as a count followed by each name
- * as a UTF String.
- *
- **/
+ * Writes the engine's persistent state; this is simply the list of active page names. For efficiency, this is
+ * written as a count followed by each name as a UTF String.
+ */
public void writeExternal(ObjectOutput out) throws IOException
{
diff --git a/tapestry-framework/src/org/apache/tapestry/engine/DefaultSpecificationSource.java b/tapestry-framework/src/org/apache/tapestry/engine/DefaultSpecificationSource.java
index ceaf150..a9ed24c 100644
--- a/tapestry-framework/src/org/apache/tapestry/engine/DefaultSpecificationSource.java
+++ b/tapestry-framework/src/org/apache/tapestry/engine/DefaultSpecificationSource.java
@@ -15,7 +15,6 @@
package org.apache.tapestry.engine;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
-import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -27,6 +26,7 @@
import org.apache.tapestry.spec.ILibrarySpecification;
import org.apache.tapestry.spec.LibrarySpecification;
import org.apache.tapestry.util.IRenderDescription;
+import org.apache.tapestry.util.ResourceLockManager;
import org.apache.tapestry.util.pool.Pool;
import org.apache.tapestry.util.xml.DocumentParseException;
@@ -35,31 +35,26 @@
import java.util.Set;
/**
- * Default implementation of {@link ISpecificationSource} that
- * expects to use the normal class loader to locate component
- * specifications from within the classpath.
- *
+ * Default implementation of {@link ISpecificationSource} that expects to use the normal class loader to locate
+ * component specifications from within the classpath.
+ * <p/>
* <p>Caches specifications in memory forever, or until {@link #reset()} is invoked.
- *
- * <p>An instance of this class acts like a singleton and is shared by multiple sessions,
- * so it must be threadsafe.
+ * <p/>
+ * <p>An instance of this class acts like a singleton and is shared by multiple sessions, so it must be threadsafe.
*
* @author Howard Lewis Ship
* @version $Id$
- *
- **/
+ */
public class DefaultSpecificationSource implements ISpecificationSource, IRenderDescription
{
private static final Log LOG = LogFactory.getLog(DefaultSpecificationSource.class);
/**
- * Key used to get and store {@link SpecificationParser} instances
- * from the Pool.
+ * Key used to get and store {@link SpecificationParser} instances from the Pool.
*
- * @since 3.0
- *
- **/
+ * @since 3.0
+ */
private static final String PARSER_POOL_KEY = "org.apache.tapestry.SpecificationParser";
@@ -70,60 +65,42 @@
private INamespace _frameworkNamespace;
/**
- * Contains previously parsed component specifications.
- *
- **/
+ * Contains previously parsed component specifications.
+ */
- private Map _componentCache = new ConcurrentHashMap();
+ private final Map _componentCache = new ConcurrentHashMap();
/**
- * Contains previously parsed page specifications.
+ * Contains previously parsed page specifications.
*
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
- private Map _pageCache = new ConcurrentHashMap();
+ private final Map _pageCache = new ConcurrentHashMap();
/**
- * Contains previously parsed library specifications, keyed
- * on specification resource path.
+ * Contains previously parsed library specifications, keyed on specification resource path.
*
- * @since 2.2
- *
- **/
+ * @since 2.2
+ */
- private Map _libraryCache = new ConcurrentHashMap();
+ private final Map _libraryCache = new ConcurrentHashMap();
- /**
- * Contains {@link INamespace} instances, keyed on id (which will
- * be null for the application specification).
- *
- **/
-
- private Map _namespaceCache = new ConcurrentHashMap();
/**
* Used to synchronize concurrent operations on specific resources.
*/
- private ConcurrentHashMap _lockCache = new ConcurrentHashMap();
+ private final ResourceLockManager _resourceLockManager = new ResourceLockManager();
/**
- * Reference to the shared {@link org.apache.tapestry.util.pool.Pool}.
+ * Reference to the shared {@link org.apache.tapestry.util.pool.Pool}.
*
- * @see org.apache.tapestry.IEngine#getPool()
- *
- * @since 3.0
- *
- **/
+ * @see org.apache.tapestry.IEngine#getPool()
+ * @since 3.0
+ */
private Pool _pool;
- /**
- * Used to synchronize global member access.
- */
- private ReentrantLock _monitor = new ReentrantLock();
-
public DefaultSpecificationSource(
IResourceResolver resolver,
IApplicationSpecification specification,
@@ -135,28 +112,18 @@
}
/**
- * Clears the specification cache. This is used during debugging.
- *
- **/
+ * Clears the specification cache. This is used during debugging.
+ */
- public void reset()
+ public synchronized void reset()
{
- _monitor.lock();
+ _componentCache.clear();
+ _pageCache.clear();
+ _libraryCache.clear();
+ _resourceLockManager.clear();
- try
- {
- _componentCache.clear();
- _pageCache.clear();
- _libraryCache.clear();
- _namespaceCache.clear();
- _lockCache.clear();
-
- _applicationNamespace = null;
- _frameworkNamespace = null;
- } finally
- {
- _monitor.unlock();
- }
+ _applicationNamespace = null;
+ _frameworkNamespace = null;
}
protected IComponentSpecification parseSpecification(
@@ -224,7 +191,9 @@
return builder.toString();
}
- /** @since 1.0.6 **/
+ /**
+ * @since 1.0.6 *
+ */
public void renderDescription(IMarkupWriter writer)
{
@@ -273,12 +242,11 @@
}
/**
- * Gets a component specification.
+ * Gets a component specification.
*
- * @param resourceLocation the complete resource path to the specification.
- * @throws ApplicationRuntimeException if the specification cannot be obtained.
- *
- **/
+ * @param resourceLocation the complete resource path to the specification.
+ * @throws ApplicationRuntimeException if the specification cannot be obtained.
+ */
public IComponentSpecification getComponentSpecification(IResourceLocation resourceLocation)
{
@@ -288,9 +256,7 @@
if (result != null)
return result;
- ReentrantLock lock = getLock(resourceLocation);
-
- lock.lock();
+ _resourceLockManager.lock(resourceLocation);
try
{
@@ -302,9 +268,11 @@
result = parseSpecification(resourceLocation, false);
_componentCache.put(resourceLocation, result);
- } finally
+ }
+ finally
{
- lock.unlock();
+ _resourceLockManager.unlock(resourceLocation);
+
}
return result;
@@ -317,23 +285,27 @@
if (result != null)
return result;
- ReentrantLock lock = getLock(resourceLocation);
-
- lock.lock();
+ _resourceLockManager.lock(resourceLocation);
try
{
+ // In a race condition, one thread may be parsing the specification while others block.
+ // The specification is in the cache once they un-block.
+
result = (IComponentSpecification) _pageCache.get(resourceLocation);
+
if (result != null)
return result;
result = parseSpecification(resourceLocation, true);
_pageCache.put(resourceLocation, result);
- } finally
+ }
+ finally
{
- lock.unlock();
+ _resourceLockManager.unlock(resourceLocation);
+
}
return result;
@@ -346,12 +318,13 @@
if (result != null)
return result;
- ReentrantLock lock = getLock(resourceLocation);
-
- lock.lock();
+ _resourceLockManager.lock(resourceLocation);
try
{
+ // In a race condition, one thread may be parsing the specification while others block.
+ // The specification is in the cache once they un-block.
+
result = (LibrarySpecification) _libraryCache.get(resourceLocation);
if (result != null)
@@ -359,15 +332,19 @@
result = parseLibrarySpecification(resourceLocation);
_libraryCache.put(resourceLocation, result);
- } finally
+ }
+ finally
{
- lock.unlock();
+ _resourceLockManager.unlock(resourceLocation);
+
}
return result;
}
- /** @since 2.2 **/
+ /**
+ * @since 2.2 *
+ */
protected SpecificationParser getParser()
{
@@ -379,59 +356,35 @@
return result;
}
- /** @since 3.0 **/
+ /**
+ * @since 3.0 *
+ */
protected void discardParser(SpecificationParser parser)
{
_pool.store(PARSER_POOL_KEY, parser);
}
- public INamespace getApplicationNamespace()
+ public synchronized INamespace getApplicationNamespace()
{
- _monitor.lock();
+ if (_applicationNamespace == null)
+ _applicationNamespace = new Namespace(null, null, _specification, this);
- try
+ return _applicationNamespace;
+ }
+
+ public synchronized INamespace getFrameworkNamespace()
+ {
+ if (_frameworkNamespace == null)
{
- if (_applicationNamespace == null)
- _applicationNamespace = new Namespace(null, null, _specification, this);
+ IResourceLocation frameworkLocation =
+ new ClasspathResourceLocation(_resolver, "/org/apache/tapestry/Framework.library");
- return _applicationNamespace;
+ ILibrarySpecification ls = getLibrarySpecification(frameworkLocation);
- } finally
- {
- _monitor.unlock();
+ _frameworkNamespace = new Namespace(INamespace.FRAMEWORK_NAMESPACE, null, ls, this);
}
+
+ return _frameworkNamespace;
}
-
- public INamespace getFrameworkNamespace()
- {
- _monitor.lock();
-
- try
- {
- if (_frameworkNamespace == null)
- {
- IResourceLocation frameworkLocation =
- new ClasspathResourceLocation(_resolver, "/org/apache/tapestry/Framework.library");
-
- ILibrarySpecification ls = getLibrarySpecification(frameworkLocation);
-
- _frameworkNamespace = new Namespace(INamespace.FRAMEWORK_NAMESPACE, null, ls, this);
- }
-
- return _frameworkNamespace;
-
- } finally
- {
- _monitor.unlock();
- }
- }
-
- private ReentrantLock getLock(Object key)
- {
- _lockCache.putIfAbsent(key, new ReentrantLock());
-
- return (ReentrantLock) _lockCache.get(key);
- }
-
}
\ No newline at end of file
diff --git a/tapestry-framework/src/org/apache/tapestry/engine/DefaultTemplateSource.java b/tapestry-framework/src/org/apache/tapestry/engine/DefaultTemplateSource.java
index 538d475..8ba40c5 100644
--- a/tapestry-framework/src/org/apache/tapestry/engine/DefaultTemplateSource.java
+++ b/tapestry-framework/src/org/apache/tapestry/engine/DefaultTemplateSource.java
@@ -15,7 +15,6 @@
package org.apache.tapestry.engine;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
-import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -35,22 +34,18 @@
import java.util.Map;
/**
- * Default implementation of {@link ITemplateSource}. Templates, once parsed,
- * stay in memory until explicitly cleared.
+ * Default implementation of {@link ITemplateSource}. Templates, once parsed, stay in memory until explicitly cleared.
+ * <p/>
+ * <p>An instance of this class acts as a singleton shared by all sessions, so it must be threadsafe.
*
- * <p>An instance of this class acts as a singleton shared by all sessions, so it
- * must be threadsafe.
- *
- * @author Howard Lewis Ship
- * @version $Id$
- *
- **/
+ * @author Howard Lewis Ship
+ * @version $Id$
+ */
public class DefaultTemplateSource implements ITemplateSource, IRenderDescription
{
private static final Log LOG = LogFactory.getLog(DefaultTemplateSource.class);
-
// The name of the component/application/etc property that will be used to
// determine the encoding to use when loading the template
@@ -60,20 +55,18 @@
// specification resource path and locale (local may be null), value
// is the ComponentTemplate.
- private Map _cache = new ConcurrentHashMap();
+ private final Map _cache = new ConcurrentHashMap();
// Previously read templates; key is the IResourceLocation, value
// is the ComponentTemplate.
- private Map _templates = new ConcurrentHashMap();
+ private final Map _templates = new ConcurrentHashMap();
- // Used to synchronize access to specific templates
- private ConcurrentHashMap _lockCache = new ConcurrentHashMap();
+ private final ResourceLockManager _resourceLockManager = new ResourceLockManager();
/**
- * Number of tokens (each template contains multiple tokens).
- *
- **/
+ * Number of tokens (each template contains multiple tokens).
+ */
private int _tokenCount;
@@ -81,34 +74,36 @@
private TemplateParser _parser;
- /** @since 2.2 **/
+ /**
+ * @since 2.2 *
+ */
private IResourceLocation _applicationRootLocation;
- /** @since 3.0 **/
+ /**
+ * @since 3.0 *
+ */
private ITemplateSourceDelegate _delegate;
/**
- * Clears the template cache. This is used during debugging.
- *
- **/
+ * Clears the template cache. This is used during debugging.
+ */
public void reset()
{
_cache.clear();
_templates.clear();
- _lockCache.clear();
+ _resourceLockManager.clear();
_tokenCount = 0;
}
/**
- * Reads the template for the component.
- *
- * <p>Returns null if the template can't be found.
- *
- **/
+ * Reads the template for the component.
+ * <p/>
+ * <p>Returns null if the template can't be found.
+ */
public ComponentTemplate getTemplate(IRequestCycle cycle, IComponent component)
{
@@ -117,17 +112,14 @@
Locale locale = component.getPage().getLocale();
- Object key = new MultiKey(new Object[] { specificationLocation, locale }, false);
+ Object key = new MultiKey(new Object[]{specificationLocation, locale}, false);
ComponentTemplate result = searchCache(key);
if (result != null)
return result;
- _lockCache.putIfAbsent(key, new ReentrantLock());
+ _resourceLockManager.lock(key);
- ReentrantLock lock = (ReentrantLock)_lockCache.get(key);
-
- lock.lock();
try
{
result = searchCache(key);
@@ -145,8 +137,8 @@
String stringKey =
component.getSpecification().isPageSpecification()
- ? "DefaultTemplateSource.no-template-for-page"
- : "DefaultTemplateSource.no-template-for-component";
+ ? "DefaultTemplateSource.no-template-for-page"
+ : "DefaultTemplateSource.no-template-for-component";
throw new ApplicationRuntimeException(
Tapestry.format(stringKey, component.getExtendedId(), locale),
@@ -156,11 +148,14 @@
}
saveToCache(key, result);
- } finally
- {
- lock.unlock();
+
+ return result;
}
- return result;
+ finally
+ {
+ _resourceLockManager.unlock(key);
+ }
+
}
private ComponentTemplate searchCache(Object key)
@@ -198,17 +193,12 @@
}
/**
- * Finds the template for the given component, using the following rules:
- * <ul>
- * <li>If the component has a $template asset, use that
- * <li>Look for a template in the same folder as the component
- * <li>If a page in the application namespace, search in the application root
- * <li>Fail!
- * </ul>
+ * Finds the template for the given component, using the following rules: <ul> <li>If the component has a $template
+ * asset, use that <li>Look for a template in the same folder as the component <li>If a page in the application
+ * namespace, search in the application root <li>Fail! </ul>
*
- * @return the template, or null if not found
- *
- **/
+ * @return the template, or null if not found
+ */
private ComponentTemplate findTemplate(
IRequestCycle cycle,
@@ -229,8 +219,8 @@
findStandardTemplate(cycle, location, component, templateBaseName, locale);
if (result == null
- && component.getSpecification().isPageSpecification()
- && component.getNamespace().isApplicationNamespace())
+ && component.getSpecification().isPageSpecification()
+ && component.getNamespace().isApplicationNamespace())
result = findPageTemplateInApplicationRoot(cycle, component, templateBaseName, locale);
return result;
@@ -259,9 +249,8 @@
}
/**
- * Reads an asset to get the template.
- *
- **/
+ * Reads an asset to get the template.
+ */
private ComponentTemplate readTemplateFromAsset(
IRequestCycle cycle,
@@ -293,13 +282,11 @@
}
/**
- * Search for the template corresponding to the resource and the locale.
- * This may be in the template map already, or may involve reading and
- * parsing the template.
+ * Search for the template corresponding to the resource and the locale. This may be in the template map already, or
+ * may involve reading and parsing the template.
*
- * @return the template, or null if not found.
- *
- **/
+ * @return the template, or null if not found.
+ */
private ComponentTemplate findStandardTemplate(
IRequestCycle cycle,
@@ -311,9 +298,9 @@
if (LOG.isDebugEnabled())
LOG.debug(
"Searching for localized version of template for "
- + location
- + " in locale "
- + locale.getDisplayName());
+ + location
+ + " in locale "
+ + locale.getDisplayName());
IResourceLocation baseTemplateLocation = location.getRelativeLocation(templateBaseName);
@@ -327,11 +314,9 @@
}
/**
- * Returns a previously parsed template at the specified location (which must already
- * be localized). If not already in the template Map, then the
- * location is parsed and stored into the templates Map, then returned.
- *
- **/
+ * Returns a previously parsed template at the specified location (which must already be localized). If not already
+ * in the template Map, then the location is parsed and stored into the templates Map, then returned.
+ */
private ComponentTemplate getOrParseTemplate(
IRequestCycle cycle,
@@ -354,12 +339,9 @@
}
/**
- * Reads the template for the given resource; returns null if the
- * resource doesn't exist. Note that this method is only invoked
- * from a synchronized block, so there shouldn't be threading
- * issues here.
- *
- **/
+ * Reads the template for the given resource; returns null if the resource doesn't exist. Note that this method is
+ * only invoked from a synchronized block, so there shouldn't be threading issues here.
+ */
private ComponentTemplate parseTemplate(
IRequestCycle cycle,
@@ -376,12 +358,9 @@
}
/**
- * This method is currently synchronized, because
- * {@link TemplateParser} is not threadsafe. Another good candidate
- * for a pooling mechanism, especially because parsing a template
- * may take a while.
- *
- **/
+ * This method is currently synchronized, because {@link TemplateParser} is not threadsafe. Another good candidate
+ * for a pooling mechanism, especially because parsing a template may take a while.
+ */
private synchronized ComponentTemplate constructTemplateInstance(
IRequestCycle cycle,
@@ -416,10 +395,8 @@
}
/**
- * Reads the template, given the complete path to the
- * resource. Returns null if the resource doesn't exist.
- *
- **/
+ * Reads the template, given the complete path to the resource. Returns null if the resource doesn't exist.
+ */
private char[] readTemplate(IResourceLocation location, String encoding)
{
@@ -461,9 +438,8 @@
}
/**
- * Reads a Stream into memory as an array of characters.
- *
- **/
+ * Reads a Stream into memory as an array of characters.
+ */
private char[] readTemplateStream(InputStream stream, String encoding) throws IOException
{
@@ -520,11 +496,10 @@
}
/**
- * Checks for the {@link Tapestry#TEMPLATE_EXTENSION_PROPERTY} in the component's
- * specification, then in the component's namespace's specification. Returns
- * {@link Tapestry#DEFAULT_TEMPLATE_EXTENSION} if not otherwise overriden.
- *
- **/
+ * Checks for the {@link Tapestry#TEMPLATE_EXTENSION_PROPERTY} in the component's specification, then in the
+ * component's namespace's specification. Returns {@link Tapestry#DEFAULT_TEMPLATE_EXTENSION} if not otherwise
+ * overriden.
+ */
private String getTemplateExtension(IComponent component)
{
@@ -544,7 +519,9 @@
return Tapestry.DEFAULT_TEMPLATE_EXTENSION;
}
- /** @since 1.0.6 **/
+ /**
+ * @since 1.0.6 *
+ */
public synchronized void renderDescription(IMarkupWriter writer)
{
diff --git a/tapestry-framework/src/org/apache/tapestry/engine/ExpressionCacheImpl.java b/tapestry-framework/src/org/apache/tapestry/engine/ExpressionCacheImpl.java
index 46466bd..b7198a7 100644
--- a/tapestry-framework/src/org/apache/tapestry/engine/ExpressionCacheImpl.java
+++ b/tapestry-framework/src/org/apache/tapestry/engine/ExpressionCacheImpl.java
@@ -14,7 +14,6 @@
package org.apache.tapestry.engine;
-import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
import ognl.ClassCacheInspector;
import ognl.Node;
import ognl.OgnlRuntime;
@@ -27,9 +26,8 @@
* @author Howard M. Lewis Ship
* @since 4.0
*/
-public class ExpressionCacheImpl implements ExpressionCache, ClassCacheInspector {
-
- private final ReentrantLock _lock = new ReentrantLock();
+public class ExpressionCacheImpl implements ExpressionCache, ClassCacheInspector
+{
private final Map _compiledExpressionCache = new HashMap();
@@ -50,77 +48,53 @@
}
}
- public void reset()
+ public synchronized void reset()
{
- try
- {
- _lock.lock();
-
- _compiledExpressionCache.clear();
- _expressionCache.clear();
- } finally
- {
- _lock.unlock();
- }
+ _compiledExpressionCache.clear();
+ _expressionCache.clear();
}
public boolean shouldCache(Class type)
{
if (!_cachingDisabled || type == null
- || AbstractComponent.class.isAssignableFrom(type))
+ || AbstractComponent.class.isAssignableFrom(type))
return false;
return true;
}
- public Object get(Object target, String expression)
+ public synchronized Object get(Object target, String expression)
{
- try
+ Map cached = (Map) _compiledExpressionCache.get(target.getClass());
+ if (cached == null)
{
- _lock.lock();
-
- Map cached = (Map)_compiledExpressionCache.get(target.getClass());
- if (cached == null)
- {
- return _expressionCache.get(expression);
- } else
- {
- return cached.get(expression);
- }
-
- } finally
+ return _expressionCache.get(expression);
+ }
+ else
{
- _lock.unlock();
+ return cached.get(expression);
}
}
- public void cache(Object target, String expression, Node node)
+ public synchronized void cache(Object target, String expression, Node node)
{
- try
+ if (node.getAccessor() != null)
{
- _lock.lock();
+ Map cached = (Map) _compiledExpressionCache.get(target.getClass());
- if (node.getAccessor() != null)
+ if (cached == null)
{
- Map cached = (Map)_compiledExpressionCache.get(target.getClass());
-
- if (cached == null)
- {
- cached = new HashMap();
- _compiledExpressionCache.put(target.getClass(), cached);
- }
-
- cached.put(expression, node);
-
- _expressionCache.remove(target.getClass());
- } else
- {
- _expressionCache.put(expression, node);
+ cached = new HashMap();
+ _compiledExpressionCache.put(target.getClass(), cached);
}
- } finally
+ cached.put(expression, node);
+
+ _expressionCache.remove(target.getClass());
+ }
+ else
{
- _lock.unlock();
+ _expressionCache.put(expression, node);
}
}
}
diff --git a/tapestry-framework/src/org/apache/tapestry/engine/ExpressionEvaluatorImpl.java b/tapestry-framework/src/org/apache/tapestry/engine/ExpressionEvaluatorImpl.java
index 785f5fb..3c56696 100644
--- a/tapestry-framework/src/org/apache/tapestry/engine/ExpressionEvaluatorImpl.java
+++ b/tapestry-framework/src/org/apache/tapestry/engine/ExpressionEvaluatorImpl.java
@@ -29,7 +29,8 @@
/**
* @since 4.0
*/
-public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
+public class ExpressionEvaluatorImpl implements ExpressionEvaluator
+{
private static final long POOL_MIN_IDLE_TIME = 1000 * 60 * 50;
@@ -72,7 +73,8 @@
void initializeService()
{
if (_applicationSpecification.checkExtension(Tapestry.OGNL_TYPE_CONVERTER))
- _typeConverter = (TypeConverter) _applicationSpecification.getExtension(Tapestry.OGNL_TYPE_CONVERTER, TypeConverter.class);
+ _typeConverter = (TypeConverter) _applicationSpecification.getExtension(Tapestry.OGNL_TYPE_CONVERTER,
+ TypeConverter.class);
_defaultContext = Ognl.createDefaultContext(null, _ognlResolver, _typeConverter);
@@ -88,17 +90,19 @@
public Node parse(Object target, String expression)
{
- Node node = (Node)_expressionCache.get(target, expression);
+ Node node = (Node) _expressionCache.get(target, expression);
if (node == null)
{
try
{
- node = (Node)Ognl.parseExpression(expression);
+ node = (Node) Ognl.parseExpression(expression);
_expressionCache.cache(target, expression, node);
- } catch (OgnlException ex)
+ }
+ catch (OgnlException ex)
{
- throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
+ throw new ApplicationRuntimeException(
+ Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
}
}
@@ -120,33 +124,57 @@
OgnlContext context = null;
try
{
- context = (OgnlContext)_contextPool.borrowObject();
+ context = (OgnlContext) _contextPool.borrowObject();
context.setRoot(target);
-
+
return Ognl.getValue(expression, context, target);
}
catch (Exception ex)
{
- throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
- } finally {
- try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
+ throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex),
+ target, null, ex);
+ }
+ finally
+ {
+ discardContext(context);
+ }
+ }
+
+ /**
+ * Invoked from various finally blocks to discard a OgnlContext used during an operation.
+ */
+ private void discardContext(OgnlContext context)
+ {
+ if (context == null) return;
+
+ try
+ {
+ _contextPool.returnObject(context);
+ }
+ catch (Exception ex)
+ {
+ // Ignored. Should be logged?
}
}
public Object read(Object target, ExpressionAccessor expression)
{
OgnlContext context = null;
+
try
{
- context = (OgnlContext)_contextPool.borrowObject();
+ context = (OgnlContext) _contextPool.borrowObject();
return expression.get(context, target);
}
catch (Exception ex)
{
- throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
- } finally {
- try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
+ throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex),
+ target, null, ex);
+ }
+ finally
+ {
+ discardContext(context);
}
}
@@ -160,7 +188,7 @@
OgnlContext context = null;
try
{
- context = (OgnlContext)_contextPool.borrowObject();
+ context = (OgnlContext) _contextPool.borrowObject();
// set up context
context.setRoot(target);
@@ -170,10 +198,12 @@
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-write-expression",
- new Object[] {expression, target, value, ex}),
+ new Object[]{expression, target, value, ex}),
target, null, ex);
- } finally {
- try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
+ }
+ finally
+ {
+ discardContext(context);
}
}
@@ -182,17 +212,19 @@
OgnlContext context = null;
try
{
- context = (OgnlContext)_contextPool.borrowObject();
+ context = (OgnlContext) _contextPool.borrowObject();
Ognl.setValue(expression, context, target, value);
}
catch (Exception ex)
{
throw new ApplicationRuntimeException(Tapestry.format("unable-to-write-expression",
- new Object[] {expression, target, value, ex}),
+ new Object[]{expression, target, value, ex}),
target, null, ex);
- } finally {
- try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
+ }
+ finally
+ {
+ discardContext(context);
}
}
@@ -218,10 +250,10 @@
public void compileExpression(Object target, Node node, String expression)
{
OgnlContext context = null;
-
+
try
{
- context = (OgnlContext)_contextPool.borrowObject();
+ context = (OgnlContext) _contextPool.borrowObject();
// set up context
context.setRoot(target);
@@ -230,11 +262,15 @@
_expressionCache.cache(target, expression, node);
- } catch (Exception ex)
+ }
+ catch (Exception ex)
{
- throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex), target, null, ex);
- } finally {
- try { if (context != null) _contextPool.returnObject(context); } catch (Exception e) {}
+ throw new ApplicationRuntimeException(Tapestry.format("unable-to-read-expression", expression, target, ex),
+ target, null, ex);
+ }
+ finally
+ {
+ discardContext(context);
}
}
@@ -246,7 +282,9 @@
OgnlRuntime.clearCache();
Introspector.flushCaches();
- } catch (Exception et) {
+ }
+ catch (Exception et)
+ {
// ignore
}
}
diff --git a/tapestry-framework/src/org/apache/tapestry/util/ResourceLockManager.java b/tapestry-framework/src/org/apache/tapestry/util/ResourceLockManager.java
new file mode 100644
index 0000000..1cec27d
--- /dev/null
+++ b/tapestry-framework/src/org/apache/tapestry/util/ResourceLockManager.java
@@ -0,0 +1,57 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.util;
+
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
+import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Manages {@link edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock}s keyed on some arbitrary object.
+ */
+public class ResourceLockManager
+{
+ /**
+ * Map from some object (which should be a proper key) to a ReentrantLock.
+ */
+ private final ConcurrentMap resourceToLock = new ConcurrentHashMap();
+
+ public void clear()
+ {
+ resourceToLock.clear();
+ }
+
+ private ReentrantLock get(Object object)
+ {
+ if (!resourceToLock.containsKey(object))
+ {
+ // Watch out for a race condition where two threads may put conflicting locks
+ // for the name resource.
+ resourceToLock.putIfAbsent(object, new ReentrantLock());
+ }
+
+ return (ReentrantLock) resourceToLock.get(object);
+ }
+
+ public void lock(Object object)
+ {
+ get(object).lock();
+ }
+
+ public void unlock(Object object)
+ {
+ get(object).unlock();
+ }
+}