Source

webwork / docs / wikidocs / Chaining Interceptor.html

<html>
    <head>
        <title>WebWork 2 : Chaining Interceptor</title>
	    <link rel="stylesheet" href="styles/site.css" type="text/css" />
        <META http-equiv="Content-Type" content="text/html; charset=UTF-8">	    
    </head>

    <body>
	    <table class="pagecontent" border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="#ffffff">
		    <tr>
			    <td valign="top" class="pagebody">
				    <div class="pageheader">
					    <span class="pagetitle">
                            WebWork 2 : Chaining Interceptor
                                                    </span>
				    </div>
				    <div class="pagesubheading">
					    This page last changed on Jun 18, 2004 by <font color="#0050B2">plightbo</font>.
				    </div>

				    <p class="paragraph"><h2 style="margin: 4px 0px 4px 0px;" class="heading2"><a name="ChainingInterceptor-HowtousetheChainingInterceptor"> How to use the Chaining Interceptor</a></h2></p>The following code snippet shows how interceptor stacks work for chaining.  If someone wants to post xwork.xml (and more complex) examples it would be appreciated <img class="rendericon" src="./icons/emoticons/smile.gif" height="20" width="20" align="absmiddle" alt="" border="0"/><br/>

<div class="code"><div class="codeContent">
<pre>Interceptors&#45;stack A before&#10;  Action A&#10;  Interceptor&#45;stack B before&#10;    Action B&#10;    Action B result&#10;  Interceptor&#45;stack B after&#10;Interceptor&#45;stack A after</pre>
</div></div>
<h2 class="heading2"><a name="ChainingInterceptor-InterceptorsthatwrapChainedActions"> Interceptors that wrap Chained Actions</a></h2><p class="paragraph">Sometimes you may want to have an interceptor that wraps a number of chained actions (and is included in the Interceptor stack for each), but is only invoked at the start and end of the chain.  For example, an Interceptor that manages a Hibernate Session / Transaction.  Here is an example from my &#039;teach-myself-webwork-and-hibernate project named &#039;cash&#039; after Johnny Cash.</p><div class="code"><div class="codeContent">
<pre>&lt;interceptor name=<span class="java&#45;quote">&quot;hibernate&quot;</span> class=<span class="java&#45;quote">&quot;cash.interceptor.HibernateInterceptor&quot;</span>/&gt;&#10;      &lt;interceptor name=<span class="java&#45;quote">&quot;login&quot;</span> class=<span class="java&#45;quote">&quot;cash.interceptor.LoginInterceptor&quot;</span>/&gt;&#10;&#10;      &lt;interceptor&#45;stack name=<span class="java&#45;quote">&quot;cashDefaultStack&quot;</span>&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;defaultStack&quot;</span>/&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;component&quot;</span>/&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;hibernate&quot;</span>/&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;login&quot;</span>/&gt;&#10;      &lt;/interceptor&#45;stack&gt;&#10;      &lt;interceptor&#45;stack name=<span class="java&#45;quote">&quot;cashValidationWorkflowStack&quot;</span>&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;cashDefaultStack&quot;</span>/&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;validation&quot;</span>/&gt;&#10;        &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;workflow&quot;</span>/&gt;&#10;      &lt;/interceptor&#45;stack&gt;&#10;    &lt;/interceptors&gt;&#10;&#10;    &lt;<span class="java&#45;keyword">default</span>&#45;interceptor&#45;ref name=<span class="java&#45;quote">&quot;cashDefaultStack&quot;</span>/&gt;&#10;&#10;    &lt;action name=<span class="java&#45;quote">&quot;list&quot;</span> class=<span class="java&#45;quote">&quot;cash.action.SelectUserAction&quot;</span>&gt;&#10;      &lt;result name=<span class="java&#45;quote">&quot;success&quot;</span> type=<span class="java&#45;quote">&quot;dispatcher&quot;</span>&gt;list.vm&lt;/result&gt;&#10;    &lt;/action&gt;&#10;&#10;    &lt;action name=<span class="java&#45;quote">&quot;edit&quot;</span> class=<span class="java&#45;quote">&quot;cash.action.EditAction&quot;</span>&gt;&#10;      &lt;result name=<span class="java&#45;quote">&quot;success&quot;</span> type=<span class="java&#45;quote">&quot;chain&quot;</span>&gt;list&lt;/result&gt;&#10;      &lt;result name=<span class="java&#45;quote">&quot;input&quot;</span> type=<span class="java&#45;quote">&quot;dispatcher&quot;</span>&gt;edit.vm&lt;/result&gt;&#10;      &lt;interceptor&#45;ref name=<span class="java&#45;quote">&quot;cashValidationWorkflowStack&quot;</span>/&gt;&#10;    &lt;/action&gt;</pre>
</div></div><br/>
In this example, after editing a user, the EditAction is chained to the ListAction to display a list of all users to the screen.<p class="paragraph">We want the following
<div class="code"><div class="codeContent">
<pre>EditActionInterceptorStack &#45; before&#10;    EditAction&#10;    ListActionInterceptorStack (except <span class="java&#45;keyword">for</span> Hibernate) &#45; before&#10;      ListAction&#10;    ListActionInterceptorStack (except <span class="java&#45;keyword">for</span> Hibernate) &#45; end&#10;  EditActinInterceptorStack &#45; end</pre>
</div></div></p>But instead we get:
<div class="code"><div class="codeContent">
<pre>EditActionInterceptorStack &#45; before&#10;    EditAction&#10;    ListActionInterceptorStack (including Hibernate) &#45; before&#10;      ListAction&#10;    ListActionInterceptorStack (including Hibernate) &#45; end&#10;  EditActinInterceptorStack &#45; end  ERROR&#33;  Hibernate Session / Transaction is already closed&#33;&#33;&#33;</pre>
</div></div><br/>
The way to get the desired behaviour is to either not use a chained action (and incorporate the ListAction logic into EditAction, or to make the HibernateInterceptor smart enough to handle chained actions.<p class="paragraph">The HibernateInterceptor can use a ThreadLocal to hold state and detect if it is inside a chain.  When it detects this, it can do nothing.</p><div class="code"><div class="codeContent">
<pre><span class="java&#45;keyword">package</span> cash.interceptor;&#10;&#10;<span class="java&#45;keyword">import</span> net.sf.hibernate.HibernateException;&#10;<span class="java&#45;keyword">import</span> net.sf.hibernate.Transaction;&#10;&#10;<span class="java&#45;keyword">import</span> org.apache.log4j.Logger;&#10;&#10;<span class="java&#45;keyword">import</span> com.opensymphony.xwork.Action;&#10;<span class="java&#45;keyword">import</span> com.opensymphony.xwork.ActionInvocation;&#10;<span class="java&#45;keyword">import</span> com.opensymphony.xwork.interceptor.Interceptor;&#10;&#10;<span class="java&#45;keyword">import</span> cash.action.HibernateAction;&#10;<span class="java&#45;keyword">import</span> cash.util.HibernateUtil;&#10;&#10;/&#42;&#42;&#10; &#42; &#64;author Gavin King&#10; &#42; &#64;author Joel Hockey&#10; &#42; &#64;version $Id$&#10; &#42;/&#10;<span class="java&#45;keyword">public</span> class HibernateInterceptor <span class="java&#45;keyword">implements</span> Interceptor &#123;&#10;    <span class="java&#45;keyword">private</span>&#160;<span class="java&#45;keyword">static</span>&#160;<span class="java&#45;keyword">final</span> Logger LOG = Logger.getLogger(HibernateInterceptor.class);&#10;&#10;    <span class="java&#45;keyword">private</span>&#160;<span class="java&#45;keyword">static</span> ThreadLocal s&#95;threadLocal = <span class="java&#45;keyword">new</span> ThreadLocal();&#10;&#10;    /&#42;&#42; destroy &#42;/&#10;    <span class="java&#45;keyword">public</span> void destroy() &#123; &#125;&#10;&#10;    /&#42;&#42; init &#42;/&#10;    <span class="java&#45;keyword">public</span> void init() &#123; &#125;&#10;&#10;    /&#42;&#42; implement intercept &#42;/&#10;    <span class="java&#45;keyword">public</span>&#160;<span class="java&#45;object">String</span> intercept(ActionInvocation invocation) <span class="java&#45;keyword">throws</span> Exception &#123;&#10;        LOG.debug(<span class="java&#45;quote">&quot;HibernateInterceptor called&quot;</span>);&#10;&#10;        Action action = invocation.getAction();&#10;        <span class="java&#45;keyword">if</span> (&#33;(action <span class="java&#45;keyword">instanceof</span> HibernateAction)) &#123; <span class="java&#45;keyword">return</span> invocation.invoke(); &#125;&#10;&#10;        <span class="java&#45;comment">// <span class="java&#45;keyword">continue</span> with HibernateAction</span>&#10;        HibernateAction ha = (HibernateAction)action;&#10;&#10;        <span class="java&#45;comment">// <span class="java&#45;keyword">if</span>&#160;<span class="java&#45;keyword">this</span> interceptor is being chained, then transaction will already exist</span>&#10;        <span class="java&#45;comment">// in that <span class="java&#45;keyword">case</span>, we should let the <span class="java&#45;keyword">outer</span> interceptor dispose of the sesion</span>&#10;        <span class="java&#45;object">boolean</span> inChainedAction = <span class="java&#45;keyword">true</span>;&#10;        Transaction transaction = (Transaction)s&#95;threadLocal.get();&#10;        <span class="java&#45;keyword">if</span> (transaction == <span class="java&#45;keyword">null</span>) &#123;&#10;            inChainedAction = <span class="java&#45;keyword">false</span>;&#10;            transaction = HibernateUtil.currentSession().beginTransaction();&#10;            s&#95;threadLocal.set(transaction);&#10;        &#125;&#10;&#10;        <span class="java&#45;object">boolean</span> rollback = <span class="java&#45;keyword">false</span>;&#10;&#10;        <span class="java&#45;keyword">try</span> &#123;&#10;&#10;            <span class="java&#45;keyword">return</span> invocation.invoke();&#10;        &#125; <span class="java&#45;keyword">catch</span> (Exception e) &#123;&#10;            <span class="java&#45;comment">// Note that all the cleanup is done</span>&#10;            <span class="java&#45;comment">// after the view is rendered, so we</span>&#10;            <span class="java&#45;comment">// have an open session in the view</span>&#10;&#10;            rollback = <span class="java&#45;keyword">true</span>;&#10;            <span class="java&#45;keyword">if</span> (e <span class="java&#45;keyword">instanceof</span> HibernateException) &#123;&#10;                LOG.error(<span class="java&#45;quote">&quot;HibernateException in execute()&quot;</span>, e);&#10;                <span class="java&#45;keyword">return</span> HibernateAction.DBERROR;&#10;            &#125; <span class="java&#45;keyword">else</span> &#123;&#10;                LOG.error(<span class="java&#45;quote">&quot;Exception in execute()&quot;</span>, e);&#10;                <span class="java&#45;keyword">throw</span> e;&#10;            &#125;&#10;        &#125; <span class="java&#45;keyword">finally</span> &#123;&#10;            <span class="java&#45;keyword">try</span> &#123;&#10;                <span class="java&#45;keyword">if</span> (&#33;inChainedAction) &#123;&#10;                    s&#95;threadLocal.set(<span class="java&#45;keyword">null</span>);&#10;                    disposeSession(transaction, ha.getRollback() || rollback);&#10;                &#125;&#10;            &#125; <span class="java&#45;keyword">catch</span> (HibernateException e) &#123;&#10;                LOG.error(<span class="java&#45;quote">&quot;HibernateException in dispose()&quot;</span>, e);&#10;                <span class="java&#45;keyword">return</span> HibernateAction.DBERROR;&#10;            &#125;&#10;        &#125;&#10;    &#125;&#10;&#10;    /&#42;&#42; dispose of session &#42;/&#10;    <span class="java&#45;keyword">public</span> void disposeSession(Transaction transaction, <span class="java&#45;object">boolean</span> rollback) <span class="java&#45;keyword">throws</span> HibernateException &#123;&#10;        LOG.debug(<span class="java&#45;quote">&quot;disposing&quot;</span>);&#10;&#10;        <span class="java&#45;keyword">if</span> (&#33;HibernateUtil.currentSession().isConnected()) &#123;&#10;            LOG.debug(<span class="java&#45;quote">&quot;Session has already been disposed of &#45; <span class="java&#45;keyword">this</span> will happen in a chained action&quot;</span>);&#10;            <span class="java&#45;keyword">return</span>;&#10;        &#125;&#10;&#10;        <span class="java&#45;keyword">try</span> &#123;&#10;            <span class="java&#45;keyword">if</span> (transaction &#33;= <span class="java&#45;keyword">null</span>) &#123;&#10;                <span class="java&#45;keyword">if</span> (rollback) &#123;&#10;                    LOG.debug(<span class="java&#45;quote">&quot;rolling back&quot;</span>);&#10;                    transaction.rollback();&#10;                &#125; <span class="java&#45;keyword">else</span> &#123;&#10;                    LOG.debug(<span class="java&#45;quote">&quot;committing&quot;</span>);&#10;                    transaction.commit();&#10;                &#125;&#10;            &#125;&#10;        &#125; <span class="java&#45;keyword">catch</span> (HibernateException e) &#123;&#10;            LOG.error(<span class="java&#45;quote">&quot;error during commit/rollback&quot;</span>, e);&#10;            <span class="java&#45;keyword">if</span> (&#33;rollback &amp;&amp; transaction &#33;= <span class="java&#45;keyword">null</span>) &#123;&#10;                LOG.error(<span class="java&#45;quote">&quot;rolling back affter previous attempt to commit&quot;</span>);&#10;                transaction.rollback();&#10;            &#125;&#10;            <span class="java&#45;keyword">throw</span> e;&#10;        &#125; <span class="java&#45;keyword">finally</span> &#123;&#10;            HibernateUtil.closeSession();&#10;        &#125;&#10;    &#125;&#10;&#125;</pre>
</div></div><p class="paragraph">For more information, also see OS:Webwork - Why would I use Action Chaining?</p>

				    					    <br/>
                        <div class="tabletitle">
                            <a name="attachments">Attachments:</a>
                        </div>

                        <div class="greybox" align="left">
                                                            <img src="icons/bullet_blue.gif" height="8" width="8" alt=""/>
                                <a href="Chaining Interceptor_attachments/HibernateUtil.java">HibernateUtil.java</a> (application/octet-stream)
                                <br/>
                                                            <img src="icons/bullet_blue.gif" height="8" width="8" alt=""/>
                                <a href="Chaining Interceptor_attachments/HibernateAction.java">HibernateAction.java</a> (application/octet-stream)
                                <br/>
                                                    </div>
				    
                    			    </td>
		    </tr>
	    </table>
	    <table border="0" cellpadding="0" cellspacing="0" width="100%">
			<tr>
				<td height="12" background="border/border_bottom.gif"><img src="border/spacer.gif" width="1" height="1" border="0"/></td>
			</tr>
		    <tr>
			    <td align="center"><font color="grey">Document generated by Confluence on Oct 15, 2004 02:03</font></td>
		    </tr>
	    </table>
    </body>
</html>