Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/tapestry/engine/AbstractEngine.java


1   /* $$ Clover has instrumented this file $$ */// Copyright 2004 The Apache Software Foundation
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package org.apache.tapestry.engine;
16  
17  import java.io.Externalizable;
18  import java.io.IOException;
19  import java.io.ObjectInput;
20  import java.io.ObjectOutput;
21  import java.io.UnsupportedEncodingException;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Map;
30  
31  import javax.servlet.RequestDispatcher;
32  import javax.servlet.ServletContext;
33  import javax.servlet.ServletException;
34  import javax.servlet.http.HttpServlet;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  import javax.servlet.http.HttpSession;
38  import javax.servlet.http.HttpSessionBindingEvent;
39  import javax.servlet.http.HttpSessionBindingListener;
40  
41  import org.apache.commons.lang.builder.ToStringBuilder;
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  import org.apache.hivemind.ApplicationRuntimeException;
45  import org.apache.hivemind.ClassResolver;
46  import org.apache.tapestry.ApplicationServlet;
47  import org.apache.tapestry.Constants;
48  import org.apache.tapestry.IEngine;
49  import org.apache.tapestry.IMarkupWriter;
50  import org.apache.tapestry.INamespace;
51  import org.apache.tapestry.IPage;
52  import org.apache.tapestry.IRequestCycle;
53  import org.apache.tapestry.PageRedirectException;
54  import org.apache.tapestry.RedirectException;
55  import org.apache.tapestry.StaleLinkException;
56  import org.apache.tapestry.StaleSessionException;
57  import org.apache.tapestry.Tapestry;
58  import org.apache.tapestry.listener.ListenerMap;
59  import org.apache.tapestry.request.RequestContext;
60  import org.apache.tapestry.request.ResponseOutputStream;
61  import org.apache.tapestry.services.ComponentMessagesSource;
62  import org.apache.tapestry.services.DataSqueezer;
63  import org.apache.tapestry.services.Infrastructure;
64  import org.apache.tapestry.services.ObjectPool;
65  import org.apache.tapestry.services.TemplateSource;
66  import org.apache.tapestry.services.impl.ComponentMessagesSourceImpl;
67  import org.apache.tapestry.spec.IApplicationSpecification;
68  import org.apache.tapestry.util.exception.ExceptionAnalyzer;
69  import org.apache.tapestry.util.io.DataSqueezerImpl;
70  
71  import com.sun.jndi.ldap.pool.Pool;
72  
73  /**
74   * Basis for building real Tapestry applications. Immediate subclasses provide different strategies
75   * for managing page state and other resources between request cycles.
76   * <p>
77   * Note: much of this description is <em>in transition</em> as part of Tapestry 3.1. All ad-hoc
78   * singletons and such are being replaced with HiveMind services.
79   * <p>
80   * Uses a shared instance of {@link ITemplateSource},{@link ISpecificationSource},
81   * {@link IScriptSource}and {@link IComponentMessagesSource}stored as attributes of the
82   * {@link ServletContext}(they will be shared by all sessions).
83   * <p>
84   * An engine is designed to be very lightweight. Particularily, it should <b>never </b> hold
85   * references to any {@link IPage}or {@link org.apache.tapestry.IComponent}objects. The entire
86   * system is based upon being able to quickly rebuild the state of any page(s).
87   * <p>
88   * Where possible, instance variables should be transient. They can be restored inside
89   * {@link #setupForRequest(RequestContext)}.
90   * <p>
91   * In practice, a subclass (usually {@link BaseEngine}) is used without subclassing. Instead, a
92   * visit object is specified. To facilitate this, the application specification may include a
93   * property, <code>org.apache.tapestry.visit-class</code> which is the class name to instantiate
94   * when a visit object is first needed. See {@link #createVisit(IRequestCycle)}for more details.
95   * <p>
96   * Some of the classes' behavior is controlled by JVM system properties (typically only used during
97   * development): <table border=1>
98   * <tr>
99   * <th>Property</th>
100  * <th>Description</th>
101  * </tr>
102  * <tr>
103  * <td>org.apache.tapestry.enable-reset-service</td>
104  * <td>If true, enabled an additional service, reset, that allow page, specification and template
105  * caches to be cleared on demand. See {@link #isResetServiceEnabled()}.</td>
106  * </tr>
107  * <tr>
108  * <td>org.apache.tapestry.disable-caching</td>
109  * <td>If true, then the page, specification, template and script caches will be cleared after each
110  * request. This slows things down, but ensures that the latest versions of such files are used.
111  * Care should be taken that the source directories for the files preceeds any versions of the files
112  * available in JARs or WARs.</td>
113  * </tr>
114  * </table>
115  * 
116  * @author Howard Lewis Ship
117  */
118 
119 public abstract class AbstractEngine implements IEngine, IEngineServiceView, Externalizable,
120         HttpSessionBindingListener
121 {public static com.cortexeb.tools.clover.d __CLOVER_71_0 = com.cortexeb.tools.clover.aq.getRecorder(new char[] {67,58,92,119,111,114,107,115,112,97,99,101,92,106,97,107,97,114,116,97,45,116,97,112,101,115,116,114,121,92,102,114,97,109,101,119,111,114,107,92,116,97,114,103,101,116,92,99,108,111,118,101,114,45,100,98},1096998272901L);
122     private static final Log LOG = LogFactory.getLog(AbstractEngine.class);
123 
124     /**
125      * @since 2.0.4
126      */
127 
128     private static final long serialVersionUID = 6884834397673817117L;
129 
130     /**
131      * The link to the world of HiveMind services.
132      * 
133      * @since 3.1
134      */
135     private transient Infrastructure _infrastructure;
136 
137     private transient String _contextPath;
138 
139     private transient String _servletPath;
140 
141     private transient String _clientAddress;
142 
143     private transient String _sessionId;
144 
145     private transient boolean _stateful;
146 
147     private transient ListenerMap _listeners;
148 
149     /**
150      * An object used to contain application-specific server side state.
151      */
152 
153     private Object _visit;
154 
155     /**
156      * The globally shared application object. Typically, this is created when first needed, shared
157      * between sessions and engines, and stored in the {@link ServletContext}.
158      * 
159      * @since 2.3
160      */
161 
162     private transient Object _global;
163 
164     /**
165      * The base name for the servlet context key used to store the application-defined Global
166      * object, if any.
167      * 
168      * @since 2.3
169      */
170 
171     public static final String GLOBAL_NAME = "org.apache.tapestry.global";
172 
173     /**
174      * The name of the application property that will be used to determine the encoding to use when
175      * generating the output
176      * 
177      * @since 3.0
178      */
179 
180     public static final String OUTPUT_ENCODING_PROPERTY_NAME = "org.apache.tapestry.output-encoding";
181 
182     /**
183      * The default encoding that will be used when generating the output. It is used if no output
184      * encoding property has been specified.
185      * 
186      * @since 3.0
187      */
188 
189     public static final String DEFAULT_OUTPUT_ENCODING = "UTF-8";
190 
191     /**
192      * The curent locale for the engine, which may be changed at any time.
193      */
194 
195     private Locale _locale;
196 
197     /**
198      * Set by {@link #setLocale(Locale)}when the locale is changed; this allows the locale cookie
199      * to be updated.
200      */
201 
202     private boolean _localeChanged;
203 
204     /**
205      * The name of the application specification property used to specify the class of the visit
206      * object.
207      */
208 
209     public static final String VISIT_CLASS_PROPERTY_NAME = "org.apache.tapestry.visit-class";
210 
211     /**
212      * If true (set from JVM system parameter <code>org.apache.tapestry.enable-reset-service</code>)
213      * then the reset service will be enabled, allowing the cache of pages, specifications and
214      * template to be cleared on demand.
215      */
216 
217     private static final boolean _resetServiceEnabled = Boolean
218             .getBoolean("org.apache.tapestry.enable-reset-service");
219 
220     /**
221      * If true (set from the JVM system parameter <code>org.apache.tapestry.disable-caching</code>)
222      * then the cache of pages, specifications and template will be cleared after each request.
223      */
224 
225     private static final boolean _disableCaching = Boolean
226             .getBoolean("org.apache.tapestry.disable-caching");
227 
228     /**
229      * Set to true when there is a (potential) change to the internal state of the engine, set to
230      * false when the engine is stored into the {@link HttpSession}.
231      * 
232      * @since 3.0
233      */
234 
235     private transient boolean _dirty;
236 
237     /**
238      * The instance of {@link IMonitorFactory}used to create a monitor.
239      * 
240      * @since 3.0
241      */
242 
243     private transient IMonitorFactory _monitorFactory;
244 
245     /**
246      * Sets the Exception page's exception property, then renders the Exception page.
247      * <p>
248      * If the render throws an exception, then copious output is sent to <code>System.err</code>
249      * and a {@link ServletException}is thrown.
250      */
251 
252     protected void activateExceptionPage(IRequestCycle cycle, ResponseOutputStream output,
253             Throwable cause) throws ServletException
254     {try { __CLOVER_71_0.M[373]++;
255         __CLOVER_71_0.S[1540]++;try
256         {
257             __CLOVER_71_0.S[1541]++;IPage exceptionPage = cycle.getPage(getExceptionPageName());
258 
259             __CLOVER_71_0.S[1542]++;exceptionPage.setProperty("exception", cause);
260 
261             __CLOVER_71_0.S[1543]++;cycle.activate(exceptionPage);
262 
263             __CLOVER_71_0.S[1544]++;renderResponse(cycle, output);
264 
265         }
266         catch (Throwable ex)
267         {
268             // Worst case scenario. The exception page itself is broken, leaving
269             // us with no option but to write the cause to the output.
270 
271             __CLOVER_71_0.S[1545]++;reportException(
272                     Tapestry.getMessage("AbstractEngine.unable-to-process-client-request"),
273                     cause);
274 
275             // Also, write the exception thrown when redendering the exception
276             // page, so that can get fixed as well.
277 
278             __CLOVER_71_0.S[1546]++;reportException(
279                     Tapestry.getMessage("AbstractEngine.unable-to-present-exception-page"),
280                     ex);
281 
282             // And throw the exception.
283 
284             __CLOVER_71_0.S[1547]++;throw new ServletException(ex.getMessage(), ex);
285         }
286     } finally { }}
287 
288     /**
289      * Writes a detailed report of the exception to <code>System.err</code>.
290      */
291 
292     public void reportException(String reportTitle, Throwable ex)
293     {try { __CLOVER_71_0.M[374]++;
294         __CLOVER_71_0.S[1548]++;LOG.warn(reportTitle, ex);
295 
296         __CLOVER_71_0.S[1549]++;System.err.println("\n\n**********************************************************\n\n");
297 
298         __CLOVER_71_0.S[1550]++;System.err.println(reportTitle);
299 
300         __CLOVER_71_0.S[1551]++;System.err.println("\n\n      Session id: " + _sessionId + "\n  Client address: "
301                 + _clientAddress + "\n\nExceptions:\n");
302 
303         __CLOVER_71_0.S[1552]++;new ExceptionAnalyzer().reportException(ex, System.err);
304 
305         __CLOVER_71_0.S[1553]++;System.err.println("\n**********************************************************\n");
306 
307     } finally { }}
308 
309     /**
310      * Invoked at the end of the request cycle to release any resources specific to the request
311      * cycle.
312      */
313 
314     protected abstract void cleanupAfterRequest(IRequestCycle cycle);
315 
316     /**
317      * Extends the description of the class generated by {@link #toString()}. If a subclass adds
318      * additional instance variables that should be described in the instance description, it may
319      * overide this method. This implementation does nothing.
320      * 
321      * @see #toString()
322      */
323 
324     protected void extendDescription(ToStringBuilder builder)
325     {try { __CLOVER_71_0.M[375]++;
326 
327     } finally { }}
328 
329     /**
330      * Returns the locale for the engine. This is initially set by the {@link ApplicationServlet}
331      * but may be updated by the application.
332      */
333 
334     public Locale getLocale()
335     {try { __CLOVER_71_0.M[376]++;
336         __CLOVER_71_0.S[1554]++;return _locale;
337     } finally { }}
338 
339     /**
340      * Overriden in subclasses that support monitoring. Should create and return an instance of
341      * {@link IMonitor}that is appropriate for the request cycle described by the
342      * {@link RequestContext}.
343      * <p>
344      * The monitor is used to create a {@link RequestCycle}.
345      * <p>
346      * This implementation uses a {@link IMonitorFactory}to create the monitor instance. The
347      * factory is provided as an application extension. If the application extension does not exist,
348      * {@link DefaultMonitorFactory}is used.
349      * <p>
350      * As of release 3.0, this method should <em>not</em> return null.
351      */
352 
353     public IMonitor getMonitor(RequestContext context)
354     {try { __CLOVER_71_0.M[377]++;
355         __CLOVER_71_0.S[1555]++;if ((((_monitorFactory == null) && (++__CLOVER_71_0.CT[297] != 0)) || (++__CLOVER_71_0.CF[297] == 0))){
356         {
357             __CLOVER_71_0.S[1556]++;IApplicationSpecification spec = getSpecification();
358 
359             __CLOVER_71_0.S[1557]++;if ((((spec.checkExtension(Tapestry.MONITOR_FACTORY_EXTENSION_NAME)) && (++__CLOVER_71_0.CT[298] != 0)) || (++__CLOVER_71_0.CF[298] == 0))){
360                 __CLOVER_71_0.S[1558]++;_monitorFactory = (IMonitorFactory) spec.getExtension(
361                         Tapestry.MONITOR_FACTORY_EXTENSION_NAME,
362                         IMonitorFactory.class);}
363             else{
364                 __CLOVER_71_0.S[1559]++;_monitorFactory = DefaultMonitorFactory.SHARED;}
365         }}
366 
367         __CLOVER_71_0.S[1560]++;return _monitorFactory.createMonitor(context);
368     } finally { }}
369 
370     /** @see Infrastructure#getPageSource() */
371 
372     public IPageSource getPageSource()
373     {try { __CLOVER_71_0.M[378]++;
374         __CLOVER_71_0.S[1561]++;return _infrastructure.getPageSource();
375     } finally { }}
376 
377     /**
378      * Returns a service with the given name.
379      * 
380      * @see Infrastructure#getServiceMap()
381      * @see org.apache.tapestry.services.ServiceMap
382      */
383 
384     public IEngineService getService(String name)
385     {try { __CLOVER_71_0.M[379]++;
386         __CLOVER_71_0.S[1562]++;return _infrastructure.getServiceMap().getService(name);
387     } finally { }}
388 
389     public String getServletPath()
390     {try { __CLOVER_71_0.M[380]++;
391         __CLOVER_71_0.S[1563]++;return _servletPath;
392     } finally { }}
393 
394     /**
395      * Returns the context path, the prefix to apply to any URLs so that they are recognized as
396      * belonging to the Servlet 2.2 context.
397      * 
398      * @see org.apache.tapestry.asset.ContextAsset
399      */
400 
401     public String getContextPath()
402     {try { __CLOVER_71_0.M[381]++;
403         __CLOVER_71_0.S[1564]++;return _contextPath;
404     } finally { }}
405 
406     /** @see Infrastructure#getApplicationSpecification() */
407 
408     public IApplicationSpecification getSpecification()
409     {try { __CLOVER_71_0.M[382]++;
410         __CLOVER_71_0.S[1565]++;return _infrastructure.getApplicationSpecification();
411     } finally { }}
412 
413     /** @see Infrastructure#getSpecificationSource() */
414 
415     public ISpecificationSource getSpecificationSource()
416     {try { __CLOVER_71_0.M[383]++;
417         __CLOVER_71_0.S[1566]++;return _infrastructure.getSpecificationSource();
418     } finally { }}
419 
420     /** @see Infrastructure#getTemplateSource() */
421 
422     public TemplateSource getTemplateSource()
423     {try { __CLOVER_71_0.M[384]++;
424         __CLOVER_71_0.S[1567]++;return _infrastructure.getTemplateSource();
425     } finally { }}
426 
427     /**
428      * Reads the state serialized by {@link #writeExternal(ObjectOutput)}.
429      * <p>
430      * This always set the stateful flag. By default, a deserialized session is stateful (else, it
431      * would not have been serialized).
432      */
433 
434     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
435     {try { __CLOVER_71_0.M[385]++;
436         __CLOVER_71_0.S[1568]++;_stateful = true;
437 
438         __CLOVER_71_0.S[1569]++;String localeName = in.readUTF();
439         __CLOVER_71_0.S[1570]++;_locale = Tapestry.getLocale(localeName);
440 
441         __CLOVER_71_0.S[1571]++;_visit = in.readObject();
442     } finally { }}
443 
444     /**
445      * Writes the following properties:
446      * <ul>
447      * <li>locale name ({@link Locale#toString()})
448      * <li>visit
449      * </ul>
450      */
451 
452     public void writeExternal(ObjectOutput out) throws IOException
453     {try { __CLOVER_71_0.M[386]++;
454         __CLOVER_71_0.S[1572]++;out.writeUTF(_locale.toString());
455         __CLOVER_71_0.S[1573]++;out.writeObject(_visit);
456     } finally { }}
457 
458     /**
459      * Invoked, typically, when an exception occurs while servicing the request. This method resets
460      * the output, sets the new page and renders it.
461      */
462 
463     protected void redirect(String pageName, IRequestCycle cycle, ResponseOutputStream out,
464             ApplicationRuntimeException exception) throws IOException, ServletException
465     {try { __CLOVER_71_0.M[387]++;
466         // Discard any output from the previous page.
467 
468         __CLOVER_71_0.S[1574]++;out.reset();
469 
470         __CLOVER_71_0.S[1575]++;IPage page = cycle.getPage(pageName);
471 
472         __CLOVER_71_0.S[1576]++;cycle.activate(page);
473 
474         __CLOVER_71_0.S[1577]++;renderResponse(cycle, out);
475     } finally { }}
476 
477     public void renderResponse(IRequestCycle cycle, ResponseOutputStream output)
478             throws ServletException, IOException
479     {try { __CLOVER_71_0.M[388]++;
480         __CLOVER_71_0.S[1578]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[299] != 0)) || (++__CLOVER_71_0.CF[299] == 0))){
481             __CLOVER_71_0.S[1579]++;LOG.debug("Begin render response.");}
482 
483         // If the locale has changed during this request cycle then
484         // do the work to propogate the locale change into
485         // subsequent request cycles.
486 
487         __CLOVER_71_0.S[1580]++;if ((((_localeChanged) && (++__CLOVER_71_0.CT[300] != 0)) || (++__CLOVER_71_0.CF[300] == 0))){
488         {
489             __CLOVER_71_0.S[1581]++;_localeChanged = false;
490 
491             __CLOVER_71_0.S[1582]++;RequestContext context = cycle.getRequestContext();
492 
493             __CLOVER_71_0.S[1583]++;ApplicationServlet.writeLocaleCookie(_locale, this, context);
494         }}
495 
496         // Commit all changes and ignore further changes.
497 
498         __CLOVER_71_0.S[1584]++;IPage page = cycle.getPage();
499 
500         __CLOVER_71_0.S[1585]++;IMarkupWriter writer = page.getResponseWriter(output);
501 
502         __CLOVER_71_0.S[1586]++;output.setContentType(writer.getContentType());
503 
504         __CLOVER_71_0.S[1587]++;boolean discard = true;
505 
506         __CLOVER_71_0.S[1588]++;try
507         {
508             __CLOVER_71_0.S[1589]++;cycle.renderPage(writer);
509 
510             __CLOVER_71_0.S[1590]++;discard = false;
511         }
512         finally
513         {
514             // Closing the writer closes its PrintWriter and a whole stack of
515             // java.io objects,
516             // which tend to stream a lot of output that eventually hits the
517             // ResponseOutputStream. If we are discarding output anyway (due to
518             // an exception
519             // getting thrown during the render), we can save ourselves some
520             // trouble
521             // by ignoring it.
522 
523             __CLOVER_71_0.S[1591]++;if ((((discard) && (++__CLOVER_71_0.CT[301] != 0)) || (++__CLOVER_71_0.CF[301] == 0))){
524                 __CLOVER_71_0.S[1592]++;output.setDiscard(true);}
525 
526             __CLOVER_71_0.S[1593]++;writer.close();
527 
528             __CLOVER_71_0.S[1594]++;if ((((discard) && (++__CLOVER_71_0.CT[302] != 0)) || (++__CLOVER_71_0.CF[302] == 0))){
529                 __CLOVER_71_0.S[1595]++;output.setDiscard(false);}
530         }
531 
532     } finally { }}
533 
534     /**
535      * Invalidates the session, then redirects the client web browser to the servlet's prefix,
536      * starting a new visit.
537      * <p>
538      * Subclasses should perform their own restart (if necessary, which is rarely) before invoking
539      * this implementation.
540      */
541 
542     public void restart(IRequestCycle cycle) throws IOException
543     {try { __CLOVER_71_0.M[389]++;
544         __CLOVER_71_0.S[1596]++;RequestContext context = cycle.getRequestContext();
545 
546         __CLOVER_71_0.S[1597]++;HttpSession session = context.getSession();
547 
548         __CLOVER_71_0.S[1598]++;if ((((session != null) && (++__CLOVER_71_0.CT[303] != 0)) || (++__CLOVER_71_0.CF[303] == 0))){
549         {
550             __CLOVER_71_0.S[1599]++;try
551             {
552                 __CLOVER_71_0.S[1600]++;session.invalidate();
553             }
554             catch (IllegalStateException ex)
555             {
556                 __CLOVER_71_0.S[1601]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[304] != 0)) || (++__CLOVER_71_0.CF[304] == 0))){
557                     __CLOVER_71_0.S[1602]++;LOG.debug("Exception thrown invalidating HttpSession.", ex);}
558 
559                 // Otherwise, ignore it.
560             }
561         }}
562 
563         // Make isStateful() return false, so that the servlet doesn't
564         // try to store the engine back into the (now invalid) session.
565 
566         __CLOVER_71_0.S[1603]++;_stateful = false;
567 
568         __CLOVER_71_0.S[1604]++;String url = context.getAbsoluteURL(_servletPath);
569 
570         __CLOVER_71_0.S[1605]++;context.redirect(url);
571     } finally { }}
572 
573     /**
574      * Delegate method for the servlet. Services the request.
575      */
576 
577     public boolean service(RequestContext context) throws ServletException, IOException
578     {try { __CLOVER_71_0.M[390]++;
579         __CLOVER_71_0.S[1606]++;IRequestCycle cycle = null;
580         __CLOVER_71_0.S[1607]++;ResponseOutputStream output = null;
581         __CLOVER_71_0.S[1608]++;IMonitor monitor = null;
582 
583         __CLOVER_71_0.S[1609]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[305] != 0)) || (++__CLOVER_71_0.CF[305] == 0))){
584             __CLOVER_71_0.S[1610]++;LOG.debug("Begin service " + context.getRequestURI());}
585 
586         __CLOVER_71_0.S[1611]++;if ((((_infrastructure == null) && (++__CLOVER_71_0.CT[306] != 0)) || (++__CLOVER_71_0.CF[306] == 0))){
587             __CLOVER_71_0.S[1612]++;_infrastructure = (Infrastructure) context.getAttribute(Constants.INFRASTRUCTURE_KEY);}
588 
589         // The servlet invokes setLocale() before invoking service(). We want
590         // to ignore that setLocale() ... that is, not force a cookie to be
591         // written.
592 
593         __CLOVER_71_0.S[1613]++;_localeChanged = false;
594 
595         __CLOVER_71_0.S[1614]++;try
596         {
597             __CLOVER_71_0.S[1615]++;setupForRequest(context);
598 
599             __CLOVER_71_0.S[1616]++;monitor = getMonitor(context);
600 
601             __CLOVER_71_0.S[1617]++;output = new ResponseOutputStream(context.getResponse());
602         }
603         catch (Exception ex)
604         {
605             __CLOVER_71_0.S[1618]++;reportException(Tapestry.getMessage("AbstractEngine.unable-to-begin-request"), ex);
606 
607             __CLOVER_71_0.S[1619]++;throw new ServletException(ex.getMessage(), ex);
608         }
609 
610         __CLOVER_71_0.S[1620]++;IEngineService service = null;
611 
612         __CLOVER_71_0.S[1621]++;try
613         {
614             __CLOVER_71_0.S[1622]++;try
615             {
616                 __CLOVER_71_0.S[1623]++;String serviceName;
617 
618                 __CLOVER_71_0.S[1624]++;try
619                 {
620                     __CLOVER_71_0.S[1625]++;serviceName = extractServiceName(context);
621 
622                     __CLOVER_71_0.S[1626]++;if ((((Tapestry.isBlank(serviceName)) && (++__CLOVER_71_0.CT[307] != 0)) || (++__CLOVER_71_0.CF[307] == 0))){
623                         __CLOVER_71_0.S[1627]++;serviceName = Tapestry.HOME_SERVICE;}
624 
625                     // Must have a service to create the request cycle.
626                     // Must have a request cycle to report an exception.
627 
628                     __CLOVER_71_0.S[1628]++;service = getService(serviceName);
629                 }
630                 catch (Exception ex)
631                 {
632                     __CLOVER_71_0.S[1629]++;service = getService(Tapestry.HOME_SERVICE);
633                     __CLOVER_71_0.S[1630]++;cycle = createRequestCycle(context, service, monitor);
634 
635                     __CLOVER_71_0.S[1631]++;throw ex;
636                 }
637 
638                 __CLOVER_71_0.S[1632]++;cycle = createRequestCycle(context, service, monitor);
639 
640                 __CLOVER_71_0.S[1633]++;monitor.serviceBegin(serviceName, context.getRequestURI());
641 
642                 // Invoke the service, which returns true if it may have changed
643                 // the state of the engine (most do return true).
644 
645                 __CLOVER_71_0.S[1634]++;service.service(this, cycle, output);
646 
647                 // Return true only if the engine is actually dirty. This cuts
648                 // down
649                 // on the number of times the engine is stored into the
650                 // session unceccesarily.
651 
652                 __CLOVER_71_0.S[1635]++;return _dirty;
653             }
654             catch (PageRedirectException ex)
655             {
656                 __CLOVER_71_0.S[1636]++;handlePageRedirectException(ex, cycle, output);
657             }
658             catch (RedirectException ex)
659             {
660                 __CLOVER_71_0.S[1637]++;handleRedirectException(cycle, ex);
661             }
662             catch (StaleLinkException ex)
663             {
664                 __CLOVER_71_0.S[1638]++;handleStaleLinkException(ex, cycle, output);
665             }
666             catch (StaleSessionException ex)
667             {
668                 __CLOVER_71_0.S[1639]++;handleStaleSessionException(ex, cycle, output);
669             }
670         }
671         catch (Exception ex)
672         {
673             __CLOVER_71_0.S[1640]++;monitor.serviceException(ex);
674 
675             // Discard any output (if possible). If output has already been sent
676             // to
677             // the client, then things get dicey. Note that this block
678             // gets activated if the StaleLink or StaleSession pages throws
679             // any kind of exception.
680 
681             // Attempt to switch to the exception page. However, this may itself
682             // fail
683             // for a number of reasons, in which case a ServletException is
684             // thrown.
685 
686             __CLOVER_71_0.S[1641]++;output.reset();
687 
688             __CLOVER_71_0.S[1642]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[308] != 0)) || (++__CLOVER_71_0.CF[308] == 0))){
689                 __CLOVER_71_0.S[1643]++;LOG.debug("Uncaught exception", ex);}
690 
691             __CLOVER_71_0.S[1644]++;activateExceptionPage(cycle, output, ex);
692         }
693         finally
694         {
695             __CLOVER_71_0.S[1645]++;if ((((service != null) && (++__CLOVER_71_0.CT[309] != 0)) || (++__CLOVER_71_0.CF[309] == 0))){
696                 __CLOVER_71_0.S[1646]++;monitor.serviceEnd(service.getName());}
697 
698             __CLOVER_71_0.S[1647]++;try
699             {
700                 __CLOVER_71_0.S[1648]++;cycle.cleanup();
701 
702                 // Closing the buffered output closes the underlying stream as
703                 // well.
704 
705                 __CLOVER_71_0.S[1649]++;if ((((output != null) && (++__CLOVER_71_0.CT[310] != 0)) || (++__CLOVER_71_0.CF[310] == 0))){
706                     __CLOVER_71_0.S[1650]++;output.forceFlush();}
707 
708                 __CLOVER_71_0.S[1651]++;cleanupAfterRequest(cycle);
709             }
710             catch (Exception ex)
711             {
712                 __CLOVER_71_0.S[1652]++;reportException(Tapestry.getMessage("AbstractEngine.exception-during-cleanup"), ex);
713             }
714 
715             __CLOVER_71_0.S[1653]++;if ((((_disableCaching) && (++__CLOVER_71_0.CT[311] != 0)) || (++__CLOVER_71_0.CF[311] == 0))){
716             {
717                 __CLOVER_71_0.S[1654]++;try
718                 {
719                     __CLOVER_71_0.S[1655]++;clearCachedData();
720                 }
721                 catch (Exception ex)
722                 {
723                     __CLOVER_71_0.S[1656]++;reportException(Tapestry
724                             .getMessage("AbstractEngine.exception-during-cache-clear"), ex);
725                 }
726             }}
727 
728             __CLOVER_71_0.S[1657]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[312] != 0)) || (++__CLOVER_71_0.CF[312] == 0))){
729                 __CLOVER_71_0.S[1658]++;LOG.debug("End service");}
730 
731         }
732 
733         __CLOVER_71_0.S[1659]++;return _dirty;
734     } finally { }}
735 
736     /**
737      * Handles {@link PageRedirectException}which involves executing
738      * {@link IPage#validate(IRequestCycle)}on the target page (of the exception), until either a
739      * loop is found, or a page succesfully validates and can be activated.
740      * <p>
741      * This should generally not be overriden in subclasses.
742      * 
743      * @since 3.0
744      */
745 
746     protected void handlePageRedirectException(PageRedirectException ex, IRequestCycle cycle,
747             ResponseOutputStream output) throws IOException, ServletException
748     {try { __CLOVER_71_0.M[391]++;
749         __CLOVER_71_0.S[1660]++;List pageNames = new ArrayList();
750 
751         __CLOVER_71_0.S[1661]++;String pageName = ex.getTargetPageName();
752 
753         __CLOVER_71_0.S[1662]++;while (true){
754         {
755             __CLOVER_71_0.S[1663]++;if ((((pageNames.contains(pageName)) && (++__CLOVER_71_0.CT[313] != 0)) || (++__CLOVER_71_0.CF[313] == 0))){
756             {
757                 // Add the offending page to pageNames so it shows in the
758                 // list.
759 
760                 __CLOVER_71_0.S[1664]++;pageNames.add(pageName);
761 
762                 __CLOVER_71_0.S[1665]++;StringBuffer buffer = new StringBuffer();
763                 __CLOVER_71_0.S[1666]++;int count = pageNames.size();
764 
765                 __CLOVER_71_0.S[1667]++;for (int i = 0; (((i < count) && (++__CLOVER_71_0.CT[314] != 0)) || (++__CLOVER_71_0.CF[314] == 0)); i++){
766                 {
767                     __CLOVER_71_0.S[1668]++;if ((((i > 0) && (++__CLOVER_71_0.CT[315] != 0)) || (++__CLOVER_71_0.CF[315] == 0))){
768                         __CLOVER_71_0.S[1669]++;buffer.append("; ");}
769 
770                     __CLOVER_71_0.S[1670]++;buffer.append(pageNames.get(i));
771                 }}
772 
773                 __CLOVER_71_0.S[1671]++;throw new ApplicationRuntimeException(Tapestry.format(
774                         "AbstractEngine.validate-cycle",
775                         buffer.toString()));
776             }}
777 
778             // Record that this page has been a target.
779 
780             __CLOVER_71_0.S[1672]++;pageNames.add(pageName);
781 
782             __CLOVER_71_0.S[1673]++;try
783             {
784                 // Attempt to activate the new page.
785 
786                 __CLOVER_71_0.S[1674]++;cycle.activate(pageName);
787 
788                 __CLOVER_71_0.S[1675]++;break;
789             }
790             catch (PageRedirectException ex2)
791             {
792                 __CLOVER_71_0.S[1676]++;pageName = ex2.getTargetPageName();
793             }
794         }}
795 
796         // Discard any output from the previous page.
797 
798         __CLOVER_71_0.S[1677]++;output.reset();
799 
800         __CLOVER_71_0.S[1678]++;renderResponse(cycle, output);
801     } finally { }}
802 
803     /**
804      * Invoked from {@link #service(RequestContext)}to create an instance of {@link IRequestCycle}
805      * for the current request. This implementation creates an returns an instance of
806      * {@link RequestCycle}.
807      * 
808      * @since 3.0
809      */
810 
811     protected IRequestCycle createRequestCycle(RequestContext context, IEngineService service,
812             IMonitor monitor)
813     {try { __CLOVER_71_0.M[392]++;
814         __CLOVER_71_0.S[1679]++;return new RequestCycle(this, context, service, monitor);
815     } finally { }}
816 
817     /**
818      * Invoked by {@link #service(RequestContext)}if a {@link StaleLinkException}is thrown by the
819      * {@link IEngineService service}. This implementation sets the message property of the
820      * StaleLink page to the message provided in the exception, then invokes
821      * {@link #redirect(String, IRequestCycle, ResponseOutputStream, ApplicationRuntimeException)}
822      * to render the StaleLink page.
823      * <p>
824      * Subclasses may overide this method (without invoking this implementation). A common practice
825      * is to present an error message on the application's Home page.
826      * <p>
827      * Alternately, the application may provide its own version of the StaleLink page, overriding
828      * the framework's implementation (probably a good idea, because the default page hints at
829      * "application errors" and isn't localized). The overriding StaleLink implementation must
830      * implement a message property of type String.
831      * 
832      * @since 0.2.10
833      */
834 
835     protected void handleStaleLinkException(StaleLinkException ex, IRequestCycle cycle,
836             ResponseOutputStream output) throws IOException, ServletException
837     {try { __CLOVER_71_0.M[393]++;
838         __CLOVER_71_0.S[1680]++;String staleLinkPageName = getStaleLinkPageName();
839         __CLOVER_71_0.S[1681]++;IPage page = cycle.getPage(staleLinkPageName);
840 
841         __CLOVER_71_0.S[1682]++;page.setProperty("message", ex.getMessage());
842 
843         __CLOVER_71_0.S[1683]++;redirect(staleLinkPageName, cycle, output, ex);
844     } finally { }}
845 
846     /**
847      * Invoked by {@link #service(RequestContext)}if a {@link StaleSessionException}is thrown by
848      * the {@link IEngineService service}. This implementation invokes
849      * {@link #redirect(String, IRequestCycle, ResponseOutputStream, ApplicationRuntimeException)}
850      * to render the StaleSession page.
851      * <p>
852      * Subclasses may overide this method (without invoking this implementation). A common practice
853      * is to present an eror message on the application's Home page.
854      * 
855      * @since 0.2.10
856      */
857 
858     protected void handleStaleSessionException(StaleSessionException ex, IRequestCycle cycle,
859             ResponseOutputStream output) throws IOException, ServletException
860     {try { __CLOVER_71_0.M[394]++;
861         __CLOVER_71_0.S[1684]++;redirect(getStaleSessionPageName(), cycle, output, ex);
862     } finally { }}
863 
864     /**
865      * Discards all cached pages, component specifications and templates. Subclasses who override
866      * this method should invoke this implementation as well.
867      * 
868      * @since 1.0.1
869      */
870 
871     public void clearCachedData()
872     {try { __CLOVER_71_0.M[395]++;
873         __CLOVER_71_0.S[1685]++;_infrastructure.getResetEventCoordinator().fireResetEvent();
874     } finally { }}
875 
876     /**
877      * Changes the locale for the engine.
878      */
879 
880     public void setLocale(Locale value)
881     {try { __CLOVER_71_0.M[396]++;
882         __CLOVER_71_0.S[1686]++;Tapestry.notNull(value, "locale");
883 
884         // Because locale changes are expensive (it involves writing a cookie
885         // and all that),
886         // we're careful not to really change unless there's a true change in
887         // value.
888 
889         __CLOVER_71_0.S[1687]++;if ((((!value.equals(_locale)) && (++__CLOVER_71_0.CT[316] != 0)) || (++__CLOVER_71_0.CF[316] == 0))){
890         {
891             __CLOVER_71_0.S[1688]++;_locale = value;
892             __CLOVER_71_0.S[1689]++;_localeChanged = true;
893             __CLOVER_71_0.S[1690]++;markDirty();
894         }}
895     } finally { }}
896 
897     /**
898      * Invoked from {@link #service(RequestContext)}to ensure that the engine's instance variables
899      * are setup. This allows the application a chance to restore transient variables that will not
900      * have survived deserialization. Determines the servlet prefix: this is the base URL used by
901      * {@link IEngineService services}to build URLs. It consists of two parts: the context path and
902      * the servlet path.
903      * <p>
904      * The servlet path is retrieved from {@link HttpServletRequest#getServletPath()}.
905      * <p>
906      * The context path is retrieved from {@link HttpServletRequest#getContextPath()}.
907      * <p>
908      * The global object is retrieved from {@link IEngine#getGlobal()}method.
909      * <p>
910      * The final path is available via the {@link #getServletPath()}method.
911      * <p>
912      * In addition, this method locates and/or creates the:
913      * <ul>
914      * <li>{@link IComponentClassEnhancer}
915      * <li>{@link Pool}
916      * <li>{@link ITemplateSource}
917      * <li>{@link ISpecificationSource}
918      * <li>{@link IPageSource}
919      * <li>{@link IEngineService}{@link Map}<ll>{@link IScriptSource}
920      * <li>{@link IComponentMessagesSource}
921      * <li>{@link IPropertySource}
922      * </ul>
923      * <p>
924      * This order is important, because some of the later shared objects depend on some of the
925      * earlier shared objects already having been located or created (especially
926      * {@link #getPool() pool}).
927      * <p>
928      * Subclasses should invoke this implementation first, then perform their own setup.
929      */
930 
931     protected void setupForRequest(RequestContext context)
932     {try { __CLOVER_71_0.M[397]++;
933         __CLOVER_71_0.S[1691]++;HttpServlet servlet = context.getServlet();
934         __CLOVER_71_0.S[1692]++;ServletContext servletContext = servlet.getServletContext();
935         __CLOVER_71_0.S[1693]++;HttpServletRequest request = context.getRequest();
936         __CLOVER_71_0.S[1694]++;HttpSession session = context.getSession();
937 
938         __CLOVER_71_0.S[1695]++;if ((((session != null) && (++__CLOVER_71_0.CT[317] != 0)) || (++__CLOVER_71_0.CF[317] == 0))){
939             __CLOVER_71_0.S[1696]++;_sessionId = context.getSession().getId();}
940         else{
941             __CLOVER_71_0.S[1697]++;_sessionId = null;}
942 
943         // Previously, this used getRemoteHost(), but that requires an
944         // expensive reverse DNS lookup. Possibly, the host name lookup
945         // should occur ... but only if there's an actual error message
946         // to display.
947 
948         __CLOVER_71_0.S[1698]++;if ((((_clientAddress == null) && (++__CLOVER_71_0.CT[318] != 0)) || (++__CLOVER_71_0.CF[318] == 0))){
949             __CLOVER_71_0.S[1699]++;_clientAddress = request.getRemoteAddr();}
950 
951         // servletPath is null, so this means either we're doing the
952         // first request in this session, or we're handling a subsequent
953         // request in another JVM (i.e. another server in the cluster).
954         // In any case, we have to do some late (re-)initialization.
955 
956         __CLOVER_71_0.S[1700]++;if ((((_servletPath == null) && (++__CLOVER_71_0.CT[319] != 0)) || (++__CLOVER_71_0.CF[319] == 0))){
957         {
958             // Get the path *within* the servlet context
959 
960             // In rare cases related to the tagsupport service, getServletPath()
961             // is wrong
962             // (its a JSP, which invokes Tapestry as an include, thus muddling
963             // what
964             // the real servlet and servlet path is). In those cases, the JSP
965             // tag
966             // will inform us.
967 
968             __CLOVER_71_0.S[1701]++;String path = (String) request
969                     .getAttribute(Tapestry.TAG_SUPPORT_SERVLET_PATH_ATTRIBUTE);
970 
971             __CLOVER_71_0.S[1702]++;if ((((path == null) && (++__CLOVER_71_0.CT[320] != 0)) || (++__CLOVER_71_0.CF[320] == 0))){
972                 __CLOVER_71_0.S[1703]++;path = request.getServletPath();}
973 
974             // Get the context path, which may be the empty string
975             // (but won't be null).
976 
977             __CLOVER_71_0.S[1704]++;_contextPath = request.getContextPath();
978 
979             __CLOVER_71_0.S[1705]++;_servletPath = _contextPath + path;
980         }}
981 
982         __CLOVER_71_0.S[1706]++;String servletName = context.getServlet().getServletName();
983 
984         __CLOVER_71_0.S[1707]++;if ((((_global == null) && (++__CLOVER_71_0.CT[321] != 0)) || (++__CLOVER_71_0.CF[321] == 0))){
985         {
986             __CLOVER_71_0.S[1708]++;String name = GLOBAL_NAME + ":" + servletName;
987 
988             __CLOVER_71_0.S[1709]++;_global = servletContext.getAttribute(name);
989 
990             __CLOVER_71_0.S[1710]++;if ((((_global == null) && (++__CLOVER_71_0.CT[322] != 0)) || (++__CLOVER_71_0.CF[322] == 0))){
991             {
992                 __CLOVER_71_0.S[1711]++;_global = createGlobal(context);
993 
994                 __CLOVER_71_0.S[1712]++;servletContext.setAttribute(name, _global);
995             }}
996         }}
997 
998         __CLOVER_71_0.S[1713]++;String encoding = request.getCharacterEncoding();
999         __CLOVER_71_0.S[1714]++;if ((((encoding == null) && (++__CLOVER_71_0.CT[323] != 0)) || (++__CLOVER_71_0.CF[323] == 0))){
1000        {
1001            __CLOVER_71_0.S[1715]++;encoding = getOutputEncoding();
1002            __CLOVER_71_0.S[1716]++;try
1003            {
1004                __CLOVER_71_0.S[1717]++;request.setCharacterEncoding(encoding);
1005            }
1006            catch (UnsupportedEncodingException e)
1007            {
1008                __CLOVER_71_0.S[1718]++;throw new IllegalArgumentException(Tapestry.format("illegal-encoding", encoding));
1009            }
1010            catch (NoSuchMethodError e)
1011            {
1012                // Servlet API 2.2 compatibility
1013                // Behave okay if the setCharacterEncoding() method is
1014                // unavailable
1015            }
1016            catch (AbstractMethodError e)
1017            {
1018                // Servlet API 2.2 compatibility
1019                // Behave okay if the setCharacterEncoding() method is
1020                // unavailable
1021            }
1022        }}
1023    } finally { }}
1024
1025    /**
1026     * @see Infrastructure#getClassResolver()
1027     */
1028
1029    public ClassResolver getClassResolver()
1030    {try { __CLOVER_71_0.M[398]++;
1031        __CLOVER_71_0.S[1719]++;return _infrastructure.getClassResolver();
1032    } finally { }}
1033
1034    /**
1035     * Generates a description of the instance. Invokes {@link #extendDescription(ToStringBuilder)}
1036     * to fill in details about the instance.
1037     * 
1038     * @see #extendDescription(ToStringBuilder)
1039     */
1040
1041    public String toString()
1042    {try { __CLOVER_71_0.M[399]++;
1043        __CLOVER_71_0.S[1720]++;ToStringBuilder builder = new ToStringBuilder(this);
1044
1045        __CLOVER_71_0.S[1721]++;builder.append("dirty", _dirty);
1046        __CLOVER_71_0.S[1722]++;builder.append("locale", _locale);
1047        __CLOVER_71_0.S[1723]++;builder.append("stateful", _stateful);
1048        __CLOVER_71_0.S[1724]++;builder.append("visit", _visit);
1049
1050        __CLOVER_71_0.S[1725]++;extendDescription(builder);
1051
1052        __CLOVER_71_0.S[1726]++;return builder.toString();
1053    } finally { }}
1054
1055    /**
1056     * Returns true if the reset service is curently enabled.
1057     */
1058
1059    public boolean isResetServiceEnabled()
1060    {try { __CLOVER_71_0.M[400]++;
1061        __CLOVER_71_0.S[1727]++;return _resetServiceEnabled;
1062    } finally { }}
1063
1064    /**
1065     * Implemented by subclasses to return the names of the active pages (pages for which recorders
1066     * exist). May return the empty list, but should not return null.
1067     */
1068
1069    abstract public Collection getActivePageNames();
1070
1071    /**
1072     * Gets the visit object, if it has been created already.
1073     * <p>
1074     * If the visit is non-null then the {@link #isDirty()}flag is set (because the engine can't
1075     * tell what the caller will <i>do </i> with the visit).
1076     */
1077
1078    public Object getVisit()
1079    {try { __CLOVER_71_0.M[401]++;
1080        __CLOVER_71_0.S[1728]++;if ((((_visit != null) && (++__CLOVER_71_0.CT[324] != 0)) || (++__CLOVER_71_0.CF[324] == 0))){
1081            __CLOVER_71_0.S[1729]++;markDirty();}
1082
1083        __CLOVER_71_0.S[1730]++;return _visit;
1084    } finally { }}
1085
1086    /**
1087     * Gets the visit object, invoking {@link #createVisit(IRequestCycle)}to create it lazily if
1088     * needed. If cycle is null, the visit will not be lazily created.
1089     * <p>
1090     * After creating the visit, but before returning, the {@link HttpSession}will be created, and
1091     * {@link #setStateful()}will be invoked.
1092     * <p>
1093     * Sets the {@link #isDirty()}flag, if the return value is not null.
1094     */
1095
1096    public Object getVisit(IRequestCycle cycle)
1097    {try { __CLOVER_71_0.M[402]++;
1098        __CLOVER_71_0.S[1731]++;if ((((_visit == null && cycle != null) && (++__CLOVER_71_0.CT[325] != 0)) || (++__CLOVER_71_0.CF[325] == 0))){
1099        {
1100            __CLOVER_71_0.S[1732]++;_visit = createVisit(cycle);
1101
1102            // Now that a visit object exists, we need to force the creation
1103            // of a HttpSession.
1104
1105            __CLOVER_71_0.S[1733]++;cycle.getRequestContext().createSession();
1106
1107            __CLOVER_71_0.S[1734]++;setStateful();
1108        }}
1109
1110        __CLOVER_71_0.S[1735]++;if ((((_visit != null) && (++__CLOVER_71_0.CT[326] != 0)) || (++__CLOVER_71_0.CF[326] == 0))){
1111            __CLOVER_71_0.S[1736]++;markDirty();}
1112
1113        __CLOVER_71_0.S[1737]++;return _visit;
1114    } finally { }}
1115
1116    /**
1117     * Updates the visit object and sets the {@link #isDirty() dirty flag}.
1118     */
1119
1120    public void setVisit(Object value)
1121    {try { __CLOVER_71_0.M[403]++;
1122        __CLOVER_71_0.S[1738]++;_visit = value;
1123
1124        __CLOVER_71_0.S[1739]++;markDirty();
1125    } finally { }}
1126
1127    public boolean getHasVisit()
1128    {try { __CLOVER_71_0.M[404]++;
1129        __CLOVER_71_0.S[1740]++;return _visit != null;
1130    } finally { }}
1131
1132    /**
1133     * Invoked to lazily create a new visit object when it is first referenced (by
1134     * {@link #getVisit(IRequestCycle)}). This implementation works by looking up the name of the
1135     * class to instantiate in the {@link #getPropertySource() configuration}.
1136     * <p>
1137     * Subclasses may want to overide this method if some other means of instantiating a visit
1138     * object is required.
1139     */
1140
1141    protected Object createVisit(IRequestCycle cycle)
1142    {try { __CLOVER_71_0.M[405]++;
1143        __CLOVER_71_0.S[1741]++;String visitClassName;
1144        __CLOVER_71_0.S[1742]++;Class visitClass;
1145        __CLOVER_71_0.S[1743]++;Object result = null;
1146
1147        __CLOVER_71_0.S[1744]++;visitClassName = getPropertySource().getPropertyValue(VISIT_CLASS_PROPERTY_NAME);
1148
1149        __CLOVER_71_0.S[1745]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[327] != 0)) || (++__CLOVER_71_0.CF[327] == 0))){
1150            __CLOVER_71_0.S[1746]++;LOG.debug("Creating visit object as instance of " + visitClassName);}
1151
1152        __CLOVER_71_0.S[1747]++;visitClass = getClassResolver().findClass(visitClassName);
1153
1154        __CLOVER_71_0.S[1748]++;try
1155        {
1156            __CLOVER_71_0.S[1749]++;result = visitClass.newInstance();
1157        }
1158        catch (Throwable t)
1159        {
1160            __CLOVER_71_0.S[1750]++;throw new ApplicationRuntimeException(Tapestry.format(
1161                    "AbstractEngine.unable-to-instantiate-visit",
1162                    visitClassName), t);
1163        }
1164
1165        __CLOVER_71_0.S[1751]++;return result;
1166    } finally { }}
1167
1168    /**
1169     * Returns the global object for the application. The global object is created at the start of
1170     * the request ({@link #setupForRequest(RequestContext)}invokes
1171     * {@link #createGlobal(RequestContext)}if needed), and is stored into the
1172     * {@link ServletContext}. All instances of the engine for the application share the global
1173     * object; however, the global object is explicitly <em>not</em> replicated to other servers
1174     * within a cluster.
1175     * 
1176     * @since 2.3
1177     */
1178
1179    public Object getGlobal()
1180    {try { __CLOVER_71_0.M[406]++;
1181        __CLOVER_71_0.S[1752]++;return _global;
1182    } finally { }}
1183
1184    public IScriptSource getScriptSource()
1185    {try { __CLOVER_71_0.M[407]++;
1186        __CLOVER_71_0.S[1753]++;return _infrastructure.getScriptSource();
1187    } finally { }}
1188
1189    public boolean isStateful()
1190    {try { __CLOVER_71_0.M[408]++;
1191        __CLOVER_71_0.S[1754]++;return _stateful;
1192    } finally { }}
1193
1194    /**
1195     * Invoked by subclasses to indicate that some state must now be stored in the engine (and that
1196     * the engine should now be stored in the HttpSession). The caller is responsible for actually
1197     * creating the HttpSession (it will have access to the {@link RequestContext}).
1198     * 
1199     * @since 1.0.2
1200     */
1201
1202    protected void setStateful()
1203    {try { __CLOVER_71_0.M[409]++;
1204        __CLOVER_71_0.S[1755]++;_stateful = true;
1205    } finally { }}
1206
1207    /**
1208     * Allows subclasses to include listener methods easily.
1209     * 
1210     * @since 1.0.2
1211     */
1212
1213    public ListenerMap getListeners()
1214    {try { __CLOVER_71_0.M[410]++;
1215        __CLOVER_71_0.S[1756]++;if ((((_listeners == null) && (++__CLOVER_71_0.CT[328] != 0)) || (++__CLOVER_71_0.CF[328] == 0))){
1216            __CLOVER_71_0.S[1757]++;_listeners = new ListenerMap(this);}
1217
1218        __CLOVER_71_0.S[1758]++;return _listeners;
1219    } finally { }}
1220
1221    /**
1222     * Invoked when a {@link RedirectException}is thrown during the processing of a request.
1223     * 
1224     * @throws ApplicationRuntimeException
1225     *             if an {@link IOException},{@link ServletException}is thrown by the redirect,
1226     *             or if no {@link RequestDispatcher}can be found for local resource.
1227     * @since 2.2
1228     */
1229
1230    protected void handleRedirectException(IRequestCycle cycle, RedirectException ex)
1231    {try { __CLOVER_71_0.M[411]++;
1232        __CLOVER_71_0.S[1759]++;String location = ex.getRedirectLocation();
1233
1234        __CLOVER_71_0.S[1760]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_71_0.CT[329] != 0)) || (++__CLOVER_71_0.CF[329] == 0))){
1235            __CLOVER_71_0.S[1761]++;LOG.debug("Redirecting to: " + location);}
1236
1237        __CLOVER_71_0.S[1762]++;RedirectAnalyzer analyzer = new RedirectAnalyzer(location);
1238
1239        __CLOVER_71_0.S[1763]++;analyzer.process(cycle);
1240    } finally { }}
1241
1242    /**
1243     * @since 2.0.4
1244     */
1245
1246    public ComponentMessagesSource getComponentMessagesSource()
1247    {try { __CLOVER_71_0.M[412]++;
1248        __CLOVER_71_0.S[1764]++;return _infrastructure.getComponentMessagesSource();
1249    } finally { }}
1250
1251    /**
1252     * @see Infrastructure#getDataSqueezer()
1253     */
1254
1255    public DataSqueezer getDataSqueezer()
1256    {try { __CLOVER_71_0.M[413]++;
1257        __CLOVER_71_0.S[1765]++;return _infrastructure.getDataSqueezer();
1258    } finally { }}
1259
1260    /**
1261     * Invoked from {@link #service(RequestContext)}to extract, from the URL, the name of the
1262     * service. The current implementation expects the first pathInfo element to be the service
1263     * name. At some point in the future, the method of constructing and parsing URLs may be
1264     * abstracted into a developer-selected class.
1265     * <p>
1266     * Subclasses may override this method if the application defines specific services with unusual
1267     * URL encoding rules.
1268     * <p>
1269     * This implementation simply extracts the value for query parameter
1270     * {@link Tapestry#SERVICE_QUERY_PARAMETER_NAME}and extracts the service name from that.
1271     * <p>
1272     * For supporting the JSP tags, this method first checks for attribute
1273     * {@link Tapestry#TAG_SUPPORT_SERVICE_ATTRIBUTE}. If non-null, then
1274     * {@link Tapestry#TAGSUPPORT_SERVICE}is returned.
1275     * 
1276     * @since 2.2
1277     */
1278
1279    protected String extractServiceName(RequestContext context)
1280    {try { __CLOVER_71_0.M[414]++;
1281        __CLOVER_71_0.S[1766]++;if ((((context.getRequest().getAttribute(Tapestry.TAG_SUPPORT_SERVICE_ATTRIBUTE) != null) && (++__CLOVER_71_0.CT[330] != 0)) || (++__CLOVER_71_0.CF[330] == 0))){
1282            __CLOVER_71_0.S[1767]++;return Tapestry.TAGSUPPORT_SERVICE;}
1283
1284        __CLOVER_71_0.S[1768]++;String serviceData = context.getParameter(Tapestry.SERVICE_QUERY_PARAMETER_NAME);
1285
1286        __CLOVER_71_0.S[1769]++;if ((((serviceData == null) && (++__CLOVER_71_0.CT[331] != 0)) || (++__CLOVER_71_0.CF[331] == 0))){
1287            __CLOVER_71_0.S[1770]++;return Tapestry.HOME_SERVICE;}
1288
1289        // The service name is anything before the first slash,
1290        // if there is one.
1291
1292        __CLOVER_71_0.S[1771]++;int slashx = serviceData.indexOf('/');
1293
1294        __CLOVER_71_0.S[1772]++;if ((((slashx < 0) && (++__CLOVER_71_0.CT[332] != 0)) || (++__CLOVER_71_0.CF[332] == 0))){
1295            __CLOVER_71_0.S[1773]++;return serviceData;}
1296
1297        __CLOVER_71_0.S[1774]++;return serviceData.substring(0, slashx);
1298    } finally { }}
1299
1300    /** @since 2.3 */
1301
1302    public IPropertySource getPropertySource()
1303    {try { __CLOVER_71_0.M[415]++;
1304        __CLOVER_71_0.S[1775]++;return _infrastructure.getApplicationPropertySource();
1305    } finally { }}
1306
1307    /** @since 3.0 */
1308
1309    protected String getExceptionPageName()
1310    {try { __CLOVER_71_0.M[416]++;
1311        __CLOVER_71_0.S[1776]++;return EXCEPTION_PAGE;
1312    } finally { }}
1313
1314    /** @since 3.0 */
1315
1316    protected String getStaleLinkPageName()
1317    {try { __CLOVER_71_0.M[417]++;
1318        __CLOVER_71_0.S[1777]++;return STALE_LINK_PAGE;
1319    } finally { }}
1320
1321    /** @since 3.0 */
1322
1323    protected String getStaleSessionPageName()
1324    {try { __CLOVER_71_0.M[418]++;
1325        __CLOVER_71_0.S[1778]++;return STALE_SESSION_PAGE;
1326    } finally { }}
1327
1328    /**
1329     * Creates the shared Global object. This implementation looks for an configuration property,
1330     * <code>org.apache.tapestry.global-class</code>, and instantiates that class using a
1331     * no-arguments constructor. If the property is not defined, a synchronized
1332     * {@link java.util.HashMap}is created.
1333     * 
1334     * @since 2.3
1335     */
1336
1337    protected Object createGlobal(RequestContext context)
1338    {try { __CLOVER_71_0.M[419]++;
1339        __CLOVER_71_0.S[1779]++;String className = getPropertySource().getPropertyValue("org.apache.tapestry.global-class");
1340
1341        __CLOVER_71_0.S[1780]++;if ((((Tapestry.isBlank(className)) && (++__CLOVER_71_0.CT[333] != 0)) || (++__CLOVER_71_0.CF[333] == 0))){
1342            __CLOVER_71_0.S[1781]++;return Collections.synchronizedMap(new HashMap());}
1343
1344        __CLOVER_71_0.S[1782]++;Class globalClass = getClassResolver().findClass(className);
1345
1346        __CLOVER_71_0.S[1783]++;try
1347        {
1348            __CLOVER_71_0.S[1784]++;return globalClass.newInstance();
1349        }
1350        catch (Exception ex)
1351        {
1352            __CLOVER_71_0.S[1785]++;throw new ApplicationRuntimeException(Tapestry.format(
1353                    "AbstractEngine.unable-to-instantiate-global",
1354                    className), ex);
1355        }
1356    } finally { }}
1357
1358    /** @see Infrastructure#getObjectPool() */
1359
1360    public ObjectPool getPool()
1361    {try { __CLOVER_71_0.M[420]++;
1362        __CLOVER_71_0.S[1786]++;return _infrastructure.getObjectPool();
1363    } finally { }}
1364
1365    /** @see Infrastructure#getComponentClassEnhancer() */
1366
1367    public IComponentClassEnhancer getComponentClassEnhancer()
1368    {try { __CLOVER_71_0.M[421]++;
1369        __CLOVER_71_0.S[1787]++;return _infrastructure.getComponentClassEnhancer();
1370    } finally { }}
1371
1372    /**
1373     * Returns true if the engine has (potentially) changed state since the last time it was stored
1374     * into the {@link javax.servlet.http.HttpSession}. Various events set this property to true.
1375     * 
1376     * @since 3.0
1377     */
1378
1379    public boolean isDirty()
1380    {try { __CLOVER_71_0.M[422]++;
1381        __CLOVER_71_0.S[1788]++;return _dirty;
1382    } finally { }}
1383
1384    /**
1385     * Invoked to set the dirty flag, indicating that the engine should be stored into the
1386     * {@link javax.servlet.http.HttpSession}.
1387     * 
1388     * @since 3.0
1389     */
1390
1391    protected void markDirty()
1392    {try { __CLOVER_71_0.M[423]++;
1393        __CLOVER_71_0.S[1789]++;if ((((!_dirty) && (++__CLOVER_71_0.CT[334] != 0)) || (++__CLOVER_71_0.CF[334] == 0))){
1394            __CLOVER_71_0.S[1790]++;LOG.debug("Setting dirty flag.");}
1395
1396        __CLOVER_71_0.S[1791]++;_dirty = true;
1397    } finally { }}
1398
1399    /**
1400     * Clears the dirty flag when a engine is stored into the {@link HttpSession}.
1401     * 
1402     * @since 3.0
1403     */
1404
1405    public void valueBound(HttpSessionBindingEvent arg0)
1406    {try { __CLOVER_71_0.M[424]++;
1407        __CLOVER_71_0.S[1792]++;LOG.debug((((_dirty ) && (++__CLOVER_71_0.CT[335] != 0)) || (++__CLOVER_71_0.CF[335] == 0))? "Clearing dirty flag." : "Dirty flag already cleared.");
1408
1409        __CLOVER_71_0.S[1793]++;_dirty = false;
1410    } finally { }}
1411
1412    /**
1413     * Does nothing.
1414     * 
1415     * @since 3.0
1416     */
1417
1418    public void valueUnbound(HttpSessionBindingEvent arg0)
1419    {try { __CLOVER_71_0.M[425]++;
1420    } finally { }}
1421
1422    /**
1423     * The encoding to be used if none has been defined using the output encoding property. Override
1424     * this method to change the default.
1425     * 
1426     * @return the default output encoding
1427     * @since 3.0
1428     */
1429    protected String getDefaultOutputEncoding()
1430    {try { __CLOVER_71_0.M[426]++;
1431        __CLOVER_71_0.S[1794]++;return DEFAULT_OUTPUT_ENCODING;
1432    } finally { }}
1433
1434    /**
1435     * Returns the encoding to be used to generate the servlet responses and accept the servlet
1436     * requests. The encoding is defined using the org.apache.tapestry.output-encoding and is UTF-8
1437     * by default
1438     * 
1439     * @since 3.0
1440     * @see org.apache.tapestry.IEngine#getOutputEncoding()
1441     */
1442    public String getOutputEncoding()
1443    {try { __CLOVER_71_0.M[427]++;
1444        __CLOVER_71_0.S[1795]++;IPropertySource source = getPropertySource();
1445
1446        __CLOVER_71_0.S[1796]++;String encoding = source.getPropertyValue(OUTPUT_ENCODING_PROPERTY_NAME);
1447        __CLOVER_71_0.S[1797]++;if ((((encoding == null) && (++__CLOVER_71_0.CT[336] != 0)) || (++__CLOVER_71_0.CF[336] == 0))){
1448            __CLOVER_71_0.S[1798]++;encoding = getDefaultOutputEncoding();}
1449
1450        __CLOVER_71_0.S[1799]++;return encoding;
1451    } finally { }}
1452
1453}