http://git-wip-us.apache.org/repos/asf/struts-site/blob/2b2ec9b3/content/tag-developers/ognl-expression-compilation.html ---------------------------------------------------------------------- diff --git a/content/tag-developers/ognl-expression-compilation.html b/content/tag-developers/ognl-expression-compilation.html new file mode 100644 index 0000000..1ef39b9 --- /dev/null +++ b/content/tag-developers/ognl-expression-compilation.html @@ -0,0 +1,519 @@ +<!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>Tag Developers Guide (WIP)</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="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.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="/downloads.html">Downloads</a></li> + <li><a href="/announce.html">Announcements</a></li> + <li><a href="http://www.apache.org/licenses/">License</a></li> + <li><a href="http://apache.org/foundation/thanks.html">Thanks!</a></li> + <li><a href="http://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="/maven/project-info.html">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 class="divider"></li> + <li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li> + <li><a href="/docs/plugins.html">Plugin APIs</a></li> + <li><a href="/docs/tag-reference.html">Tag reference</a></li> + <li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li> + <li class="divider"></li> + <li><a href="/docs/tutorials.html">Tutorials - DEPRECATED</a></li> + <li><a href="/docs/faqs.html">FAQs - DEPRECATED</a></li> + <li><a href="/docs/guides.html">Guides - DEPRECATED</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 class="divider"></li> + <li><a href="/submitting-patches.html">Submitting patches</a></li> + <li><a href="/builds.html">Source Code</a></li> + <li><a href="/coding-standards.html">Coding standards</a></li> + <li class="divider"></li> + <li><a href="/releases.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://git-wip-us.apache.org/repos/asf?p=struts.git">Source Repository</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/tag-developers/ognl-expression-compilation.md" title="Edit this page on GitHub">Edit on GitHub</a> + <h1 id="ognl-expression-compilation">OGNL Expression Compilation</h1> + +<p>This document is meant as a development/integration guide for anyone wanting to use the new OGNL 2.7 features for doing +byte code runtime enhancements on OGNL statements. This is <em>not</em> meant for general user reference as it covers what +are mostly internal API development concerns.</p> + +<p>## Basic Usage</p> + +<p>By default there isnât much you have to do to use the new compilation abilities in OGNL. Following is an example of compiling +a simple property expression and invoking it.</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">SimpleObject</span> <span class="n">root</span> <span class="o">=</span> <span class="k">new</span> <span class="n">SimpleObject</span><span class="o">();</span> +<span class="n">OgnlContext</span> <span class="n">context</span> <span class="o">=</span> <span class="o">(</span><span class="n">OgnlContext</span><span class="o">)</span> <span class="n">Ognl</span><span class="o">.</span><span class="na">createDefaultContext</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span> + +<span class="n">Node</span> <span class="n">node</span> <span class="o">=</span> <span class="o">(</span><span class="n">Node</span><span class="o">)</span> <span class="n">Ognl</span><span class="o">.</span><span class="na">compileExpression</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">root</span><span class="o">,</span> <span class="s">"user.name"</span><span class="o">);</span> +<span class="n">String</span> <span class="n">userName</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">getAccessor</span><span class="o">().</span><span class="na">get</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">root</span><span class="o">);</span> +</code></pre> +</div> + +<p>Youâll notice that this example references the new <code class="highlighter-rouge">ognl.enhance.ExpressionAccessor</code> class. This is the interface used +to create the enhanced expression versions of any given expression via javassist and should be used to set/get expression +values from the compiled versions of the code. Although the old <code class="highlighter-rouge">Ognl.getValue(node, context, root)</code> method of getting/setting +values will correctly detect a compiled expression and use the accessor directly as well, itâs not going to be as fast +as you doing it directly.</p> + +<p>## ognl.enhance.OgnlExpressionCompiler</p> + +<p>The core class involved in doing the management of these expression compilations by default is <code class="highlighter-rouge">ognl.enhance.ExpressionCompiler</code>, +which implements <code class="highlighter-rouge">ognl.enhance.OgnlExpressionCompiler</code>. Although you can in theory use this default implementation it +is not recommended for more robust integration points - such as being incorporated within a web framework. The majority +of examples here are going to be based around the strategy that Tapestry has used to integrate these new features.</p> + +<h3 id="tapestry-ognl-integration">Tapestry OGNL Integration</h3> + +<p>There are only small handful of classes/services involved in the Tapestry implementation of these features, so hopefully +using them as a reference will help anyone trying to get started with this:</p> + +<ul> + <li><a href="http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/HiveMindExpressionCompiler.java?view=markup">org.apache.tapestry.services.impl.HiveMindExpressionCompiler</a> +The Tapestry implementation of <code class="highlighter-rouge">ognl.enhance.OgnlExpressionCompiler</code> - which is a subclass +of the <code class="highlighter-rouge">ognl.enhance.ExpressionCompiler</code> default implementation. +_ <a href="http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ExpressionEvaluatorImpl.java?view=markup">org.apache.tapestry.services.impl.ExpressionEvaluatorImpl</a> +Main service point involved in compiling/evaluating OGNL expressions. This is the core service that the rest of Tapestry +uses when dealing with OGNL expressions.</li> + <li><a href="http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/services/impl/ExpressionCacheImpl.java?view=markup">org.apache.tapestry.services.impl.ExpressionCacheImpl</a> +Service responsible for caching OGNL statements where appropriate.</li> + <li><a href="http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/binding/ExpressionBinding.java?view=markup">org.apache.tapestry.binding.ExpressionBinding</a> +Wrapper class which represents a single OGNL binding expression within Tapestry templates/annotations/html/etc. +Anything formally specified in an html attribute for components in Tapestry is represented by a specific type of <code class="highlighter-rouge">IBinding</code>, +<code class="highlighter-rouge">ExpressionBinding</code> represents the type of bindings for OGNL expressions.</li> + <li><a href="http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/bean/BeanProviderPropertyAccessor.java?view=markup">org.apache.tapestry.bean.BeanProviderPropertyAccessor</a> +One of the custom <code class="highlighter-rouge">PropertyAccessor</code> classes Tapestry registers with OGNL. This will be a good reference for the new +source code generation methods you will need to implement for your <code class="highlighter-rouge">PropertyAccessor</code> classes if you want to compile +expressions.</li> +</ul> + +<h3 id="expressionevaluator">ExpressionEvaluator</h3> + +<p>If you look at the <code class="highlighter-rouge">ExpressionEvaluator</code> source youâll see a block of initialization where the <code class="highlighter-rouge">HiveMindExpressionCompiler</code> +and <code class="highlighter-rouge">OgnlContext</code> pools are setup:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">OgnlRuntime</span><span class="o">.</span><span class="na">setCompiler</span><span class="o">(</span><span class="k">new</span> <span class="n">HiveMindExpressionCompiler</span><span class="o">(</span><span class="n">_classFactory</span><span class="o">));</span> + +<span class="n">_contextPool</span> <span class="o">=</span> <span class="k">new</span> <span class="n">GenericObjectPool</span><span class="o">(</span><span class="k">new</span> <span class="n">PoolableOgnlContextFactory</span><span class="o">(</span><span class="n">_ognlResolver</span><span class="o">,</span> <span class="n">_typeConverter</span><span class="o">));</span> + +<span class="n">_contextPool</span><span class="o">.</span><span class="na">setMaxActive</span><span class="o">(-</span><span class="mi">1</span><span class="o">);</span> +<span class="n">_contextPool</span><span class="o">.</span><span class="na">setMaxIdle</span><span class="o">(-</span><span class="mi">1</span><span class="o">);</span> +<span class="n">_contextPool</span><span class="o">.</span><span class="na">setMinEvictableIdleTimeMillis</span><span class="o">(</span><span class="n">POOL_MIN_IDLE_TIME</span><span class="o">);</span> +<span class="n">_contextPool</span><span class="o">.</span><span class="na">setTimeBetweenEvictionRunsMillis</span><span class="o">(</span><span class="n">POOL_SLEEP_TIME</span><span class="o">);</span> +</code></pre> +</div> + +<p>Some things like null handlers/property accessor configuration has been left out but you should have enough there to get +a good idea of what is going on. Because creating new OgnlContext objects for every expression evaluation can be needlessly +expensive Tapestry uses the Apache commons-pool library to manage pooling of these instances. It is recommended that +you do the same where you can. You will also notice in other portions of the source some new method calls made on +<code class="highlighter-rouge">OgnlRuntime</code>:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">OgnlRuntime</span><span class="o">.</span><span class="na">clearCache</span><span class="o">();</span> +<span class="n">Introspector</span><span class="o">.</span><span class="na">flushCaches</span><span class="o">();</span> +</code></pre> +</div> + +<p>The OgnlRuntime class stores static <code class="highlighter-rouge">Map</code>-like instances of reflection meta cache information for all objects evaluated +in OGNL expressions. The new <code class="highlighter-rouge">clearCache</code> method clears these caches out as the memory footprint can get quite large +after a while. How often/when to call this will largely depend on how your framework works - just keep in mind that +calling it too often will have a big impact on runtime performance of your app if you are doing normal application +development sort of things with it.</p> + +<h3 id="hivemindexpressioncompiler">HiveMindExpressionCompiler</h3> + +<p>Perhaps the most important class to examine is Tapestrys implementation of <code class="highlighter-rouge">OgnlExpressionCompiler</code>. This class still +extends the default <code class="highlighter-rouge">ExpressionCompiler</code> provided by OGNL - but does a few more things that canât be made generic enough +to live in the default implementation.</p> + +<p>One of these important differences is how Javassist is used to compile the expressions and the ClassLoader/ClassResolver +it uses. Because these expressions are being compiled against what are already Javassist enhanced Tapestry component +class instances this implementation needed to re-use existing hivemind Javassist services so that these enhanced classes +could be correctly resolved while OGNL is evaluating them.</p> + +<p>If you donât have a need to provide this kind of classloading functionality you will probably still need to modify +at least how the javassist <code class="highlighter-rouge">ClassPool</code> is being managed in your own implementations. The internal functionality of that +library is such that the memory consumption of the pool is very large and will get unwieldy especially in development +of web apps. Tapestry has a special state that users are used to which is known as âdisable cachingâ - more or less +meaning that javassist enhancements happen for every request instead of only once.</p> + +<p>Another very important piece of logic that this class handles is the generation of âfail safeâ getters/setters when +expressions just canât be compiled because of either internal errors or a specific syntax type used isnât yet able to support +javassist compilations. This logic can sometimes get tricky in that in many instances OGNL expressions wonât be compilable +because the full expression contains a null reference. The basic idea is that the compiler keeps trying to compile these +kinds of expressions until it either gets a fatal exception thrown or the full expression is able to be resolved. +For example, the following expression would throw a <code class="highlighter-rouge">UnsupportedCompilationException</code> if the âuserâ object returned +was null - resulting in no direct compilation being done at all:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code>"user.firstName" +</code></pre> +</div> + +<p>That doesnât mean that the user object might not be resolvable the next time this expression is invoked though, +so the next time the compiler tries it may succeed in which case the whole expression is enhanced and the new <code class="highlighter-rouge">ExpressionAccessor</code> +instance is attached to the root <code class="highlighter-rouge">Node</code> object by calling <code class="highlighter-rouge">SimpleNode.setAccessor(newInstance)</code>.</p> + +<p>The fail safe logic is there for expressions that are likely to never be resolvable for one reason or another. In these +instances a <code class="highlighter-rouge">ExpressionAccessor</code> class instance is still created - with the major difference being that instead of pure +java object expressions being compiled the get/set methods on the instance just call back to the standard OGNL +getValue/setValue methods:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="n">Object</span> <span class="nf">get</span><span class="p">(</span><span class="n">OgnlContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">Object</span> <span class="n">root</span><span class="o">)</span> +<span class="o">{</span> + <span class="k">return</span> <span class="n">_node</span><span class="o">.</span><span class="na">getValue</span><span class="o">(</span><span class="err">$</span><span class="mi">1</span><span class="o">,</span> <span class="err">$</span><span class="mi">2</span><span class="o">);</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>The <code class="highlighter-rouge">$1, $2</code> references are Javassist constructs which allow you to specify the first and second argument passed in +to the calling method.</p> + +<h3 id="expressionbinding">ExpressionBinding</h3> + +<p>As stated previously, this class represents a single OGNL expression in Tapestry when used directly in html templates +- such as:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">jwcid=</span><span class="s">"@Input"</span> <span class="na">value=</span><span class="s">"ognl:user.firstName"</span> <span class="nt">/></span> +</code></pre> +</div> + +<p>What you will want to examine in this class is how it deals with incrementally attempting expression evaluations using +the local members <code class="highlighter-rouge">_writeFailed, _accessor</code>. Looking through the source of this implementation will probably be the best +documentation available - but keep in mind that in many instances this object also has to deal with the possibility +that a write statement may never happen.</p> + +<h3 id="beanproviderpropertyaccessor--custom-propertyaccessor-implementations">BeanProviderPropertyAccessor / Custom PropertyAccessor implementations</h3> + +<p>Besides the <code class="highlighter-rouge">OgnlExpressionCompiler</code> logic this will probably be the second most impactual area people will have to deal +with in terms of having to write new code. In this specific instance there are three new <code class="highlighter-rouge">PropertyAccessor</code> methods +you must implement in order to compile your expressions:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="n">Class</span> <span class="nf">getPropertyClass</span><span class="p">(</span><span class="n">OgnlContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">Object</span> <span class="n">target</span><span class="o">,</span> <span class="n">Object</span> <span class="n">name</span><span class="o">)</span> +<span class="o">{</span> + <span class="n">IBeanProvider</span> <span class="n">provider</span> <span class="o">=</span> <span class="o">(</span><span class="n">IBeanProvider</span><span class="o">)</span><span class="n">target</span><span class="o">;</span> + <span class="n">String</span> <span class="n">beanName</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span><span class="n">name</span><span class="o">).</span><span class="na">replaceAll</span><span class="o">(</span><span class="s">"\""</span><span class="o">,</span> <span class="s">""</span><span class="o">);</span> + + <span class="k">if</span> <span class="o">(</span><span class="n">provider</span><span class="o">.</span><span class="na">canProvideBean</span><span class="o">(</span><span class="n">beanName</span><span class="o">))</span> + <span class="k">return</span> <span class="n">provider</span><span class="o">.</span><span class="na">getBean</span><span class="o">(</span><span class="n">beanName</span><span class="o">).</span><span class="na">getClass</span><span class="o">();</span> + + <span class="k">return</span> <span class="kd">super</span><span class="o">.</span><span class="na">getPropertyClass</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">target</span><span class="o">,</span> <span class="n">name</span><span class="o">);</span> +<span class="o">}</span> + +<span class="kd">public</span> <span class="n">String</span> <span class="nf">getSourceAccessor</span><span class="p">(</span><span class="n">OgnlContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">Object</span> <span class="n">target</span><span class="o">,</span> <span class="n">Object</span> <span class="n">name</span><span class="o">)</span> +<span class="o">{</span> + <span class="n">IBeanProvider</span> <span class="n">provider</span> <span class="o">=</span> <span class="o">(</span><span class="n">IBeanProvider</span><span class="o">)</span><span class="n">target</span><span class="o">;</span> + <span class="n">String</span> <span class="n">beanName</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span><span class="n">name</span><span class="o">).</span><span class="na">replaceAll</span><span class="o">(</span><span class="s">"\""</span><span class="o">,</span> <span class="s">""</span><span class="o">);</span> + + <span class="k">if</span> <span class="o">(</span><span class="n">provider</span><span class="o">.</span><span class="na">canProvideBean</span><span class="o">(</span><span class="n">beanName</span><span class="o">))</span> <span class="o">{</span> + + <span class="n">Class</span> <span class="n">type</span> <span class="o">=</span> <span class="n">OgnlRuntime</span><span class="o">.</span><span class="na">getCompiler</span><span class="o">().</span><span class="na">getInterfaceClass</span><span class="o">(</span><span class="n">provider</span><span class="o">.</span><span class="na">getBean</span><span class="o">(</span><span class="n">beanName</span><span class="o">).</span><span class="na">getClass</span><span class="o">());</span> + + <span class="n">ExpressionCompiler</span><span class="o">.</span><span class="na">addCastString</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="s">"(("</span> <span class="o">+</span> <span class="n">type</span><span class="o">.</span><span class="na">getName</span><span class="o">()</span> <span class="o">+</span> <span class="s">")"</span><span class="o">);</span> + + <span class="n">context</span><span class="o">.</span><span class="na">setCurrentAccessor</span><span class="o">(</span><span class="n">IBeanProvider</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> + <span class="n">context</span><span class="o">.</span><span class="na">setCurrentType</span><span class="o">(</span><span class="n">type</span><span class="o">);</span> + + <span class="k">return</span> <span class="s">".getBean("</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">"))"</span><span class="o">;</span> + <span class="o">}</span> + + <span class="k">return</span> <span class="kd">super</span><span class="o">.</span><span class="na">getSourceAccessor</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">target</span><span class="o">,</span> <span class="n">name</span><span class="o">);</span> +<span class="o">}</span> + +<span class="kd">public</span> <span class="n">String</span> <span class="nf">getSourceSetter</span><span class="p">(</span><span class="n">OgnlContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">Object</span> <span class="n">target</span><span class="o">,</span> <span class="n">Object</span> <span class="n">name</span><span class="o">)</span> +<span class="o">{</span> + <span class="k">throw</span> <span class="k">new</span> <span class="n">UnsupportedCompilationException</span><span class="o">(</span><span class="s">"Can't set beans on IBeanProvider."</span><span class="o">);</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>Although this example may not provide with all of the possible use cases you may need to learn to properly implement +these methods in your own <code class="highlighter-rouge">PropertyAccessor</code> implementations - the built in OGNL versions like <code class="highlighter-rouge">ObjectPropertyAccessor</code>, +<code class="highlighter-rouge">MapPropertyAccessor</code>, <code class="highlighter-rouge">ListPropertyAccessor</code>, etc should provide more than enough data to work from.</p> + +<p>The most important part of the above logic you will want to look at is in how the new <code class="highlighter-rouge">OgnlContext</code> methods for setting +object/accessor types are being set:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">context</span><span class="o">.</span><span class="na">setCurrentAccessor</span><span class="o">(</span><span class="n">IBeanProvider</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> +<span class="n">context</span><span class="o">.</span><span class="na">setCurrentType</span><span class="o">(</span><span class="n">type</span><span class="o">);</span> +</code></pre> +</div> + +<p>This meta information is used by the <code class="highlighter-rouge">OgnlExpressionCompiler</code> to correctly cast your specific expression object types +during compilation. This process of casting/converting in to and out of native types is the most complicated part of this +new logic and also the source of the greatest number of bugs reported in the OGNL jira.</p> + +<p>In this property accessor example the goal is to turn general statements like <code class="highlighter-rouge">beans.emailValidator</code> in to their pure +source form - which would look something like this when all is said and done:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="o">((</span><span class="n">ValidatingBean</span><span class="o">)</span><span class="n">beanProvider</span><span class="o">.</span><span class="na">getBean</span><span class="o">(</span><span class="s">"emailValidator"</span><span class="o">))</span> +</code></pre> +</div> + +<p>There is also the ever important cast handling which you must do:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">Class</span> <span class="n">type</span> <span class="o">=</span> <span class="n">OgnlRuntime</span><span class="o">.</span><span class="na">getCompiler</span><span class="o">().</span><span class="na">getInterfaceClass</span><span class="o">(</span><span class="n">provider</span><span class="o">.</span><span class="na">getBean</span><span class="o">(</span><span class="n">beanName</span><span class="o">).</span><span class="na">getClass</span><span class="o">());</span> + +<span class="n">ExpressionCompiler</span><span class="o">.</span><span class="na">addCastString</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="s">"(("</span> <span class="o">+</span> <span class="n">type</span><span class="o">.</span><span class="na">getName</span><span class="o">()</span> <span class="o">+</span> <span class="s">")"</span><span class="o">);</span> +</code></pre> +</div> + +<p>In this example the <code class="highlighter-rouge">PropertyAccessor</code> is trying to determine the class type and manually adding the cast string for +the specific type to the overall statement by invoking the utility method <code class="highlighter-rouge">addCastString(OgnlContext, String)</code> on +<code class="highlighter-rouge">ExpressionCompiler</code>. In many instances of expression compilation you might also be dealing with unknown method calls, +where the more preferred way to do this kind of logic would be something like this: (taken from the OGNL +<code class="highlighter-rouge">ObjectPropertyAccessor</code> implementation)</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">Method</span> <span class="n">m</span> <span class="o">=</span> <span class="o">...(</span><span class="n">various</span> <span class="n">reflection</span> <span class="n">gynamistics</span> <span class="n">used</span> <span class="n">to</span> <span class="n">find</span> <span class="n">a</span> <span class="n">java</span><span class="o">.</span><span class="na">reflect</span><span class="o">.</span><span class="na">Method</span> <span class="n">instance</span><span class="o">)</span> + +<span class="n">context</span><span class="o">.</span><span class="na">setCurrentType</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">getReturnType</span><span class="o">());</span> +<span class="n">context</span><span class="o">.</span><span class="na">setCurrentAccessor</span><span class="o">(</span><span class="n">OgnlRuntime</span><span class="o">.</span><span class="na">getCompiler</span><span class="o">().</span><span class="na">getSuperOrInterfaceClass</span><span class="o">(</span><span class="n">m</span><span class="o">,</span> <span class="n">m</span><span class="o">.</span><span class="na">getDeclaringClass</span><span class="o">()));</span> +</code></pre> +</div> + +<p>When dealing with method calls it is very important that you do this specific kind of type setting on the <code class="highlighter-rouge">OgnlContext</code> +class so that the casting done on your statements (which happens outside of the <code class="highlighter-rouge">ObjectPropertyAccessor</code> in this instance) +can be done on the highest level interface defining that method. This becomes important when you are dealing with expressions +that you would like to re-use against different object instances. For example, suppose we had an ognl expression like +this (for Tapestry):</p> + +<div class="highlighter-rouge"><pre class="highlight"><code>user.firstName +</code></pre> +</div> + +<p>and the object it was compiled against was an instance of something looking like this:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">abstract</span> <span class="n">LoginPage</span> <span class="kd">extends</span> <span class="n">BasePage</span> <span class="kd">implements</span> <span class="n">UserPermissions</span> <span class="o">{</span> + + <span class="kd">public</span> <span class="kd">abstract</span> <span class="n">User</span> <span class="n">getUser</span><span class="o">();</span> + +<span class="o">}</span> + +<span class="o">..</span> +<span class="cm">/** + * Interface for any page/component that holds references to the current system + * User. + */</span> +<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">UserPermissions</span> <span class="o">{</span> + <span class="n">User</span> <span class="n">getUser</span><span class="o">();</span> +<span class="o">}</span> +</code></pre> +</div> + +<p><code class="highlighter-rouge">BasePage</code> is a Tapestry specific class which is unimportant in this example. What is important to know is that if we +had done something like this in the previous context setting example:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">context</span><span class="o">.</span><span class="na">setCurrentType</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">getReturnType</span><span class="o">());</span> +<span class="n">context</span><span class="o">.</span><span class="na">setCurrentAccessor</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">getDeclaringClass</span><span class="o">());</span> +</code></pre> +</div> + +<p>It would have resulted in a compiled expression of:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">get</span><span class="p">(</span><span class="n">OgnlContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">Object</span> <span class="n">root</span><span class="o">)</span> <span class="o">{</span> + <span class="k">return</span> <span class="o">((</span><span class="n">LoginPage</span><span class="o">)</span><span class="n">root</span><span class="o">).</span><span class="na">getUser</span><span class="o">();</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>This is undesirable in situations where you would like to re-use OGNL expressions across many different class instances +(which is what Tapestry does via the <code class="highlighter-rouge">ExpressionCacheImpl</code> listed above). The better/more re-usable compiled version +should really look like:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">get</span><span class="p">(</span><span class="n">OgnlContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">Object</span> <span class="n">root</span><span class="o">)</span> <span class="o">{</span> + <span class="k">return</span> <span class="o">((</span><span class="n">UserPermissions</span><span class="o">)</span><span class="n">root</span><span class="o">).</span><span class="na">getUser</span><span class="o">();</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>These are the more delicate parts of the compiler API that the majority of people will need to worry about during any +integration efforts.</p> + +<p>## Known Issues / Limitations</p> + +<h3 id="compiler-errors">Compiler Errors</h3> + +<p>Despite the substantially large number of unit tests set up and thorough usage of many different +types of expressions Tapestry users are still currently running in to fatal/non caught runtime errors when some of their +OGNL expressions are compiled. In some instances these errors are blockers and they must either wait for someone +to fix the bug (after being posted to <a href="http://jira.opensymphony.com/browse/OGNL">http://jira.opensymphony.com/browse/OGNL</a> +correctly) or re-work their expression to get around the error. I (jesse) generally try to fix these reported errors +within a day or two (or sooner) when I can and immediately deploy the fixes to the OGNL snapshot maven2 repository.<br /> +This doesnât mean that the vast majority of expressions wonât compile fine, but it is something to keep in mind when +you decide how to integrate the compiler logic in to your own framework.</p> + +<h3 id="compile-vs-normal-expression-evaluation">Compile vs. normal expression evaluation</h3> + +<p>The current Tapestry implementation compiles OGNL expressions in both development AND production modes. This has +the undesirable side effect of causing needless multiple method invocations on objects when compiling as well as the general +overhead of performing compilations at all when people are just developing applications and not serving them in production +environments. It is hoped that when OGNL becomes final this special development mode can go back to using normal OGNL +expression evaluation during development and save compilation for production environments, but until then weâve been +worried about giving people false positives when testing their applications. Meaning - something may evaluate just fine +when using</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">Ognl</span><span class="o">.</span><span class="na">getValue</span><span class="o">(</span><span class="n">OgnlContext</span><span class="o">,</span> <span class="n">Object</span> <span class="n">root</span><span class="o">,</span> <span class="n">String</span> <span class="n">expression</span> +</code></pre> +</div> + +<p>but fail completely when they deploy their app to production and the compiler kicks in. If you framework doesnât handle +separate modes or have this kind of state set up it is something to keep in mind. The number of JIRA issues reported +has gone way down since this all started but they do still trickle in which is enough to know that things arenât yet 100% +reliable. Iâm sure the plethora of Struts/WebWork/etc users available should be enough to iron out any remaining issues +found but itâs something to keep in mind.</p> + +<h3 id="snapshot-repository">Snapshot Repository</h3> + +<p>The current maven2 location of the OGNL development/snapshot release are all made to <a href="http://opencomponentry.com/repository/m2-snapshot-repo/">http://opencomponentry.com/repository/m2-snapshot-repo/</a>, +while releases go out to ibiblio as per normal. If someone has a better place for these release to be made please feel free to contact jesse ( jkuhnert at gmail.com) with accessor information / instructions.</p> + + + </section> +</article> + + +<footer class="container"> + <div class="col-md-12"> + Copyright © 2000-2016 <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> + + +<script> +$(function() { + return $("h2, h3, h4, h5, h6").each(function(i, el) { + var $el, id; + $el = $(el); + id = $el.attr('id'); + if (id) { + $el.removeAttr('id'); + return $el.before($("<a />").addClass('anchor').attr('name', id)); + } + }); +}); +</script> + +</body> +</html>
http://git-wip-us.apache.org/repos/asf/struts-site/blob/2b2ec9b3/content/tag-developers/ognl.html ---------------------------------------------------------------------- diff --git a/content/tag-developers/ognl.html b/content/tag-developers/ognl.html new file mode 100644 index 0000000..823d232 --- /dev/null +++ b/content/tag-developers/ognl.html @@ -0,0 +1,320 @@ +<!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>Tag Developers Guide (WIP)</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="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.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="/downloads.html">Downloads</a></li> + <li><a href="/announce.html">Announcements</a></li> + <li><a href="http://www.apache.org/licenses/">License</a></li> + <li><a href="http://apache.org/foundation/thanks.html">Thanks!</a></li> + <li><a href="http://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="/maven/project-info.html">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 class="divider"></li> + <li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li> + <li><a href="/docs/plugins.html">Plugin APIs</a></li> + <li><a href="/docs/tag-reference.html">Tag reference</a></li> + <li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li> + <li class="divider"></li> + <li><a href="/docs/tutorials.html">Tutorials - DEPRECATED</a></li> + <li><a href="/docs/faqs.html">FAQs - DEPRECATED</a></li> + <li><a href="/docs/guides.html">Guides - DEPRECATED</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 class="divider"></li> + <li><a href="/submitting-patches.html">Submitting patches</a></li> + <li><a href="/builds.html">Source Code</a></li> + <li><a href="/coding-standards.html">Coding standards</a></li> + <li class="divider"></li> + <li><a href="/releases.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://git-wip-us.apache.org/repos/asf?p=struts.git">Source Repository</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/tag-developers/ognl.md" title="Edit this page on GitHub">Edit on GitHub</a> + <h1 class="no_toc" id="ognl">OGNL</h1> + +<ul id="markdown-toc"> + <li><a href="#collections-maps-lists-sets" id="markdown-toc-collections-maps-lists-sets">Collections (Maps, Lists, Sets)</a></li> + <li><a href="#lambda-expressions" id="markdown-toc-lambda-expressions">Lambda Expressions</a></li> +</ul> + +<p>OGNL is the Object Graph Navigation Language (see [http://commons.apache.org/proper/commons-ognl/] for the full +documentation of OGNL). Here, we will cover a few examples of OGNL features that co-exist with the framework. To review +basic concepts, refer to <a href="ognl-basics.html">OGNL Basics</a>.</p> + +<p>The framework uses a standard naming context to evaluate OGNL expressions. The top level object dealing with OGNL is +a Map (usually referred as a context map or context). OGNL has a notion of there being a root (or default) object within +the context. In expression, the properties of the root object can be referenced without any special âmarkerâ notion. +References to other objects are marked with a pound sign (<code class="highlighter-rouge">#</code>).</p> + +<p>The framework sets the OGNL context to be our ActionContext, and the value stack to be the OGNL root object. +(The value stack is a set of several objects, but to OGNL it appears to be a single object.) Along with the value stack, +the framework places other objects in the ActionContext, including Maps representing the application, session, +and request contexts. These objects coexist in the ActionContext, alongside the value stack (our OGNL root).</p> + +<div class="highlighter-rouge"><pre class="highlight"><code> | + |--application + | + |--session + context map---| + |--value stack(root) + | + |--action (the current action) + | + |--request + | + |--parameters + | + |--attr (searches page, request, session, then application scopes) + | +</code></pre> +</div> + +<p>The Action instance is always pushed onto the value stack. Because the Action is on the stack, and the stack is +the OGNL root, references to Action properties can omit the <code class="highlighter-rouge">#</code> marker. But, to access other objects in the ActionContext, +we must use the <code class="highlighter-rouge">#</code> notation so OGNL knows not to look in the root object, but for some other object in the ActionContext.</p> + +<p><strong>Referencing an Action property</strong></p> + +<pre><code class="language-jsp"><s:property value="postalCode"/> +</code></pre> + +<p>Other (non-root) objects in the ActionContext can be rendered use the <code class="highlighter-rouge">#</code> notation.</p> + +<pre><code class="language-jsp"><s:property value="#session.mySessionPropKey"/> or +<s:property value="#session['mySessionPropKey']"/> or +<s:property value="#request['myRequestPropKey']"/> +</code></pre> + +<p>The ActionContext is also exposed to Action classes via a static method but you <strong>should not</strong> use this approach. +Safer is to use one of the <code class="highlighter-rouge">*Aware</code> interafces.</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="n">ActionContext</span><span class="o">.</span><span class="na">getContext</span><span class="o">().</span><span class="na">getSession</span><span class="o">().</span><span class="na">put</span><span class="o">(</span><span class="s">"mySessionPropKey"</span><span class="o">,</span> <span class="n">mySessionObject</span><span class="o">);</span> +</code></pre> +</div> + +<p>You can also put expression for attributes that donât support dynamic content, like below:</p> + +<pre><code class="language-jsp"><c:set var="foo" value="bar" scope="request"/> +<s:textfield name="username" label="%{#request.foo}" /> +</code></pre> + +<h2 id="collections-maps-lists-sets">Collections (Maps, Lists, Sets)</h2> + +<p>Dealing with Collections (Maps, Lists, and Sets) in the framework comes often, so below please there are a few examples +using the select tag. The <a href="http://commons.apache.org/proper/commons-ognl/language-guide.html#Collection_Construction">OGNL documentation</a> +also includes some examples.</p> + +<p>Syntax for list: <code class="highlighter-rouge"><span class="p">{</span><span class="err">e1,e2,e3</span><span class="p">}</span></code>. This idiom creates a List containing the String âname1â, âname2â and âname3â. It also +selects âname2â as the default value.</p> + +<pre><code class="language-jsp"><s:select label="label" name="name" list="{'name1','name2','name3'}" value="%{'name2'}" /> +</code></pre> + +<p>Syntax for map: <code class="highlighter-rouge">#{key1:value1,key2:value2}</code>. This idiom creates a map that maps the string âfooâ to the string +âfoovalueâ and âbarâ to the string âbarvalueâ:</p> + +<pre><code class="language-jsp"><s:select label="label" name="name" list="#{'foo':'foovalue', 'bar':'barvalue'}" /> +</code></pre> + +<p>To determine if an element exists in a Collection, use the operations <code class="highlighter-rouge">in</code> and <code class="highlighter-rouge">not in</code>.</p> + +<pre><code class="language-jsp"><s:if test="'foo' in {'foo','bar'}"> + muhahaha +</s:if> +<s:else> + boo +</s:else> + +<s:if test="'foo' not in {'foo','bar'}"> + muhahaha +</s:if> +<s:else> + boo +</s:else> +</code></pre> + +<p>To select a subset of a collection (called projection), use a wildcard within the collection.</p> + +<ul> + <li><code class="highlighter-rouge">?</code> - All elements matching the selection logic</li> + <li><code class="highlighter-rouge">^</code> - Only the first element matching the selection logic</li> + <li><code class="highlighter-rouge">$</code> - Only the last element matching the selection logic</li> +</ul> + +<p>To obtain a subset of just male relatives from the object person:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code>person.relatives.{? #this.gender == 'male'} +</code></pre> +</div> + +<h2 id="lambda-expressions">Lambda Expressions</h2> + +<p>OGNL supports basic lamba expression syntax enabling you to write simple functions. +(Dedicated to all you math majors who didnât think you would ever see this one again.)</p> + +<p>Fibonacci: if n==0 return 0; elseif n==1 return 1; else return fib(n-2)+fib(n-1); + fib(0) = 0 + fib(1) = 1 + fib(11) = 89</p> + +<p><strong>How the expression works</strong></p> + +<blockquote> + <p>The lambda expression is everything inside the square brackets. The <code class="highlighter-rouge">#this</code> variable holds the argument to the expression, +which in the following example is the number 11 (the code after the square-bracketed lamba expression, <code class="highlighter-rouge">#fib(11)</code>).</p> +</blockquote> + +<pre><code class="language-jsp"><s:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" /> +</code></pre> + + </section> +</article> + + +<footer class="container"> + <div class="col-md-12"> + Copyright © 2000-2016 <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> + + +<script> +$(function() { + return $("h2, h3, h4, h5, h6").each(function(i, el) { + var $el, id; + $el = $(el); + id = $el.attr('id'); + if (id) { + $el.removeAttr('id'); + return $el.before($("<a />").addClass('anchor').attr('name', id)); + } + }); +}); +</script> + +</body> +</html> http://git-wip-us.apache.org/repos/asf/struts-site/blob/2b2ec9b3/content/tag-developers/param-tag.html ---------------------------------------------------------------------- diff --git a/content/tag-developers/param-tag.html b/content/tag-developers/param-tag.html new file mode 100644 index 0000000..45d18c8 --- /dev/null +++ b/content/tag-developers/param-tag.html @@ -0,0 +1,216 @@ +<!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>Tag Developers Guide (WIP)</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="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.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="/downloads.html">Downloads</a></li> + <li><a href="/announce.html">Announcements</a></li> + <li><a href="http://www.apache.org/licenses/">License</a></li> + <li><a href="http://apache.org/foundation/thanks.html">Thanks!</a></li> + <li><a href="http://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="/maven/project-info.html">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 class="divider"></li> + <li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li> + <li><a href="/docs/plugins.html">Plugin APIs</a></li> + <li><a href="/docs/tag-reference.html">Tag reference</a></li> + <li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li> + <li class="divider"></li> + <li><a href="/docs/tutorials.html">Tutorials - DEPRECATED</a></li> + <li><a href="/docs/faqs.html">FAQs - DEPRECATED</a></li> + <li><a href="/docs/guides.html">Guides - DEPRECATED</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 class="divider"></li> + <li><a href="/submitting-patches.html">Submitting patches</a></li> + <li><a href="/builds.html">Source Code</a></li> + <li><a href="/coding-standards.html">Coding standards</a></li> + <li class="divider"></li> + <li><a href="/releases.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://git-wip-us.apache.org/repos/asf?p=struts.git">Source Repository</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/tag-developers/param-tag.md" title="Edit this page on GitHub">Edit on GitHub</a> + <h1 id="param">param</h1> + +<p>Please make sure you have read the <a href="#PAGE_13927">Tag Syntax</a> document and understand how tag attribute syntax works.</p> + +<table> + <tbody> + <tr> + </tr> + </tbody> +</table> + +<p><strong>Description</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=javadoc|javadoc=true|url=org.apache.struts2.components.Param</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + +<p><strong>Parameters</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=tagattributes|javadoc=false|url=struts2-tags/param.html</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + +<p><strong>Examples</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=example|lang=xml|javadoc=true|url=org.apache.struts2.components.Param</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=exampledescription|javadoc=true|url=org.apache.struts2.components.Param</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + + </section> +</article> + + +<footer class="container"> + <div class="col-md-12"> + Copyright © 2000-2016 <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> + + +<script> +$(function() { + return $("h2, h3, h4, h5, h6").each(function(i, el) { + var $el, id; + $el = $(el); + id = $el.attr('id'); + if (id) { + $el.removeAttr('id'); + return $el.before($("<a />").addClass('anchor').attr('name', id)); + } + }); +}); +</script> + +</body> +</html> http://git-wip-us.apache.org/repos/asf/struts-site/blob/2b2ec9b3/content/tag-developers/property-tag.html ---------------------------------------------------------------------- diff --git a/content/tag-developers/property-tag.html b/content/tag-developers/property-tag.html new file mode 100644 index 0000000..460e6a1 --- /dev/null +++ b/content/tag-developers/property-tag.html @@ -0,0 +1,216 @@ +<!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>Tag Developers Guide (WIP)</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="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.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="/downloads.html">Downloads</a></li> + <li><a href="/announce.html">Announcements</a></li> + <li><a href="http://www.apache.org/licenses/">License</a></li> + <li><a href="http://apache.org/foundation/thanks.html">Thanks!</a></li> + <li><a href="http://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="/maven/project-info.html">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 class="divider"></li> + <li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li> + <li><a href="/docs/plugins.html">Plugin APIs</a></li> + <li><a href="/docs/tag-reference.html">Tag reference</a></li> + <li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li> + <li class="divider"></li> + <li><a href="/docs/tutorials.html">Tutorials - DEPRECATED</a></li> + <li><a href="/docs/faqs.html">FAQs - DEPRECATED</a></li> + <li><a href="/docs/guides.html">Guides - DEPRECATED</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 class="divider"></li> + <li><a href="/submitting-patches.html">Submitting patches</a></li> + <li><a href="/builds.html">Source Code</a></li> + <li><a href="/coding-standards.html">Coding standards</a></li> + <li class="divider"></li> + <li><a href="/releases.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://git-wip-us.apache.org/repos/asf?p=struts.git">Source Repository</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/tag-developers/property-tag.md" title="Edit this page on GitHub">Edit on GitHub</a> + <h1 id="property">property</h1> + +<p>Please make sure you have read the <a href="#PAGE_13927">Tag Syntax</a> document and understand how tag attribute syntax works.</p> + +<table> + <tbody> + <tr> + </tr> + </tbody> +</table> + +<p><strong>Description</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=javadoc|javadoc=true|url=org.apache.struts2.components.Property</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + +<p><strong>Parameters</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=tagattributes|javadoc=false|url=struts2-tags/property.html</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + +<p><strong>Examples</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=example|lang=xml|javadoc=true|url=org.apache.struts2.components.Property</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">snippet:id=exampledescription|lang=none|javadoc=true|url=org.apache.struts2.components.Property</span><span class="p">}</span><span class="w"> +</span></code></pre> +</div> + + </section> +</article> + + +<footer class="container"> + <div class="col-md-12"> + Copyright © 2000-2016 <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> + + +<script> +$(function() { + return $("h2, h3, h4, h5, h6").each(function(i, el) { + var $el, id; + $el = $(el); + id = $el.attr('id'); + if (id) { + $el.removeAttr('id'); + return $el.before($("<a />").addClass('anchor').attr('name', id)); + } + }); +}); +</script> + +</body> +</html>