blob: 03a0ee137daefb45dc028e32cc2e9f0103a001c7 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="Date-Revision-yyyymmdd" content="20140918"/>
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Plugins Architecture</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="/css/syntax.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/js/community.js"></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '41']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
<a href="https://github.com/apache/struts" class="github-ribbon">
<img decoding="async" loading="lazy" style="position: absolute; right: 0; border: 0;" width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_red_aa0000.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1">
</a>
<header>
<nav>
<div role="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#struts-menu" class="navbar-toggle">
Menu
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/index.html" class="navbar-brand logo"><img src="/img/struts-logo.svg"></a>
</div>
<div id="struts-menu" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Home<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/index.html">Welcome</a></li>
<li><a href="/download.cgi">Download</a></li>
<li><a href="/releases.html">Releases</a></li>
<li><a href="/announce-2024.html">Announcements</a></li>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks!</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</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><a href="/commercial-support.html">Commercial Support</a></li>
<li class="divider"></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Migration+Guide">Version Notes</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Security+Bulletins">Security Bulletins</a></li>
<li class="divider"></li>
<li><a href="/maven/project-info.html">Maven Project Info</a></li>
<li><a href="/maven/struts2-core/dependencies.html">Struts Core Dependencies</a></li>
<li><a href="/maven/struts2-plugins/modules.html">Plugin Dependencies</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Documentation<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/birdseye.html">Birds Eye</a></li>
<li><a href="/primer.html">Key Technologies</a></li>
<li><a href="/kickstart.html">Kickstart FAQ</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Home">Wiki</a></li>
<li class="divider"></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/security/">Security Guide</a></li>
<li><a href="/core-developers/">Core Developers Guide</a></li>
<li><a href="/tag-developers/">Tag Developers Guide</a></li>
<li><a href="/maven-archetypes/">Maven Archetypes</a></li>
<li><a href="/plugins/">Plugins</a></li>
<li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li>
<li><a href="/tag-developers/tag-reference.html">Tag reference</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/FAQs">FAQs</a></li>
<li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Contributing<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/youatstruts.html">You at Struts</a></li>
<li><a href="/helping.html">How to Help FAQ</a></li>
<li><a href="/dev-mail.html">Development Lists</a></li>
<li class="divider"></li>
<li><a href="/submitting-patches.html">Submitting patches</a></li>
<li><a href="/builds.html">Source Code and Builds</a></li>
<li><a href="/coding-standards.html">Coding standards</a></li>
<li><a href="/contributors/">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/release-guidelines.html">Release Guidelines</a></li>
<li><a href="/bylaws.html">PMC Charter</a></li>
<li><a href="/volunteers.html">Volunteers</a></li>
<li><a href="https://gitbox.apache.org/repos/asf?p=struts.git">Source Repository</a></li>
<li><a href="/updating-website.html">Updating the website</a></li>
</ul>
</li>
<li class="apache"><a href="http://www.apache.org/"><img src="/img/apache.png"></a></li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<article class="container">
<section class="col-md-12">
<a class="edit-on-gh" href="https://github.com/apache/struts-site/edit/master/source/plugins/plugins-architecture.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="index.html" title="back to Plugins"><< back to Plugins</a>
<h1 class="no_toc" id="plugins-architecture">Plugins architecture</h1>
<ul id="markdown-toc">
<li><a href="#static-resources" id="markdown-toc-static-resources">Static resources</a></li>
<li><a href="#extension-points" id="markdown-toc-extension-points">Extension Points</a></li>
<li><a href="#plugin-examples" id="markdown-toc-plugin-examples">Plugin Examples</a> <ul>
<li><a href="#sitemesh-plugin" id="markdown-toc-sitemesh-plugin">Sitemesh plugin</a></li>
<li><a href="#tiles-plugin" id="markdown-toc-tiles-plugin">Tiles plugin</a></li>
</ul>
</li>
<li><a href="#developing-new-extension-point" id="markdown-toc-developing-new-extension-point">Developing new extension point</a> <ul>
<li><a href="#extension-point-provided-by-the-core" id="markdown-toc-extension-point-provided-by-the-core">Extension point provided by the Core</a></li>
<li><a href="#plugin-ext" id="markdown-toc-plugin-ext">Plugin-defined extension points</a></li>
</ul>
</li>
<li><a href="#plugin-registry" id="markdown-toc-plugin-registry">Plugin Registry</a></li>
</ul>
<p>Struts 2 plugins contain classes and configuration that extend, replace, or add to existing Struts framework
functionality. A plugin can be installed by adding its JAR file to the application’s class path, in addition to the JAR
files to fulfill whatever dependencies the plugin itself may have. To configure the plugin, the JAR should contain
a <code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> file and optionally a <code class="language-plaintext highlighter-rouge">struts-deferred.xml</code>, which follow the same format as an
ordinary <code class="language-plaintext highlighter-rouge">struts.xml</code> file.</p>
<p>Since a plugin can contain these xml files, they have the ability to:</p>
<ul>
<li>Define new packages with results, interceptors, and/or actions</li>
<li>Override framework constants</li>
<li>Introduce new extension point implementation classes</li>
</ul>
<p>Whilst configuration from <code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> is loaded prior to <code class="language-plaintext highlighter-rouge">struts.xml</code>, <code class="language-plaintext highlighter-rouge">struts-deferred.xml</code> is loaded after all
other configuration is loaded. This makes it useful for defining <a href="#plugin-ext">plugin extension points</a>.</p>
<p>Many popular but optional features of the framework are distributed as plugins. An application can retain all the
plugins provided with the distribution, or just include the ones it uses. Plugins can be used to organize application
code or to distribute code to third-parties.</p>
<p>Packages defined in a plugin can have parent packages that are defined in another plugin. Plugins may define
configuration elements with classes not contained in the plugin. Any classes not included in the plugin’s JAR must be on
the application’s classpath at runtime. As from Struts 2.3.5</p>
<p>The framework loads its default configuration first, then any <code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> files found in others JARs on the
classpath, the “bootstrap” <code class="language-plaintext highlighter-rouge">struts.xml</code>, then finally any <code class="language-plaintext highlighter-rouge">struts-deferred.xml</code> files.</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">struts-default.xml</code> (bundled in the Core JAR)</li>
<li><code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> (as many as can be found in other JARs)</li>
<li><code class="language-plaintext highlighter-rouge">struts.xml</code> (provided by your application)</li>
<li><code class="language-plaintext highlighter-rouge">struts-deferred.xml</code> (as many as can be found in other JARs)</li>
</ol>
<p>Since the <code class="language-plaintext highlighter-rouge">struts.xml</code> file is loaded between <code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> and before any potential plugin extension points
in <code class="language-plaintext highlighter-rouge">struts-deferred.xml</code>, it can make use of any resources provided by the plugins bundled with the distribution, or any
other plugins available to an application.</p>
<h2 id="static-resources">Static resources</h2>
<p>To include static resources in your plugins add them under “/static” in your jar. And include them in your page using
“/static” as the path, like in the following example:</p>
<div class="language-ftl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">&lt;!--</span><span class="w"> </span>Assuming /static/main.css is inside a plugin jar, to add it to the page: --&gt;<span class="w">
</span><span class="err">&lt;@</span><span class="no">s</span><span class="na">.url</span><span class="w"> </span>value="/static/main.css" var="css" /&gt;<span class="w">
</span><span class="err">&lt;</span><span class="no">link</span><span class="w"> </span>rel="stylesheet" type="text/css" href="%<span class="p">{</span><span class="err">#</span><span class="no">css</span><span class="p">}</span>" /&gt;<span class="w">
</span></code></pre></div></div>
<p>Read also <a href="../core-developers/static-content">Static Content</a> and JavaDoc of <a href="https://struts.apache.org/maven/struts2-core/apidocs/org/apache/struts2/dispatcher/StaticContentLoader">StaticContentLoader</a>.</p>
<h2 id="extension-points">Extension Points</h2>
<p>Extension points allow a plugin to override a key class in the Struts framework with an alternate implementation.
For example, a plugin could provide a new class to create Action classes or map requests to Actions.</p>
<p>The following extension points are available in Struts 2:</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Description</th>
<th>Scope</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>struts.objectFactory</td>
<td>Creates actions, results, and interceptors</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.ObjectFactory</td>
</tr>
<tr>
<td>struts.objectFactory.actionFactory</td>
<td>Dedicated factory used to create Actions, you can implement/extend existing one instead of defining new ObjectFactory</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.factory.ActionFactory</td>
</tr>
<tr>
<td>struts.objectFactory.resultFactory</td>
<td>Dedicated factory used to create Results, you can implement/extend existing one instead of defining new ObjectFactory</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.factory.ResultFactory</td>
</tr>
<tr>
<td>struts.objectFactory.interceptorFactory</td>
<td>Dedicated factory used to create Interceptors, you can implement/extend existing one instead of defining new ObjectFactory</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.factory.InterceptorFactory</td>
</tr>
<tr>
<td>struts.objectFactory.converterFactory</td>
<td>Dedicated factory used to create TypeConverters, you can implement/extend existing one instead of defining new ObjectFactory</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.factory.ConverterFactory</td>
</tr>
<tr>
<td>struts.objectFactory.validatorFactory</td>
<td>Dedicated factory used to create Validators, you can implement/extend existing one instead of defining new ObjectFactory</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.factory.ValidatorFactory</td>
</tr>
<tr>
<td>struts.actionProxyFactory</td>
<td>Creates the ActionProxy</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.ActionProxyFactory</td>
</tr>
<tr>
<td>struts.objectTypeDeterminer</td>
<td>Determines what the key and element class of a Map or Collection should be</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.util.ObjectTypeDeterminer</td>
</tr>
<tr>
<td>struts.mapper.class</td>
<td>Determines the ActionMapping from a request and a URI from an ActionMapping</td>
<td>singleton</td>
<td>org.apache.struts2.dispatcher.mapper.ActionMapper</td>
</tr>
<tr>
<td>struts.multipart.parser</td>
<td>Parses a multipart request (file upload)</td>
<td>per request</td>
<td>org.apache.struts2.dispatcher.multipart.MultiPartRequest</td>
</tr>
<tr>
<td>struts.freemarker.manager.classname</td>
<td>Loads and processes Freemarker templates</td>
<td>singleton</td>
<td>org.apache.struts2.views.freemarker.FreemarkerManager</td>
</tr>
<tr>
<td>struts.velocity.manager.classname</td>
<td>Loads and processes Velocity templates</td>
<td>singleton</td>
<td>org.apache.struts2.views.velocity.VelocityManagerInterface</td>
</tr>
<tr>
<td>struts.actionValidatorManager</td>
<td>Main interface for validation managers (regular and annotation based). Handles both the loading of configuration and the actual validation (since 2.1)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.validator.ActionValidatorManager</td>
</tr>
<tr>
<td>struts.valueStackFactory</td>
<td>Creates value stacks (since 2.1)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.util.ValueStackFactory</td>
</tr>
<tr>
<td>struts.reflectionProvider</td>
<td>Provides reflection services, key place to plug in a custom expression language (since 2.1)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.reflection.ReflectionProvider</td>
</tr>
<tr>
<td>struts.reflectionContextFactory</td>
<td>Creates reflection context maps used for reflection and expression language operations (since 2.1)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.reflection.ReflectionContextFactory</td>
</tr>
<tr>
<td>N/A</td>
<td>All beans registered as PackageProvider implementations will be automatically included in configuration building (since 2.1)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.config.PackageProvider</td>
</tr>
<tr>
<td>struts.patternMatcher</td>
<td>Matches patterns, such as action names, generally used in configuration (since 2.1)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.util.PatternMatcher</td>
</tr>
<tr>
<td>struts.staticContentLoader</td>
<td>Loads static resources (since 2.1)</td>
<td>singleton</td>
<td>org.apache.struts2.views.dispatcher.DefaultStaticContentLoader</td>
</tr>
<tr>
<td>struts.xworkConverter</td>
<td>Handles conversion logic and allows to load custom converters per class or per action</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.impl.XWorkConverter</td>
</tr>
<tr>
<td>struts.localeProviderFactory</td>
<td>Allows provide custom LocaleProvider for whole application</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.LocaleProviderFactory</td>
</tr>
<tr>
<td>struts.urlRenderer</td>
<td>Allows provide custom implementation of environment specific URL rendering/creating class</td>
<td>singleton</td>
<td>org.apache.struts2.components.UrlRenderer</td>
</tr>
<tr>
<td>struts.unknownHandlerManager</td>
<td>Implementation of this interface allows handle logic of unknown Actions, Methods or Results</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.UnknownHandlerManager</td>
</tr>
<tr>
<td>struts.view.urlHelper</td>
<td>Helper class used with URLRenderer to provide exact logic for building URLs</td>
<td>singleton</td>
<td>org.apache.struts2.views.util.UrlHelper</td>
</tr>
<tr>
<td>struts.fileManagerFactory</td>
<td>Used to create FileManager instance to access files on the File System as also to monitor if reload is needed, can be implemented / overwritten to meet specific an application server needs</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.FileManagerFactory</td>
</tr>
<tr>
<td>struts.converter.collection</td>
<td>Converter used to convert any object to Collection and back</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.impl.CollectionConverter</td>
</tr>
<tr>
<td>struts.converter.array</td>
<td>Converter used to convert any object to Array and back</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.impl.ArrayConverter</td>
</tr>
<tr>
<td>struts.converter.date</td>
<td>Converter used to convert any object to Date and back</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.impl.DateConverter</td>
</tr>
<tr>
<td>struts.converter.number</td>
<td>Converter used to convert any object to Number and back</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.impl.NumberConverter</td>
</tr>
<tr>
<td>struts.converter.string</td>
<td>Converter used to convert any object to String and back</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.impl.StringConverter</td>
</tr>
<tr>
<td>struts.conversion.properties.processor</td>
<td>Process Properties to create converters</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor</td>
</tr>
<tr>
<td>struts.converter.file.processor</td>
<td>Process {class}-conversion.properties file create converters</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor</td>
</tr>
<tr>
<td>struts.converter.annotation.processor</td>
<td>Process TypeConversion annotation to create converters</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor</td>
</tr>
<tr>
<td>struts.converter.creator</td>
<td>Creates user converters</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.TypeConverterCreator</td>
</tr>
<tr>
<td>struts.converter.holder</td>
<td>Holds user converters’ instances</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.conversion.TypeConverterHolder</td>
</tr>
<tr>
<td>struts.expression.parser</td>
<td>Used to parse expressions like ${foo.bar} or %{bar.foo} but it is up tp the TextParser’s implementation what kind of opening char to use (#, $, %, etc)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.util.TextParser</td>
</tr>
<tr>
<td>struts.excludedPatterns.checker</td>
<td>Used across different interceptors to check if given string matches one of the excluded patterns</td>
<td>request</td>
<td>com.opensymphony.xwork2.ExcludedPatternsChecker</td>
</tr>
<tr>
<td>struts.acceptedPatterns.checker</td>
<td>Used across different interceptors to check if given string matches one of the accepted patterns</td>
<td>request</td>
<td>com.opensymphony.xwork2.AcceptedPatternsChecker</td>
</tr>
<tr>
<td>struts.contentTypeMatcher</td>
<td>Matches content type of uploaded files (since 2.3.22)</td>
<td>singleton</td>
<td>org.apache.struts2.util.ContentTypeMatcher</td>
</tr>
<tr>
<td>struts.localizedTextProvider</td>
<td>Provides access to resource bundles used to localise messages (since 2.5.11)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.LocalizedTextProvider</td>
</tr>
<tr>
<td>struts.date.formatter</td>
<td>Allow define a date formatter used by <code class="language-plaintext highlighter-rouge">&lt;s:date/&gt;</code> tag (since 6.0.0)</td>
<td>singleton</td>
<td>org.apache.struts2.components.date.DateFormatter</td>
</tr>
<tr>
<td>struts.ognlGuard</td>
<td>Define a custom OgnlGuard implementation to block raw or compiled OGNL expressions (since 6.4.0)</td>
<td>singleton</td>
<td>org.apache.struts2.ognl.OgnlGuard</td>
</tr>
<tr>
<td>struts.securityMemberAccess</td>
<td>Define a custom SecurityMemberAccess implementation, used to restrict OGNL evaluations based on classes involved (since 6.4.0)</td>
<td>prototype</td>
<td>com.opensymphony.xwork2.ognl.SecurityMemberAccess</td>
</tr>
<tr>
<td>struts.compoundRootAccessor</td>
<td>Define a custom CompoundRootAccessor implementation, used to resolve classes and manipulate the CompoundRoot (since 6.4.0)</td>
<td>singleton</td>
<td>com.opensymphony.xwork2.ognl.accessor.RootAccessor</td>
</tr>
<tr>
<td>struts.methodAccessor</td>
<td>Define a custom MethodAccessor implementation, used to evaluate OGNL method calls (since 6.4.0)</td>
<td>singleton</td>
<td>ognl.MethodAccessor</td>
</tr>
</tbody>
</table>
<h2 id="plugin-examples">Plugin Examples</h2>
<p>Let’s look at two similar but different plugins bundled with the core distribution.</p>
<h3 id="sitemesh-plugin">Sitemesh plugin</h3>
<p><a href="http://opensymphony.com/sitemesh/">SiteMesh</a> is a popular alternative to Tiles. SiteMesh provides a common look-and-feel
to an application’s pages by automatically wrapping a plain page with common elements like headers and menubars.</p>
<p>The <code class="language-plaintext highlighter-rouge">sitemesh-plugin.jar</code> contains several classes, a standard JAR manifest, and a plugin configuration file.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code> + META-INF/
+ manifest.mf
+ org
+ apache
+ struts2
+ sitemesh
+ FreeMarkerPageFilter.class
+ TemplatePageFilter.class
+ VelocityPageFilter.class
+ struts-plugin.xml
</code></pre></div></div>
<p>While the SiteMesh Plugin doesn’t provide any new results, interceptors, or actions, or even extend any Struts integration
points, it does need to know what settings have been enabled in the Struts framework. Therefore, its <code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> looks like this:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;</span>
<span class="c">&lt;!--
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
--&gt;</span>
<span class="cp">&lt;!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd"&gt;</span>
<span class="nt">&lt;struts&gt;</span>
<span class="nt">&lt;bean</span> <span class="na">class=</span><span class="s">"org.apache.struts2.sitemesh.FreemarkerPageFilter"</span> <span class="na">static=</span><span class="s">"true"</span> <span class="na">optional=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;bean</span> <span class="na">class=</span><span class="s">"org.apache.struts2.sitemesh.VelocityPageFilter"</span> <span class="na">static=</span><span class="s">"true"</span> <span class="na">optional=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<p>The two bean elements, with the “static” flag enabled, tell Struts to inject the current settings and framework objects
into static property setters on startup. This allows, for example, the FreeMarkerPageFilter class to get an instance
of the Struts FreemarkerManager and the current encoding setting.</p>
<h3 id="tiles-plugin">Tiles plugin</h3>
<p><a href="http://struts.apache.org/struts-sandbox/tiles/index">Tiles</a> is a popular alternative to SiteMesh. Tiles provides
a common look-and-feel to an application’s pages by breaking the page down into common fragments or “tiles”.</p>
<p>The <code class="language-plaintext highlighter-rouge">tiles-plugin.jar</code> contains several classes, a standard JAR manifest, and a configuration file.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code> + META-INF/
+ manifest.mf
+ org
+ apache
+ struts2
+ tiles
+ StrutsTilesListener.class
+ StrutsTileUtilImpl.class
+ views
+ tiles
+ TilesResult.class
+ struts-plugin.xml
</code></pre></div></div>
<p>Since the Tiles Plugin does need to register configuration elements, a result class, it provides a <code class="language-plaintext highlighter-rouge">struts-plugin.xml</code> file.</p>
<h2 id="developing-new-extension-point">Developing new extension point</h2>
<p>An extension point it’s a name which will be used to locate other beans by the name and inject them into a given place.
Extension point isn’t a bean, you cannot inject it. It’s a bridge between your interface/class and the final implementation,
provided either by a plugin or by a user.</p>
<p>If needed you can define your own extension point. This can happen in two ways: either define it in the Struts Core,
or define the extension in the plugin you are developing.</p>
<h3 id="extension-point-provided-by-the-core">Extension point provided by the Core</h3>
<p>First step is to name your extension point, basically we are using a pattern like follow:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struts.&lt;component | functionallity&gt;.&lt;name of the extebsion point&gt;
</code></pre></div></div>
<p>e.g.: <code class="language-plaintext highlighter-rouge">struts.date.formatter</code>.</p>
<p>Now you must provide an interface or a class as the extension point, it will be used by others to implement they own behaviour
of the extension point, e.g.: <code class="language-plaintext highlighter-rouge">org.apache.struts2.components.date.DateFormatter</code>.</p>
<p>The next step is to tie the name of the extension point with the interface/class. It happens in <code class="language-plaintext highlighter-rouge">StrutsBeanSelectionProvider</code></p>
<p>by using <code class="language-plaintext highlighter-rouge">alias()</code> method as below:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">alias</span><span class="o">(</span><span class="nc">DateFormatter</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="nc">StrutsConstants</span><span class="o">.</span><span class="na">STRUTS_DATE_FORMATTER</span><span class="o">,</span> <span class="n">builder</span><span class="o">,</span> <span class="n">props</span><span class="o">,</span> <span class="nc">Scope</span><span class="o">.</span><span class="na">SINGLETON</span><span class="o">);</span>
</code></pre></div></div>
<p>as you can see you must provide:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Class&lt;?&gt;</code> class behind the extension point, which is used by users to implement the extension point</li>
<li><code class="language-plaintext highlighter-rouge">String</code> a key, the name of the extension point</li>
<li><code class="language-plaintext highlighter-rouge">ContainerBuilder</code> builder used to setup the Container</li>
<li><code class="language-plaintext highlighter-rouge">Properties</code> additional properties when needed</li>
<li><code class="language-plaintext highlighter-rouge">Scope</code> scope of the extension point, all the beans extneding the extension point must have the same scope</li>
</ul>
<p>Having all that set, you can define where to use the extension point by injecting beans implementing it by using <code class="language-plaintext highlighter-rouge">@Inject</code></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Inject</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setDateFormatter</span><span class="o">(</span><span class="nc">DateFormatter</span> <span class="n">dateFormatter</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">dateFormatter</span> <span class="o">=</span> <span class="n">dateFormatter</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>you can use <code class="language-plaintext highlighter-rouge">optional = true</code> if the implementation is not required, yet please remember to handle <code class="language-plaintext highlighter-rouge">null</code> in such case.</p>
<p>All the above steps have defined a new extension point, now you can implement a bean which will be <em>bridged</em> throughout
the extension point with the <code class="language-plaintext highlighter-rouge">@Inject</code>. Just implement the interface/class used to define the extension point and define
the bean in <code class="language-plaintext highlighter-rouge">struts-default.xml</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">DateTimeFormatterAdapter</span> <span class="kd">implements</span> <span class="nc">DateFormatter</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">format</span><span class="o">(</span><span class="nc">TemporalAccessor</span> <span class="n">temporal</span><span class="o">,</span> <span class="nc">String</span> <span class="n">format</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">DateTimeFormatter</span> <span class="n">dtf</span><span class="o">;</span>
<span class="nc">Locale</span> <span class="n">locale</span> <span class="o">=</span> <span class="nc">ActionContext</span><span class="o">.</span><span class="na">getContext</span><span class="o">().</span><span class="na">getLocale</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">format</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">dtf</span> <span class="o">=</span> <span class="nc">DateTimeFormatter</span><span class="o">.</span><span class="na">ofLocalizedDateTime</span><span class="o">(</span><span class="nc">FormatStyle</span><span class="o">.</span><span class="na">MEDIUM</span><span class="o">)</span>
<span class="o">.</span><span class="na">withLocale</span><span class="o">(</span><span class="n">locale</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">dtf</span> <span class="o">=</span> <span class="nc">DateTimeFormatter</span><span class="o">.</span><span class="na">ofPattern</span><span class="o">(</span><span class="n">format</span><span class="o">,</span> <span class="n">locale</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">dtf</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="n">temporal</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.components.date.DateFormatter"</span>
<span class="na">name=</span><span class="s">"dateTimeFormatter"</span>
<span class="na">class=</span><span class="s">"org.apache.struts2.components.date.DateTimeFormatterAdapter"</span>
<span class="na">scope=</span><span class="s">"singleton"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">name</code> attribute it’s of your choice, it just needs to be unique.</p>
<p>And the final step is to use the new bean with the extension point, this will happen in <code class="language-plaintext highlighter-rouge">default.properties</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struts.date.formatter=dateTimeFormatter
</code></pre></div></div>
<p>and done!</p>
<p>If a user would like to provide its own implementation they just needs to implement the interface, define a bean
in <code class="language-plaintext highlighter-rouge">struts.xml</code> with a name and then tie it to the extension point overriding the one provided by the framework:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.components.date.DateFormatter"</span>
<span class="na">name=</span><span class="s">"myDateTimeFormatter"</span>
<span class="na">class=</span><span class="s">"com.company.date.MyDateTimeFormatterAdapter"</span>
<span class="na">scope=</span><span class="s">"singleton"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struts.date.formatter=myDateTimeFormatter
</code></pre></div></div>
<h3 id="plugin-ext">Plugin-defined extension points</h3>
<p>It’s very much like above except that the plugin must provide a <code class="language-plaintext highlighter-rouge">bean-selection</code> configuration option
in <code class="language-plaintext highlighter-rouge">struts-deferred.xml</code>. The <code class="language-plaintext highlighter-rouge">bean-selection</code> option represents an implementation of a
class <code class="language-plaintext highlighter-rouge">org.apache.struts2.config.AbstractBeanSelectionProvider</code>
with <em>no-arguments</em> constructor:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">VelocityBeanSelectionProvider</span> <span class="kd">extends</span> <span class="nc">AbstractBeanSelectionProvider</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">register</span><span class="o">(</span><span class="nc">ContainerBuilder</span> <span class="n">builder</span><span class="o">,</span> <span class="nc">LocatableProperties</span> <span class="n">props</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">ConfigurationException</span> <span class="o">{</span>
<span class="n">alias</span><span class="o">(</span><span class="nc">VelocityManagerInterface</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="nc">VelocityConstants</span><span class="o">.</span><span class="na">STRUTS_VELOCITY_MANAGER_CLASSNAME</span><span class="o">,</span> <span class="n">builder</span><span class="o">,</span> <span class="n">props</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The class defines extension points by implementing <code class="language-plaintext highlighter-rouge">register()</code> method and using <code class="language-plaintext highlighter-rouge">alias()</code> method to register them.</p>
<p>And finally it must be added to the <code class="language-plaintext highlighter-rouge">struts-deferred.xml</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;</span>
<span class="cp">&lt;!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
"http://struts.apache.org/dtds/struts-2.6.dtd"&gt;</span>
<span class="nt">&lt;struts&gt;</span>
...
<span class="nt">&lt;bean-selection</span> <span class="na">name=</span><span class="s">"velocityBeans"</span> <span class="na">class=</span><span class="s">"org.apache.struts2.views.velocity.VelocityBeanSelectionProvider"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<p>And now other plugins or user application can use the new extension point represented by <code class="language-plaintext highlighter-rouge">VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME</code>.</p>
<h2 id="plugin-registry">Plugin Registry</h2>
<blockquote>
<p>For a list of bundled plugins, see the <a href="index">Plugin Reference Documentation</a>. For more about bundled and third-party
plugins, visit the <a href="http://cwiki.apache.org/S2PLUGINS/home">Apache Struts Plugin Registry</a>.</p>
</blockquote>
</section>
</article>
<footer class="container">
<div class="col-md-12">
Copyright &copy; 2000-2022 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation. All Rights Reserved.
</div>
<div class="col-md-12">Logo and website design donated by <a href="https://softwaremill.com/">SoftwareMill</a>.</div>
</footer>
<script>!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
<script src="https://apis.google.com/js/platform.js" async="async" defer="defer"></script>
<div id="fb-root"></div>
<script>(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
</body>
</html>