blob: 88eba91729e7715c8923bc58e1294fa7b6337c19 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="Date-Revision-yyyymmdd" content="20140918"/>
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Execute and Wait Interceptor</title>
<link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,400italic,600italic,700italic" rel="stylesheet" type="text/css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link href="/css/main.css" rel="stylesheet">
<link href="/css/custom.css" rel="stylesheet">
<link href="/highlighter/github-theme.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/js/community.js"></script>
</head>
<body>
<a href="http://github.com/apache/struts" class="github-ribbon">
<img style="position: absolute; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub">
</a>
<header>
<nav>
<div role="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#struts-menu" class="navbar-toggle">
Menu
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/index.html" class="navbar-brand logo"><img src="/img/struts-logo.svg"></a>
</div>
<div id="struts-menu" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Home<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/index.html">Welcome</a></li>
<li><a href="/download.cgi">Download</a></li>
<li><a href="/releases.html">Releases</a></li>
<li><a href="/announce-2021.html">Announcements</a></li>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks!</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Support<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/mail.html">User Mailing List</a></li>
<li><a href="https://issues.apache.org/jira/browse/WW">Issue Tracker</a></li>
<li><a href="/security.html">Reporting Security Issues</a></li>
<li class="divider"></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Migration+Guide">Version Notes</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Security+Bulletins">Security Bulletins</a></li>
<li class="divider"></li>
<li><a href="/maven/project-info.html">Maven Project Info</a></li>
<li><a href="/maven/struts2-core/dependencies.html">Struts Core Dependencies</a></li>
<li><a href="/maven/struts2-plugins/modules.html">Plugin Dependencies</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Documentation<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/birdseye.html">Birds Eye</a></li>
<li><a href="/primer.html">Key Technologies</a></li>
<li><a href="/kickstart.html">Kickstart FAQ</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Home">Wiki</a></li>
<li class="divider"></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/security/">Security Guide</a></li>
<li><a href="/core-developers/">Core Developers Guide</a></li>
<li><a href="/tag-developers/">Tag Developers Guide</a></li>
<li><a href="/maven-archetypes/">Maven Archetypes</a></li>
<li><a href="/plugins/">Plugins</a></li>
<li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li>
<li><a href="/tag-developers/tag-reference.html">Tag reference</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/FAQs">FAQs</a></li>
<li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Contributing<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/youatstruts.html">You at Struts</a></li>
<li><a href="/helping.html">How to Help FAQ</a></li>
<li><a href="/dev-mail.html">Development Lists</a></li>
<li><a href="/contributors/">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/submitting-patches.html">Submitting patches</a></li>
<li><a href="/builds.html">Source Code and Builds</a></li>
<li><a href="/coding-standards.html">Coding standards</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Contributors+Guide">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/release-guidelines.html">Release Guidelines</a></li>
<li><a href="/bylaws.html">PMC Charter</a></li>
<li><a href="/volunteers.html">Volunteers</a></li>
<li><a href="https://gitbox.apache.org/repos/asf?p=struts.git">Source Repository</a></li>
<li><a href="/updating-website.html">Updating the website</a></li>
</ul>
</li>
<li class="apache"><a href="http://www.apache.org/"><img src="/img/apache.png"></a></li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<article class="container">
<section class="col-md-12">
<a class="edit-on-gh" href="https://github.com/apache/struts-site/edit/master/source/core-developers/execute-and-wait-interceptor.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="interceptors.html" title="back to Interceptors"><< back to Interceptors</a>
<h1 id="execute-and-wait-interceptor">Execute and Wait Interceptor</h1>
<p>The ExecuteAndWaitInterceptor is great for running long-lived actions in the background while showing the user a nice
progress meter. This also prevents the HTTP request from timing out when the action takes more than 5 or 10 minutes.</p>
<p>Using this interceptor is pretty straight forward. Assuming that you are including struts-default.xml, this interceptor
is already configured but is not part of any of the default stacks. Because of the nature of this interceptor, it must
be the <code class="highlighter-rouge">last</code> interceptor in the stack.</p>
<p>This interceptor works on a per-session basis. That means that the same action name (<code class="highlighter-rouge">myLongRunningAction</code>, in
the above example) cannot be run more than once at a time in a given session. On the initial request or any subsequent
requests (before the action has completed), the <code class="highlighter-rouge">wait</code> result will be returned.</p>
<blockquote>
<p>The wait result is responsible for issuing a subsequent request back to the action, giving the effect
of a self-updating progress meter.</p>
</blockquote>
<p>If no <code class="highlighter-rouge">wait</code> result is found, Struts will automatically generate a wait result on the fly. This result is written
in FreeMarker and cannot run unless FreeMarker is installed. If you don’t wish to deploy with FreeMarker, you must
provide your own wait result. This is generally a good thing to do anyway, as the default wait page is very plain.</p>
<p>Whenever the wait result is returned, the action that is currently running in the background will be placed on top
of the stack. This allows you to display progress data, such as a count, in the wait page. By making the wait page
automatically reload the request to the action (which will be short-circuited by the interceptor), you can give
the appearance of an automatic progress meter.</p>
<p>This interceptor also supports using an initial wait delay. An initial delay is a time in milliseconds we let the server
wait before the wait page is shown to the user. During the wait this interceptor will wake every 100 millis to check
if the background process is done premature, thus if the job for some reason doesn’t take to long the wait page is not
shown to the user.
This is useful for e.g. search actions that have a wide span of execution time. Using a delay time of 2000 millis we
ensure the user is presented fast search results immediately and for the slow results a wait page is used.</p>
<blockquote>
<p>Important: Because the action will be running in a separate thread, you can’t use ActionContext because it
is a ThreadLocal. This means if you need to access, for example, session data, you need to implement <code class="highlighter-rouge">SessionAware</code>
rather than calling <code class="highlighter-rouge">ActionContext.getSession()</code>.</p>
</blockquote>
<p>The thread kicked off by this interceptor will be named in the form <code class="highlighter-rouge">&lt;actionName&gt;BackgroundProcess</code>.
For example, the <code class="highlighter-rouge">search</code> action would run as a thread named <code class="highlighter-rouge">searchBackgroundProcess</code>.</p>
<h2 id="parameters">Parameters</h2>
<ul>
<li><code class="highlighter-rouge">threadPriority</code> (optional) - the priority to assign the thread. Default is <code class="highlighter-rouge">Thread.NORM_PRIORITY</code>.</li>
<li><code class="highlighter-rouge">delay</code> (optional) - an initial delay in millis to wait before the wait page is shown (returning <code class="highlighter-rouge">wait</code> as result code).
Default is no initial delay.</li>
<li><code class="highlighter-rouge">delaySleepInterval</code> (optional) - only used with delay. Used for waking up at certain intervals to check if the background
process is already done. Default is 100 millis.</li>
</ul>
<h2 id="extending-the-interceptor">Extending the Interceptor</h2>
<p>If you wish to make special preparations before and/or after the invocation of the background thread, you can extend
the <code class="highlighter-rouge">BackgroundProcess</code> class and implement the <code class="highlighter-rouge">beforeInvocation()</code> and <code class="highlighter-rouge">afterInvocation()</code> methods. This may be useful
for obtaining and releasing resources that the background process will need to execute successfully. To use your background
process extension, extend <code class="highlighter-rouge">ExecuteAndWaitInterceptor</code> and implement the <code class="highlighter-rouge">getNewBackgroundProcess()</code> method.</p>
<h2 id="examples">Examples</h2>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"someAction"</span> <span class="na">class=</span><span class="s">"com.examples.SomeAction"</span><span class="nt">&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"completeStack"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"execAndWait"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"wait"</span><span class="nt">&gt;</span>longRunningAction-wait.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"success"</span><span class="nt">&gt;</span>longRunningAction-success.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="err">&lt;</span>%@ taglib prefix="s" uri="/struts" %&gt;
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
<span class="nt">&lt;title&gt;</span>Please wait<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">http-equiv=</span><span class="s">"refresh"</span> <span class="na">content=</span><span class="s">"5;url=&lt;s:url includeParams="</span><span class="err">all"</span> <span class="nt">/&gt;</span>"/&gt;
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
Please wait while we process your request.
Click <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"&lt;s:url includeParams="</span><span class="err">all"</span> <span class="nt">/&gt;</span>"&gt;<span class="nt">&lt;/a&gt;</span> if this page does not reload automatically.
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
<span class="nt">&lt;/pre&gt;</span>
<span class="nt">&lt;p&gt;&lt;u&gt;</span>Example code2:<span class="nt">&lt;/u&gt;&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;</span>
This example will wait 2 second (2000 millis) before the wait page is shown to the user. Therefore
if the long process didn't last long anyway the user isn't shown a wait page.
<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;pre&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"someAction"</span> <span class="na">class=</span><span class="s">"com.examples.SomeAction"</span><span class="nt">&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"completeStack"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"execAndWait"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"delay"</span><span class="nt">&gt;</span>2000<span class="nt">&lt;param&gt;</span>
<span class="nt">&lt;interceptor-ref&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"wait"</span><span class="nt">&gt;</span>longRunningAction-wait.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"success"</span><span class="nt">&gt;</span>longRunningAction-success.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="nt">&lt;/pre&gt;</span>
<span class="nt">&lt;p&gt;&lt;u&gt;</span>Example code3:<span class="nt">&lt;/u&gt;&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;</span>
This example will wait 1 second (1000 millis) before the wait page is shown to the user.
And at every 50 millis this interceptor will check if the background process is done, if so
it will return before the 1 second has elapsed, and the user isn't shown a wait page.
<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;pre&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"someAction"</span> <span class="na">class=</span><span class="s">"com.examples.SomeAction"</span><span class="nt">&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"completeStack"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;interceptor-ref</span> <span class="na">name=</span><span class="s">"execAndWait"</span><span class="nt">&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"delay"</span><span class="nt">&gt;</span>1000<span class="nt">&lt;param&gt;</span>
<span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">"delaySleepInterval"</span><span class="nt">&gt;</span>50<span class="nt">&lt;param&gt;</span>
<span class="nt">&lt;interceptor-ref&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"wait"</span><span class="nt">&gt;</span>longRunningAction-wait.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"success"</span><span class="nt">&gt;</span>longRunningAction-success.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="nt">&lt;/pre&gt;</span>
</code></pre></div></div>
</section>
</article>
<footer class="container">
<div class="col-md-12">
Copyright &copy; 2000-2018 <a href="http://www.apache.org/">The Apache Software Foundation </a>.
All Rights Reserved.
</div>
<div class="col-md-12">
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation.
</div>
<div class="col-md-12">Logo and website design donated by <a href="https://softwaremill.com/">SoftwareMill</a>.</div>
</footer>
<script>!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
<script src="https://apis.google.com/js/platform.js" async="async" defer="defer"></script>
<div id="fb-root"></div>
<script>(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
</body>
</html>