tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Service Advisors
Date Thu, 14 Feb 2013 16:34:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Service+Advisors">Service
Advisors</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~demey.emmanuel@gmail.com">DEMEY
Emmanuel</a>
    </h4>
        <br/>
                         <h4>Changes (2)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >    MethodAdvice advice = new MethodAdvice()
<br>    { <br></td></tr>
            <tr><td class="diff-changed-lines" >void <span class="diff-changed-words">advise(<span
class="diff-added-chars"style="background-color: #dfd;">Method</span>Invocation</span>
invocation) <br></td></tr>
            <tr><td class="diff-unchanged" >      { <br>        invocation.proceed();
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >    MethodAdvice advice = new MethodAdvice()
<br>    { <br></td></tr>
            <tr><td class="diff-changed-lines" >void <span class="diff-changed-words">advise(<span
class="diff-added-chars"style="background-color: #dfd;">Method</span>Invocation</span>
invocation) <br></td></tr>
            <tr><td class="diff-unchanged" >      { <br>        invocation.proceed();
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Defining+Tapestry+IOC+Services"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Defining+Tapestry+IOC+Services">Defining
Tapestry IOC Services</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/IoC"><img border='0' align='middle' src='/confluence/images/icons/up_16.gif'
width='8' height='8'></a></sup><a href="/confluence/display/TAPESTRY/IoC">IoC</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/Tapestry+IoC+Decorators">Tapestry
IoC Decorators</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Tapestry+IoC+Decorators"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>

<h1><a name="ServiceAdvisors-ServiceAdvisors"></a>Service Advisors</h1>

<p>Service advice represents a powerful meta-programming facility available to services.
In fact, it is a kind of limited Aspect Oriented Programming.</p>

<p>Service advice allows you to intercept method invocations on your services; you have
the ability to see what methods get invoked, what the parameters are. You can let the normal
code do it work, and then inspect or even adjust the return value, or any thrown exceptions.
And you can do this all in normal Java code.</p>

<p>A common example of method-level service advice is to log method entry and exit,
complete with parameter values, return values, and thrown exceptions. Other approaches include
security checks, transaction management, and other broadly spanning concerns.</p>

<p>Let's start with a (contrived) example. Let's say you have an existing set of services
that have methods that sometimes return null, and you want them to return an empty string
instead because you are getting some NullPointerExceptions elsewhere in your application.</p>

<p>You could track down the implementation of each service and fix the logic that provides
a return value ... or you could advise the methods:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Match(<span class="code-quote">"*"</span>)
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void adviseNonNull(MethodAdviceReceiver receiver)
  {
    MethodAdvice advice = <span class="code-keyword">new</span> MethodAdvice()
    {
      void advise(MethodInvocation invocation)
      {
        invocation.proceed();

        <span class="code-keyword">if</span> (invocation.getResultType().equals(<span
class="code-object">String</span>.class) &amp;&amp; invocation.getResult()
== <span class="code-keyword">null</span>)
          invocation.overrideResult("");
      }
    };

    receiver.adviseAllMethods(advice);
  };
</pre>
</div></div>

<p>This is a method that is placed in a module class. Note the terminology: <em>advise</em>
is the verb ("to advise a method") and <em>advice</em> is the noun ("with this
advice"). The <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdviceReceiver.html"
class="external-link" rel="nofollow">MethodAdviceReceiver</a> is a wrapper around
the service being advised: you can add advice to some or all methods of the service, and also
obtain the interface of the service. It is automatically passed into service advisor methods.</p>

<p>See <a href="/confluence/display/TAPESTRY/Injection+in+Detail" title="Injection
in Detail">Injection in Detail</a> for what can be injected into a service advisor
method.</p>

<p>Service advisor methods must have a parameter of type MethodAdviceReceiver.</p>

<p>A service will often be advised multiple times; any method may have any number of
advice objects applied to it. Some methods may not get any advice. All of this is acceptable.</p>

<p>Service advisor methods are always void methods (this is different from <a href="/confluence/display/TAPESTRY/Tapestry+IoC+Decorators"
title="Tapestry IoC Decorators">service decorator methods</a>).</p>

<p>The @<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html"
class="external-link" rel="nofollow">Match</a>("*") annotation indicates that this
advice applies to all services (both your own, and those defined by Tapestry). You will want
to narrow down which services are actually targeted in most cases.</p>

<p>Note that some services, especially those built into Tapestry IoC, are marked as
<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.html"
class="external-link" rel="nofollow">not subject to decoration</a>, this applies
to service advice as well as service decoration.</p>

<p>The <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdvice.html"
class="external-link" rel="nofollow">MethodAdvice</a> interface is very simple; it
receives an <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Invocation.html"
class="external-link" rel="nofollow">Invocation</a> representing a method call. Invocation
has methods for inspecting the type and value of the parameters, and for overriding the values
of the parameters.</p>

<p>The call to <tt>proceed()</tt> allows the invocation to continue; that
is, the original method is invoked. If the method has been advised multiple times, the call
to proceed() may chain into the next MethodAdvice object. In any case, after invoking <tt>proceed()</tt>,
you may inspect and override the result (the return value).</p>

<p>Advice is pretty efficient, but it is still better to apply it only to methods that
make sense. We can improve the service advisor method in our example to only advise methods
that return String:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Match(<span class="code-quote">"*"</span>)
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void adviseNonNull(MethodAdviceReceiver receiver)
  {
    MethodAdvice advice = <span class="code-keyword">new</span> MethodAdvice()
    {
      void advise(MethodInvocation invocation)
      {
        invocation.proceed();

        <span class="code-keyword">if</span> (invocation.getResult().equals(<span
class="code-keyword">null</span>))
          invocation.overrideResult("");
      }
    };

    <span class="code-keyword">for</span> (Method m : receiver.getServiceInterface().getMethods())
    {
      <span class="code-keyword">if</span> (m.getReturnType().equals(<span
class="code-object">String</span>.class))
        receiver.adviseMethod(m, advice);
    }
  };
</pre>
</div></div>

<h1><a name="ServiceAdvisors-BuiltinAdvice"></a>Built-in Advice</h1>

<p>Tapestry includes two built-in advisor services.</p>

<h2><a name="ServiceAdvisors-LoggingAdvice"></a>Logging Advice</h2>

<p>Logging advice is built into Tapestry. You can apply logging advice to your services
very easily:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Match(<span class="code-quote">"*"</span>)
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void adviseLogging(LoggingAdvisor loggingAdvisor, Logger logger, MethodAdviceReceiver receiver)
  {
    loggingAdvisor.addLoggingAdvice(logger, receiver);
  }
</pre>
</div></div>

<p><a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/LoggingAdvisor.html"
class="external-link" rel="nofollow">LoggingAdvisor</a> is a built-in Tapestry IoC
service. This demonstrates how services can be injected into service advisor methods. The
Logger parameter is the logger for the service being advised.</p>

<h2><a name="ServiceAdvisors-LazyAdvice"></a>Lazy Advice</h2>

<p><a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/LazyAdvisor.html"
class="external-link" rel="nofollow">LazyAdvisor</a> makes method invocations lazy:
methods that return an interface (rather than a value) will not execute immediately; instead,
the method invocation is postponed until a method of the return value is invoked.</p>

<h1><a name="ServiceAdvisors-MatchingAndOrdering"></a>Matching And Ordering</h1>

<p>Each service advice method gets a unique id, obtained by stripping the "advise" prefix
from the method name. Advice ids must be unique across all modules.</p>

<p>If the @Match annotation is omitted, the advice will match against a service with
the same id.</p>

<p>In many cases, the order in which the advice is given is very important; for example,
you may want logging first, then transaction management, then security checks. The @<a
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Order.html"
class="external-link" rel="nofollow">Order</a> annotation allows you to explicitly
set the order.</p>

<h1><a name="ServiceAdvisors-Annotationdrivenadvisors"></a>Annotation driven
advisors</h1>



<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><b>Added in
5.2</b><br /></td></tr></table></div>
<div style="border-right: 20px solid #D8E4F1;border-left: 20px solid #D8E4F1;"></div>

<p>Starting from version 5.2, Tapestry supports annotation-driven advise methods. If
the <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Advise.html"
class="external-link" rel="nofollow">@Advise</a> annotation is present, the advise
method can be arbitrary named, as shown in the following example.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Advise
  @Match(<span class="code-quote">"*DAO"</span>)
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void byServiceId(MethodAdviceReceiver receiver)
  {
    ...
  }
</pre>
</div></div>

<p>The advice above is applied to any service whose id matches the "*DAO" pattern.</p>

<p>Alternatively, marker annotations can be placed on the advise method to match a specific
service.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Advise
  @Blue
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void byMarkerAnnotation(MethodAdviceReceiver receiver)
  {
    ...
  }
</pre>
</div></div>

<p>The advice above is applied to any service that is marked by the @Blue annotation.</p>

<p>By default, <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Advise.html"
class="external-link" rel="nofollow">@Advise</a> annotation applies the advice to
any service matched by the <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html"
class="external-link" rel="nofollow">@Match</a> or marker annotations. You can limit
the matching to a single service interface, as shown in the following example.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Advise(serviceInterface=MyService.class)
  @Match(<span class="code-quote">"*DAO"</span>)
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void byMatchAnnotation(MethodAdviceReceiver receiver)
  {
    ...
  }
</pre>
</div></div>

<p>In the example above, the advice is applied to any implementation of MyService interfaces
whose id matches the "*DAO" pattern.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Advise(serviceInterface=MyService.class)
  @Blue
  <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void byMarkerAnnotation(MethodAdviceReceiver receiver)
  {
    ...
  }
</pre>
</div></div>

<p>The advice above is applied to any implementation of the MyService interface that
is marked by the @Blue annotation.</p>

<h1><a name="ServiceAdvisors-DecoratorsandAdvice"></a>Decorators and Advice</h1>

<p><a href="/confluence/display/TAPESTRY/Tapestry+IoC+Decorators" title="Tapestry
IoC Decorators">Service decorators</a> are another way to achieve the same thing;
service advisors are a more recent addition, added in Tapestry 5.1.</p>

<p>It is not recommended that you mix advice and decoration. If you do, decoration take
precedence; all decorators will be in effect before any advice (internally, they are two separate
steps, with advice being processed and the result of that used by the decorators).</p>

<style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Defining+Tapestry+IOC+Services"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Defining+Tapestry+IOC+Services">Defining
Tapestry IOC Services</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/IoC"><img border='0' align='middle' src='/confluence/images/icons/up_16.gif'
width='8' height='8'></a></sup><a href="/confluence/display/TAPESTRY/IoC">IoC</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/Tapestry+IoC+Decorators">Tapestry
IoC Decorators</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Tapestry+IoC+Decorators"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Service+Advisors">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23338475&revisedVersion=14&originalVersion=13">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message