struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lukaszlen...@apache.org
Subject struts-site git commit: Exports Convention plugin documentation
Date Thu, 13 Jul 2017 11:37:44 GMT
Repository: struts-site
Updated Branches:
  refs/heads/master 233616b58 -> 6b268e76b


Exports Convention plugin documentation


Project: http://git-wip-us.apache.org/repos/asf/struts-site/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts-site/commit/6b268e76
Tree: http://git-wip-us.apache.org/repos/asf/struts-site/tree/6b268e76
Diff: http://git-wip-us.apache.org/repos/asf/struts-site/diff/6b268e76

Branch: refs/heads/master
Commit: 6b268e76b89f6c99a99ee46158398a6d9e2f0c7e
Parents: 233616b
Author: Lukasz Lenart <lukasz.lenart@gmail.com>
Authored: Thu Jul 13 13:32:47 2017 +0200
Committer: Lukasz Lenart <lukasz.lenart@gmail.com>
Committed: Thu Jul 13 13:32:47 2017 +0200

----------------------------------------------------------------------
 pom.xml                                 |   4 +-
 source/_includes/header.html            |   1 +
 source/_layouts/plugin.html             |  50 ++
 source/core-developers/index.md         |   4 +-
 source/plugins/convention/converting.md |  39 ++
 source/plugins/convention/index.md      | 866 +++++++++++++++++++++++++++
 source/plugins/index.md                 |   9 +
 7 files changed, 969 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts-site/blob/6b268e76/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 82fe124..e5fbb97 100644
--- a/pom.xml
+++ b/pom.xml
@@ -94,14 +94,14 @@
                                         <argument>-a</argument>
                                         <argument>${project.build.directory}/md/attachments</argument>
                                         <argument>-o</argument>
-                                        <argument>${project.build.directory}/md/core-developers.md</argument>
+                                        <argument>${project.build.directory}/md/convention-plugin.md</argument>
                                         <argument>-u</argument>
                                         <argument>${confluence.user}:${confluence.password}</argument>
                                         <argument>-server</argument>
                                         <argument>https://cwiki.apache.org/confluence</argument>
                                         <argument>+gfm</argument>
                                         <argument>true</argument>
-                                        <argument>13945</argument>
+                                        <argument>105613</argument>
                                     </arguments>
                                 </configuration>
                             </execution>

http://git-wip-us.apache.org/repos/asf/struts-site/blob/6b268e76/source/_includes/header.html
----------------------------------------------------------------------
diff --git a/source/_includes/header.html b/source/_includes/header.html
index faeaa2a..1009d07 100644
--- a/source/_includes/header.html
+++ b/source/_includes/header.html
@@ -67,6 +67,7 @@
                 <li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin
registry</a></li>
                 <li class="divider"></li>                
                 <li><a href="/core-developers/">Core Developers Guide (WIP)</a></li>
+                <li><a href="/plugins/">Plugins (WIP)</a></li>
               </ul>
             </li>
             <li class="dropdown">

http://git-wip-us.apache.org/repos/asf/struts-site/blob/6b268e76/source/_layouts/plugin.html
----------------------------------------------------------------------
diff --git a/source/_layouts/plugin.html b/source/_layouts/plugin.html
new file mode 100644
index 0000000..88d96db
--- /dev/null
+++ b/source/_layouts/plugin.html
@@ -0,0 +1,50 @@
+<!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>{{ page.title }}</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>
+
+{% include header.html %}
+
+<article class="container">
+  <section class="col-md-12">
+    <a href="../" title="back to Plugins"><< back to Plugins</a>
+    {{ content }}
+  </section>
+</article>
+
+{% include footer.html %}
+
+<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/6b268e76/source/core-developers/index.md
----------------------------------------------------------------------
diff --git a/source/core-developers/index.md b/source/core-developers/index.md
index 2760641..df58ef6 100644
--- a/source/core-developers/index.md
+++ b/source/core-developers/index.md
@@ -5,7 +5,7 @@ title: Core Developers Guide (WIP)
 
 # Core Developers Guide (WIP)
 
-Struts 2 processes requests using three core types: [interceptors](interceptor-configuration.html),
[actions](#PAGE_14122), and [results](result-configuration.html). 
+Struts 2 processes requests using three core types: [interceptors](interceptor-configuration.html),
[actions](action-configuration.html), and [results](result-configuration.html). 
 Each may be configured via XML or annotations.
 
 ## Developing Applications with Struts 2
@@ -18,7 +18,7 @@ Each may be configured via XML or annotations.
 
 ## Configuration
 
-- [Configuration by Convention] - export https://cwiki.apache.org/confluence/display/WW/Convention+Plugin
+- [Configuration by Convention](../plugins/convention/)
 - [Annotations](annotations.html)
 - [Configuration Elements](configuration-elements.html)
   - [Actions](action-configuration.html), [Wildcard Mappings](wildcard-mappings.html), [Beans](bean-configuration.html),
[Constants](constant-configuration.html)

http://git-wip-us.apache.org/repos/asf/struts-site/blob/6b268e76/source/plugins/convention/converting.md
----------------------------------------------------------------------
diff --git a/source/plugins/convention/converting.md b/source/plugins/convention/converting.md
new file mode 100644
index 0000000..410a86c
--- /dev/null
+++ b/source/plugins/convention/converting.md
@@ -0,0 +1,39 @@
+---
+layout: default
+title: Converting application from Codebehind to Convention Plugin (WIP)
+---
+
+[<< back to Convention Plugin](./)
+
+# Converting application from Codebehind to Convention Plugin
+
+[Edit on GitHub]({{ site.repository_url }}/edit/master/source/{{ page.path }}){: .edit-on-gh
title="Edit this page on GitHub"}
+
+## Changes required
+
+ - Replace `org.apache.struts2.config.Namespace` with `org.apache.struts2.convention.annotation.Namespace`
+ - Replace `org.apache.struts2.config.Results` with `org.apache.struts2.convention.annotation.Results`
+ - Replace `org.apache.struts2.config.Result` with `org.apache.struts2.convention.annotation.Result`
+ - Update `@Result` uses to use result **name** instead of `Class<Result>`
+ - Update `@Result` uses to use **location** instead of value attribute
+ - Update `web.xml` and remove Codebehind params from filter
+ - Update CamelCase action results and references to match Convention. For example:
+
+   ```
+    Previously in Codebehind:
+    Given an action named AnExampleAction, a request to /anExample -> AnExampleAction.execute()
-> > anExample-index.ftl
+
+    Now in Convention:
+    Given an action named AnExampleAction, a request to /an-example -> AnExampleAction.execute()
-> an-example-index.ftl    
+   ```
+
+## When REST plugin is used
+
+Add these constants to `struts.xml`
+
+```xml
+<constant name="struts.convention.action.suffix" value="Controller"/>
+<constant name="struts.convention.action.mapAllMatches" value="true"/>
+<constant name="struts.convention.default.parent.package" value="rest-default"/>
+<constant name="struts.convention.package.locators" value="example"/>
+```

http://git-wip-us.apache.org/repos/asf/struts-site/blob/6b268e76/source/plugins/convention/index.md
----------------------------------------------------------------------
diff --git a/source/plugins/convention/index.md b/source/plugins/convention/index.md
new file mode 100644
index 0000000..37c794c
--- /dev/null
+++ b/source/plugins/convention/index.md
@@ -0,0 +1,866 @@
+---
+layout: plugin
+title: Convention plugin
+---
+
+# Convention Plugin
+{:.no_toc}
+
+[Edit on GitHub]({{ site.repository_url }}/edit/master/source/{{ page.path }}){: .edit-on-gh
title="Edit this page on GitHub"}
+
+* Will be replaced with the ToC, excluding a header
+{:toc}
+
+## Introduction
+
+The Convention Plugin is bundled with Struts since 2.1 and replaces the _Codebehind Plugin_
 and Zero Config plugins. 
+It provides the following features:
+
+ - Action location by package naming conventions
+ - Result (JSP, FreeMarker, etc) location by naming conventions
+ - Class name to URL naming convention
+ - Package name to namespace convention
+ - SEO compliant URLs (i.e. `my-action` rather than `MyAction`)
+ - Action name overrides using annotations
+ - Interceptor overrides using annotations
+ - Namespace overrides using annotations
+ - XWork package overrides using annotations
+ - Default action and result handling (i.e. `/products` will try `com.example.actions.Products`
as well as 
+   `com.example.actions.products.Index`)
+
+The Convention Plugin should require no configuration to use. Many of the conventions can
be controlled using 
+configuration properties and many of the classes can be extended or overridden.
+
+## Setup
+
+In order to use the Convention plugin, you first need to add the JAR file to the `WEB-INF/lib`
directory of your 
+application or include the dependency in your project's Maven POM file.
+
+```xml
+<dependency>
+    <groupId>org.apache.struts</groupId>
+    <artifactId>struts2-convention-plugin</artifactId>
+    <version>X.X.X</version>
+</dependency>
+```
+
+Where `X.X.X` is the current version of Struts 2. Please remember that the Convention Plugin
is available from 
+version 2.1.6.
+
+## Converting a Codebehind based application to Convention
+
+See [this page](converting.html) for the required changes and tips.
+
+If you are using REST with the Convention plugin, make sure you set these constants in `struts.xml`:
+
+```xml
+<constant name="struts.convention.action.suffix" value="Controller"/>
+<constant name="struts.convention.action.mapAllMatches" value="true"/>
+<constant name="struts.convention.default.parent.package" value="rest-default"/>
+```
+
+## Hello world
+
+Now that the Convention plugin has been added to your application, let's start with a very
simple example. This example 
+will use an actionless result that is identified by the URL. By default, the Convention plugin
assumes that all 
+of the results are stored in **WEB-INF/content**. This can be changed by setting the property

+`struts.convention.result.path` in the Struts properties file to the new location. Don't
worry about trailing slashes, 
+the Convention plugin handles this for you. Here is our hello world JSP:
+
+```jsp
+<html>
+<body>
+  Hello world!
+</body>
+</html>
+```
+
+If you start Tomcat (or whichever J2EE container you are using) and type in 
+[http://localhost:8080/hello-world](http://localhost:8080/hello-world) (assuming that your
context path is `/`, 
+ie. starting application from Eclipse) into your browser you should get this result:
+
+**WEB-INF/content/hello-world.jsp**
+
+```
+Hello world!
+```
+   
+This illustrates that the Convention plugin will find results even when no action exists
and it is all based on the URL 
+passed to Struts.
+
+## Code behind hello world
+
+Let's expand on this example and add a code behind class. In order to do this we need to
ensure that the Convention 
+plugin is able to find our action classes. By default, the Convention plugin will find all
action classes that implement 
+`com.opensymphony.xwork2.Action` or whose name ends with the word **Action** in specific
packages.
+
+These packages are located by the Convention plugin using a search methodology. First the
Convention plugin finds 
+packages named `struts`, `struts2`, `action` or `actions`. Any packages that match those
names are considered the root 
+packages for the Convention plugin. Next, the plugin looks at all of the classes in those
packages as well 
+as sub-packages and determines if the classes implement `com.opensymphony.xwork2.Action`
or if their name ends with 
+**Action** (i.e. `FooAction`). Here's an example of a few classes that the Convention plugin
will find:
+
+**Classes**
+
+```
+com.example.actions.MainAction
+com.example.actions.products.Display (implements com.opensymphony.xwork2.Action)
+com.example.struts.company.details.ShowCompanyDetailsAction
+```
+
+Each of the action classes that the plugin finds will be configured to respond to specific
URLs. The URL is based on 
+the package name that the class is defined in and the class name itself. First the plugin
determines the namespace of 
+the URL using the package names between the root package and the package the class is defined
in. For our examples above, 
+the namespaces would be:
+
+**Namespaces**
+
+```
+com.example.actions.MainAction -> /
+com.example.actions.products.Display -> /products
+com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details
+```
+
+Next, the plugin determines the URL of the resource using the class name. It first removes
the word **Action** from the end of the class name and then converts camel case names to dashes.
In our example the full URLs would be:
+
+**Full URLs**
+
+```
+com.example.actions.MainAction -> /main
+com.example.actions.products.Display -> /products/display
+com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details/show-company-details
+```
+
+You can tell the Convention plugin to ignore certain packages using the property `struts.convention.exclude.packages`.

+You can also tell the plugin to use different strings to locate root packages using the property

+`struts.convention.package.locators`. Finally, you can tell the plugin to search specific
root packages using 
+the property `struts.convention.action.packages`.
+
+Here is our code behind action class:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+
+public class HelloWorld extends ActionSupport {
+  private String message;
+
+  public String getMessage() {
+    return message;
+  }
+
+  public String execute() {
+    message = "Hello World!";
+    return SUCCESS;
+  }
+}
+```
+
+If you compile this class and place it into your application in the WEB-INF/classes, the
Convention plugin will find 
+the class and map the URL **/hello-world** to it. Next, we need to update our JSP to print
out the message we setup in 
+the action class. Here is the new JSP:
+
+**WEB-INF/content/hello-world.jsp**
+
+```jsp
+<html>
+<body>
+  The message is ${message}
+</body>
+</html>
+```
+
+> Please notice that the expression `${message}`  will work without adding JSP directive
`isELIgnored="false"`.
+
+
+If start up the application server and open up [http://localhost:8080/hello-world](http://localhost:8080/hello-world)

+in our browser, we should get this result:
+
+**Result**
+
+```
+The message is Hello World!
+```
+
+## Results and result codes
+
+The Convention Plugin will pre-configure all of you action classes when Struts is started.
By default, this 
+configuration will also contain results for any JSPs that it can find within the application.
The JSPs have 
+an additional feature that allows different JSPs to be used based on the result code of the
action. Since action 
+methods return Strings and these Strings are traditionally used to locate results for the
action, the Convention plugin 
+allows you to define different results based on the result code.
+
+Building on our example from above, let's say we want to provide a different result if the
result code from our action 
+is the String `zero` rather than `success`. First, we update the action class to return different
result codes:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+
+public class HelloWorld extends ActionSupport {
+  private String message;
+
+  public String getMessage() {
+    return message;
+  }
+
+  public String execute() {
+    if (System.currentTimeMillis() % 2 == 0) {
+      message = "It's 0";
+      return "zero";
+    }
+
+    message = "It's 1";
+    return SUCCESS;
+  }
+}
+```
+
+Next, we add a new JSP to the application named `WEB-INF/content/hello-world-zero.jsp`. Notice
that the first part 
+of the file name is the same as the URL of the action and the last part of the name is the
result code. This is 
+the convention that the plugin uses to determine which results to render. Here is our new
JSP:
+
+**WEB-INF/content/hello-world.jsp**
+
+```jsp
+<html>
+<body>
+  The error message is ${message}
+</body>
+</html>
+```
+
+Now, if you compile the action and restart the application, based on the current time, you'll
either see the result from
+`WEB-INF/content/hello-world.jsp` or `WEB-INF/content/hello-world-zero.jsp`.
+
+The result type is based on the extension of the file. The supported extensions are: jsp,ftl,vm,html,html.

+Examples of Action and Result to Template mapping:
+
+|URL|Result|File that could match|Result Type|
+|---|------|---------------------|-----------|
+|/hello|success|/WEB-INF/content/hello.jsp|Dispatcher|
+|/hello|success|/WEB-INF/content/hello-success.htm|Dispatcher|
+|/hello|success|/WEB-INF/content/hello.ftl|FreeMarker|
+|/hello-world|input|/WEB-INF/content/hello-world-input.vm|Velocity|
+|/test1/test2/hello|error|/WEB-INF/content/test/test2/hello-error.html|Dispatcher|
+
+## Multiple names
+
+It is possible to define multiple names for the same result:
+
+```java
+@Action(results = {
+    @Result(name={"error", "input"}, location="input-form.jsp"),
+    @Result(name="success", location="success.jsp")
+})
+```
+
+Such functionality was added in Struts version 2.5.
+
+##Chaining
+
+If one action returns the name of another action in the same package, they will be chained
together, if the first action 
+doesn't have any result defined for that code. In the following example:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionSupport;
+
+public class HelloAction extends ActionSupport {
+    @Action("foo")
+    public String foo() {
+        return "bar";
+    }
+
+    @Action("foo-bar")
+    public String bar() {
+        return SUCCESS;
+    }
+}
+```
+
+The "foo" action will be executed, because no result is found, the Convention plugin tries
to find an action named 
+"foo-bar" on the same package where "foo" is defined. If such an action is found, it will
be invoked using 
+the "chain" result.
+
+## XWork packages
+
+Actions are placed on a custom XWork package which prevents conflicts. The name of this package
is based on the Java 
+package the action is defined in, the namespace part of the URL for the action and the parent
XWork package for 
+the action. The parent XWork package is determined based on the property named `struts.convention.default.parent.package`
+(defaults to `convention-default`), which is a custom XWork package that extends `struts-default`.
+
+Therefore the naming for XWork packages used by the Convention plugin are in the form:
+
+**XWork package naming**
+
+```
+<java-package>#<namespace>#<parent-package>
+```
+
+Using our example from above, the XWork package for our action would be:
+
+**XWork package naming**
+
+```
+com.example.actions#/#conventionDefault
+```
+
+## Annotation reference
+
+The Convention plugin uses a number of different annotations to override the default conventions
that are used to map 
+actions to URLs and locate results. In addition, you can modify the parent XWork package
that actions are configured with.
+
+### Action annotation
+
+The Convention plugin allows action classes to change the URL that they are mapped to using
the **Action** annotation. 
+This annotation can also be used inside the **Actions** annotation to allow multiple URLs
to map to a single action 
+class. This annotation must be defined on action methods like this:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+
+public class HelloWorld extends ActionSupport {
+  @Action("/different/url")
+  public String execute() {
+    return SUCCESS;
+  }
+}
+```
+
+Our action class will now map to the URL `/different/url` rather than `/hello-world`. If
no `@Result` (see next section) 
+is specified, then the namespace of the action will be used as the path to the result, on
our last example it would be 
+`/WEB-INF/content/different/url.jsp`.
+
+A single method within an action class can also map to multiple URLs using the **Actions**
annotation like this:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+
+public class HelloWorld extends ActionSupport {
+  @Actions({
+    @Action("/different/url"),
+    @Action("/another/url")
+  })
+  public String execute() {
+    return SUCCESS;
+  }
+}
+```
+
+Another usage of the **Action** or **Actions** annotation is to define multiple action methods
within a single action 
+class, each of which respond to a different URL. Here is an example of multiple action methods:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+
+public class HelloWorld extends ActionSupport {
+  @Action("/different/url")
+  public String execute() {
+    return SUCCESS;
+
+
+  }
+
+  @Action("url")
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+The previous example defines a second URL that is not fully qualified. This means that the
namespace for the URL 
+is determined using the Java package name rather than the Action annotation.
+
+Interceptor and interceptor stacks can be specified using the `interceptorRefs` attribute.
The following example applies 
+the `validation` interceptor and the `defaultStack` interceptor stack to the action:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+
+public class HelloWorld extends ActionSupport {
+  @Action(interceptorRefs={@InterceptorRef("validation"), @InterceptorRef("defaultStack")})
+  public String execute() {
+    return SUCCESS;
+  }
+
+  @Action("url")
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+Parameters can be passed to results using the **params** attribute. The value of this attribute
is a string array with 
+an even number of elements in the form `{"key0", "value0, "key1", "value1" ... "keyN", "valueN"}`.
For example:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+
+public class HelloWorld extends ActionSupport {
+  @Action(interceptorRefs=@InterceptorRef(value="validation",params={"programmatic", "false",
"declarative", "true}))
+  public String execute() {
+    return SUCCESS;
+  }
+
+  @Action("url")
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+If interceptors are not specified, the default stack is applied.
+
+> You can specify className parameter which can be especially useful when Spring Framework
is used to instantiate actions.
+
+#### Applying `@Action` and `@Actions` at the class level
+
+There are circumstances when this is desired, like when using _Dynamic Method Invocation_
. If an `execute` method is 
+defined in the class, then it will be used for the action mapping, otherwise the method to
be used will be determined 
+when a request is made (by Dynamic Method Invocation for example)
+
+### InterceptorRef annotation
+
+Interceptors can be specified at the method level, using the **Action** annotation or at
the class level using 
+the  `InterceptorRefs` annotation. Interceptors specified at the class level will be applied
to all actions defined
+on that class. In the following example:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+
+@InterceptorRefs({
+    @InterceptorRef("interceptor-1"),
+    @InterceptorRef("defaultStack")
+})
+public class HelloWorld extends ActionSupport {
+  @Action(value="action1", interceptorRefs=@InterceptorRef("validation"))
+  public String execute() {
+    return SUCCESS;
+  }
+
+  @Action(value="action2")
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+The following interceptors will be applied to "action1": `interceptor-1` , all interceptors
from `defaultStack`,
+`validation`. All interceptors from `defaultStack` will be applied to "action2".
+
+> If you get errors like "Unable to find interceptor class referenced by ref-name XYZ".
This means that the package 
+> where Convention is placing your actions, does not extend the package where the interceptor
is defined. To fix this 
+> problem either 1)Use @ParentPackage annotation(or struts.convention.default.parent.package)
passing the name of the 
+> package that defines the interceptor, or 2) Create a package in XML that extends the
package that defines the 
+> interceptor, and use @ParentPackage(or struts.convention.default.parent.package) to
point to it.
+
+### Result annotation
+
+The Convention plugin allows action classes to define different results for an action. Results
fall into two categories, 
+global and local. Global results are shared across all actions defined within the action
class. These results are 
+defined as annotations on the action class. Local results apply only to the action method
they are defined on. Here is 
+an example of the different types of result annotations:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+import org.apache.struts2.convention.annotation.Result;
+import org.apache.struts2.convention.annotation.Results;
+
+@Results({
+  @Result(name="failure", location="fail.jsp")
+})
+public class HelloWorld extends ActionSupport {
+  @Action(value="/different/url",
+    results={@Result(name="success", location="http://struts.apache.org", type="redirect")}
+  )
+  public String execute() {
+    return SUCCESS;
+  }
+
+  @Action("/another/url")
+
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+Parameters can be passed to results using the **params** attribute. The value of this attribute
is a string array with 
+an even number of elements in the form `{"key0", "value0, "key1", "value1" ... "keyN", "valueN"}`.
For example:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Actions;
+import org.apache.struts2.convention.annotation.Result;
+import org.apache.struts2.convention.annotation.Results;
+
+public class HelloWorld extends ActionSupport {
+  @Action(value="/different/url",
+    results={@Result(name="success", type="httpheader", params={"status", "500", "errorMessage",
"Internal Error"})}
+  )
+  public String execute() {
+    return SUCCESS;
+  }
+
+  @Action("/another/url")
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+From 2.1.7 on, global results (defined on the class level) defined using annotations will
be inherited. Child classes 
+can override the inherited result(s) by redefining it. Also, results defined at the method
level take precedence 
+(overwrite), over results with the same name at the action level.
+
+### Namespace annotation
+
+The namespace annotation allows the namespace for action classes to be changed instead of
using the convention of the Java 
+package name. This annotation can be placed on an action class or within the package-info.java
class that allows 
+annotations to be placed on Java packages. When this annotation is put on an action class,
it applies to all actions 
+defined in the class, that are not fully qualified action URLs. When this annotation is place
in the `package-info.java` 
+file, it changes the default namespace for all actions defined in the Java package. Here
is an example of the annotation 
+on an action class:
+
+**com.example.actions.HelloWorl**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.Namespace;
+
+@Namespace("/custom")
+public class HelloWorld extends ActionSupport {
+  @Action("/different/url")
+  public String execute() {
+    return SUCCESS;
+  }
+
+  @Action("url")
+  public String doSomething() {
+    return SUCCESS;
+  }
+}
+```
+
+In this example, the action will respond to two different URLs `/different/url` and `/custom/url`.
Here is an example 
+of using this annotation in the package-info.java file:
+
+**com/example/actions/package-info.java**
+
+```java
+@org.apache.struts2.convention.annotation.Namespace("/custom")
+package com.example.actions;
+```
+
+This changes the default namespace for all actions defined in the package `com.example.actions`.
This annotation however 
+doesn't apply to sub-packages.
+
+### ResultPath annotation
+
+The ResultPath annotation allows applications to change the location where results are stored.
This annotation can be 
+placed on an action class and also in the package-info.java file. Here is an example of using
this annotation:
+
+**com.example.actions.HelloWorl**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.ResultPath;
+
+@ResultPath("/WEB-INF/jsps")
+public class HelloWorld extends ActionSupport {
+  public String execute() {
+    return SUCCESS;
+  }
+}
+```
+
+The result for this class will be located in `WEB-INF/jsps` rather than the default of `WEB-INF/content`.
+
+### ParentPackage annotation
+
+The ParentPackage annotation allows applications to define different parent Struts package
for specific action classes 
+or Java packages. Here is an example of using the annotation on an action class:
+
+**com.example.actions.HelloWorld**
+
+```java
+package com.example.actions;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.ParentPackage;
+
+@ParentPackage("customXWorkPackage")
+public class HelloWorld extends ActionSupport {
+  public String execute() {
+    return SUCCESS;
+  }
+}
+```
+
+To apply this annotation to all actions in a package (and subpackages), add it to package-info.java.
An alternative 
+to this annotation is to set `struts.convention.default.parent.package` in XML.
+
+### ExceptionMapping Annotation
+
+This annotation can be used to define exception mappings to actions. See the _exception mapping
documentation_  for more 
+details. These mappings can be applied to the class level, in which case they will be applied
to all actions defined 
+on that class:
+
+**ExceptionsActionLevelAction.java**
+
+```java
+@ExceptionMappings({
+    @ExceptionMapping(exception = "java.lang.NullPointerException", result = "success", params
= {"param1", "val1"})
+})
+public class ExceptionsActionLevelAction {
+
+    public String execute() throws Exception {
+        return null;
+    }
+}
+```
+
+The parameters defined by `params` are passed to the result. Exception mappings can also
be applied to the action level:
+
+```java
+public class ExceptionsMethodLevelAction {
+    @Action(value = "exception1", exceptionMappings = {
+            @ExceptionMapping(exception = "java.lang.NullPointerException", result = "success",
params = {"param1", "val1"})
+    })
+    public String run1() throws Exception {
+        return null;
+    }
+}
+```
+
+## Actions in jar files
+
+By default the Convention plugin will **not** scan jar files for actions. For a jar to be
scanned, its URL needs 
+to match at least one of the regular expressions in `struts.convention.action.includeJars`
. In this example
+`myjar1.jar` and `myjar2.jar` will be scanned:
+
+```xml
+<constant name="struts.convention.action.includeJars" value=".*?/myjar1.*?jar(!/)?,.*?/myjar2*?jar(!/)?"
+```
+
+Note that **the regular expression will be evaluated against the URL of the jar, and not
the file name**, the jar URL 
+can contain a path to the jar file and a trailing `!/`.
+
+## Automatic configuration reloading
+
+The Convention plugin can automatically reload configuration changes, made in classes the
contain actions, without 
+restarting the container. This is a similar behavior to the automatic xml configuration reloading.
To enable this 
+feature, add this to your `struts.xml` file:
+
+```xml
+<constant name="struts.devMode" value="true"/>
+<constant name="struts.convention.classes.reload" value="true" />
+```
+
+This feature is experimental and has not been tested on all container, and it is **strongly**
advised not to use it 
+in production environments.
+
+## JBoss
+
+When using this plugin with JBoss, you need to set the following constants:
+
+```xml
+<constant name="struts.convention.exclude.parentClassLoader" value="true" />
+<constant name="struts.convention.action.fileProtocols" value="jar,vfsfile,vfszip" />
+```
+
+You can also check the _JBoss 5_  page for more details.
+
+## Jetty (embedded)
+
+When using this plugin with Jetty in embedded mode, you need to set the following constants:
+
+```xml
+<constant name="struts.convention.exclude.parentClassLoader" value="false" />
+<constant name="struts.convention.action.fileProtocols" value="jar,code-source" />
+```
+
+## Troubleshooting
+
+### Tips
+
+- Make sure the namespace of the action is matched by one of the locators. The rest of the
namespace after the locator, 
+  will be the namespace of the action, and will be used to find the results. For example,
a class called "ViewAction" in 
+  the package "my.example.actions.orders" will be mapped to the URL /orders/view.action,
and the results must be under 
+  /WEB-INF/content/orders, like /WEB-INF/content/orders/view-success.jsp.
+
+-  Add the _Config Browser Plugin_  plugin to the lib folder or maven dependencies, and then
visit: 
+  [http://localhost:8080/CONTEXT/config-browser/index.action](http://localhost:8080/CONTEXT/config-browser/index.action),

+  to see the current action mappings.
+
+- The Convention plugin can generate a rather verbose output when set to debug mode for logging.
Use "Trace" logging 
+  level if you are using the JDK logger. If you are using Log4J, you can do something like:
+  log4j.logger.org.apache.struts2.convention=DEBUG
+
+### Common Errors
+
+1. I get an error like "There is no Action mapped for namespace /orders and action name view.".
This means that the URL 
+  `/orders/view.action` is not mapping to any action class. Check the namespace and the name
of the action.
+
+2. I get an error like "No result defined for action my.example.actions.orders.ViewAction
and result success". This 
+  means that the action was mapped to the right URL, but the Convention plugin was unable
to find a `success` result 
+  for it. Check that the result file exists, like `/WEB-INF/content/orders/view-success.jsp`.
+
+3. I get lots of errors like "java.lang.Exception: Could not load org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.class".

+  This happens when `struts.convention.action.includeJars` is matching jar URLs from external
jars.
+
+4. I am using a custom interceptor stack and I get an error like "Unable to find interceptor
class referenced by ref-name XYZ". 
+  This means that the package where Convention is placing your actions, does not extend the
package where the interceptor 
+  is defined. To fix this problem either 1)Use @ParentPackage annotation (or `struts.convention.default.parent.package`)

+  passing the name of the package that defines the interceptor, or 2) Create a package in
XML that extends the package 
+  that defines the interceptor, and use @ParentPackage (or `struts.convention.default.parent.package`)
to point to it.
+
+## Overwriting plugin classes
+
+The Convention plugin can be extended in the same fashion that Struts does. The following
beans are defined by default:
+
+```xml
+<bean type="org.apache.struts2.convention.ActionConfigBuilder" name="convention" 
+  class="org.apache.struts2.convention.PackageBasedActionConfigBuilder"/>
+<!--
+This interface defines how the action configurations for the current web application can
be constructed. This must 
+find all actions that are not specifically defined in the struts XML files or any plugins.
Furthermore, it must make 
+every effort to locate all action results as well.
+-->
+
+<bean type="org.apache.struts2.convention.ActionNameBuilder" name="convention" 
+  class="org.apache.struts2.convention.SEOActionNameBuilder"/>
+<!--
+This interface defines the method that is used to create action names based on the name of
a class.
+-->
+
+<bean type="org.apache.struts2.convention.ResultMapBuilder" name="convention" 
+  class="org.apache.struts2.convention.DefaultResultMapBuilder"/>
+<!--
+This interface defines how results are constructed for an Action. The action information
is supplied and the result is 
+a mapping of ResultConfig instances to the result name.
+-->
+
+<bean type="org.apache.struts2.convention.InterceptorMapBuilder" name="convention" 
+  class="org.apache.struts2.convention.DefaultInterceptorMapBuilder"/>
+<!--
+This interface defines how interceptors are built from annotations.
+-->
+
+<bean type="org.apache.struts2.convention.ConventionsService" name="convention" 
+  class="org.apache.struts2.convention.ConventionsServiceImpl"/>
+<!--
+This interface defines the conventions that are used by the convention plugin. In most cases
the methods on this class
+will provide the best default for any values and also handle locating overrides of the default
via the annotations that 
+are part of the plugin.
+-->
+
+<constant name="struts.convention.actionConfigBuilder" value="convention"/>
+<constant name="struts.convention.actionNameBuilder" value="convention"/>
+<constant name="struts.convention.resultMapBuilder" value="convention"/>
+<constant name="struts.convention.interceptorMapBuilder" value="convention"/>
+<constant name="struts.convention.conventionsService" value="convention"/>
+```
+
+To plugin a different implementation for one of these classes, implement the interface, define
a bean for it, and set 
+the appropriate constant's value with the name of the new bean, for example:
+
+```xml
+<bean type="org.apache.struts2.convention.ActionNameBuilder" name="MyActionNameBuilder"
class="example.SultansOfSwingNameBuilder"/>
+<constant name="struts.convention.actionNameBuilder" value="MyActionNameBuilder"/>
+```
+
+## Configuration reference
+
+Add a **constant** element to your struts config file to change the value of a configuration
setting, like:
+
+```xml
+<constant name="struts.convention.result.path" value="/WEB-INF/mytemplates/"/>
+```
+
+|Name|Default Value|Description|
+|----|-------------|-----------|
+|struts.convention.action.alwaysMapExecute|true|Set to false, to prevent Convention from
creating a default mapping to "execute" when there are other methods annotated as actions
in the class|
+|struts.convention.action.includeJars| |Comma separated list of regular expressions of jar
URLs to be scanned. eg. ".**myJar-0\\.2.**, .**thirdparty-0\\.1.**"|
+|struts.convention.action.packages| |An optional list of action packages that this should
create configuration for (they don't need to match a locator pattern)|
+|struts.convention.result.path|/WEB-INF/content/|Directory where templates are located|
+|struts.convention.result.flatLayout|true|If set to false, the result can be put in its own
directory: resultsRoot/namespace/actionName/result.extension|
+|struts.convention.action.suffix|Action|Suffix used to find actions based on class names|
+|struts.convention.action.disableScanning|false|Scan packages for actions|
+|struts.convention.action.mapAllMatches|false|Create action mappings, even if no @Action
is found|
+|struts.convention.action.checkImplementsAction|true|Check if an action implements com.opensymphony.xwork2.Action
to create an action mapping|
+|struts.convention.default.parent.package|convention-default|Default parent package for action
mappins|
+|struts.convention.action.name.lowercase|true|Convert action name to lowercase|
+|struts.convention.action.name.separator|-|Separator used to build the action name, MyAction
-\> my-action. This character is also used as the separator between the action name and
the result in templates, like action-result.jsp|
+|struts.convention.package.locators|action,actions,struts,struts2|Packages whose name end
with one of these strings will be scanned for actions|
+|struts.convention.package.locators.disable|false|Disable the scanning of packages based
on package locators|
+|struts.convention.exclude.packages|`org.apache.struts.\*`, `org.apache.struts2.\*`, `org.springframework.web.struts.\*`,
`org.springframework.web.struts2.\*`, `org.hibernate.\*`|Packages excluded from the action
scanning, packages already excluded cannot be included in other way, eg. org.demo.actions.exclude
is specified as a part of the struts.convention.exclude.packages so all packages below are
also excluded, eg. org.demo.actions.exclude.include even if **include** is specified as a
struts.convention.package.locators or struts.convention.action.packages|
+|struts.convention.package.locators.basePackage| |If set, only packages that start with
its value will be scanned for actions|
+|struts.convention.relative.result.types|dispatcher,velocity,freemarker|The list of result
types that can have locations that are relative and the result location (which is the resultPath
plus the namespace) prepended to them|
+|struts.convention.redirect.to.slash|true|A boolean parameter that controls whether or not
this will handle unknown actions in the same manner as Apache, Tomcat and other web servers.
This handling will send back a redirect for URLs such as /foo to /foo/ if there doesn't exist
an action that responds to /foo|
+|struts.convention.classLoader.excludeParent|true|Exclude URLs found by the parent class
loader from the list of URLs scanned to find actions (needs to be set to false for JBoss 5)|
+|struts.convention.action.eagerLoading|false|If set, found action classes will be instantiated
by the ObjectFactory to accelerate future use, setting it up can clash with Spring managed
beans|

http://git-wip-us.apache.org/repos/asf/struts-site/blob/6b268e76/source/plugins/index.md
----------------------------------------------------------------------
diff --git a/source/plugins/index.md b/source/plugins/index.md
new file mode 100644
index 0000000..98ff721
--- /dev/null
+++ b/source/plugins/index.md
@@ -0,0 +1,9 @@
+---
+layout: default
+title: Plugins (WIP)
+---
+
+# Plugins
+
+ - [Convention plugin](convention/)
+ 
\ No newline at end of file


Mime
View raw message