You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2022/11/27 08:24:43 UTC

[struts] branch WW-5233-tiles updated (34f30be74 -> 6fc1b9c97)

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a change to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git


    omit 34f30be74 WW-5233 Marks Velocity dependencies as optional
    omit 09895768e Merge pull request #616 from gregh3269/WW-5233-tiles
    omit 7de63911a Make plugin standalone with all generated resources for velocity.
    omit c95e23667 Make plugin standalone with all generated resources for velocity.
    omit 360f51dd5 Merge pull request #612 from gregh3269/WW-5233-tiles
    omit 64db73184 Make plugin standalone with all generated resources.
    omit 88caa890f Add generating of Autotags and tests.
    omit f71e32202 Merge pull request #610 from gregh3269/WW-5233-tiles
    omit b3f1c1e6d Add missing classes and tld definition.
    omit 00a37236a WW-5233 Adds Tiles DTD definition
    omit be172e6c5 WW-5233 Fixes broken test
    omit d0b153a7b WW-5233 Copies Tiles Portal related tests
    omit e9cad7ab3 WW-5233 Addresses a few code smells
    omit fb08d7bdf WW-5233 Addresses bugs reported by Sonar
    omit 30f8832be WW-5233 Drops useless @version tag and addresses some potential RegEx vulnerabilities
    omit 567828244 WW-5233 Copies Tiles Autotag related tests
    omit df5cf368f WW-5233 Copies Tiles Request related tests
    omit ffe556262 WW-5233 Upgrades Easymock to version 4.3 to support Java 17
    omit 17cd2e3d2 WW-5233 Copies Tiles Servlet related tests
    omit fa7d76951 WW-5233 Copies Tiles Template related tests
    omit 3207bfd0e WW-5233 Copies Tiles OGNL related tests
    omit 044021ca1 WW-5233 Copies Tiles EL related tests
    omit 9b4bc635e WW-5233 Copies Tiles Core related tests
    omit ba7ef186f WW-5233 Copies Tiles API related tests
    omit 017a2e30b WW-5233 Copies Portlet related Tiles code base
    omit 3189fe84f WW-5233 Copies a based set of Tiles classes used by Struts
     add dc5dac7be WW-5228 Upgrades OWASP dependency-check-maven to version 7.2.0
     add 88bc5c680 Merge pull request #600 from apache/WW-5228-owasp
     add 062b76718 WW-5231 Upgrades apache-rat-plugin to version 0.15
     add 9faa002fa Merge pull request #601 from apache/WW-5231-rat
     add ab22c7377 WW-5232 Introduces GH Actions build instead of using Travis
     add 6b2cc20b2 WW-5232 Defines default ENV settings
     add 36ac23acf WW-5232 Uses Sonar Coverage badge instead of Travis on
     add dc1a663d6 WW-5232 Uses default SONAR_TOKEN name
     add 0fc71949c WW-5232 Uses Apache specific SONARCLOUD_TOKEN secret
     add 9fb86054b Reverts back to SONAR_TOKEN
     add 296b3cc89 Uses SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
     add eb6836828 WW-5232 Avoids building assemblies
     add e0e7e3cb2 Merge pull request #602 from apache/WW-5232-gh-actions
     add 7183d32ca Replaces Travis badge with GH Actions badge
     add cf2078d1d Merge pull request #603 from apache/lukaszlenart-patch-1
     add 3774ffa7c WW-5234 Improves DTD definitions to use proper URL
     add a4fe51f5b Merge pull request #604 from apache/WW-5234-dtds
     add 32201b2ef WW-5232 Applies proper coverage settings for Jacoco plugin and Sonar
     add 326de812a Merge pull request #605 from apache/WW-5232-coverage
     add 6887ef900 WW-5235 Uses debug log level when setting expression max length to avoid cluttering logs
     add ddfaa1683 Merge pull request #606 from apache/WW-5235-ognl
     add 097297aff WW-5232 Stop generating Jacoco reports which are not used
     add 04cf1dae5 Puts back JaCoCo report generation
     add ddbd02e6b WW-5184 Uses debug log level when parameter value was not accepted
     add cbfd3a7ab WW-5184 Improves logging around excluding/accepting values of incoming parameters
     add 2217e2c1c Disables Code quality step in Jenkins pipeline to avoid overriding GH Actions results
     add 5338b44c2 WW-5184 Reduces code complexity when handling excluded/accepted values patterns
     add e0da03c26 Sets proper Sonar options in Jenkins pipeline and removes duplicated sonar properties
     add 58f287bf4 Merge pull request #607 from apache/WW-5184-log
     add a21bd994e WW-5238 Uses proper order of mapping functions to support action: prefix
     add 8f0db1d22 WW-3691 Converts BackgroundProcess into interface and uses Executor to execute BackgroundProcess
     add 4c8cc361d Merge pull request #609 from apache/WW-3691-executor
     add 26effbf05 WW-5241 Improves Exec&Wait example in Showcase app
     add 415e0fbd4 WW-5241 Ignores calls to append !method when DMI is disabled
     add 9dd256017 WW-5241 Adds test cases to cover checking namespace, action and method names
     add 864f51336 WW-5241 Adds test cases to cover DMI when mapping action
     add 511ec6210 Merge pull request #611 from apache/WW-5241-exec-and-wait
     add e783d1871 WW-5242 Marks struts.mapper.action.prefix.crossNamespaces as deprecated
     add cca986df3 Merge pull request #613 from apache/WW-5242-cross-action
     add 50842e8d1 WW-5242 Marks constant definition as deprecated
     add 2cb0d2896 WW-5244 Upgrades commons-text to version 1.10.0
     add 3d7f66f42 Merge pull request #614 from apache/WW-5244-commons-text
     add 984f8eff2 WW-5245 Upgrades Jackson Databind to version 2.13.4.2
     add 738d27952 Merge pull request #618 from apache/WW-5245-jackson-databind
     add bb7161029 WW-2815 Refactors XStreamHandler to allow to provide a custom configuration
     add ac13c32bd WW-2815 Drops deprecated API
     add a562f8f80 WW-2815 Fixes support for Collections and String
     add 339c30320 WW-2815 Drops clearing existing permissions to avoid messing with user provided configuration
     add 802afb0cc WW-2815 Drops unused import
     add 1069cf8c0 Merge pull request #615 from apache/WW-2815-xstream
     add 01164c4d7 WW-5230 Upgrades OGNL to version 3.3.4
     add 3fdb91812 Merge pull request #619 from apache/WW-5230-ognl
     add 993c4c4ca WW-3529 Fixes using RegEx related characters in named pattern
     add 7064c53f5 Merge pull request #620 from apache/WW-3529-named-pattern
     add c41f05fe6 WW-3737 Allows to define a custom separator used to split patterns
     add 79d6c07a5 Merge pull request #621 from apache/WW-3737-custom-separator
     add a02cc6507 Defines OSSF Scorecard action to perform analysis
     add 936481e7e Adds badge with OSSF CII best practises scoring
     add 943cb6295 WW-5133 Drops labelposition attribute
     add 58dcc830e Merge pull request #622 from apache/WW-5133-labelposition
     add 956888870 WW-3725 Removes unused template
     add 784293e46 Merge pull request #623 from apache/WW-3725-remove
     add 3e30d0c37 WW-5137 Removes deprecated class attribute
     add 9e7e0b395 Merge pull request #624 from apache/WW-5137-class
     add 94a0c6e42 WW-4173 Adds support to disable processing a given interceptor
     add 084c257d6 WW-4173 Passes current ActionInvocation to allow based disabling interceptor on it
     add c74287f74 Merge pull request #625 from apache/WW-4173-disable
     add b53613619 Introduces CodeQL analyses
     add eb51594ed Adds proper header with Apache 2.0 license
     add 9c078aef1 WW-4440 Adds basic README.md to all submodules
     add 34aeeded5 Merge pull request #627 from apache/WW-4440-readme
     add 2660aaec5 [WW-4692] Extracts Url encoder/decoder into dedicated interfaces/classes (#626)
     add 6658c6360 WW-5252 Disables parsing external entities
     add 8d2d99605 WW-5252 Reuses factory method
     add 79a84a8f0 Merge pull request #628 from apache/WW-5252-external
     add 054f1f4cd Includes apps in code Coverage scan
     add 4bb81d590 WW-5255 Fixes <s:script/> and <s:link/> and uses them across tags
     add 4a585347e WW-5255 Fixes debug console and validators' details page
     add 5a30cdbed Merge pull request #629 from apache/WW-5255-script-link
     add 6330bb1ce WW-4514 Fixes building query string with empty parameters
     add 6135a7133 WW-4514 Extracts parameters string building into a dedicated class with a proper extension point
     add 728edbef5 Increases sleep to avoid false test failures
     add 4a51aacf4 WW-4514 Avoids logging user provided data
     add bfcc0b589 Swaps expected with actual
     add 35a50ea83 Merge pull request #630 from apache/WW-4514-url
     add ac168968a WW-5240 Uses doubleOn* attributes in the template This allows assign custom JS event handlers to the second select box
     add 0fe27a673 Merge pull request #631 from apache/WW-5240-doubleselect
     add 9a431ea47 Packages with assembly before publishing nightlies
     add 341a8f20e Cleans remote before uploading new packages
     add 138a8d74f WW-5257 Cleans up template
     add 0a30eb44e Merge pull request #632 from apache/WW-5257-checkbox
     add 927c58b7d WW-5258 Upgrades Struts Annotations to version 1.0.8
     add 4ab427f2f Merge pull request #633 from apache/WW-5258-annotations
     add ea7fba284 WW-5259 Extracts UrlHelper#parseQueryString into a dedicated bean
     add 6ea50122d Merge pull request #634 from apache/WW-5259-parser
     add 18a72c3df [maven-release-plugin] prepare release STRUTS_6_1_0
     add 1af3e3154 [maven-release-plugin] prepare for next development iteration
     add bcfa8113a WW-4173 Introduces a dedicated interface to allow conditionally executing a given interceptor
     add 09da11ba0 Merge pull request #635 from apache/WW-4173-optional
     add 65ae2b7e4 WW-5260 Introduces a constant to set submitUnchecked attribute of checkbox tag globally
     add 4d58dd196 Merge pull request #636 from apache/WW-5260-global-submit-unchecked
     add a77a80a80 Refactors name/value calculation logic
     add f5c0aa5f3 [maven-release-plugin] prepare release STRUTS_6_1_1
     add d166d79a6 [maven-release-plugin] prepare for next development iteration
     add efd4c61a2 Updates OWASP supressions as some reports are false positive
     add 0d9a87418 Merge pull request #637 from apache/owasp-check
     new 1d58de276 WW-5233 Copies a based set of Tiles classes used by Struts
     new 2fd075271 WW-5233 Copies Portlet related Tiles code base
     new 128d5a519 WW-5233 Copies Tiles API related tests
     new c77dcb530 WW-5233 Copies Tiles Core related tests
     new 53e219931 WW-5233 Copies Tiles EL related tests
     new fe815e879 WW-5233 Copies Tiles OGNL related tests
     new 1d36a148b WW-5233 Copies Tiles Template related tests
     new e6f8f68af WW-5233 Copies Tiles Servlet related tests
     new 48c522fa1 WW-5233 Upgrades Easymock to version 4.3 to support Java 17
     new c912c4eea WW-5233 Copies Tiles Request related tests
     new 3eeb2885b WW-5233 Copies Tiles Autotag related tests
     new 6d1f60ae1 WW-5233 Drops useless @version tag and addresses some potential RegEx vulnerabilities
     new 69e5efc84 WW-5233 Addresses bugs reported by Sonar
     new c8d843e70 WW-5233 Addresses a few code smells
     new 55987963a WW-5233 Copies Tiles Portal related tests
     new d694cce7c WW-5233 Fixes broken test
     new add505a3b WW-5233 Adds Tiles DTD definition
     new fff3cc8ac Add missing classes and tld definition.
     new 6715a5243 Add generating of Autotags and tests.
     new bae3e3954 Make plugin standalone with all generated resources.
     new 0568c2d3e Make plugin standalone with all generated resources for velocity.
     new 86c81ca27 Make plugin standalone with all generated resources for velocity.
     new 6fc1b9c97 WW-5233 Marks Velocity dependencies as optional

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (34f30be74)
            \
             N -- N -- N   refs/heads/WW-5233-tiles (6fc1b9c97)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 23 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/workflows/codeql.yml                       |   47 +
 .github/workflows/maven.yml                        |   57 +
 .github/workflows/scorecards-analysis.yaml         |   69 +
 .travis.yml                                        |   29 -
 Jenkinsfile                                        |    8 +-
 README.md                                          |    7 +-
 apps/README.md                                     |   12 +
 apps/pom.xml                                       |    2 +-
 apps/rest-showcase/pom.xml                         |    5 +-
 apps/rest-showcase/src/main/resources/struts.xml   |    4 +-
 apps/showcase/pom.xml                              |    3 +-
 .../showcase/wait/ThreadPoolExecutorProvider.java  |   56 +
 ...ction-lotsOfRichtexteditorSubmit-validation.xml |   14 +-
 .../showcase/action/EmployeeAction-validation.xml  |    2 +-
 .../showcase/action/SkillAction-validation.xml     |    2 +-
 .../fileupload/FileUploadAction-validation.xml     |    5 +-
 .../showcase/person/NewPersonAction-validation.xml |    2 +-
 .../struts2/showcase/person/Person-validation.xml  |    2 +-
 .../IteratorGeneratorTagDemo-validation.xml        |   12 +-
 ...ubmitClientSideValidationExample-validation.xml |    8 +-
 ...on-submitFieldValidatorsExamples-validation.xml |   10 +-
 ...submitNonFieldValidatorsExamples-validation.xml |   12 +-
 .../showcase/validation/QuizAction-validation.xml  |    4 +-
 ...mitApplication-submitApplication-validation.xml |    2 +-
 .../validation/User-userContext-validation.xml     |   10 +-
 ...-submitVisitorValidatorsExamples-validation.xml |    6 +-
 .../src/main/resources/struts-actionchaining.xml   |    6 +-
 apps/showcase/src/main/resources/struts-async.xml  |    2 +-
 .../src/main/resources/struts-conversion.xml       |   22 +-
 .../src/main/resources/struts-dispatcher.xml       |    2 +-
 .../src/main/resources/struts-filedownload.xml     |    2 +-
 .../src/main/resources/struts-fileupload.xml       |    8 +-
 .../src/main/resources/struts-freemarker.xml       |    6 +-
 .../showcase/src/main/resources/struts-hangman.xml |   10 +-
 .../src/main/resources/struts-interactive.xml      |    4 +-
 .../src/main/resources/struts-model-driven.xml     |    7 +-
 apps/showcase/src/main/resources/struts-person.xml |    2 +-
 .../src/main/resources/struts-tags-non-ui.xml      |   28 +-
 .../showcase/src/main/resources/struts-tags-ui.xml |    2 +-
 apps/showcase/src/main/resources/struts-tags.xml   |    2 +-
 apps/showcase/src/main/resources/struts-tiles.xml  |    2 +-
 apps/showcase/src/main/resources/struts-token.xml  |    2 +-
 .../src/main/resources/struts-validation.xml       |   40 +-
 apps/showcase/src/main/resources/struts-wait.xml   |    9 +-
 apps/showcase/src/main/resources/struts-xslt.xml   |    4 +-
 apps/showcase/src/main/resources/struts.xml        |    2 +-
 .../src/main/webapp/WEB-INF/decorators/main.jsp    |   21 +-
 .../src/main/webapp/WEB-INF/wait/complete.jsp      |   29 +-
 .../src/main/webapp/WEB-INF/wait/index.jsp         |   53 +
 .../showcase/src/main/webapp/WEB-INF/wait/wait.jsp |   68 +-
 apps/showcase/src/main/webapp/wait/index.html      |   53 -
 assembly/README.md                                 |    3 +
 assembly/pom.xml                                   |    2 +-
 bom/README.md                                      |   20 +
 bom/pom.xml                                        |    4 +-
 bundles/admin/pom.xml                              |    2 +-
 bundles/admin/src/main/resources/struts.xml        |    4 +-
 bundles/demo/pom.xml                               |    2 +-
 bundles/demo/src/main/resources/struts.xml         |    8 +-
 bundles/pom.xml                                    |    2 +-
 core/README.md                                     |    6 +
 core/pom.xml                                       |    6 +-
 .../xwork2/DefaultActionInvocation.java            |   37 +-
 .../com/opensymphony/xwork2/XWorkTestCase.java     |   31 +-
 .../xwork2/config/entities/PackageConfig.java      |   14 +-
 .../StrutsDefaultConfigurationProvider.java        |  219 +--
 .../opensymphony/xwork2/inject/ContainerImpl.java  |  175 +-
 .../xwork2/interceptor/AbstractInterceptor.java    |   22 +-
 ...nterceptor.java => ConditionalInterceptor.java} |   28 +-
 .../xwork2/interceptor/ParametersInterceptor.java  |  211 ++-
 .../com/opensymphony/xwork2/ognl/OgnlUtil.java     |    4 +-
 .../com/opensymphony/xwork2/util/DomHelper.java    |  130 +-
 .../xwork2/util/NamedVariablePatternMatcher.java   |   67 +-
 .../opensymphony/xwork2/validator/Validator.java   |    2 +-
 .../xwork2/validator/ValidatorFactory.java         |    2 +-
 .../java/org/apache/struts2/StrutsConstants.java   |   19 +-
 .../org/apache/struts2/components/Checkbox.java    |   62 +-
 .../struts2/components/ExtraParameterProvider.java |    4 +-
 .../struts2/components/ServletUrlRenderer.java     |   29 +-
 .../java/org/apache/struts2/components/UIBean.java |   95 +-
 .../org/apache/struts2/components/UrlProvider.java |   22 +-
 .../config/AbstractBeanSelectionProvider.java      |    1 -
 .../config/StrutsBeanSelectionProvider.java        |    9 +
 .../apache/struts2/dispatcher/InitOperations.java  |   37 +-
 .../dispatcher/mapper/DefaultActionMapper.java     |   44 +-
 .../dispatcher/mapper/Restful2ActionMapper.java    |   34 +-
 .../dispatcher/mapper/RestfulActionMapper.java     |   19 +-
 .../struts2/interceptor/CoepInterceptor.java       |   15 +-
 .../struts2/interceptor/CoopInterceptor.java       |   13 +-
 .../interceptor/ExecuteAndWaitInterceptor.java     |   66 +-
 .../interceptor/FetchMetadataInterceptor.java      |    9 -
 .../struts2/interceptor/csp/CspInterceptor.java    |   18 +-
 .../interceptor/exec/BackgroundProcess.java}       |   38 +-
 .../struts2/interceptor/exec/ExecutorProvider.java |   21 +-
 .../StrutsBackgroundProcess.java}                  |   80 +-
 .../interceptor/exec/StrutsExecutorProvider.java   |   53 +
 .../struts2/result/ServletDispatcherResult.java    |   14 +-
 .../struts2/result/ServletRedirectResult.java      |   19 +-
 .../apache/struts2/url/QueryStringBuilder.java}    |   29 +-
 .../QueryStringParser.java}                        |   57 +-
 .../struts2/url/StrutsQueryStringBuilder.java      |   92 +
 .../struts2/url/StrutsQueryStringParser.java       |   98 +
 .../org/apache/struts2/url/StrutsUrlDecoder.java   |  118 ++
 .../org/apache/struts2/url/StrutsUrlEncoder.java   |   58 +
 .../java/org/apache/struts2/url/UrlDecoder.java    |   56 +
 .../apache/struts2/url/UrlEncoder.java}            |   33 +-
 .../org/apache/struts2/util/URLDecoderUtil.java    |   52 -
 .../org/apache/struts2/util/tomcat/buf/Ascii.java  |  257 ---
 .../struts2/util/tomcat/buf/B2CConverter.java      |  203 ---
 .../apache/struts2/util/tomcat/buf/ByteChunk.java  |  937 ----------
 .../apache/struts2/util/tomcat/buf/CharChunk.java  |  702 --------
 .../apache/struts2/util/tomcat/buf/HexUtils.java   |  115 --
 .../struts2/util/tomcat/buf/MessageBytes.java      |  548 ------
 .../struts2/util/tomcat/buf/StringCache.java       |  697 -------
 .../apache/struts2/util/tomcat/buf/UDecoder.java   |  423 -----
 .../struts2/util/tomcat/buf/Utf8Decoder.java       |  295 ---
 .../apache/struts2/views/jsp/ui/AbstractUITag.java |    9 -
 .../struts2/views/util/DefaultUrlHelper.java       |  241 +--
 .../org/apache/struts2/views/util/UrlHelper.java   |   18 +-
 .../org/apache/struts2/views/xslt/XSLTResult.java  |   62 +-
 .../{template/xhtml/script.ftl => author.dtd}      |    5 +-
 .../xwork2/validator/validators/default.xml        |    2 +-
 .../org/apache/struts2/default.properties          |   14 +
 .../struts2/interceptor/debugging/console.ftl      |    8 +-
 core/src/main/resources/struts-2.0.dtd             |    8 +-
 core/src/main/resources/struts-2.1.7.dtd           |    2 +-
 core/src/main/resources/struts-2.1.dtd             |    2 +-
 core/src/main/resources/struts-2.3.dtd             |    2 +-
 core/src/main/resources/struts-2.5.dtd             |    2 +-
 core/src/main/resources/struts-6.0.dtd             |    2 +-
 core/src/main/resources/struts-default.xml         |  383 ++--
 .../template/archive/xhtml/controlheader.vm        |   47 -
 .../src/main/resources/template/css_xhtml/head.ftl |    2 +-
 .../main/resources/template/simple/checkbox.ftl    |    6 +-
 .../main/resources/template/simple/combobox.ftl    |   14 +-
 .../template/simple/common-attributes.ftl          |    4 +-
 core/src/main/resources/template/simple/debug.ftl  |   16 +-
 .../resources/template/simple/doubleselect.ftl     |   91 +-
 .../template/simple/form-close-tooltips.ftl        |   11 +-
 .../main/resources/template/simple/form-close.ftl  |    4 +-
 core/src/main/resources/template/simple/head.ftl   |    2 +-
 .../template/simple/inputtransferselect.ftl        |    2 +-
 core/src/main/resources/template/simple/link.ftl   |   47 +-
 core/src/main/resources/template/simple/nonce.ftl  |    4 +-
 .../template/simple/optiontransferselect.ftl       |    2 +-
 core/src/main/resources/template/simple/script.ftl |   33 +-
 core/src/main/resources/template/simple/select.ftl |    6 +-
 .../resources/template/simple/updownselect.ftl     |    4 +-
 .../src/main/resources/template/xhtml/checkbox.ftl |    5 +-
 .../template/xhtml/form-close-validate.ftl         |    8 +-
 .../main/resources/template/xhtml/form-close.ftl   |    4 +-
 .../resources/template/xhtml/form-validate.ftl     |    2 +-
 core/src/main/resources/template/xhtml/head.ftl    |    2 +-
 core/src/main/resources/template/xhtml/link.ftl    |   21 -
 .../main/resources/template/xhtml/validation.js    |    4 +-
 core/src/main/resources/xwork-default.xml          |    2 +-
 core/src/main/resources/xwork-validator-1.0.2.dtd  |    6 +-
 core/src/main/resources/xwork-validator-1.0.3.dtd  |    2 +-
 core/src/main/resources/xwork-validator-1.0.dtd    |    6 +-
 .../main/resources/xwork-validator-config-1.0.dtd  |    2 +-
 .../resources/xwork-validator-definition-1.0.dtd   |    2 +-
 core/src/site/resources/tags/a-attributes.html     |  982 +++++-----
 .../src/site/resources/tags/action-attributes.html |  144 +-
 .../resources/tags/actionerror-attributes.html     |  742 ++++----
 .../resources/tags/actionmessage-attributes.html   |  742 ++++----
 .../src/site/resources/tags/append-attributes.html |   48 +-
 core/src/site/resources/tags/bean-attributes.html  |   64 +-
 .../site/resources/tags/checkbox-attributes.html   |  758 ++++----
 .../resources/tags/checkboxlist-attributes.html    |  854 +++++----
 .../site/resources/tags/combobox-attributes.html   |  902 +++++-----
 .../site/resources/tags/component-attributes.html  |  726 ++++----
 core/src/site/resources/tags/date-attributes.html  |  112 +-
 .../resources/tags/datetextfield-attributes.html   |  742 ++++----
 core/src/site/resources/tags/debug-attributes.html |  726 ++++----
 .../resources/tags/doubleselect-attributes.html    | 1462 ++++++++-------
 core/src/site/resources/tags/else-attributes.html  |   32 +-
 .../src/site/resources/tags/elseif-attributes.html |   48 +-
 .../site/resources/tags/fielderror-attributes.html |  758 ++++----
 core/src/site/resources/tags/file-attributes.html  |  758 ++++----
 core/src/site/resources/tags/form-attributes.html  |  950 +++++-----
 .../site/resources/tags/generator-attributes.html  |  112 +-
 core/src/site/resources/tags/head-attributes.html  |  726 ++++----
 .../src/site/resources/tags/hidden-attributes.html |  726 ++++----
 core/src/site/resources/tags/i18n-attributes.html  |   48 +-
 core/src/site/resources/tags/if-attributes.html    |   48 +-
 .../site/resources/tags/include-attributes.html    |   48 +-
 .../tags/inputtransferselect-attributes.html       | 1094 ++++++-----
 .../site/resources/tags/iterator-attributes.html   |  128 +-
 core/src/site/resources/tags/label-attributes.html |  742 ++++----
 core/src/site/resources/tags/link-attributes.html  |  870 +++++----
 core/src/site/resources/tags/merge-attributes.html |   48 +-
 .../src/site/resources/tags/number-attributes.html |  208 +--
 .../site/resources/tags/optgroup-attributes.html   |  160 +-
 .../tags/optiontransferselect-attributes.html      | 1894 ++++++++++----------
 core/src/site/resources/tags/param-attributes.html |   80 +-
 .../site/resources/tags/password-attributes.html   |  822 +++++----
 .../site/resources/tags/property-attributes.html   |  128 +-
 core/src/site/resources/tags/push-attributes.html  |   48 +-
 core/src/site/resources/tags/radio-attributes.html |  854 +++++----
 core/src/site/resources/tags/reset-attributes.html |  806 ++++-----
 .../src/site/resources/tags/script-attributes.html |  886 +++++----
 .../src/site/resources/tags/select-attributes.html |  934 +++++-----
 core/src/site/resources/tags/set-attributes.html   |  102 +-
 core/src/site/resources/tags/sort-attributes.html  |   80 +-
 .../src/site/resources/tags/submit-attributes.html |  822 +++++----
 .../src/site/resources/tags/subset-attributes.html |  112 +-
 core/src/site/resources/tags/text-attributes.html  |  128 +-
 .../site/resources/tags/textarea-attributes.html   |  822 +++++----
 .../site/resources/tags/textfield-attributes.html  |  806 ++++-----
 core/src/site/resources/tags/token-attributes.html |  726 ++++----
 .../resources/tags/updownselect-attributes.html    | 1030 ++++++-----
 core/src/site/resources/tags/url-attributes.html   |  278 +--
 .../xwork2/DefaultActionInvocationTest.java        |  144 +-
 .../com/opensymphony/xwork2/TestInterceptor.java   |   89 -
 .../config/providers/InterceptorBuilderTest.java   |  286 ++-
 .../providers/InterceptorForTestPurpose.java       |   51 +-
 .../interceptor/ParametersInterceptorTest.java     |   33 +-
 .../opensymphony/xwork2/util/DomHelperTest.java    |   56 +-
 .../util/NamedVariablePatternMatcherTest.java      |   27 +-
 .../org/apache/struts2/components/UIBeanTest.java  |    4 +-
 .../struts2/dispatcher/InitOperationsTest.java     |   86 +
 .../ServletDispatchedTestAssertInterceptor.java    |   56 -
 .../dispatcher/mapper/DefaultActionMapperTest.java |  210 ++-
 .../mapper/Restful2ActionMapperTest.java           |   10 +-
 .../dispatcher/mapper/RestfulActionMapperTest.java |   21 +-
 .../struts2/interceptor/BackgroundProcessTest.java |  104 --
 .../struts2/interceptor/CoepInterceptorTest.java   |    9 -
 .../struts2/interceptor/CoopInterceptorTest.java   |    9 -
 .../struts2/interceptor/CspInterceptorTest.java    |   11 -
 .../interceptor/ExecuteAndWaitInterceptorTest.java |   46 +-
 .../interceptor/FetchMetadataInterceptorTest.java  |    8 -
 .../exec/StrutsBackgroundProcessTest.java          |  179 ++
 .../apache/struts2/result/PostbackResultTest.java  |    5 +-
 .../result/ServletActionRedirectResultTest.java    |  111 +-
 .../result/ServletDispatcherResultTest.java        |   21 +-
 .../struts2/result/ServletRedirectResultTest.java  |   14 +-
 .../struts2/url/StrutsQueryStringBuilderTest.java  |   99 +
 .../struts2/url/StrutsQueryStringParserTest.java   |   84 +
 .../apache/struts2/url/StrutsUrlDecoderTest.java   |  120 ++
 .../apache/struts2/url/StrutsUrlEncoderTest.java   |   97 +
 .../apache/struts2/util/URLDecoderUtilTest.java    |   96 -
 .../freemarker/FreemarkerResultMockedTest.java     |    3 +-
 .../struts2/views/jsp/AbstractUITagTest.java       |   50 +-
 .../apache/struts2/views/jsp/ui/CheckboxTest.java  |   84 +-
 .../struts2/views/jsp/ui/DoubleSelectTest.java     |  233 ++-
 .../apache/struts2/views/jsp/ui/FormTagTest.java   |   24 +-
 .../org/apache/struts2/views/jsp/ui/LabelTest.java |   10 +-
 .../apache/struts2/views/jsp/ui/LinkTagTest.java   |    6 +-
 .../apache/struts2/views/jsp/ui/SelectTest.java    |    2 +-
 .../struts2/views/util/DefaultUrlHelperTest.java   |  173 +-
 .../xwork2/ModelDrivenAction-validation.xml        |    2 +-
 .../xwork2/SimpleAction-some-alias-validation.xml  |    2 +-
 .../xwork2/SimpleAction-subproperty-validation.xml |    2 +-
 .../xwork2/SimpleAction-validation.xml             |    2 +-
 .../SimpleAction-validationAlias-validation.xml    |    2 +-
 .../xwork2/TestBean-anotherContext-validation.xml  |    2 +-
 .../xwork2/TestBean-badtest-validation.xml         |    2 +-
 .../TestBean-beanMessageBundle-validation.xml      |    2 +-
 .../TestBean-expressionValidation-validation.xml   |    2 +-
 .../opensymphony/xwork2/TestBean-validation.xml    |    2 +-
 .../TestBean-visitorChildValidation-validation.xml |    2 +-
 .../TestBean-visitorValidation-validation.xml      |    2 +-
 .../xwork2/TestChildBean-validation.xml            |    4 +-
 .../xwork2/ValidationOrderAction-validation.xml    |   18 +-
 .../providers/loadorder1/xwork-test-load-order.xml |    2 +-
 .../providers/loadorder2/xwork-test-load-order.xml |    2 +-
 .../providers/loadorder3/xwork-test-load-order.xml |    2 +-
 .../xwork2/config/providers/xwork- test.xml        |    2 +-
 .../providers/xwork-include-after-package-2.xml    |    2 +-
 .../providers/xwork-include-after-package.xml      |    2 +-
 .../providers/xwork-include-before-package-2.xml   |    2 +-
 .../providers/xwork-include-before-package.xml     |    2 +-
 .../config/providers/xwork-include-parent.xml      |    2 +-
 .../config/providers/xwork-test-action-invalid.xml |    2 +-
 .../xwork-test-actions-packagedefaultclassref.xml  |    2 +-
 .../xwork2/config/providers/xwork-test-actions.xml |    2 +-
 .../providers/xwork-test-allowed-methods.xml       |    2 +-
 .../providers/xwork-test-bad-inheritance.xml       |    4 +-
 .../config/providers/xwork-test-basic-packages.xml |    2 +-
 .../providers/xwork-test-default-package.xml       |    2 +-
 .../xwork-test-defaultclassref-package.xml         |    4 +-
 .../providers/xwork-test-envs-substitution.xml     |    2 +-
 .../providers/xwork-test-exception-mappings.xml    |    2 +-
 .../xwork-test-global-result-inheritence.xml       |    2 +-
 .../providers/xwork-test-include-wildcard.xml      |    2 +-
 .../xwork-test-interceptor-defaultref.xml          |    2 +-
 .../xwork-test-interceptor-inheritance.xml         |    2 +-
 .../xwork-test-interceptor-param-overriding.xml    |   11 +-
 .../providers/xwork-test-interceptor-params.xml    |    2 +-
 ...ork-test-interceptor-stack-param-overriding.xml |    2 +-
 .../providers/xwork-test-interceptors-basic.xml    |    2 +-
 .../providers/xwork-test-interceptors-spring.xml   |    2 +-
 .../config/providers/xwork-test-multilevel.xml     |    2 +-
 .../providers/xwork-test-package-inheritance.xml   |    4 +-
 .../xwork2/config/providers/xwork-test-reload.xml  |    2 +-
 .../providers/xwork-test-result-inheritance.xml    |    2 +-
 .../config/providers/xwork-test-result-names.xml   |    2 +-
 .../config/providers/xwork-test-result-types.xml   |    2 +-
 .../xwork2/config/providers/xwork-test-results.xml |    2 +-
 .../config/providers/xwork-test-wildcard-1.xml     |    2 +-
 .../config/providers/xwork-test-wildcard-2.xml     |    2 +-
 .../providers/xwork-test-wildcard-include.xml      |    4 +-
 .../providers/xwork-unknownhandler-stack-empty.xml |    2 +-
 .../providers/xwork-unknownhandler-stack.xml       |    2 +-
 .../xwork2/test/DataAware-validation.xml           |    2 +-
 .../test/DataAware-validationAlias-validation.xml  |    2 +-
 .../xwork2/test/DataAware2-validation.xml          |    2 +-
 .../xwork2/test/Equidae-validation.xml             |    2 +-
 .../xwork2/test/SimpleAction2-validation.xml       |    2 +-
 .../SimpleAction2-validationAlias-validation.xml   |    2 +-
 .../opensymphony/xwork2/test/User-validation.xml   |    2 +-
 .../xwork2/test/UserMarker-validation.xml          |    2 +-
 .../VisitorValidatorModelAction-validation.xml     |    2 +-
 ...atorTestAction-beanMessageBundle-validation.xml |    2 +-
 ...alidatorTestAction-validateArray-validation.xml |    2 +-
 ...ValidatorTestAction-validateList-validation.xml |    2 +-
 .../VisitorValidatorTestAction-validation.xml      |    2 +-
 ...estAction-visitorChildValidation-validation.xml |    2 +-
 ...atorTestAction-visitorValidation-validation.xml |    2 +-
 ...estAction-visitorValidationAlias-validation.xml |    2 +-
 .../xwork2/validator/validator-parser-test.xml     |    2 +-
 .../xwork2/validator/validator-parser-test2.xml    |   10 +-
 .../xwork2/validator/validator-parser-test3.xml    |    2 +-
 .../xwork2/validator/validator-parser-test4.xml    |    2 +-
 .../xwork2/validator/validator-parser-test5.xml    |    2 +-
 .../xwork2/validator/validator-parser-test6.xml    |    2 +-
 .../xwork2/validator/validators-fail.xml           |    2 +-
 core/src/test/resources/includeTest.xml            |    2 +-
 core/src/test/resources/my-validators.xml          |    2 +-
 core/src/test/resources/myOther-validators.xml     |    2 +-
 .../org/apache/struts2/TestAction-validation.xml   |    2 +-
 .../apache/struts2/dispatcher/ng/struts-no-op.xml  |    2 +-
 .../views/freemarker/callActionFreeMarker.ftl      |    4 +-
 .../views/freemarker/callActionFreeMarker2.ftl     |    4 +-
 .../struts2/views/freemarker/customTextField.ftl   |    2 -
 .../struts2/views/freemarker/dynaAttributes.ftl    |    2 -
 .../views/freemarker/incompatible-improvements.ftl |    4 +-
 .../struts2/views/freemarker/manual-list.ftl       |    2 -
 .../org/apache/struts2/views/freemarker/nested.ftl |    4 +-
 .../apache/struts2/views/freemarker/nonceTest.ftl  |    2 -
 .../apache/struts2/views/freemarker/something.ftl  |    2 -
 .../org/apache/struts2/views/jsp/WW3090-struts.xml |    2 +-
 .../apache/struts2/views/jsp/ui/DoubleSelect-5.txt |    2 +-
 .../apache/struts2/views/jsp/ui/DoubleSelect-6.txt |   42 +
 .../jsp/ui/DoubleValidationAction-validation.xml   |    4 +-
 .../apache/struts2/views/jsp/ui/HeadTagTest-1.txt  |    4 +-
 .../jsp/ui/IntValidationAction-validation.xml      |    2 +-
 .../struts2/views/jsp/ui/User-validation.xml       |    2 +-
 .../org/apache/struts2/views/jsp/ui/tooltip-1.txt  |    2 +-
 .../org/apache/struts2/views/jsp/ui/tooltip-2.txt  |    4 +-
 .../org/apache/struts2/views/jsp/ui/tooltip-3.txt  |    2 +-
 ...dy.xml => struts-checkbox-submit-unchecked.xml} |    4 +-
 core/src/test/resources/struts-escape-body.xml     |    2 +-
 .../struts-object-factory-result-builder.xml       |    2 +-
 core/src/test/resources/struts-testing.xml         |    2 +-
 core/src/test/resources/struts.xml                 |    2 +-
 core/src/test/resources/validators.xml             |    2 +-
 core/src/test/resources/xwork-class-param-test.xml |    2 +-
 core/src/test/resources/xwork-param-test.xml       |    2 +-
 core/src/test/resources/xwork-proxyinvoke.xml      |    2 +-
 core/src/test/resources/xwork-sample.xml           |   14 +-
 core/src/test/resources/xwork-test-beans.xml       |    2 +-
 core/src/test/resources/xwork-test-default.xml     |    2 +-
 core/src/test/resources/xwork-test-validation.xml  |    4 +-
 plugins/README.md                                  |    3 +
 plugins/async/README.md                            |    6 +
 plugins/async/pom.xml                              |    2 +-
 plugins/async/src/main/resources/struts-plugin.xml |    2 +-
 plugins/bean-validation/README.md                  |    7 +
 plugins/bean-validation/pom.xml                    |    2 +-
 .../src/main/resources/struts-plugin.xml           |    2 +-
 .../src/test/resources/bean-validation-test.xml    |    2 +-
 plugins/cdi/README.md                              |    6 +
 plugins/cdi/pom.xml                                |    2 +-
 plugins/cdi/src/main/resources/struts-plugin.xml   |    4 +-
 plugins/config-browser/README.md                   |    6 +
 plugins/config-browser/pom.xml                     |    2 +-
 .../resources/config-browser/config-styles.css     |  812 ---------
 .../resources/config-browser/config-styles.ftl     |  710 ++++++++
 .../main/resources/config-browser/page-header.ftl  |   10 +-
 .../resources/config-browser/showValidators.ftl    |   34 +-
 .../resources/config-browser/validatorDetails.ftl  |    8 +-
 .../src/main/resources/struts-plugin.xml           |   12 +-
 plugins/convention/README.md                       |    6 +
 plugins/convention/pom.xml                         |    2 +-
 .../src/main/resources/struts-plugin.xml           |    2 +-
 plugins/dwr/README.md                              |    6 +
 plugins/dwr/pom.xml                                |    2 +-
 plugins/embeddedjsp/README.md                      |    2 +
 plugins/embeddedjsp/pom.xml                        |    3 +-
 .../main/java/org/apache/struts2/JSPRuntime.java   |   13 +-
 .../src/main/resources/struts-plugin.xml           |    2 +-
 .../org/apache/struts2/EmbeddedJSPResultTest.java  |   22 +-
 .../test/resources/org/apache/struts2/complex0.jsp |   13 +-
 plugins/gxp/README.md                              |    2 +
 plugins/gxp/pom.xml                                |    2 +-
 plugins/gxp/src/main/resources/struts-plugin.xml   |    4 +-
 plugins/jasperreports/README.md                    |    6 +
 plugins/jasperreports/pom.xml                      |    2 +-
 .../src/main/resources/struts-plugin.xml           |    6 +-
 plugins/javatemplates/README.md                    |    6 +
 plugins/javatemplates/pom.xml                      |    2 +-
 .../src/main/resources/struts-plugin.xml           |    4 +-
 plugins/jfreechart/README.md                       |    6 +
 plugins/jfreechart/pom.xml                         |    2 +-
 .../src/main/resources/struts-plugin.xml           |    6 +-
 plugins/json/README.md                             |    6 +
 plugins/json/pom.xml                               |    2 +-
 plugins/json/src/main/resources/struts-plugin.xml  |    2 +-
 .../struts2/json/JSONActionRedirectResultTest.java |   22 +-
 plugins/junit/README.md                            |    7 +
 plugins/junit/pom.xml                              |    2 +-
 .../resources/struts-convention-configuration.xml  |    2 +-
 .../test/resources/struts-session-values-test.xml  |    2 +-
 plugins/junit/src/test/resources/struts-test.xml   |    2 +-
 plugins/junit/src/test/resources/struts.xml        |    2 +-
 plugins/osgi/README.md                             |    2 +
 plugins/osgi/pom.xml                               |    2 +-
 plugins/osgi/src/main/resources/struts-plugin.xml  |    6 +-
 plugins/oval/README.md                             |    2 +
 plugins/oval/pom.xml                               |    8 +-
 plugins/oval/src/main/resources/struts-plugin.xml  |    2 +-
 plugins/oval/src/test/resources/oval-test.xml      |    2 +-
 plugins/pell-multipart/README.md                   |    2 +
 plugins/pell-multipart/pom.xml                     |    2 +-
 .../src/main/resources/struts-plugin.xml           |    4 +-
 plugins/plexus/README.md                           |    2 +
 plugins/plexus/pom.xml                             |    2 +-
 .../plexus/src/main/resources/struts-plugin.xml    |    4 +-
 plugins/pom.xml                                    |    2 +-
 plugins/portlet-mocks/README.md                    |    2 +
 plugins/portlet-mocks/pom.xml                      |    2 +-
 plugins/portlet-tiles/README.md                    |    2 +
 plugins/portlet-tiles/pom.xml                      |    2 +-
 .../src/main/resources/struts-plugin.xml           |    2 +-
 plugins/portlet/README.md                          |    2 +
 plugins/portlet/pom.xml                            |    2 +-
 .../struts2/components/PortletUrlRenderer.java     |   77 +-
 .../result/PortletActionRedirectResult.java        |  247 +--
 .../portlet/src/main/resources/struts-plugin.xml   |    2 +-
 plugins/portlet/src/test/resources/struts.xml      |    2 +-
 plugins/rest/README.md                             |    7 +
 plugins/rest/pom.xml                               |    2 +-
 .../struts2/rest/handler/XStreamHandler.java       |   46 +-
 .../XStreamAllowedClassNames.java}                 |    4 +-
 .../XStreamAllowedClasses.java}                    |    4 +-
 .../{ => xstream}/XStreamPermissionProvider.java   |    2 +-
 .../rest/handler/xstream/XStreamProvider.java      |   54 +-
 plugins/rest/src/main/resources/struts-plugin.xml  |    2 +-
 .../struts2/rest/handler/XStreamHandlerTest.java   |  157 ++
 plugins/sitemesh/README.md                         |    2 +
 plugins/sitemesh/pom.xml                           |    2 +-
 .../sitemesh/src/main/resources/struts-plugin.xml  |    2 +-
 plugins/spring/README.md                           |    6 +
 plugins/spring/pom.xml                             |    2 +-
 .../spring/src/main/resources/struts-plugin.xml    |    8 +-
 .../xwork2/spring/actionContext-xwork.xml          |    4 +-
 plugins/testng/README.md                           |    6 +
 plugins/testng/pom.xml                             |    2 +-
 plugins/tiles/README.md                            |    6 +
 plugins/tiles/pom.xml                              |    2 +-
 plugins/tiles/src/main/resources/struts-plugin.xml |    2 +-
 plugins/velocity/README.md                         |    6 +
 plugins/velocity/pom.xml                           |    2 +-
 .../velocity/src/main/resources/struts-plugin.xml  |    2 +-
 pom.xml                                            |   81 +-
 src/etc/project-suppression.xml                    |   31 +-
 467 files changed, 19442 insertions(+), 22455 deletions(-)
 create mode 100644 .github/workflows/codeql.yml
 create mode 100644 .github/workflows/maven.yml
 create mode 100644 .github/workflows/scorecards-analysis.yaml
 delete mode 100644 .travis.yml
 create mode 100644 apps/README.md
 create mode 100644 apps/showcase/src/main/java/org/apache/struts2/showcase/wait/ThreadPoolExecutorProvider.java
 create mode 100644 apps/showcase/src/main/webapp/WEB-INF/wait/index.jsp
 delete mode 100644 apps/showcase/src/main/webapp/wait/index.html
 create mode 100644 assembly/README.md
 create mode 100644 bom/README.md
 create mode 100644 core/README.md
 copy core/src/main/java/com/opensymphony/xwork2/interceptor/{AbstractInterceptor.java => ConditionalInterceptor.java} (59%)
 copy core/src/main/java/{com/opensymphony/xwork2/interceptor/AbstractInterceptor.java => org/apache/struts2/interceptor/exec/BackgroundProcess.java} (65%)
 copy plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamPermissionProvider.java => core/src/main/java/org/apache/struts2/interceptor/exec/ExecutorProvider.java (66%)
 rename core/src/main/java/org/apache/struts2/interceptor/{BackgroundProcess.java => exec/StrutsBackgroundProcess.java} (63%)
 create mode 100644 core/src/main/java/org/apache/struts2/interceptor/exec/StrutsExecutorProvider.java
 copy core/src/main/java/{com/opensymphony/xwork2/interceptor/AbstractInterceptor.java => org/apache/struts2/url/QueryStringBuilder.java} (57%)
 copy core/src/main/java/org/apache/struts2/{components/ExtraParameterProvider.java => url/QueryStringParser.java} (74%)
 create mode 100644 core/src/main/java/org/apache/struts2/url/StrutsQueryStringBuilder.java
 create mode 100644 core/src/main/java/org/apache/struts2/url/StrutsQueryStringParser.java
 create mode 100644 core/src/main/java/org/apache/struts2/url/StrutsUrlDecoder.java
 create mode 100644 core/src/main/java/org/apache/struts2/url/StrutsUrlEncoder.java
 create mode 100644 core/src/main/java/org/apache/struts2/url/UrlDecoder.java
 copy core/src/main/java/{com/opensymphony/xwork2/interceptor/AbstractInterceptor.java => org/apache/struts2/url/UrlEncoder.java} (58%)
 delete mode 100644 core/src/main/java/org/apache/struts2/util/URLDecoderUtil.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/Ascii.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/B2CConverter.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/ByteChunk.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/CharChunk.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/HexUtils.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/MessageBytes.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/StringCache.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/UDecoder.java
 delete mode 100644 core/src/main/java/org/apache/struts2/util/tomcat/buf/Utf8Decoder.java
 rename core/src/main/resources/{template/xhtml/script.ftl => author.dtd} (92%)
 delete mode 100644 core/src/main/resources/template/archive/xhtml/controlheader.vm
 delete mode 100644 core/src/main/resources/template/xhtml/link.ftl
 delete mode 100644 core/src/test/java/com/opensymphony/xwork2/TestInterceptor.java
 create mode 100644 core/src/test/java/org/apache/struts2/dispatcher/InitOperationsTest.java
 delete mode 100644 core/src/test/java/org/apache/struts2/dispatcher/ServletDispatchedTestAssertInterceptor.java
 delete mode 100644 core/src/test/java/org/apache/struts2/interceptor/BackgroundProcessTest.java
 create mode 100644 core/src/test/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcessTest.java
 create mode 100644 core/src/test/java/org/apache/struts2/url/StrutsQueryStringBuilderTest.java
 create mode 100644 core/src/test/java/org/apache/struts2/url/StrutsQueryStringParserTest.java
 create mode 100644 core/src/test/java/org/apache/struts2/url/StrutsUrlDecoderTest.java
 create mode 100644 core/src/test/java/org/apache/struts2/url/StrutsUrlEncoderTest.java
 delete mode 100644 core/src/test/java/org/apache/struts2/util/URLDecoderUtilTest.java
 create mode 100644 core/src/test/resources/org/apache/struts2/views/jsp/ui/DoubleSelect-6.txt
 copy core/src/test/resources/{struts-escape-body.xml => struts-checkbox-submit-unchecked.xml} (89%)
 create mode 100644 plugins/README.md
 create mode 100644 plugins/async/README.md
 create mode 100644 plugins/bean-validation/README.md
 create mode 100644 plugins/cdi/README.md
 create mode 100644 plugins/config-browser/README.md
 delete mode 100644 plugins/config-browser/src/main/resources/config-browser/config-styles.css
 create mode 100644 plugins/config-browser/src/main/resources/config-browser/config-styles.ftl
 create mode 100644 plugins/convention/README.md
 create mode 100644 plugins/dwr/README.md
 create mode 100644 plugins/embeddedjsp/README.md
 create mode 100644 plugins/gxp/README.md
 create mode 100644 plugins/jasperreports/README.md
 create mode 100644 plugins/javatemplates/README.md
 create mode 100644 plugins/jfreechart/README.md
 create mode 100644 plugins/json/README.md
 create mode 100644 plugins/junit/README.md
 create mode 100644 plugins/osgi/README.md
 create mode 100644 plugins/oval/README.md
 create mode 100644 plugins/pell-multipart/README.md
 create mode 100644 plugins/plexus/README.md
 create mode 100644 plugins/portlet-mocks/README.md
 create mode 100644 plugins/portlet-tiles/README.md
 create mode 100644 plugins/portlet/README.md
 create mode 100644 plugins/rest/README.md
 rename plugins/rest/src/main/java/org/apache/struts2/rest/handler/{AllowedClassNames.java => xstream/XStreamAllowedClassNames.java} (90%)
 rename plugins/rest/src/main/java/org/apache/struts2/rest/handler/{AllowedClasses.java => xstream/XStreamAllowedClasses.java} (90%)
 rename plugins/rest/src/main/java/org/apache/struts2/rest/handler/{ => xstream}/XStreamPermissionProvider.java (95%)
 copy core/src/main/java/org/apache/struts2/components/ExtraParameterProvider.java => plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamProvider.java (73%)
 create mode 100644 plugins/rest/src/test/java/org/apache/struts2/rest/handler/XStreamHandlerTest.java
 create mode 100644 plugins/sitemesh/README.md
 create mode 100644 plugins/spring/README.md
 create mode 100644 plugins/testng/README.md
 create mode 100644 plugins/tiles/README.md
 create mode 100644 plugins/velocity/README.md


[struts] 22/23: Make plugin standalone with all generated resources for velocity.

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 86c81ca27f582ac598ca2af96bc1135b121b6661
Author: Greg Huber <gh...@apache.org>
AuthorDate: Tue Oct 18 14:43:22 2022 +0100

    Make plugin standalone with all generated resources for velocity.
---
 .../tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
index c29ea67ef..4e90bb7ba 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
@@ -59,7 +59,7 @@ public class BuildAutotags {
         // Freemarker classes
         me.buildFreemarker(args[0]);
 
-        // Freemarker classes
+        // Velocity classes
         me.buildVelocity(args[0]);
 
     }
@@ -173,7 +173,7 @@ public class BuildAutotags {
     }
 
     /**
-     * Builds the velocity classes.
+     * Builds the velocity classes and velocity.properties.
      * 
      * To build, change template-suite.xml as required and then run this program.
      * Copy the classes from the target autotag folder into the packageName


[struts] 08/23: WW-5233 Copies Tiles Servlet related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit e6f8f68af804a862a7da7b722e5a76562b66b9d8
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 13:45:09 2022 +0200

    WW-5233 Copies Tiles Servlet related tests
---
 .../web/startup/AbstractTilesListenerTest.java     | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/plugins/tiles/src/test/java/org/apache/tiles/web/startup/AbstractTilesListenerTest.java b/plugins/tiles/src/test/java/org/apache/tiles/web/startup/AbstractTilesListenerTest.java
new file mode 100644
index 000000000..dbf6f3ec2
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/web/startup/AbstractTilesListenerTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.startup;
+
+import org.apache.tiles.core.startup.TilesInitializer;
+import org.apache.tiles.request.servlet.ServletApplicationContext;
+import org.junit.Test;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link AbstractTilesListener}.
+ */
+public class AbstractTilesListenerTest {
+
+    /**
+     * Test method for {@link AbstractTilesListener#contextInitialized(ServletContextEvent)}.
+     */
+    @Test
+    public void testContextInitialized() {
+        AbstractTilesListener listener = createMockBuilder(AbstractTilesListener.class).createMock();
+        ServletContextEvent event = createMock(ServletContextEvent.class);
+        ServletContext servletContext = createMock(ServletContext.class);
+        TilesInitializer initializer = createMock(TilesInitializer.class);
+
+        expect(event.getServletContext()).andReturn(servletContext);
+        expect(listener.createTilesInitializer()).andReturn(initializer);
+        initializer.initialize(isA(ServletApplicationContext.class));
+        initializer.destroy();
+
+        replay(listener, event, servletContext, initializer);
+        listener.contextInitialized(event);
+        listener.contextDestroyed(event);
+        verify(listener, event, servletContext, initializer);
+    }
+
+}


[struts] 03/23: WW-5233 Copies Tiles API related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 128d5a5191750cdd054e95332ca7706eead16903
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 08:39:07 2022 +0200

    WW-5233 Copies Tiles API related tests
---
 plugins/tiles/pom.xml                              |   5 +
 .../main/java/org/apache/tiles/api/Attribute.java  |  70 ++-
 .../apache/tiles/api/BasicAttributeContext.java    | 108 ++--
 .../java/org/apache/tiles/api/CompareUtil.java     |  67 --
 .../main/java/org/apache/tiles/api/Definition.java |  27 +-
 .../main/java/org/apache/tiles/api/Expression.java |  28 +-
 .../java/org/apache/tiles/api/AttributeTest.java   | 277 +++++++++
 .../tiles/api/BasicAttributeContextTest.java       | 683 +++++++++++++++++++++
 .../java/org/apache/tiles/api/ExpressionTest.java  | 110 ++++
 .../org/apache/tiles/api/ListAttributeTest.java    | 111 ++++
 .../tiles/api/NoSuchContainerExceptionTest.java    |  41 ++
 .../java/org/apache/tiles/api/TestDefinition.java  | 250 ++++++++
 .../tiles/api/TilesContainerWrapperTest.java       | 234 +++++++
 .../org/apache/tiles/api/TilesExceptionTest.java   |  64 ++
 .../apache/tiles/api/access/TilesAccessTest.java   | 206 +++++++
 .../tiles/api/preparer/PreparerExceptionTest.java  |  76 +++
 16 files changed, 2195 insertions(+), 162 deletions(-)

diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 807bd1f3d..1ee16c1f6 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -46,6 +46,11 @@
             <artifactId>jsp-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <properties>
     	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
index 60a09df9f..5a2df3e32 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -27,11 +27,9 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Objects;
 import java.util.Set;
 
-import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
-import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
-
 /**
  * Common implementation of attribute definition.
  */
@@ -44,6 +42,7 @@ public class Attribute implements Serializable, Cloneable {
 
     /**
      * The roles that can render this attribute.
+     *
      * @since 2.0.6
      */
     protected Set<String> roles = null;
@@ -69,7 +68,6 @@ public class Attribute implements Serializable, Cloneable {
 
     /**
      * Constructor.
-     *
      */
     public Attribute() {
     }
@@ -113,11 +111,11 @@ public class Attribute implements Serializable, Cloneable {
     /**
      * Constructor.
      *
-     * @param value Object to store. If specified, the <code>expression</code>
-     * parameter will be ignored.
-     * @param expression The expression to be evaluated. Ignored if the
-     * <code>value</code> is not null.
-     * @param role Associated role.
+     * @param value        Object to store. If specified, the <code>expression</code>
+     *                     parameter will be ignored.
+     * @param expression   The expression to be evaluated. Ignored if the
+     *                     <code>value</code> is not null.
+     * @param role         Associated role.
      * @param rendererName The renderer name.
      * @since 2.2.0
      */
@@ -145,31 +143,32 @@ public class Attribute implements Serializable, Cloneable {
     /**
      * Creates a template attribute, starting from the name of the template.
      *
-     * @param template The template that will be rendered.
+     * @param template           The template that will be rendered.
      * @param templateExpression The template expression that will be evaluated
-     * to a template.
-     * @param templateType The type, or renderer, of the template. If null, the
-     * default <code>template</code> will be used.
-     * @param role The comma-separated roles for which the template is
-     * authorized to be rendered.
+     *                           to a template.
+     * @param templateType       The type, or renderer, of the template. If null, the
+     *                           default <code>template</code> will be used.
+     * @param role               The comma-separated roles for which the template is
+     *                           authorized to be rendered.
      * @return The template attribute.
      * @since 2.2.2
      */
     public static Attribute createTemplateAttribute(String template,
-            String templateExpression, String templateType, String role) {
+                                                    String templateExpression, String templateType, String role) {
         Attribute templateAttribute = createTemplateAttribute(template);
         templateAttribute.setRole(role);
         if (templateType != null) {
             templateAttribute.setRenderer(templateType);
         }
         templateAttribute
-                .setExpressionObject(Expression
-                        .createExpressionFromDescribedExpression(templateExpression));
+            .setExpressionObject(Expression
+                .createExpressionFromDescribedExpression(templateExpression));
         return templateAttribute;
     }
 
     /**
      * Get role.
+     *
      * @return the name of the required role(s)
      */
     public String getRole() {
@@ -228,6 +227,7 @@ public class Attribute implements Serializable, Cloneable {
 
     /**
      * Get value.
+     *
      * @return the value
      */
     public Object getValue() {
@@ -265,7 +265,9 @@ public class Attribute implements Serializable, Cloneable {
         this.expressionObject = expressionObject;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public String toString() {
         if (value != null) {
@@ -307,8 +309,8 @@ public class Attribute implements Serializable, Cloneable {
         }
         Expression targetExpressionObject = attribute.getExpressionObject();
         if (targetExpressionObject != null
-                && (expressionObject == null || expressionObject
-                        .getExpression() == null)) {
+            && (expressionObject == null || expressionObject
+            .getExpression() == null)) {
             expressionObject = new Expression(targetExpressionObject);
         }
         if (roles == null || roles.isEmpty()) {
@@ -319,14 +321,16 @@ public class Attribute implements Serializable, Cloneable {
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public boolean equals(Object obj) {
         Attribute attribute = (Attribute) obj;
-        return nullSafeEquals(value, attribute.value)
-                && nullSafeEquals(renderer, attribute.renderer)
-                && nullSafeEquals(roles, attribute.roles)
-                && nullSafeEquals(expressionObject, attribute.expressionObject);
+        return Objects.equals(value, attribute.value)
+            && Objects.equals(renderer, attribute.renderer)
+            && Objects.equals(roles, attribute.roles)
+            && Objects.equals(expressionObject, attribute.expressionObject);
     }
 
     /**
@@ -344,21 +348,25 @@ public class Attribute implements Serializable, Cloneable {
         boolean retValue = false;
 
         for (Iterator<String> roleIt = roles.iterator(); roleIt.hasNext()
-                && !retValue;) {
+            && !retValue; ) {
             retValue = request.isUserInRole(roleIt.next());
         }
 
         return retValue;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
-        return nullSafeHashCode(value) + nullSafeHashCode(renderer)
-                + nullSafeHashCode(roles) + nullSafeHashCode(expressionObject);
+        return Objects.hashCode(value) + Objects.hashCode(renderer)
+            + Objects.hashCode(roles) + Objects.hashCode(expressionObject);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Attribute clone() {
         return new Attribute(this);
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
index 17d650754..0c13933b8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
@@ -23,11 +23,9 @@ package org.apache.tiles.api;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
-import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
-import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
-
 /**
  * Basic implementation for <code>AttributeContext</code>.
  *
@@ -51,12 +49,14 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
 
     /**
      * Template attributes.
+     *
      * @since 2.1.0
      */
     protected Map<String, Attribute> attributes = null;
 
     /**
      * Cascaded template attributes.
+     *
      * @since 2.1.0
      */
     protected Map<String, Attribute> cascadedAttributes = null;
@@ -118,27 +118,37 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         copyBasicAttributeContext(context);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Attribute getTemplateAttribute() {
         return templateAttribute;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void setTemplateAttribute(Attribute templateAttribute) {
         this.templateAttribute = templateAttribute;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public String getPreparer() {
         return preparer;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void setPreparer(String url) {
         this.preparer = url;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void inheritCascadedAttributes(AttributeContext context) {
         if (context instanceof BasicAttributeContext) {
             copyCascadedAttributes((BasicAttributeContext) context);
@@ -148,13 +158,15 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
             if (parentAttributeNames != null) {
                 for (String name : parentAttributeNames) {
                     cascadedAttributes.put(name, new Attribute(context
-                            .getCascadedAttribute(name)));
+                        .getCascadedAttribute(name)));
                 }
             }
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void inherit(AttributeContext parent) {
         if (parent instanceof BasicAttributeContext) {
             inherit((BasicAttributeContext) parent);
@@ -175,8 +187,8 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
                     if (destAttribute == null) {
                         putAttribute(name, attribute, true);
                     } else if (attribute instanceof ListAttribute
-                            && destAttribute instanceof ListAttribute
-                            && ((ListAttribute) destAttribute).isInherit()) {
+                        && destAttribute instanceof ListAttribute
+                        && ((ListAttribute) destAttribute).isInherit()) {
                         ((ListAttribute) destAttribute).inherit((ListAttribute) attribute);
                     }
                 }
@@ -189,8 +201,8 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
                     if (destAttribute == null) {
                         putAttribute(name, attribute, false);
                     } else if (attribute instanceof ListAttribute
-                            && destAttribute instanceof ListAttribute
-                            && ((ListAttribute) destAttribute).isInherit()) {
+                        && destAttribute instanceof ListAttribute
+                        && ((ListAttribute) destAttribute).isInherit()) {
                         ((ListAttribute) destAttribute).inherit((ListAttribute) attribute);
                     }
                 }
@@ -214,7 +226,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
 
         // Sets attributes.
         cascadedAttributes = addMissingAttributes(parent.cascadedAttributes,
-                cascadedAttributes);
+            cascadedAttributes);
         attributes = addMissingAttributes(parent.attributes, attributes);
     }
 
@@ -240,7 +252,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         attributes.putAll(newAttributes);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Attribute getAttribute(String name) {
         Attribute retValue = null;
         if (attributes != null) {
@@ -254,7 +268,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         return retValue;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Attribute getLocalAttribute(String name) {
         if (attributes == null) {
             return null;
@@ -263,7 +279,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         return attributes.get(name);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Attribute getCascadedAttribute(String name) {
         if (cascadedAttributes == null) {
             return null;
@@ -272,7 +290,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         return cascadedAttributes.get(name);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Set<String> getLocalAttributeNames() {
         if (attributes != null && !attributes.isEmpty()) {
             return attributes.keySet();
@@ -280,7 +300,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         return null;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Set<String> getCascadedAttributeNames() {
         if (cascadedAttributes != null && !cascadedAttributes.isEmpty()) {
             return cascadedAttributes.keySet();
@@ -288,7 +310,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         return null;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void putAttribute(String name, Attribute value) {
         if (attributes == null) {
             attributes = new HashMap<>();
@@ -297,7 +321,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         attributes.put(name, value);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void putAttribute(String name, Attribute value, boolean cascade) {
         Map<String, Attribute> mapToUse;
         if (cascade) {
@@ -314,7 +340,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         mapToUse.put(name, value);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void clear() {
         templateAttribute = null;
         preparer = null;
@@ -322,22 +350,26 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         cascadedAttributes.clear();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public boolean equals(Object obj) {
         BasicAttributeContext bac = (BasicAttributeContext) obj;
-        return nullSafeEquals(templateAttribute, bac.templateAttribute)
-                && nullSafeEquals(preparer, bac.preparer)
-                && nullSafeEquals(attributes, bac.attributes)
-                && nullSafeEquals(cascadedAttributes, bac.cascadedAttributes);
+        return Objects.equals(templateAttribute, bac.templateAttribute)
+            && Objects.equals(preparer, bac.preparer)
+            && Objects.equals(attributes, bac.attributes)
+            && Objects.equals(cascadedAttributes, bac.cascadedAttributes);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
-        return nullSafeHashCode(templateAttribute) + nullSafeHashCode(preparer)
-                + nullSafeHashCode(attributes)
-                + nullSafeHashCode(cascadedAttributes);
+        return Objects.hashCode(templateAttribute) + Objects.hashCode(preparer)
+            + Objects.hashCode(attributes)
+            + Objects.hashCode(cascadedAttributes);
     }
 
     /**
@@ -346,7 +378,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
      * @param parentTemplateAttribute The parent template attribute.
      */
     private void inheritParentTemplateAttribute(
-            Attribute parentTemplateAttribute) {
+        Attribute parentTemplateAttribute) {
         if (parentTemplateAttribute != null) {
             if (templateAttribute == null) {
                 templateAttribute = new Attribute(parentTemplateAttribute);
@@ -380,7 +412,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
      */
     private void copyCascadedAttributes(BasicAttributeContext context) {
         if (context.cascadedAttributes != null
-                && !context.cascadedAttributes.isEmpty()) {
+            && !context.cascadedAttributes.isEmpty()) {
             cascadedAttributes = deepCopyAttributeMap(context.cascadedAttributes);
         }
     }
@@ -388,7 +420,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
     /**
      * Adds missing attributes to the destination map.
      *
-     * @param source The source attribute map.
+     * @param source      The source attribute map.
      * @param destination The destination attribute map.
      * @return The destination attribute map if not null, a new one otherwise.
      */
@@ -403,10 +435,10 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
                 if (destAttribute == null) {
                     destination.put(key, entry.getValue());
                 } else if (destAttribute instanceof ListAttribute
-                        && entry.getValue() instanceof ListAttribute
-                        && ((ListAttribute) destAttribute).isInherit()) {
+                    && entry.getValue() instanceof ListAttribute
+                    && ((ListAttribute) destAttribute).isInherit()) {
                     ((ListAttribute) destAttribute)
-                            .inherit((ListAttribute) entry.getValue());
+                        .inherit((ListAttribute) entry.getValue());
                 }
             }
         }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/CompareUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/api/CompareUtil.java
deleted file mode 100644
index cf9b643a6..000000000
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/CompareUtil.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * $Id$
- *
- * 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.
- */
-
-package org.apache.tiles.api;
-
-/**
- * Utilities to work with comparator between objects.
- *
- * @version $Rev$ $Date$
- * @since 2.2.0
- */
-public final class CompareUtil {
-
-    /**
-     * Private constructor to avoid instantiation.
-     */
-    private CompareUtil() { }
-
-    /**
-     * Checks if two objects (eventually null) are the same. They are considered the same
-     * even if they are both null.
-     *
-     * @param obj1 The first object to check.
-     * @param obj2 The second object to check.
-     * @return <code>true</code> if the objects are the same.
-     * @since 2.2.0
-     */
-    public static boolean nullSafeEquals(Object obj1, Object obj2) {
-        if (obj1 != null) {
-            return obj1.equals(obj2);
-        }
-        return obj2 == null;
-    }
-
-    /**
-     * Returns <code>0</code> if the object is null, the hash code of the object
-     * otherwise.
-     *
-     * @param obj The object from which the hash code must be calculated.
-     * @return The hash code.
-     * @since 2.2.0
-     */
-    public static int nullSafeHashCode(Object obj) {
-        if (obj != null) {
-            return obj.hashCode();
-        }
-        return 0;
-    }
-}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
index 0843f1aca..85f1d9220 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
@@ -21,9 +21,7 @@
 package org.apache.tiles.api;
 
 import java.util.Map;
-
-import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
-import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
+import java.util.Objects;
 
 /**
  * A definition, i.e. a template with (completely or not) filled attributes.
@@ -65,14 +63,14 @@ public class Definition extends BasicAttributeContext {
 
     /**
      * Constructor.
-     * @param name The name of the definition.
-     * @param templateAttribute The template attribute of the definition.
-     * @param attributes The attribute map of the definition.
      *
+     * @param name              The name of the definition.
+     * @param templateAttribute The template attribute of the definition.
+     * @param attributes        The attribute map of the definition.
      * @since 2.1.2
      */
     public Definition(String name, Attribute templateAttribute,
-                               Map<String, Attribute> attributes) {
+                      Map<String, Attribute> attributes) {
         super(attributes);
         this.name = name;
         this.templateAttribute = templateAttribute;
@@ -115,20 +113,21 @@ public class Definition extends BasicAttributeContext {
     }
 
 
-
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public boolean equals(Object obj) {
         Definition def = (Definition) obj;
-        return nullSafeEquals(name, def.name)
-                && nullSafeEquals(inherit, def.inherit) && super.equals(def);
+        return Objects.equals(name, def.name) && Objects.equals(inherit, def.inherit) && super.equals(def);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
-        return nullSafeHashCode(name) + nullSafeHashCode(inherit)
-                + super.hashCode();
+        return Objects.hashCode(name) + Objects.hashCode(inherit) + super.hashCode();
     }
 
     /**
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
index 439a2c2e8..d96a9f154 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
@@ -21,8 +21,7 @@
 
 package org.apache.tiles.api;
 
-import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
-import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
+import java.util.Objects;
 
 /**
  * It is an expression, along with the expression language (e.g. EL, MVEL, OGNL)
@@ -46,7 +45,7 @@ public class Expression {
      * Constructor.
      *
      * @param expression The expression itself.
-     * @param language The language of the expression.
+     * @param language   The language of the expression.
      * @since 2.2.0
      */
     public Expression(String expression, String language) {
@@ -80,8 +79,8 @@ public class Expression {
      * <code>LANGUAGE:EXPRESSION</code>.
      *
      * @param describedExpression The expression in the form
-     * <code>LANGUAGE:EXPRESSION</code>. The LANGUAGE part should be expressed
-     * only with letters and numbers.
+     *                            <code>LANGUAGE:EXPRESSION</code>. The LANGUAGE part should be expressed
+     *                            only with letters and numbers.
      * @return The created object, or <code>null</code> if the expression is null.
      * @since 2.2.0
      */
@@ -103,7 +102,7 @@ public class Expression {
      * Creates an Expression object from the expression and its language.
      *
      * @param expression The expression itself.
-     * @param language The language of the expression.
+     * @param language   The language of the expression.
      * @return The created object, or <code>null</code> if the expression is null.
      * @since 2.2.0
      */
@@ -135,21 +134,26 @@ public class Expression {
         return language;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public boolean equals(Object obj) {
         Expression exp = (Expression) obj;
-        return nullSafeEquals(expression, exp.expression)
-                && nullSafeEquals(language, exp.language);
+        return Objects.equals(expression, exp.expression) && Objects.equals(language, exp.language);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
-        return nullSafeHashCode(expression) + nullSafeHashCode(language);
+        return Objects.hashCode(expression) + Objects.hashCode(language);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public String toString() {
         return (language == null ? "DEFAULT" : language) + ":" + expression;
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
new file mode 100644
index 000000000..d081e5634
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
@@ -0,0 +1,277 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link Attribute}.
+ */
+public class AttributeTest {
+
+
+    /**
+     * Tests {@link Attribute#createTemplateAttribute(String)}.
+     */
+    @Test
+    public void testCreateTemplateAttribute1() {
+        Attribute attribute = Attribute.createTemplateAttribute("/my/template.jsp");
+        assertEquals("/my/template.jsp", attribute.getValue());
+        assertEquals("template", attribute.getRenderer());
+    }
+
+    /**
+     * Tests {@link Attribute#Attribute()}.
+     */
+    @Test
+    public void testAttribute() {
+        Attribute attribute = new Attribute();
+        assertNull(attribute.getValue());
+    }
+
+    /**
+     * Tests {@link Attribute#Attribute(Object)}.
+     */
+    @Test
+    public void testAttributeObject() {
+        Attribute attribute = new Attribute("my.value");
+        assertEquals("my.value", attribute.getValue());
+        assertNull(attribute.getRenderer());
+    }
+
+    /**
+     * Tests {@link Attribute#Attribute(Object, String)}.
+     */
+    @Test
+    public void testAttributeObjectString() {
+        Attribute attribute = new Attribute("my.value", "role1,role2");
+        assertEquals("my.value", attribute.getValue());
+        assertNull(attribute.getRenderer());
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals(roles, attribute.getRoles());
+    }
+
+    /**
+     * Tests {@link Attribute#Attribute(Object, Expression, String, String)}.
+     */
+    @Test
+    public void testAttributeComplete() {
+        Expression expression = new Expression("my.expression", "MYLANG");
+        Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
+        assertEquals("my.value", attribute.getValue());
+        assertEquals("myrenderer", attribute.getRenderer());
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals(roles, attribute.getRoles());
+        assertEquals("my.expression", attribute.getExpressionObject().getExpression());
+        assertEquals("MYLANG", attribute.getExpressionObject().getLanguage());
+    }
+
+    /**
+     * Tests {@link Attribute#Attribute(Attribute)}.
+     */
+    @Test
+    public void testAttributeCopy() {
+        Expression expression = new Expression("my.expression", "MYLANG");
+        Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
+        attribute = new Attribute(attribute);
+        assertEquals("my.value", attribute.getValue());
+        assertEquals("myrenderer", attribute.getRenderer());
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals(roles, attribute.getRoles());
+        assertEquals("my.expression", attribute.getExpressionObject().getExpression());
+        assertEquals("MYLANG", attribute.getExpressionObject().getLanguage());
+
+        attribute = new Attribute("my.value", null, "role1,role2", "myrenderer");
+        attribute = new Attribute(attribute);
+        assertEquals("my.value", attribute.getValue());
+        assertEquals("myrenderer", attribute.getRenderer());
+        roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals(roles, attribute.getRoles());
+        assertNull(attribute.getExpressionObject());
+    }
+
+    /**
+     * Tests {@link Attribute#equals(Object)}.
+     */
+    @Test
+    public void testEquals() {
+        Expression expression = new Expression("my.expression", "MYLANG");
+        Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
+        Attribute attribute2 = new Attribute(attribute);
+        assertEquals(attribute, attribute2);
+        attribute2.setRenderer("anotherRenderer");
+        assertNotEquals(attribute, attribute2);
+        attribute2 = new Attribute(attribute);
+        attribute2.setRole("otherrole");
+        assertNotEquals(attribute, attribute2);
+        attribute2 = new Attribute(attribute);
+        attribute2.setExpressionObject(new Expression("another.expression", "MYLANG"));
+        assertNotEquals(attribute, attribute2);
+        attribute2 = new Attribute(attribute);
+        attribute2.setValue("anothervalue");
+        assertNotEquals(attribute, attribute2);
+    }
+
+    /**
+     * Tests {@link Attribute#getRole()} and {@link Attribute#setRole(String)}.
+     */
+    @Test
+    public void testGetRole() {
+        Attribute attribute = new Attribute("my.value");
+        assertNull(attribute.getRole());
+        Set<String> roles = new LinkedHashSet<>();
+        attribute.setRoles(roles);
+        assertNull(attribute.getRole());
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals("role1,role2", attribute.getRole());
+    }
+
+    /**
+     * Tests {@link Attribute#hashCode()}.
+     */
+    @Test
+    public void testHashCode() {
+        Expression expression = new Expression("my.expression", "MYLANG");
+        Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals(
+            Objects.hashCode("my.value")
+                + Objects.hashCode(expression) + Objects.hashCode(roles)
+                + Objects.hashCode("myrenderer"), attribute.hashCode()
+        );
+    }
+
+    /**
+     * Tests {@link Attribute#toString()}.
+     */
+    @Test
+    public void testToString() {
+        Expression expression = new Expression("my.expression", "MYLANG");
+        Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
+        assertEquals("my.value", attribute.toString());
+        attribute.setValue(null);
+        assertNull(attribute.toString());
+    }
+
+    @Test
+    public void testInherit() {
+        Attribute attribute = new Attribute(null, null, null, null);
+        Attribute parentAttribute = new Attribute("value", Expression
+            .createExpression("expression", "language"), "role", "renderer");
+        attribute.inherit(parentAttribute);
+        assertEquals("value", attribute.getValue());
+        assertEquals("expression", attribute.getExpressionObject().getExpression());
+        assertEquals("language", attribute.getExpressionObject().getLanguage());
+        assertEquals("role", attribute.getRole());
+        assertEquals("renderer", attribute.getRenderer());
+        Expression expression = new Expression(null, "MYLANG");
+        attribute = new Attribute(null, expression, null, null);
+        attribute.setRoles(new HashSet<>());
+        attribute.inherit(parentAttribute);
+        assertEquals("value", attribute.getValue());
+        assertEquals("expression", attribute.getExpressionObject().getExpression());
+        assertEquals("language", attribute.getExpressionObject().getLanguage());
+        assertEquals("role", attribute.getRole());
+        assertEquals("renderer", attribute.getRenderer());
+    }
+
+    /**
+     * Tests {@link Attribute#clone()}.
+     */
+    @Test
+    public void testClone() {
+        Expression expression = new Expression("my.expression", "MYLANG");
+        Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
+        attribute = attribute.clone();
+        assertEquals("my.value", attribute.getValue());
+        assertEquals("myrenderer", attribute.getRenderer());
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        assertEquals(roles, attribute.getRoles());
+        assertEquals("my.expression", attribute.getExpressionObject().getExpression());
+        assertEquals("MYLANG", attribute.getExpressionObject().getLanguage());
+    }
+
+    /**
+     * Tests {@link Attribute#createTemplateAttribute(String, String, String, String)}.
+     */
+    @Test
+    public void testCreateTemplateAttribute() {
+        Attribute attribute = Attribute.createTemplateAttribute("myTemplate", "MYLANG:myExpression", "myType", "myRole");
+        assertEquals("myTemplate", attribute.getValue());
+        assertEquals("MYLANG", attribute.getExpressionObject().getLanguage());
+        assertEquals("myExpression", attribute.getExpressionObject().getExpression());
+        assertEquals("myType", attribute.getRenderer());
+        Set<String> roles = attribute.getRoles();
+        assertEquals(1, roles.size());
+        assertTrue(roles.contains("myRole"));
+    }
+
+    @Test
+    public void testIsPermitted() {
+        Attribute attribute = new Attribute("myvalue");
+        Request requestContext = createMock(Request.class);
+        expect(requestContext.isUserInRole("first")).andReturn(Boolean.TRUE)
+            .anyTimes();
+        expect(requestContext.isUserInRole("second")).andReturn(Boolean.FALSE)
+            .anyTimes();
+        replay(requestContext);
+        assertTrue(attribute.isPermitted(requestContext));
+        Set<String> roles = new HashSet<>();
+        roles.add("first");
+        attribute.setRoles(roles);
+        assertTrue("The role is not permitted", attribute.isPermitted(
+            requestContext));
+        roles.clear();
+        roles.add("second");
+        assertFalse("The role is not permitted", attribute.isPermitted(
+            requestContext));
+        verify(requestContext);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java
new file mode 100644
index 000000000..23f021491
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java
@@ -0,0 +1,683 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests <code>BasicAttributeContext</code>.
+ *
+ * @version $Rev$ $Date$
+ */
+public class BasicAttributeContextTest {
+
+    /**
+     * Tests {@link BasicAttributeContext#BasicAttributeContext()}.
+     */
+    @Test
+    public void testBasicAttributeContext() {
+        AttributeContext context = new BasicAttributeContext();
+        assertNull("There are some spurious attributes", context
+            .getLocalAttributeNames());
+        assertNull("There are some spurious attributes", context
+            .getCascadedAttributeNames());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#BasicAttributeContext(Map)}.
+     */
+    @Test
+    public void testBasicAttributeContextMapOfStringAttribute() {
+        Map<String, Attribute> name2attrib = new HashMap<>();
+        Attribute attribute = new Attribute("Value 1");
+        name2attrib.put("name1", attribute);
+        attribute = new Attribute("Value 2");
+        name2attrib.put("name2", attribute);
+        AttributeContext context = new BasicAttributeContext(name2attrib);
+        attribute = context.getAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "Value 1",
+            attribute.getValue());
+        attribute = context.getAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "Value 2",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests
+     * {@link BasicAttributeContext#BasicAttributeContext(AttributeContext)}.
+     */
+    @Test
+    public void testBasicAttributeContextAttributeContext() {
+        Set<String> localAttributes = new LinkedHashSet<>();
+        Set<String> cascadedAttributes = new LinkedHashSet<>();
+        localAttributes.add("local1");
+        localAttributes.add("local2");
+        cascadedAttributes.add("cascaded1");
+        cascadedAttributes.add("cascaded2");
+        AttributeContext toCopy = createMock(AttributeContext.class);
+        expect(toCopy.getLocalAttributeNames()).andReturn(localAttributes);
+        expect(toCopy.getLocalAttribute("local1")).andReturn(
+            new Attribute("value1")).anyTimes();
+        expect(toCopy.getLocalAttribute("local2")).andReturn(
+            new Attribute("value2")).anyTimes();
+        expect(toCopy.getCascadedAttributeNames())
+            .andReturn(cascadedAttributes);
+        expect(toCopy.getCascadedAttribute("cascaded1")).andReturn(
+            new Attribute("value3")).anyTimes();
+        expect(toCopy.getCascadedAttribute("cascaded2")).andReturn(
+            new Attribute("value4")).anyTimes();
+        Attribute templateAttribute = new Attribute("/template.jsp", Expression
+            .createExpression("expression", null), "role1,role2",
+            "template");
+        expect(toCopy.getTemplateAttribute()).andReturn(templateAttribute);
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        expect(toCopy.getPreparer()).andReturn("my.preparer.Preparer");
+        replay(toCopy);
+        BasicAttributeContext context = new BasicAttributeContext(toCopy);
+        assertEquals("The template has not been set correctly",
+            "/template.jsp", context.getTemplateAttribute().getValue());
+        assertEquals("The template expression has not been set correctly",
+            "expression", context.getTemplateAttribute()
+                .getExpressionObject().getExpression());
+        assertEquals("The roles are not the same", roles, context
+            .getTemplateAttribute().getRoles());
+        assertEquals("The preparer has not been set correctly",
+            "my.preparer.Preparer", context.getPreparer());
+        Attribute attribute = context.getLocalAttribute("local1");
+        assertNotNull("Attribute local1 not found", attribute);
+        assertEquals("Attribute local1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("local2");
+        assertNotNull("Attribute local2 not found", attribute);
+        assertEquals("Attribute local2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("cascaded1");
+        assertNotNull("Attribute cascaded1 not found", attribute);
+        assertEquals("Attribute cascaded1 has not been set correctly",
+            "value3", attribute.getValue());
+        attribute = context.getCascadedAttribute("cascaded2");
+        assertNotNull("Attribute cascaded2 not found", attribute);
+        assertEquals("Attribute cascaded2 has not been set correctly",
+            "value4", attribute.getValue());
+    }
+
+    /**
+     * Tests
+     * {@link BasicAttributeContext#BasicAttributeContext(BasicAttributeContext)}
+     * .
+     */
+    @Test
+    public void testBasicAttributeContextBasicAttributeContext() {
+        BasicAttributeContext toCopy = new BasicAttributeContext();
+        toCopy.putAttribute("name1", new Attribute("value1"), false);
+        toCopy.putAttribute("name2", new Attribute("value2"), true);
+        Attribute templateAttribute = Attribute
+            .createTemplateAttribute("/template.jsp");
+        Set<String> roles = new HashSet<>();
+        roles.add("role1");
+        roles.add("role2");
+        templateAttribute.setRoles(roles);
+        toCopy.setTemplateAttribute(templateAttribute);
+        toCopy.setPreparer("my.preparer.Preparer");
+        AttributeContext context = new BasicAttributeContext(toCopy);
+        assertEquals("The template has not been set correctly",
+            "/template.jsp", context.getTemplateAttribute().getValue());
+        assertEquals("The roles are not the same", roles, context
+            .getTemplateAttribute().getRoles());
+        assertEquals("The preparer has not been set correctly",
+            "my.preparer.Preparer", context.getPreparer());
+        Attribute attribute = context.getLocalAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests
+     * {@link BasicAttributeContext#inheritCascadedAttributes(AttributeContext)}
+     * .
+     */
+    @Test
+    public void testInheritCascadedAttributes() {
+        AttributeContext toCopy = new BasicAttributeContext();
+        toCopy.putAttribute("name1", new Attribute("value1"), false);
+        toCopy.putAttribute("name2", new Attribute("value2"), true);
+        AttributeContext context = new BasicAttributeContext();
+        context.inheritCascadedAttributes(toCopy);
+        Attribute attribute = context.getLocalAttribute("name1");
+        assertNull("Attribute name1 found", attribute);
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#inherit(BasicAttributeContext)}
+     * testing inheritance between {@link ListAttribute} instances.
+     */
+    @Test
+    public void testInheritListAttribute() {
+        AttributeContext toCopy = new BasicAttributeContext();
+        ListAttribute parentListAttribute = new ListAttribute();
+        Attribute first = new Attribute("first");
+        Attribute second = new Attribute("second");
+        parentListAttribute.add(first);
+        toCopy.putAttribute("list", parentListAttribute);
+        AttributeContext context = new BasicAttributeContext();
+        ListAttribute listAttribute = new ListAttribute();
+        listAttribute.setInherit(true);
+        listAttribute.add(second);
+        context.putAttribute("list", listAttribute);
+        context.inherit(toCopy);
+        ListAttribute result = (ListAttribute) context.getAttribute("list");
+        assertNotNull("The attribute must exist", result);
+        List<Attribute> value = result.getValue();
+        assertNotNull("The list must exist", value);
+        assertEquals("The size is not correct", 2, value.size());
+        assertEquals("The first element is not correct", first, value.get(0));
+        assertEquals("The second element is not correct", second, value
+            .get(1));
+
+        context = new BasicAttributeContext();
+        listAttribute = new ListAttribute();
+        listAttribute.add(second);
+        context.putAttribute("list", listAttribute);
+        context.inherit(toCopy);
+        result = (ListAttribute) context.getAttribute("list");
+        assertNotNull("The attribute must exist", result);
+        value = result.getValue();
+        assertNotNull("The list must exist", value);
+        assertEquals("The size is not correct", 1, value.size());
+        assertEquals("The second element is not correct", second, value
+            .get(0));
+    }
+
+    /**
+     * Tests
+     * {@link BasicAttributeContext#inheritCascadedAttributes(AttributeContext)}
+     * .
+     */
+    @Test
+    public void testInherit() {
+        AttributeContext toCopy = new BasicAttributeContext();
+        Attribute parentTemplateAttribute = new Attribute();
+        parentTemplateAttribute.setValue("/parent/template.jsp");
+        toCopy.setTemplateAttribute(parentTemplateAttribute);
+        toCopy.putAttribute("name1", new Attribute("value1"), true);
+        toCopy.putAttribute("name2", new Attribute("value2"), true);
+        toCopy.putAttribute("name3", new Attribute("value3"), false);
+        toCopy.putAttribute("name4", new Attribute("value4"), false);
+        AttributeContext context = new BasicAttributeContext();
+        Attribute templateAttribute = new Attribute();
+        templateAttribute.setRole("role1,role2");
+        context.setTemplateAttribute(templateAttribute);
+        context.putAttribute("name1", new Attribute("newValue1"), true);
+        context.putAttribute("name3", new Attribute("newValue3"), false);
+        context.inherit(toCopy);
+        Attribute attribute = context.getTemplateAttribute();
+        assertEquals("/parent/template.jsp", attribute.getValue());
+        assertTrue(attribute.getRoles().contains("role1"));
+        assertTrue(attribute.getRoles().contains("role2"));
+        attribute = context.getCascadedAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "newValue1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "newValue3",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name4");
+        assertNotNull("Attribute name4 not found", attribute);
+        assertEquals("Attribute name4 has not been set correctly", "value4",
+            attribute.getValue());
+
+        toCopy = new BasicAttributeContext();
+        toCopy.putAttribute("name1", new Attribute("value1"), true);
+        toCopy.putAttribute("name2", new Attribute("value2"), true);
+        toCopy.putAttribute("name3", new Attribute("value3"), false);
+        toCopy.putAttribute("name4", new Attribute("value4"), false);
+        context = new BasicAttributeContext();
+        context.inherit(toCopy);
+        attribute = context.getCascadedAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "value3",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name4");
+        assertNotNull("Attribute name4 not found", attribute);
+        assertEquals("Attribute name4 has not been set correctly", "value4",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests
+     * {@link BasicAttributeContext#inherit(AttributeContext)}
+     * .
+     */
+    @Test
+    public void testInheritAttributeContext() {
+        AttributeContext toCopy = createMock(AttributeContext.class);
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+        expect(toCopy.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(toCopy.getPreparer()).andReturn("my.preparer");
+        Set<String> cascadedNames = new HashSet<>();
+        cascadedNames.add("name1");
+        cascadedNames.add("name2");
+        expect(toCopy.getCascadedAttributeNames()).andReturn(cascadedNames);
+        expect(toCopy.getCascadedAttribute("name1")).andReturn(new Attribute("value1"));
+        expect(toCopy.getCascadedAttribute("name2")).andReturn(new Attribute("value2"));
+        Set<String> names = new HashSet<>();
+        names.add("name3");
+        names.add("name4");
+        expect(toCopy.getLocalAttributeNames()).andReturn(names);
+        expect(toCopy.getLocalAttribute("name3")).andReturn(new Attribute("value3"));
+        expect(toCopy.getLocalAttribute("name4")).andReturn(new Attribute("value4"));
+
+        replay(toCopy);
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("newValue1"), true);
+        context.putAttribute("name3", new Attribute("newValue3"), false);
+        context.inherit(toCopy);
+        Attribute attribute = context.getCascadedAttribute("name1");
+        assertEquals("/my/template.jsp", context.getTemplateAttribute().getValue());
+        assertEquals("my.preparer", context.getPreparer());
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "newValue1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "newValue3",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name4");
+        assertNotNull("Attribute name4 not found", attribute);
+        assertEquals("Attribute name4 has not been set correctly", "value4",
+            attribute.getValue());
+        verify(toCopy);
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#inherit(AttributeContext)}
+     * testing inheritance between {@link ListAttribute} instances.
+     */
+    @Test
+    public void testInheritAttributeContextListAttribute() {
+        AttributeContext toCopy = createMock(AttributeContext.class);
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+        expect(toCopy.getTemplateAttribute()).andReturn(templateAttribute).times(2);
+        expect(toCopy.getPreparer()).andReturn("my.preparer").times(2);
+        ListAttribute parentListAttribute = new ListAttribute();
+        Attribute first = new Attribute("first");
+        Attribute second = new Attribute("second");
+        Attribute third = new Attribute("third");
+        Attribute fourth = new Attribute("fourth");
+        parentListAttribute.add(first);
+        ListAttribute parentListAttribute2 = new ListAttribute();
+        parentListAttribute2.add(third);
+        Set<String> names = new HashSet<>();
+        names.add("list");
+        Set<String> cascadedNames = new HashSet<>();
+        cascadedNames.add("list2");
+        expect(toCopy.getCascadedAttributeNames()).andReturn(cascadedNames).times(2);
+        expect(toCopy.getCascadedAttribute("list2")).andReturn(parentListAttribute2).times(2);
+        expect(toCopy.getLocalAttributeNames()).andReturn(names).times(2);
+        expect(toCopy.getLocalAttribute("list")).andReturn(parentListAttribute).times(2);
+
+        replay(toCopy);
+        AttributeContext context = new BasicAttributeContext();
+        ListAttribute listAttribute = new ListAttribute();
+        listAttribute.setInherit(true);
+        listAttribute.add(second);
+        context.putAttribute("list", listAttribute, false);
+        ListAttribute listAttribute2 = new ListAttribute();
+        listAttribute2.setInherit(true);
+        listAttribute2.add(fourth);
+        context.putAttribute("list2", listAttribute2, true);
+        context.inherit(toCopy);
+        ListAttribute result = (ListAttribute) context.getAttribute("list");
+        assertNotNull("The attribute must exist", result);
+        List<Attribute> value = result.getValue();
+        assertNotNull("The list must exist", value);
+        assertEquals("The size is not correct", 2, value.size());
+        assertEquals("The first element is not correct", first, value.get(0));
+        assertEquals("The second element is not correct", second, value
+            .get(1));
+        result = (ListAttribute) context.getAttribute("list2");
+        assertNotNull("The attribute must exist", result);
+        value = result.getValue();
+        assertNotNull("The list must exist", value);
+        assertEquals("The size is not correct", 2, value.size());
+        assertEquals("The first element is not correct", third, value.get(0));
+        assertEquals("The second element is not correct", fourth, value
+            .get(1));
+
+        context = new BasicAttributeContext();
+        listAttribute = new ListAttribute();
+        listAttribute.add(second);
+        context.putAttribute("list", listAttribute);
+        context.inherit(toCopy);
+        result = (ListAttribute) context.getAttribute("list");
+        assertNotNull("The attribute must exist", result);
+        value = result.getValue();
+        assertNotNull("The list must exist", value);
+        assertEquals("The size is not correct", 1, value.size());
+        assertEquals("The second element is not correct", second, value
+            .get(0));
+        verify(toCopy);
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#addAll(Map)}.
+     */
+    @Test
+    public void testAddAll() {
+        AttributeContext context = new BasicAttributeContext();
+        Map<String, Attribute> name2attrib = new HashMap<>();
+        Attribute attribute = new Attribute("Value 1");
+        name2attrib.put("name1", attribute);
+        attribute = new Attribute("Value 2");
+        name2attrib.put("name2", attribute);
+        context.addAll(name2attrib);
+        attribute = context.getAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "Value 1",
+            attribute.getValue());
+        attribute = context.getAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "Value 2",
+            attribute.getValue());
+
+        context.addAll(null);
+        attribute = context.getAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "Value 1",
+            attribute.getValue());
+        attribute = context.getAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "Value 2",
+            attribute.getValue());
+
+        name2attrib = new HashMap<>();
+        name2attrib.put("name3", new Attribute("Value 3"));
+        context.addAll(name2attrib);
+        attribute = context.getAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "Value 1",
+            attribute.getValue());
+        attribute = context.getAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "Value 2",
+            attribute.getValue());
+        attribute = context.getAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "Value 3",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#getAttribute(String)}.
+     */
+    @Test
+    public void testGetAttribute() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        context.putAttribute("name3", new Attribute("value3a"), true);
+        context.putAttribute("name3", new Attribute("value3"), false);
+        Attribute attribute = context.getAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "value3",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#getLocalAttribute(String)}.
+     */
+    @Test
+    public void testGetLocalAttribute() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        context.putAttribute("name3", new Attribute("value3a"), true);
+        context.putAttribute("name3", new Attribute("value3"), false);
+        Attribute attribute = context.getLocalAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name2");
+        assertNull("Attribute name2 found", attribute);
+        attribute = context.getLocalAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "value3",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#getCascadedAttribute(String)}.
+     */
+    @Test
+    public void testGetCascadedAttribute() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        context.putAttribute("name3", new Attribute("value3a"), true);
+        context.putAttribute("name3", new Attribute("value3"), false);
+        Attribute attribute = context.getCascadedAttribute("name1");
+        assertNull("Attribute name1 found", attribute);
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "value3a",
+            attribute.getValue());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#getLocalAttributeNames()}.
+     */
+    @Test
+    public void testGetLocalAttributeNames() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        context.putAttribute("name3", new Attribute("value3a"), true);
+        context.putAttribute("name3", new Attribute("value3"), false);
+        Set<String> names = context.getLocalAttributeNames();
+        assertTrue("Attribute name1 is not present", names.contains("name1"));
+        assertFalse("Attribute name2 is present", names.contains("name2"));
+        assertTrue("Attribute name3 is not present", names.contains("name3"));
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#getCascadedAttributeNames()}.
+     */
+    @Test
+    public void testGetCascadedAttributeNames() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        context.putAttribute("name3", new Attribute("value3a"), true);
+        context.putAttribute("name3", new Attribute("value3"), false);
+        Set<String> names = context.getCascadedAttributeNames();
+        assertFalse("Attribute name1 is present", names.contains("name1"));
+        assertTrue("Attribute name2 is not present", names.contains("name2"));
+        assertTrue("Attribute name3 is not present", names.contains("name3"));
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#putAttribute(String, Attribute)}.
+     */
+    @Test
+    public void testPutAttributeStringAttribute() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"));
+        Attribute attribute = context.getLocalAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name1");
+        assertNull("Attribute name1 found", attribute);
+    }
+
+    /**
+     * Tests
+     * {@link BasicAttributeContext#putAttribute(String, Attribute, boolean)}.
+     */
+    @Test
+    public void testPutAttributeStringAttributeBoolean() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        Attribute attribute = context.getLocalAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "value1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name1");
+        assertNull("Attribute name1 found", attribute);
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name2");
+        assertNull("Attribute name2 found", attribute);
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#clear()}.
+     */
+    @Test
+    public void testClear() {
+        AttributeContext context = new BasicAttributeContext();
+        context.putAttribute("name1", new Attribute("value1"), false);
+        context.putAttribute("name2", new Attribute("value2"), true);
+        context.clear();
+        Set<String> names = context.getLocalAttributeNames();
+        assertTrue("There are local attributes", names == null
+            || names.isEmpty());
+        names = context.getCascadedAttributeNames();
+        assertTrue("There are cascaded attributes", names == null
+            || names.isEmpty());
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#equals(Object)}.
+     */
+    @Test
+    public void testEquals() {
+        BasicAttributeContext attributeContext = new BasicAttributeContext();
+        attributeContext.setPreparer("my.preparer");
+        attributeContext.setTemplateAttribute(Attribute.createTemplateAttribute("/my/template.jsp"));
+        attributeContext.putAttribute("attribute1", new Attribute("value1"), true);
+        attributeContext.putAttribute("attribute2", new Attribute("value2"), true);
+        attributeContext.putAttribute("attribute3", new Attribute("value3"), false);
+        BasicAttributeContext toCompare = new BasicAttributeContext(attributeContext);
+        assertEquals(toCompare, attributeContext);
+        toCompare = new BasicAttributeContext(attributeContext);
+        toCompare.putAttribute("attribute4", new Attribute("value4"), true);
+        assertNotEquals(toCompare, attributeContext);
+        toCompare = new BasicAttributeContext(attributeContext);
+        toCompare.putAttribute("attribute4", new Attribute("value4"), false);
+        assertNotEquals(toCompare, attributeContext);
+        toCompare = new BasicAttributeContext(attributeContext);
+        toCompare.setPreparer("another.preparer");
+        assertNotEquals(toCompare, attributeContext);
+        toCompare = new BasicAttributeContext(attributeContext);
+        toCompare.setTemplateAttribute(Attribute.createTemplateAttribute("/another/template.jsp"));
+        assertNotEquals(toCompare, attributeContext);
+    }
+
+    /**
+     * Tests {@link BasicAttributeContext#hashCode()}.
+     */
+    @Test
+    public void testHashCode() {
+        BasicAttributeContext attributeContext = new BasicAttributeContext();
+        attributeContext.setPreparer("my.preparer");
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+        attributeContext.setTemplateAttribute(templateAttribute);
+        Attribute attribute1 = new Attribute("value1");
+        Attribute attribute2 = new Attribute("value2");
+        Attribute attribute3 = new Attribute("value3");
+        attributeContext.putAttribute("attribute1", attribute1, true);
+        attributeContext.putAttribute("attribute2", attribute2, true);
+        attributeContext.putAttribute("attribute3", attribute3, false);
+        Map<String, Attribute> cascadedAttributes = new HashMap<>();
+        cascadedAttributes.put("attribute1", attribute1);
+        cascadedAttributes.put("attribute2", attribute2);
+        Map<String, Attribute> attributes = new HashMap<>();
+        attributes.put("attribute3", attribute3);
+        assertEquals(templateAttribute.hashCode() + "my.preparer".hashCode()
+                + attributes.hashCode() + cascadedAttributes.hashCode(),
+            attributeContext.hashCode());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java
new file mode 100644
index 000000000..2aa091fdd
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java
@@ -0,0 +1,110 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link Expression}.
+ */
+public class ExpressionTest {
+
+    @Test
+    public void testHashCode() {
+        Expression expression = new Expression("hello", "there");
+        assertEquals("hello".hashCode() + "there".hashCode(), expression.hashCode());
+    }
+
+    @Test
+    public void testExpressionStringString() {
+        Expression expression = new Expression("hello", "there");
+        assertEquals("hello", expression.getExpression());
+        assertEquals("there", expression.getLanguage());
+    }
+
+    @Test
+    public void testExpressionString() {
+        Expression expression = new Expression("hello");
+        assertEquals("hello", expression.getExpression());
+        assertNull(expression.getLanguage());
+    }
+
+    @Test
+    public void testExpressionExpression() {
+        Expression expression = new Expression("hello", "there");
+        Expression expression2 = new Expression(expression);
+        assertEquals("hello", expression2.getExpression());
+        assertEquals("there", expression2.getLanguage());
+    }
+
+    @Test
+    public void testCreateExpressionFromDescribedExpression() {
+        Expression expression = Expression.createExpressionFromDescribedExpression("hello");
+        assertEquals("hello", expression.getExpression());
+        assertNull(expression.getLanguage());
+        expression = Expression.createExpressionFromDescribedExpression("there:hello");
+        assertEquals("hello", expression.getExpression());
+        assertEquals("there", expression.getLanguage());
+        expression = Expression.createExpressionFromDescribedExpression("there_:hello");
+        assertEquals("there_:hello", expression.getExpression());
+        assertNull(expression.getLanguage());
+        assertNull(Expression.createExpressionFromDescribedExpression(null));
+    }
+
+    @Test
+    public void testCreateExpression() {
+        Expression expression = Expression.createExpression("hello", "there");
+        assertEquals("hello", expression.getExpression());
+        assertEquals("there", expression.getLanguage());
+        expression = Expression.createExpression("hello", null);
+        assertEquals("hello", expression.getExpression());
+        assertNull(expression.getLanguage());
+        expression = Expression.createExpression(null, "there");
+        assertNull(expression);
+    }
+
+    @Test
+    public void testEqualsObject() {
+        Expression expression = new Expression("hello", "there");
+        Expression expression2 = new Expression("hello", "there");
+        assertEquals(expression, expression2);
+        expression2 = new Expression("hello", "there2");
+        assertNotEquals(expression, expression2);
+        expression2 = new Expression("hello");
+        assertNotEquals(expression, expression2);
+        expression = new Expression("hello");
+        assertEquals(expression, expression2);
+    }
+
+    @Test
+    public void testToString() {
+        Expression expression = new Expression("hello", "there");
+        assertEquals("there:hello", expression.toString());
+        expression = new Expression("hello");
+        assertEquals("DEFAULT:hello", expression.toString());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
new file mode 100644
index 000000000..1bff6eb93
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
@@ -0,0 +1,111 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ListAttribute}.
+ */
+public class ListAttributeTest {
+
+    @Test
+    public void testHashCode() {
+        ListAttribute attribute = new ListAttribute();
+        List<Attribute> list = new ArrayList<>();
+        list.add(new Attribute("value1"));
+        list.add(new Attribute("value2"));
+        attribute.setValue(list);
+        attribute.setInherit(true);
+        assertEquals(list.hashCode() + Boolean.TRUE.hashCode(), attribute.hashCode());
+    }
+
+    @Test
+    public void testEqualsObject() {
+        ListAttribute attribute = new ListAttribute();
+        List<Attribute> list = new ArrayList<>();
+        list.add(new Attribute("value1"));
+        list.add(new Attribute("value2"));
+        attribute.setValue(list);
+        attribute.setInherit(true);
+        ListAttribute toCheck = new ListAttribute(attribute);
+        assertEquals(attribute, toCheck);
+        toCheck = new ListAttribute(attribute);
+        toCheck.setInherit(false);
+        assertNotEquals(attribute, toCheck);
+        toCheck = new ListAttribute(attribute);
+        toCheck.add(new Attribute("value3"));
+        assertNotEquals(attribute, toCheck);
+    }
+
+    @Test
+    public void testListAttributeListAttribute() {
+        ListAttribute attribute = new ListAttribute();
+        List<Attribute> list = new ArrayList<>();
+        list.add(new Attribute("value1"));
+        list.add(new Attribute("value2"));
+        list.add(null);
+        attribute.setValue(list);
+        attribute.setInherit(true);
+        ListAttribute toCheck = new ListAttribute(attribute);
+        assertEquals(attribute, toCheck);
+    }
+
+    @Test
+    public void testSetValue() {
+        ListAttribute attribute = new ListAttribute();
+        List<Attribute> list = new ArrayList<>();
+        list.add(new Attribute("value1"));
+        list.add(new Attribute("value2"));
+        attribute.setValue(list);
+        assertEquals(list, attribute.getValue());
+    }
+
+    @Test
+    public void testSetInherit() {
+        ListAttribute attribute = new ListAttribute();
+        attribute.setInherit(true);
+        assertTrue(attribute.isInherit());
+        attribute.setInherit(false);
+        assertFalse(attribute.isInherit());
+    }
+
+    @Test
+    public void testClone() {
+        ListAttribute attribute = new ListAttribute();
+        List<Attribute> list = new ArrayList<>();
+        list.add(new Attribute("value1"));
+        list.add(new Attribute("value2"));
+        attribute.setValue(list);
+        attribute.setInherit(true);
+        ListAttribute toCheck = attribute.clone();
+        assertEquals(attribute, toCheck);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
new file mode 100644
index 000000000..777ecd57c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link NoSuchContainerException}.
+ */
+public class NoSuchContainerExceptionTest {
+
+    @Test
+    public void testNoSuchContainerExceptionString() {
+        NoSuchContainerException exception = new NoSuchContainerException("my message");
+        assertEquals("my message", exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java b/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java
new file mode 100644
index 000000000..2da936a3b
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java
@@ -0,0 +1,250 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests the Definition class.
+ */
+public class TestDefinition {
+
+    /**
+     * Tests {@link Definition#Definition(Definition)}.
+     */
+    @Test
+    public void testDefinitionCopy() {
+        Definition definition = new Definition();
+        definition.setName("myDefinition");
+        definition.setExtends("myExtends");
+        Attribute attribute1 = new Attribute("value1");
+        definition.putAttribute("name1", attribute1);
+        Attribute attribute2 = new Attribute("value2");
+        definition.putAttribute("name2", attribute2);
+        Definition toCheck = new Definition(definition);
+        assertEquals("myDefinition", toCheck.getName());
+        assertEquals("myExtends", toCheck.getExtends());
+        assertEquals(attribute1, toCheck.getAttribute("name1"));
+        assertEquals(attribute2, toCheck.getAttribute("name2"));
+    }
+
+    /**
+     * Tests {@link Definition#Definition(Definition)}.
+     */
+    @Test
+    public void testDefinitionComplete() {
+        Map<String, Attribute> attributeMap = new HashMap<>();
+        Attribute attribute1 = new Attribute("value1");
+        Attribute attribute2 = new Attribute("value2");
+        attributeMap.put("name1", attribute1);
+        attributeMap.put("name2", attribute2);
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+        Definition definition = new Definition("myDefinition",
+            templateAttribute, attributeMap);
+        assertEquals("myDefinition", definition.getName());
+        assertEquals(templateAttribute, definition.getTemplateAttribute());
+        assertEquals(attribute1, definition.getAttribute("name1"));
+        assertEquals(attribute2, definition.getAttribute("name2"));
+    }
+
+    /**
+     * Verifies the put Attribute functionality. Attributes are added or replaced in the definition.
+     */
+    @Test
+    public void testPutAttribute() {
+        Definition def = new Definition();
+        def.setName("test1");
+        def.setTemplateAttribute(Attribute
+            .createTemplateAttribute("/page1.jsp"));
+        Attribute attr1 = new Attribute("test.definition.name", null, null, "definition");
+        def.putAttribute("attr1", attr1);
+
+        attr1 = def.getAttribute("attr1");
+        assertNotNull("Null attribute.", attr1);
+        assertEquals("Wrong attribute type", "definition", attr1.getRenderer());
+    }
+
+    /**
+     * Tests the {@link Definition#inherit(BasicAttributeContext)} method.
+     */
+    @Test
+    public void testInherit() {
+        Definition toCopy = new Definition();
+        toCopy.putAttribute("name1", new Attribute("value1"), true);
+        toCopy.putAttribute("name2", new Attribute("value2"), true);
+        toCopy.putAttribute("name3", new Attribute("value3"), false);
+        toCopy.putAttribute("name4", new Attribute("value4"), false);
+        Definition context = new Definition();
+        toCopy.putAttribute("name1", new Attribute("newValue1"), true);
+        toCopy.putAttribute("name3", new Attribute("newValue3"), false);
+        context.inherit(toCopy);
+        Attribute attribute = context.getCascadedAttribute("name1");
+        assertNotNull("Attribute name1 not found", attribute);
+        assertEquals("Attribute name1 has not been set correctly", "newValue1",
+            attribute.getValue());
+        attribute = context.getCascadedAttribute("name2");
+        assertNotNull("Attribute name2 not found", attribute);
+        assertEquals("Attribute name2 has not been set correctly", "value2",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name3");
+        assertNotNull("Attribute name3 not found", attribute);
+        assertEquals("Attribute name3 has not been set correctly", "newValue3",
+            attribute.getValue());
+        attribute = context.getLocalAttribute("name4");
+        assertNotNull("Attribute name4 not found", attribute);
+        assertEquals("Attribute name4 has not been set correctly", "value4",
+            attribute.getValue());
+
+        toCopy = new Definition();
+        toCopy.setPreparer("ExtendedPreparer");
+        Attribute templateAttribute = new Attribute("extendedTemplate.jsp",
+            Expression.createExpression("expression", "language"),
+            "extendedRole", "template");
+        toCopy.setTemplateAttribute(templateAttribute);
+        context = new Definition();
+        context.inherit(toCopy);
+        assertEquals("Preparer not inherited", "ExtendedPreparer", context
+            .getPreparer());
+        assertNotNull("Roles not inherited", context.getTemplateAttribute()
+            .getRoles());
+        assertEquals("Roles not inherited", context.getTemplateAttribute()
+            .getRoles().size(), 1);
+        assertTrue("Roles not inherited", context.getTemplateAttribute()
+            .getRoles().contains(
+                "extendedRole"));
+        assertEquals("Template not inherited", "extendedTemplate.jsp", context
+            .getTemplateAttribute().getValue());
+        assertEquals("Template expression not inherited", "expression", context
+            .getTemplateAttribute().getExpressionObject().getExpression());
+        assertEquals("Template expression language not inherited", "language",
+            context.getTemplateAttribute().getExpressionObject()
+                .getLanguage());
+        context = new Definition();
+        context.setPreparer("LocalPreparer");
+        templateAttribute = new Attribute("localTemplate.jsp", Expression
+            .createExpression("localExpression", "localLanguage"),
+            "localRole", "template");
+        context.setTemplateAttribute(templateAttribute);
+        assertEquals("Preparer inherited", "LocalPreparer", context
+            .getPreparer());
+        assertNotNull("Roles not correct", context.getTemplateAttribute()
+            .getRoles());
+        assertEquals("Roles not correct", context.getTemplateAttribute()
+            .getRoles().size(), 1);
+        assertTrue("Roles inherited", context.getTemplateAttribute().getRoles()
+            .contains("localRole"));
+        assertEquals("Template inherited", "localTemplate.jsp", context
+            .getTemplateAttribute().getValue());
+        assertEquals("Template expression inherited", "localExpression",
+            context.getTemplateAttribute().getExpressionObject()
+                .getExpression());
+        assertEquals("Template expression language not inherited",
+            "localLanguage", context.getTemplateAttribute()
+                .getExpressionObject().getLanguage());
+    }
+
+    /**
+     * Tests {@link Definition#toString()}.
+     */
+    @Test
+    public void testToString() {
+        Definition definition = new Definition();
+        definition.setName("myDefinitionName");
+        assertEquals(
+            "{name=myDefinitionName, template=<null>, role=<null>, preparerInstance=null, attributes=null}",
+            definition.toString());
+        definition.setTemplateAttribute(Attribute.createTemplateAttribute("myTemplate"));
+        assertEquals(
+            "{name=myDefinitionName, template=myTemplate, role=null, preparerInstance=null, attributes=null}",
+            definition.toString());
+        definition.putAttribute("myAttributeName", new Attribute("myAttributeValue"));
+        assertEquals(
+            "{name=myDefinitionName, template=myTemplate, role=null, preparerInstance=null, "
+                + "attributes={myAttributeName=myAttributeValue}}",
+            definition.toString());
+    }
+
+    /**
+     * Tests {@link Definition#equals(Object)}.
+     */
+    @Test
+    public void testEquals() {
+        Definition definition = new Definition();
+        definition.setName("myDefinition");
+        definition.setExtends("myExtends");
+        Attribute attribute1 = new Attribute("value1");
+        definition.putAttribute("name1", attribute1);
+        Attribute attribute2 = new Attribute("value2");
+        definition.putAttribute("name2", attribute2);
+        Definition toCheck = new Definition(definition);
+        assertEquals(definition, toCheck);
+        toCheck = new Definition(definition);
+        toCheck.setName("anotherDefinition");
+        assertNotEquals(definition, toCheck);
+        toCheck = new Definition(definition);
+        toCheck.setExtends("anotherExtends");
+        assertNotEquals(definition, toCheck);
+        toCheck = new Definition(definition);
+        toCheck.putAttribute("name1", new Attribute("anotherAttribute"));
+        assertNotEquals(definition, toCheck);
+    }
+
+    /**
+     * Tests {@link Definition#hashCode()}.
+     */
+    @Test
+    public void testHashCode() {
+        Definition definition = new Definition();
+        definition.setName("myDefinition");
+        definition.setExtends("myExtends");
+        Attribute attribute1 = new Attribute("value1");
+        definition.putAttribute("name1", attribute1);
+        Attribute attribute2 = new Attribute("value2");
+        definition.putAttribute("name2", attribute2);
+        BasicAttributeContext attributeContext = new BasicAttributeContext();
+        attributeContext.putAttribute("name1", attribute1);
+        attributeContext.putAttribute("name2", attribute2);
+        assertEquals("myDefinition".hashCode() + "myExtends".hashCode()
+            + attributeContext.hashCode(), definition.hashCode());
+    }
+
+    /**
+     * Tests {@link Definition#isExtending()}.
+     */
+    @Test
+    public void testIsExtending() {
+        Definition definition = new Definition();
+        definition.setName("myDefinition");
+        assertFalse(definition.isExtending());
+        definition.setExtends("myExtends");
+        assertTrue(definition.isExtending());
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java
new file mode 100644
index 000000000..c7a6f49c0
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java
@@ -0,0 +1,234 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link TilesContainerWrapper}.
+ */
+public class TilesContainerWrapperTest {
+
+    /**
+     * The container.
+     */
+    private TilesContainer container;
+
+    /**
+     * The wrapper to test.
+     */
+    private TilesContainerWrapper wrapper;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        container = createMock(TilesContainer.class);
+        wrapper = new TilesContainerWrapper(container);
+    }
+
+    /**
+     * Tests {@link TilesContainerWrapper#TilesContainerWrapper(TilesContainer)}.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testTilesContainerWrapperNPE() {
+        new TilesContainerWrapper(null);
+    }
+
+    @Test
+    public void testEndContext() {
+        Request request = createMock(Request.class);
+
+        container.endContext(request);
+
+        replay(container, request);
+        wrapper.endContext(request);
+        verify(container, request);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#evaluate(Attribute, Request)}.
+     */
+    @Test
+    public void testEvaluate() {
+        Request request = createMock(Request.class);
+        Attribute attribute = createMock(Attribute.class);
+
+        expect(container.evaluate(attribute, request)).andReturn(1);
+
+        replay(container, request, attribute);
+        assertEquals(new Integer(1), wrapper.evaluate(attribute, request));
+        verify(container, request, attribute);
+    }
+
+    @Test
+    public void testGetApplicationContext() {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        expect(container.getApplicationContext()).andReturn(applicationContext);
+
+        replay(container, applicationContext);
+        assertSame(applicationContext, wrapper.getApplicationContext());
+        verify(container, applicationContext);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#getAttributeContext(Request)}.
+     */
+    @Test
+    public void testGetAttributeContext() {
+        Request request = createMock(Request.class);
+        AttributeContext attribute = createMock(AttributeContext.class);
+
+        expect(container.getAttributeContext(request)).andReturn(attribute);
+
+        replay(container, request, attribute);
+        assertSame(attribute, wrapper.getAttributeContext(request));
+        verify(container, request, attribute);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#getDefinition(String, Request)}.
+     */
+    @Test
+    public void testGetDefinition() {
+        Request request = createMock(Request.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(container.getDefinition("definition", request)).andReturn(definition);
+
+        replay(container, request, definition);
+        assertSame(definition, wrapper.getDefinition("definition", request));
+        verify(container, request, definition);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#isValidDefinition(String, Request)}.
+     */
+    @Test
+    public void testIsValidDefinition() {
+        Request request = createMock(Request.class);
+
+        expect(container.isValidDefinition("definition", request)).andReturn(true);
+
+        replay(container, request);
+        assertTrue(wrapper.isValidDefinition("definition", request));
+        verify(container, request);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#prepare(String, Request)}.
+     */
+    @Test
+    public void testPrepare() {
+        Request request = createMock(Request.class);
+
+        container.prepare("preparer", request);
+
+        replay(container, request);
+        wrapper.prepare("preparer", request);
+        verify(container, request);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#render(String, Request)}.
+     */
+    @Test
+    public void testRenderStringRequest() {
+        Request request = createMock(Request.class);
+
+        container.render("definition", request);
+
+        replay(container, request);
+        wrapper.render("definition", request);
+        verify(container, request);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#render(Definition, Request)}.
+     */
+    @Test
+    public void testRenderDefinitionRequest() {
+        Request request = createMock(Request.class);
+        Definition definition = createMock(Definition.class);
+
+        container.render(definition, request);
+
+        replay(container, request, definition);
+        wrapper.render(definition, request);
+        verify(container, request, definition);
+    }
+
+    /**
+     * Test method for {@link TilesContainerWrapper#render(Attribute, Request)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testRenderAttributeRequest() throws IOException {
+        Request request = createMock(Request.class);
+        Attribute attribute = createMock(Attribute.class);
+
+        container.render(attribute, request);
+
+        replay(container, request, attribute);
+        wrapper.render(attribute, request);
+        verify(container, request, attribute);
+    }
+
+    @Test
+    public void testRenderContext() {
+        Request request = createMock(Request.class);
+
+        container.renderContext(request);
+
+        replay(container, request);
+        wrapper.renderContext(request);
+        verify(container, request);
+    }
+
+    @Test
+    public void testStartContext() {
+        Request request = createMock(Request.class);
+        AttributeContext attribute = createMock(AttributeContext.class);
+
+        expect(container.startContext(request)).andReturn(attribute);
+
+        replay(container, request, attribute);
+        assertSame(attribute, wrapper.startContext(request));
+        verify(container, request, attribute);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
new file mode 100644
index 000000000..fc26afeb0
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link TilesException}.
+ */
+public class TilesExceptionTest {
+
+    @Test
+    public void testTilesException() {
+        TilesException exception = new TilesException();
+        assertNull(exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+    @Test
+    public void testTilesExceptionString() {
+        TilesException exception = new TilesException("my message");
+        assertEquals("my message", exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+    @Test
+    public void testTilesExceptionThrowable() {
+        Throwable cause = new Throwable();
+        TilesException exception = new TilesException(cause);
+        assertEquals(cause.toString(), exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+    @Test
+    public void testTilesExceptionStringThrowable() {
+        Throwable cause = new Throwable();
+        TilesException exception = new TilesException("my message", cause);
+        assertEquals("my message", exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/access/TilesAccessTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/access/TilesAccessTest.java
new file mode 100644
index 000000000..93726132b
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/access/TilesAccessTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.api.access;
+
+import org.apache.tiles.api.NoSuchContainerException;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link TilesAccess}.
+ */
+public class TilesAccessTest {
+
+    @Test
+    public void testSetContainer() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        expect(context.getApplicationScope()).andReturn(attribs);
+        replay(context, container);
+        TilesAccess.setContainer(context, container, null);
+        assertEquals(attribs.size(), 1);
+        assertEquals(attribs.get(TilesAccess.CONTAINER_ATTRIBUTE), container);
+        verify(context, container);
+    }
+
+    @Test
+    public void testSetContainerWithKey() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        replay(context, container);
+        TilesAccess.setContainer(context, container, "myKey");
+        assertEquals(1, attribs.size());
+        assertEquals(container, attribs.get("myKey"));
+
+        TilesAccess.setContainer(context, null, "myKey");
+        assertEquals(0, attribs.size());
+
+        TilesAccess.setContainer(context, container, null);
+        assertEquals(1, attribs.size());
+        assertEquals(container, attribs.get(TilesAccess.CONTAINER_ATTRIBUTE));
+        verify(context, container);
+    }
+
+    @Test
+    public void testGetContainer() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+
+        replay(context, container);
+        attribs.put(TilesAccess.CONTAINER_ATTRIBUTE, container);
+        assertEquals(container, TilesAccess.getContainer(context));
+        verify(context, container);
+    }
+
+    @Test
+    public void testGetContainerWithKey() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+
+        replay(context, container);
+        attribs.put(TilesAccess.CONTAINER_ATTRIBUTE, container);
+        attribs.put("myKey", container);
+        assertEquals(container, TilesAccess.getContainer(context, null));
+        assertEquals(container, TilesAccess.getContainer(context, "myKey"));
+        verify(context, container);
+    }
+
+    @Test
+    public void testSetCurrentContainer() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        attribs.put("myKey", container);
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(request.getApplicationContext()).andReturn(context);
+        replay(request, context, container);
+        TilesAccess.setCurrentContainer(request, "myKey");
+        assertEquals(container, requestScope.get(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME));
+        verify(request, context, container);
+    }
+
+    @Test(expected = NoSuchContainerException.class)
+    public void testSetCurrentContainerException() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        Map<String, Object> attribs = new HashMap<>();
+
+        expect(request.getApplicationContext()).andReturn(context);
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        replay(request, context);
+        try {
+            TilesAccess.setCurrentContainer(request, "myKey");
+        } finally {
+            verify(request, context);
+        }
+    }
+
+    @Test
+    public void testSetCurrentContainerWithContainer() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        attribs.put("myKey", container);
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request, context, container);
+        TilesAccess.setCurrentContainer(request, container);
+        assertEquals(container, requestScope.get(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME));
+        verify(request, context, container);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testSetCurrentContainerWithContainerException() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        Map<String, Object> attribs = new HashMap<>();
+
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+
+        replay(request, context);
+        try {
+            TilesAccess.setCurrentContainer(request, (TilesContainer) null);
+        } finally {
+            verify(request, context);
+        }
+    }
+
+    @Test
+    public void testGetCurrentContainer() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        attribs.put("myKey", container);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(context);
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request, context, container);
+        assertEquals(container, TilesAccess.getCurrentContainer(request));
+        verify(request, context, container);
+    }
+
+    @Test
+    public void testGetCurrentContainerDefault() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        attribs.put(TilesAccess.CONTAINER_ATTRIBUTE, container);
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(request.getApplicationContext()).andReturn(context);
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request, context, container);
+        assertEquals(container, TilesAccess.getCurrentContainer(request));
+        verify(request, context, container);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
new file mode 100644
index 000000000..61700f0b2
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api.preparer;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link PreparerException}.
+ */
+public class PreparerExceptionTest {
+
+    /**
+     * Test method for {@link PreparerException#PreparerException()}.
+     */
+    @Test
+    public void testPreparerException() {
+        PreparerException exception = new PreparerException();
+        assertNull(exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+    /**
+     * Test method for {@link PreparerException#PreparerException(String)}.
+     */
+    @Test
+    public void testPreparerExceptionString() {
+        PreparerException exception = new PreparerException("my message");
+        assertEquals("my message", exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+    /**
+     * Test method for {@link PreparerException#PreparerException(Throwable)}.
+     */
+    @Test
+    public void testPreparerExceptionThrowable() {
+        Throwable cause = new Throwable();
+        PreparerException exception = new PreparerException(cause);
+        assertEquals(cause.toString(), exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+    /**
+     * Test method for {@link PreparerException#PreparerException(String, Throwable)}.
+     */
+    @Test
+    public void testPreparerExceptionStringThrowable() {
+        Throwable cause = new Throwable();
+        PreparerException exception = new PreparerException("my message", cause);
+        assertEquals("my message", exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+}


[struts] 09/23: WW-5233 Upgrades Easymock to version 4.3 to support Java 17

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 48c522fa126de00afe858736a7a9f849c36f214e
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 13:53:54 2022 +0200

    WW-5233 Upgrades Easymock to version 4.3 to support Java 17
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 14a01e163..c22bda292 100644
--- a/pom.xml
+++ b/pom.xml
@@ -773,7 +773,7 @@
             <dependency>
                 <groupId>org.easymock</groupId>
                 <artifactId>easymock</artifactId>
-                <version>4.2</version>
+                <version>4.3</version>
                 <scope>test</scope>
             </dependency>
 


[struts] 21/23: Make plugin standalone with all generated resources for velocity.

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 0568c2d3e98b582dbfe7b686c994fae04cb672d1
Author: Greg Huber <gh...@apache.org>
AuthorDate: Tue Oct 18 14:35:55 2022 +0100

    Make plugin standalone with all generated resources for velocity.
---
 plugins/tiles/pom.xml                              |   6 +
 .../org/apache/struts2/tiles/BuildAutotags.java    |  60 +++++-
 .../velocity/VelocityDirectiveGenerator.java       |  67 ++++++
 .../velocity/VelocityPropertiesGenerator.java      |  64 ++++++
 .../velocity/VelocityTemplateGeneratorFactory.java |  87 ++++++++
 .../tiles/autotag/velocity/package-info.java       |  24 +++
 .../servlet/ExternalWriterHttpServletResponse.java |  58 ++++++
 .../tiles/request/velocity/VelocityRequest.java    | 169 ++++++++++++++++
 .../tiles/request/velocity/VelocityScopeMap.java   |  87 ++++++++
 .../velocity/autotag/VelocityAutotagRuntime.java   | 102 ++++++++++
 .../velocity/autotag/VelocityModelBody.java        |  61 ++++++
 .../request/velocity/autotag/VelocityUtil.java     |  67 ++++++
 .../request/velocity/autotag/package-info.java     |  22 ++
 .../velocity/extractor/VelocityScopeExtractor.java |  99 +++++++++
 .../request/velocity/extractor/package-info.java   |  22 ++
 .../tiles/request/velocity/package-info.java       |  22 ++
 .../render/ApplicationContextJeeConfig.java        |  77 +++++++
 .../request/velocity/render/VelocityRenderer.java  |  75 +++++++
 .../velocity/render/VelocityRendererBuilder.java   |  91 +++++++++
 .../request/velocity/render/package-info.java      |  22 ++
 .../tiles/velocity/TilesVelocityException.java     |  71 +++++++
 .../org/apache/tiles/velocity/package-info.java    |  22 ++
 .../AbstractDefaultToStringRenderable.java         | 119 +++++++++++
 .../velocity/template/AddAttributeDirective.java   |  78 +++++++
 .../template/AddListAttributeDirective.java        |  73 +++++++
 .../tiles/velocity/template/ContextHolder.java     | 154 ++++++++++++++
 .../velocity/template/DefinitionDirective.java     |  76 +++++++
 .../velocity/template/GetAsStringDirective.java    |  81 ++++++++
 .../template/ImportAttributeDirective.java         |  74 +++++++
 .../template/InsertAttributeDirective.java         |  94 +++++++++
 .../template/InsertDefinitionDirective.java        |  99 +++++++++
 .../velocity/template/InsertTemplateDirective.java |  98 +++++++++
 .../velocity/template/PutAttributeDirective.java   | 101 ++++++++++
 .../template/PutListAttributeDirective.java        |  76 +++++++
 .../template/SetCurrentContainerDirective.java     |  64 ++++++
 .../velocity/template/VelocityStyleTilesTool.java  | 224 +++++++++++++++++++++
 .../tiles/velocity/template/package-info.java      |  22 ++
 .../main/resources/META-INF/velocity.properties    |  30 +++
 .../org/apache/tiles/autotag/velocity.properties   |  13 --
 .../tiles/autotag/velocity/velocityDirective.vm    |  76 +++++++
 .../tiles/autotag/velocity/velocityProperties.vm   |  21 ++
 plugins/tiles/src/main/resources/tools.xml         |  24 +++
 .../velocity/VelocityDirectiveGeneratorTest.java   | 139 +++++++++++++
 .../velocity/VelocityPropertiesGeneratorTest.java  | 125 ++++++++++++
 .../VelocityTemplateGeneratorFactoryTest.java      |  60 ++++++
 .../autotag/velocity/test/DoStuffDirective.javat   |  70 +++++++
 .../velocity/test/DoStuffNoBodyDirective.javat     |  68 +++++++
 .../src/test/resources/velocity.properties.test    |  21 ++
 48 files changed, 3441 insertions(+), 14 deletions(-)

diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 627f3c317..55759a642 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -94,6 +94,12 @@
             <groupId>org.apache.velocity</groupId>
             <artifactId>velocity-engine-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-tools</artifactId>
+            <version>2.0</version>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>com.thoughtworks.xstream</groupId>
             <artifactId>xstream</artifactId>
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
index de2eaee1e..c29ea67ef 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
@@ -29,6 +29,7 @@ import org.apache.tiles.autotag.generate.TemplateGenerator;
 import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
 import org.apache.tiles.autotag.jsp.JspTemplateGeneratorFactory;
 import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.tiles.autotag.velocity.VelocityTemplateGeneratorFactory;
 import org.apache.velocity.app.VelocityEngine;
 
 import com.thoughtworks.xstream.XStream;
@@ -58,6 +59,9 @@ public class BuildAutotags {
         // Freemarker classes
         me.buildFreemarker(args[0]);
 
+        // Freemarker classes
+        me.buildVelocity(args[0]);
+
     }
 
     /**
@@ -118,7 +122,7 @@ public class BuildAutotags {
     }
 
     /**
-     * Builds the freemarker.
+     * Builds the Freemarker classes.
      * 
      * To build, change template-suite.xml as required and then run this program.
      * Copy the classes from the target autotag folder into the packageName
@@ -168,4 +172,58 @@ public class BuildAutotags {
 
     }
 
+    /**
+     * Builds the velocity classes.
+     * 
+     * To build, change template-suite.xml as required and then run this program.
+     * Copy the classes from the target autotag folder into the packageName
+     * location, and velocity.properties to
+     * src/main/resources/META-INF/velocity.properties
+     *
+     * @param outputDir the output dir
+     */
+    public void buildVelocity(String outputDir) {
+
+        // Default values
+        String packageName = "org.apache.tiles.velocity.template";
+        String requestClass = "org.apache.tiles.request.Request";
+        String runtime = "org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime";
+        // outputDir = "/target"
+
+        try {
+
+            TemplateSuite suite;
+
+            InputStream stream = getClass().getResourceAsStream("/META-INF/template-suite.xml");
+
+            try {
+                XStream xstream = new XStream(new DomDriver());
+                xstream.allowTypes(new Class[] { org.apache.tiles.autotag.model.TemplateClass.class,
+                        org.apache.tiles.autotag.model.TemplateSuite.class,
+                        org.apache.tiles.autotag.model.TemplateParameter.class });
+                suite = (TemplateSuite) xstream.fromXML(stream);
+            } finally {
+                stream.close();
+            }
+
+            Properties props = new Properties();
+            InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+            props.load(propsStream);
+            propsStream.close();
+
+            File classesOutputDirectory = new File(outputDir + "/generated-sources/autotag/classes");
+            File resourcesOutputDirectory = new File(outputDir + "/generated-sources/autotag");
+
+            TemplateGenerator generator = new VelocityTemplateGeneratorFactory(classesOutputDirectory,
+                    resourcesOutputDirectory, new VelocityEngine(props), TemplateGeneratorBuilder.createNewInstance())
+                    .createTemplateGenerator();
+
+            generator.generate(packageName, suite, null, runtime, requestClass);
+
+        } catch (Exception e) {
+            // ignored
+        }
+
+    }
+
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityDirectiveGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityDirectiveGenerator.java
new file mode 100644
index 000000000..b59b70843
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityDirectiveGenerator.java
@@ -0,0 +1,67 @@
+/*
+ * $Id: VelocityDirectiveGenerator.java 1349964 2012-06-13 17:18:51Z nlebas $
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.velocity;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.generate.AbstractTemplateClassGenerator;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Generates a Velocity directive using a template class.
+ *
+ * @version $Rev: 1349964 $ $Date: 2012-06-13 13:18:51 -0400 (Wed, 13 Jun 2012) $
+ */
+public class VelocityDirectiveGenerator extends AbstractTemplateClassGenerator {
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public VelocityDirectiveGenerator(VelocityEngine velocityEngine) {
+        super(velocityEngine);
+    }
+
+    @Override
+    protected String getDirectoryName(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return packageName.replaceAll("\\.", "/");
+    }
+
+    @Override
+    protected String getFilename(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return clazz.getTagClassPrefix() + "Directive.java";
+    }
+
+    @Override
+    protected String getTemplatePath(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return "/org/apache/tiles/autotag/velocity/velocityDirective.vm";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityPropertiesGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityPropertiesGenerator.java
new file mode 100644
index 000000000..bf340c41f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityPropertiesGenerator.java
@@ -0,0 +1,64 @@
+/*
+ * $Id: VelocityPropertiesGenerator.java 1045345 2010-12-13 19:58:23Z apetrelli $
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.velocity;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.generate.AbstractTemplateSuiteGenerator;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Generates a Velocity properties containing the list of generated user directives for future use.
+ *
+ * @version $Rev: 1045345 $ $Date: 2010-12-13 14:58:23 -0500 (Mon, 13 Dec 2010) $
+ */
+public class VelocityPropertiesGenerator extends AbstractTemplateSuiteGenerator {
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public VelocityPropertiesGenerator(VelocityEngine velocityEngine) {
+        super(velocityEngine);
+    }
+
+    @Override
+    protected String getTemplatePath(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return "/org/apache/tiles/autotag/velocity/velocityProperties.vm";
+    }
+
+    @Override
+    protected String getFilename(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return "velocity.properties";
+    }
+
+    @Override
+    protected String getDirectoryName(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return "META-INF/";
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityTemplateGeneratorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityTemplateGeneratorFactory.java
new file mode 100644
index 000000000..6ed64cf47
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/VelocityTemplateGeneratorFactory.java
@@ -0,0 +1,87 @@
+/*
+ * $Id: VelocityTemplateGeneratorFactory.java 1045345 2010-12-13 19:58:23Z apetrelli $
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.velocity;
+
+import java.io.File;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.tiles.autotag.generate.TemplateGeneratorFactory;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Creates a template generator that generates code to build Velocity code
+ * around template classes.
+ *
+ * @version $Rev: 1045345 $ $Date: 2010-12-13 14:58:23 -0500 (Mon, 13 Dec 2010) $
+ */
+public class VelocityTemplateGeneratorFactory implements
+        TemplateGeneratorFactory {
+
+    /**
+     * Location of the file.
+     */
+    private File classesOutputDirectory;
+
+    /**
+     * Location of the file.
+     */
+    private File resourcesOutputDirectory;
+
+    /**
+     * The Velocity engine.
+     */
+    private VelocityEngine velocityEngine;
+
+    /**
+     * The template generator builder.
+     */
+    private TemplateGeneratorBuilder templateGeneratorBuilder;
+
+    /**
+     * Constructor.
+     *
+     * @param classesOutputDirectory The directory where classes will be generated.
+     * @param resourcesOutputDirectory The directory where velocity.properties will be written.
+     * @param velocityEngine The Velocity engine.
+     * @param templateGeneratorBuilder The template generator builder.
+     */
+    public VelocityTemplateGeneratorFactory(File classesOutputDirectory,
+            File resourcesOutputDirectory, VelocityEngine velocityEngine,
+            TemplateGeneratorBuilder templateGeneratorBuilder) {
+        this.classesOutputDirectory = classesOutputDirectory;
+        this.resourcesOutputDirectory = resourcesOutputDirectory;
+        this.velocityEngine = velocityEngine;
+        this.templateGeneratorBuilder = templateGeneratorBuilder;
+    }
+
+    @Override
+    public TemplateGenerator createTemplateGenerator() {
+        return templateGeneratorBuilder
+                .setClassesOutputDirectory(classesOutputDirectory)
+                .setResourcesOutputDirectory(resourcesOutputDirectory)
+                .addResourcesTemplateSuiteGenerator(
+                        new VelocityPropertiesGenerator(velocityEngine))
+                .addClassesTemplateClassGenerator(
+                        new VelocityDirectiveGenerator(velocityEngine)).build();
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/package-info.java
new file mode 100644
index 000000000..15e00360f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/velocity/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * $Id: package-info.java 1045345 2010-12-13 19:58:23Z apetrelli $
+ *
+ * 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.
+ */
+/**
+ * Autotag support for Velocity.
+ */
+package org.apache.tiles.autotag.velocity;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ExternalWriterHttpServletResponse.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ExternalWriterHttpServletResponse.java
new file mode 100644
index 000000000..492530e7e
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ExternalWriterHttpServletResponse.java
@@ -0,0 +1,58 @@
+/*
+ * $Id: ExternalWriterHttpServletResponse.java 1306435 2012-03-28 15:39:11Z nlebas $
+ *
+ * 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.
+ */
+
+package org.apache.tiles.request.servlet;
+
+import java.io.PrintWriter;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Wraps an HTTP response and overrides its print writer.
+ *
+ * @version $Rev: 1306435 $ $Date: 2012-03-29 02:39:11 +1100 (Thu, 29 Mar 2012) $
+ */
+public class ExternalWriterHttpServletResponse extends
+        HttpServletResponseWrapper {
+
+    /**
+     * The print writer to use, instead of the response's one.
+     */
+    private PrintWriter writer;
+
+    /**
+     * Constructor.
+     *
+     * @param response The response to wrap.
+     * @param writer The print writer to use, instead of the response's one.
+     */
+    public ExternalWriterHttpServletResponse(HttpServletResponse response, PrintWriter writer) {
+        super(response);
+        this.writer = writer;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public PrintWriter getWriter() {
+        return writer;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/VelocityRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/VelocityRequest.java
new file mode 100644
index 000000000..328d67c9e
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/VelocityRequest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.request.velocity;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tiles.request.AbstractViewRequest;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.DispatchRequest;
+import org.apache.tiles.request.servlet.ExternalWriterHttpServletResponse;
+import org.apache.tiles.request.servlet.ServletRequest;
+import org.apache.tiles.request.servlet.ServletUtil;
+import org.apache.velocity.context.Context;
+
+/**
+ * The implementation of the Tiles request context specific for Velocity.
+ */
+public class VelocityRequest extends AbstractViewRequest {
+
+    /**
+     * The native available scopes, in fact only "page".
+     */
+    private final List<String> scopes;
+
+    /**
+     * The Velocity current context.
+     */
+    private final Context ctx;
+
+    /**
+     * The writer to use to render the response. It may be null, if not necessary.
+     */
+    private Writer writer;
+
+    /**
+     * The map of the page scope.
+     */
+    private Map<String, Object> pageScope;
+
+    /**
+     * Factory method to create a Velocity request.
+     *
+     * @param applicationContext The application context.
+     * @param request            The request.
+     * @param response           The response.
+     * @param velocityContext    The Velocity context.
+     * @param writer             The writer to write into.
+     * @return The request.
+     */
+    public static VelocityRequest createVelocityRequest(ApplicationContext applicationContext,
+            HttpServletRequest request, HttpServletResponse response, Context velocityContext, Writer writer) {
+        DispatchRequest servletRequest = new ServletRequest(applicationContext, request, response);
+        VelocityRequest velocityRequest = new VelocityRequest(servletRequest, velocityContext, writer);
+        return velocityRequest;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param enclosedRequest The request that exposes non-Velocity specific
+     *                        properties
+     * @param ctx             The Velocity current context.
+     * @param writer          The writer to use to render the response. It may be
+     *                        null, if not necessary.
+     */
+    public VelocityRequest(DispatchRequest enclosedRequest, Context ctx, Writer writer) {
+        super(enclosedRequest);
+        List<String> scopes = new ArrayList<String>();
+        scopes.addAll(enclosedRequest.getAvailableScopes());
+        scopes.add("page");
+        this.scopes = Collections.unmodifiableList(scopes);
+        this.ctx = ctx;
+        this.writer = writer;
+    }
+
+    @Override
+    public List<String> getAvailableScopes() {
+        return scopes;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInclude(String path) throws IOException {
+        ServletRequest servletRequest = org.apache.tiles.request.servlet.ServletUtil.getServletRequest(this);
+        HttpServletRequest request = servletRequest.getRequest();
+        HttpServletResponse response = servletRequest.getResponse();
+        RequestDispatcher rd = request.getRequestDispatcher(path);
+
+        if (rd == null) {
+            throw new IOException("No request dispatcher returned for path '" + path + "'");
+        }
+
+        PrintWriter printWriter = getPrintWriter();
+        try {
+            rd.include(request, new ExternalWriterHttpServletResponse(response, printWriter));
+        } catch (ServletException ex) {
+            throw ServletUtil.wrapServletException(ex, "ServletException including path '" + path + "'.");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public PrintWriter getPrintWriter() {
+        if (writer == null) {
+            throw new IllegalStateException(
+                    "A writer-less Tiles request has been created, cannot return a PrintWriter");
+        }
+        if (writer instanceof PrintWriter) {
+            return (PrintWriter) writer;
+        }
+        return new PrintWriter(writer);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Writer getWriter() {
+        if (writer == null) {
+            throw new IllegalStateException(
+                    "A writer-less Tiles request has been created, cannot return a PrintWriter");
+        }
+        return writer;
+    }
+
+    /**
+     * Returns the page scope.
+     *
+     * @return The page scope.
+     */
+    public Map<String, Object> getPageScope() {
+        if (pageScope == null) {
+            pageScope = new VelocityScopeMap(ctx);
+        }
+        return pageScope;
+    }
+
+    @Override
+    public Map<String, Object> getContext(String scope) {
+        return "page".equals(scope) ? getPageScope() : super.getContext(scope);
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/VelocityScopeMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/VelocityScopeMap.java
new file mode 100644
index 000000000..36e7c21be
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/VelocityScopeMap.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.velocity;
+
+import static org.apache.tiles.request.collection.CollectionUtil.key;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.tiles.request.collection.ScopeMap;
+import org.apache.tiles.request.velocity.extractor.VelocityScopeExtractor;
+import org.apache.velocity.context.Context;
+
+/**
+ * <p>
+ * Private implementation of <code>Map</code> for servlet request attributes.
+ * </p>
+ *
+ */
+
+final class VelocityScopeMap extends ScopeMap {
+
+    /**
+     * The request object to use.
+     */
+    private Context request = null;
+
+    /**
+     * Constructor.
+     *
+     * @param request The request object to use.
+     */
+    public VelocityScopeMap(Context request) {
+        super(new VelocityScopeExtractor(request));
+        this.request = request;
+    }
+
+    @Override
+    public Object remove(Object key) {
+        return request.remove(key(key));
+    }
+
+    @Override
+    public Object put(String key, Object value) {
+        return request.put(key, value);
+    }
+
+    /** {@inheritDoc} */
+    public boolean containsKey(Object key) {
+        return request.containsKey(key(key));
+    }
+
+    /** {@inheritDoc} */
+    public boolean isEmpty() {
+        return size() < 1;
+    }
+
+    /** {@inheritDoc} */
+    public Set<String> keySet() {
+        Set<String> set = new HashSet<String>();
+        for (Object key : request.getKeys()) {
+            set.add((String) key);
+        }
+        return (set);
+    }
+
+    /** {@inheritDoc} */
+    public int size() {
+        return request.getKeys().length;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityAutotagRuntime.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityAutotagRuntime.java
new file mode 100644
index 000000000..32e00e745
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityAutotagRuntime.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.velocity.autotag;
+
+import java.io.Writer;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.servlet.ServletUtil;
+import org.apache.tiles.request.velocity.VelocityRequest;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.ASTBlock;
+import org.apache.velocity.runtime.parser.node.ASTMap;
+import org.apache.velocity.runtime.parser.node.Node;
+import org.apache.velocity.tools.view.ViewContext;
+
+/**
+ * A Runtime for implementing Velocity Directives.
+ */
+public class VelocityAutotagRuntime extends Directive implements AutotagRuntime<Request> {
+    private InternalContextAdapter context;
+    private Writer writer;
+    private Node node;
+    private Map<String, Object> params;
+
+    @Override
+    public Request createRequest() {
+        ViewContext viewContext = (ViewContext) context.getInternalUserContext();
+        HttpServletRequest request = viewContext.getRequest();
+        HttpServletResponse response = viewContext.getResponse();
+        ServletContext servletContext = viewContext.getServletContext();
+        return VelocityRequest.createVelocityRequest(ServletUtil.getApplicationContext(servletContext), request,
+                response, context, writer);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ModelBody createModelBody() {
+        ASTBlock block = (ASTBlock) node.jjtGetChild(1);
+        return new VelocityModelBody(context, block, writer);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getParameter(String name, Class<T> type, T defaultValue) {
+        if (params == null) {
+            ASTMap astMap = (ASTMap) node.jjtGetChild(0);
+            params = (Map<String, Object>) astMap.value(context);
+        }
+        T result = (T) params.get(name);
+        if (result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int getType() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) {
+        this.context = context;
+        this.writer = writer;
+        this.node = node;
+        return false;
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityModelBody.java
new file mode 100644
index 000000000..1022175f6
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityModelBody.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.velocity.autotag;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.AbstractModelBody;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.parser.node.ASTBlock;
+
+/**
+ * Body abstraction for a Velocity directive body.
+ */
+public class VelocityModelBody extends AbstractModelBody {
+
+    /**
+     * The real body.
+     */
+    private ASTBlock body;
+
+    /**
+     * The Velocity context.
+     */
+    private InternalContextAdapter context;
+
+    /**
+     * Constructor.
+     *
+     * @param context       The Velocity context.
+     * @param body          The real body.
+     * @param defaultWriter The default writer.
+     */
+    public VelocityModelBody(InternalContextAdapter context, ASTBlock body, Writer defaultWriter) {
+        super(defaultWriter);
+        this.context = context;
+        this.body = body;
+    }
+
+    @Override
+    public void evaluate(Writer writer) throws IOException {
+        body.render(context, writer);
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityUtil.java
new file mode 100644
index 000000000..bca193836
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/VelocityUtil.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.velocity.autotag;
+
+import java.util.Map;
+
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.parser.node.ASTMap;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * Utilities for Velocity usage in Tiles.
+ */
+public final class VelocityUtil {
+
+    /**
+     * Private constructor to avoid instantiation.
+     */
+    private VelocityUtil() {
+    }
+
+    /**
+     * Extracts the parameters from the directives, by getting the child at position
+     * 0 supposing it is a map.
+     *
+     * @param context The Velocity context.
+     * @param node    The node to use.
+     * @return The extracted parameters.
+     */
+    @SuppressWarnings("unchecked")
+    public static Map<String, Object> getParameters(InternalContextAdapter context, Node node) {
+        ASTMap astMap = (ASTMap) node.jjtGetChild(0);
+        Map<String, Object> params = (Map<String, Object>) astMap.value(context);
+        return params;
+    }
+
+    /**
+     * Returns the "value" parameter if it is not null, otherwise returns
+     * "defaultValue".
+     *
+     * @param value        The value to return, if it is not null.
+     * @param defaultValue The value to return, if <code>value</code> is null.
+     * @return The value, defaulted if necessary.
+     */
+    public static Object getObject(Object value, Object defaultValue) {
+        if (value == null) {
+            value = defaultValue;
+        }
+        return value;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/package-info.java
new file mode 100644
index 000000000..456abb238
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/autotag/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Runtime part of Autotag support for Velocity.
+ */
+package org.apache.tiles.request.velocity.autotag;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/extractor/VelocityScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/extractor/VelocityScopeExtractor.java
new file mode 100644
index 000000000..1481c3844
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/extractor/VelocityScopeExtractor.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.velocity.extractor;
+
+import java.util.Enumeration;
+
+import org.apache.tiles.request.attribute.AttributeExtractor;
+import org.apache.velocity.context.Context;
+
+/**
+ * Extracts attributes from Velocity context..
+ */
+public class VelocityScopeExtractor implements AttributeExtractor {
+
+    /**
+     * The Velocity context.
+     */
+    private Context context;
+
+    /**
+     * Constructor.
+     *
+     * @param context The Velocity context.
+     */
+    public VelocityScopeExtractor(Context context) {
+        this.context = context;
+    }
+
+    @Override
+    public void removeValue(String name) {
+        context.remove(name);
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return new KeyEnumeration(context.getKeys());
+    }
+
+    @Override
+    public Object getValue(String key) {
+        return context.get(key);
+    }
+
+    @Override
+    public void setValue(String key, Object value) {
+        context.put(key, value);
+    }
+
+    /**
+     * Enumerates an array.
+     */
+    private static class KeyEnumeration implements Enumeration<String> {
+
+        /**
+         * The current index.
+         */
+        private int index = 0;
+
+        /**
+         * The array to enumerate.
+         */
+        private Object[] keys;
+
+        /**
+         * Constructor.
+         *
+         * @param keys The array to enumerate.
+         */
+        public KeyEnumeration(Object[] keys) {
+            this.keys = keys;
+        }
+
+        @Override
+        public boolean hasMoreElements() {
+            return index < keys.length;
+        }
+
+        @Override
+        public String nextElement() {
+            return (String) keys[index++];
+        }
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/extractor/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/extractor/package-info.java
new file mode 100644
index 000000000..d0c099c58
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/extractor/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Extractors to get info about Velocity-specific objects.
+ */
+package org.apache.tiles.request.velocity.extractor;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/package-info.java
new file mode 100644
index 000000000..2a3e45f0a
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Tiles request support for Velocity.
+ */
+package org.apache.tiles.request.velocity;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/ApplicationContextJeeConfig.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/ApplicationContextJeeConfig.java
new file mode 100644
index 000000000..9810ce3d9
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/ApplicationContextJeeConfig.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.velocity.render;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.servlet.ServletUtil;
+import org.apache.velocity.tools.view.JeeConfig;
+
+/**
+ * Implements JeeConfig to use parameters set through
+ */
+public class ApplicationContextJeeConfig implements JeeConfig {
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * The initialization parameters for VelocityView.
+     */
+    private Map<String, String> params;
+
+    /**
+     * Constructor.
+     *
+     * @param applicationContext The application context.
+     * @param params Configuration parameters.
+     */
+    public ApplicationContextJeeConfig(ApplicationContext applicationContext, Map<String, String> params) {
+        this.applicationContext = applicationContext;
+        this.params = new HashMap<String, String>(params);
+    }
+
+    public String getInitParameter(String name) {
+        return params.get(name);
+    }
+
+    public String findInitParameter(String key) {
+        return params.get(key);
+    }
+
+    public Enumeration<String> getInitParameterNames() {
+        return Collections.enumeration(params.keySet());
+    }
+
+    public String getName() {
+        return "Application Context JEE Config";
+    }
+
+    public ServletContext getServletContext() {
+        return ServletUtil.getServletContext(applicationContext);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/VelocityRenderer.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/VelocityRenderer.java
new file mode 100644
index 000000000..780a28569
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/VelocityRenderer.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.request.velocity.render;
+
+import java.io.IOException;
+
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.render.CannotRenderException;
+import org.apache.tiles.request.render.Renderer;
+import org.apache.tiles.request.servlet.ServletRequest;
+import org.apache.tiles.request.servlet.ServletUtil;
+import org.apache.velocity.Template;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.tools.view.VelocityView;
+
+/**
+ * Attribute renderer for rendering Velocity templates as attributes. It is
+ * available only to Servlet-based environment. It uses VelocityView to render
+ * the response. To initialize it correctly, call #setParameter(String, String)
+ * for all the parameters that you want to set, and then call #commit().
+ */
+public class VelocityRenderer implements Renderer {
+
+    /**
+     * The VelocityView object to use.
+     */
+    private VelocityView velocityView;
+
+    /**
+     * Constructor.
+     *
+     * @param velocityView The Velocity view manager.
+     */
+    public VelocityRenderer(VelocityView velocityView) {
+        this.velocityView = velocityView;
+    }
+
+    @Override
+    public void render(String path, Request request) throws IOException {
+        if (path == null) {
+            throw new CannotRenderException("Cannot dispatch a null path");
+        }
+
+        ServletRequest servletRequest = ServletUtil.getServletRequest(request);
+        // then get a context
+        Context context = velocityView.createContext(servletRequest.getRequest(), servletRequest.getResponse());
+
+        // get the template
+        Template template = velocityView.getTemplate((String) path);
+
+        // merge the template and context into the writer
+        velocityView.merge(template, context, request.getWriter());
+    }
+
+    public boolean isRenderable(String path, Request request) {
+        return path != null && path.startsWith("/") && path.endsWith(".vm");
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/VelocityRendererBuilder.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/VelocityRendererBuilder.java
new file mode 100644
index 000000000..6f028ea01
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/VelocityRendererBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * $Id: VelocityRendererBuilder.java 1066512 2011-02-02 16:13:31Z apetrelli $
+ *
+ * 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.
+ */
+package org.apache.tiles.request.velocity.render;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.velocity.tools.view.VelocityView;
+
+/**
+ * Builds a VelocityRenderer.
+ */
+public final class VelocityRendererBuilder {
+
+    /**
+     * The initialization parameters for VelocityView.
+     */
+    private Map<String, String> params = new HashMap<String, String>();
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * Constructor.
+     */
+    private VelocityRendererBuilder() {
+    }
+
+    /**
+     * Returns a new instance of the builder.
+     *
+     * @return A new builder.
+     */
+    public static VelocityRendererBuilder createInstance() {
+        return new VelocityRendererBuilder();
+    }
+
+    /**
+     * Sets a parameter for the internal servlet.
+     *
+     * @param key   The name of the parameter.
+     * @param value The value of the parameter.
+     * @return This builder.
+     */
+    public VelocityRendererBuilder setParameter(String key, String value) {
+        params.put(key, value);
+        return this;
+    }
+
+    /**
+     * Sets the application context.
+     *
+     * @param applicationContext The application context.
+     * @return This builder.
+     */
+    public VelocityRendererBuilder setApplicationContext(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+        return this;
+    }
+
+    /**
+     * Creates the Velocity renderer.
+     *
+     * @return The Velocity renderer.
+     */
+    public VelocityRenderer build() {
+        VelocityView velocityView = new VelocityView(new ApplicationContextJeeConfig(applicationContext, params));
+        return new VelocityRenderer(velocityView);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/package-info.java
new file mode 100644
index 000000000..bb0b2d39d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/velocity/render/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Renderering support for Velocity.
+ */
+package org.apache.tiles.request.velocity.render;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/TilesVelocityException.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/TilesVelocityException.java
new file mode 100644
index 000000000..165bce373
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/TilesVelocityException.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.velocity;
+
+import org.apache.tiles.api.TilesException;
+
+/**
+ * Exception connected to the usage of Velocity and Tiles.
+ *
+ * @since 2.2.0
+ */
+public class TilesVelocityException extends TilesException {
+
+    private static final long serialVersionUID = -7013866521398042363L;
+
+    /**
+     * Constructor.
+     *
+     * @since 2.2.0
+     */
+    public TilesVelocityException() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The message of the exception.
+     * @since 2.2.0
+     */
+    public TilesVelocityException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param e The cause of the exception.
+     * @since 2.2.0
+     */
+    public TilesVelocityException(Throwable e) {
+        super(e);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The message of the exception.
+     * @param e The cause of the exception.
+     * @since 2.2.0
+     */
+    public TilesVelocityException(String message, Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/package-info.java
new file mode 100644
index 000000000..084432124
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Classes to support Velocity under a servlet environment in Tiles.
+ */
+package org.apache.tiles.velocity;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AbstractDefaultToStringRenderable.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AbstractDefaultToStringRenderable.java
new file mode 100644
index 000000000..3628833bb
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AbstractDefaultToStringRenderable.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tiles.velocity.TilesVelocityException;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.Renderable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Renderable that provides a default implementation of Renderable#toString()
+ * and allows access to parameters and context objects.
+ *
+ * @since 2.2.0
+ */
+public abstract class AbstractDefaultToStringRenderable implements Renderable {
+
+    /**
+     * The Velocity context.
+     *
+     * @since 2.2.0
+     */
+    protected final Context velocityContext;
+
+    /**
+     * The parameters used in the current tool call.
+     *
+     * @since 2.2.0
+     */
+    protected final Map<String, Object> params;
+
+    /**
+     * The HTTP response.
+     *
+     * @since 2.2.0
+     */
+    protected final HttpServletResponse response;
+
+    /**
+     * The HTTP request.
+     *
+     * @since 2.2.0
+     */
+    protected final HttpServletRequest request;
+
+    /**
+     * The logging object.
+     */
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /**
+     * Constructor.
+     *
+     * @param velocityContext The Velocity context.
+     * @param params          The parameters used in the current tool call.
+     * @param response        The HTTP response.
+     * @param request         The HTTP request.
+     * @since 2.2.0
+     */
+    public AbstractDefaultToStringRenderable(Context velocityContext, Map<String, Object> params,
+            HttpServletResponse response, HttpServletRequest request) {
+        this.velocityContext = velocityContext;
+        this.params = params;
+        this.response = response;
+        this.request = request;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringWriter writer = new StringWriter();
+        try {
+            render(null, writer);
+        } catch (MethodInvocationException e) {
+            throw new TilesVelocityException("Cannot invoke method when rendering", e);
+        } catch (ParseErrorException e) {
+            throw new TilesVelocityException("Cannot parse when rendering", e);
+        } catch (ResourceNotFoundException e) {
+            throw new TilesVelocityException("Cannot find resource when rendering", e);
+        } catch (IOException e) {
+            throw new TilesVelocityException("I/O exception when rendering", e);
+        } finally {
+            try {
+                writer.close();
+            } catch (IOException e) {
+                log.error("Error when closing a StringWriter, the impossible happened!", e);
+            }
+        }
+        return writer.toString();
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AddAttributeDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AddAttributeDirective.java
new file mode 100644
index 000000000..49f6c3112
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AddAttributeDirective.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Add an element to the surrounding list. Equivalent to 'putAttribute', but for
+ * list element.
+ * </p>
+ * 
+ * <p>
+ * Add an element to the surrounding list. This tag can only be used inside
+ * 'putListAttribute' or 'addListAttribute' tags. Value can come from a direct
+ * assignment (value="aValue")
+ * </p>
+ */
+public class AddAttributeDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.AddAttributeModel model = new org.apache.tiles.template.AddAttributeModel();
+
+    @Override
+    public String getName() {
+        return "tiles_addAttribute";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("value", java.lang.Object.class, null),
+                runtime.getParameter("expression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("type", java.lang.String.class, null), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AddListAttributeDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AddListAttributeDirective.java
new file mode 100644
index 000000000..b42b120b0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/AddListAttributeDirective.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Declare a list that will be pass as an attribute.
+ * </p>
+ * <p>
+ * Declare a list that will be pass as an attribute . List elements are added
+ * using the tag 'addAttribute' or 'addListAttribute'. This tag can only be used
+ * inside 'insertTemplate', 'insertDefinition' or 'definition' tag.
+ * </p>
+ */
+public class AddListAttributeDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.AddListAttributeModel model = new org.apache.tiles.template.AddListAttributeModel();
+
+    @Override
+    public String getName() {
+        return "tiles_addListAttribute";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("role", java.lang.String.class, null), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/ContextHolder.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/ContextHolder.java
new file mode 100644
index 000000000..ad43f3941
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/ContextHolder.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.velocity.template;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.velocity.context.Context;
+
+/**
+ * An object that holds the current state of Velocity in a Servlet environment.
+ *
+ * @since 2.2.0
+ */
+public class ContextHolder {
+
+    /**
+     * The Velocity context.
+     */
+    private Context velocityContext;
+
+    /**
+     * The HTTP request.
+     */
+    private HttpServletRequest request;
+
+    /**
+     * The HTTP response.
+     */
+    private HttpServletResponse response;
+
+    /**
+     * The servlet context.
+     */
+    private ServletContext application;
+
+    /**
+     * Sets the current {@link HttpServletRequest}. This is required for this tool
+     * to operate and will throw a NullPointerException if this is not set or is set
+     * to {@code null}.
+     *
+     * @param request The HTTP request.
+     * @since 2.2.0
+     */
+    public void setRequest(HttpServletRequest request) {
+        if (request == null) {
+            throw new NullPointerException("request should not be null");
+        }
+        this.request = request;
+    }
+
+    /**
+     * Sets the current {@link HttpServletResponse}. This is required for this tool
+     * to operate and will throw a NullPointerException if this is not set or is set
+     * to {@code null}.
+     *
+     * @param response The HTTP response.
+     * @since 2.2.0
+     */
+    public void setResponse(HttpServletResponse response) {
+        if (response == null) {
+            throw new NullPointerException("response should not be null");
+        }
+        this.response = response;
+    }
+
+    /**
+     * Sets the {@link ServletContext}. This is required for this tool to operate
+     * and will throw a NullPointerException if this is not set or is set to
+     * {@code null}.
+     *
+     * @param application The Servlet context.
+     * @since 2.2.0
+     */
+    public void setServletContext(ServletContext application) {
+        if (application == null) {
+            throw new NullPointerException("servlet context should not be null");
+        }
+        this.application = application;
+    }
+
+    /**
+     * Sets the Velocity {@link Context}. This is required for this tool to operate
+     * and will throw a NullPointerException if this is not set or is set to
+     * {@code null}.
+     *
+     * @param context The Velocity context.
+     * @since 2.2.0
+     */
+    public void setVelocityContext(Context context) {
+        if (context == null) {
+            throw new NullPointerException("velocity context should not be null");
+        }
+        this.velocityContext = context;
+    }
+
+    /**
+     * Returns the HTTP request.
+     *
+     * @return The HTTP request.
+     * @since 2.2.0
+     */
+    protected HttpServletRequest getRequest() {
+        return request;
+    }
+
+    /**
+     * Returns the HTTP response.
+     *
+     * @return The HTTP response.
+     * @since 2.2.0
+     */
+    protected HttpServletResponse getResponse() {
+        return response;
+    }
+
+    /**
+     * Returns the Servlet context.
+     *
+     * @return The Servlet context..
+     * @since 2.2.0
+     */
+    protected ServletContext getServletContext() {
+        return application;
+    }
+
+    /**
+     * Returns the Velocity context..
+     *
+     * @return The Velocity context.
+     * @since 2.2.0
+     */
+    protected Context getVelocityContext() {
+        return velocityContext;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/DefinitionDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/DefinitionDirective.java
new file mode 100644
index 000000000..90373e332
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/DefinitionDirective.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Create a definition at runtime.
+ * </p>
+ * <p>
+ * Create a new definition at runtime. Newly created definition will be
+ * available across the entire request.
+ * </p>
+ */
+public class DefinitionDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.DefinitionModel model = new org.apache.tiles.template.DefinitionModel();
+
+    @Override
+    public String getName() {
+        return "tiles_definition";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("template", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("extends", java.lang.String.class, null),
+                runtime.getParameter("preparer", java.lang.String.class, null), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/GetAsStringDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/GetAsStringDirective.java
new file mode 100644
index 000000000..24109ab3f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/GetAsStringDirective.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Render the value of the specified template attribute to the current Writer
+ * </p>
+ * 
+ * <p>
+ * Retrieve the value of the specified template attribute property, and render
+ * it to the current Writer as a String. The usual toString() conversions is
+ * applied on found value.
+ * </p>
+ */
+public class GetAsStringDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.GetAsStringModel model = new org.apache.tiles.template.GetAsStringModel();
+
+    @Override
+    public String getName() {
+        return "tiles_getAsString";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("ignore", java.lang.Boolean.class, false),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("defaultValue", java.lang.Object.class, null),
+                runtime.getParameter("defaultValueRole", java.lang.String.class, null),
+                runtime.getParameter("defaultValueType", java.lang.String.class, null),
+                runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("value", org.apache.tiles.api.Attribute.class, null), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/ImportAttributeDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/ImportAttributeDirective.java
new file mode 100644
index 000000000..7fa6f4f9f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/ImportAttributeDirective.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Import attribute(s) in specified context.
+ * </p>
+ * <p>
+ * Import attribute(s) to requested scope. Attribute name and scope are
+ * optional. If not specified, all attributes are imported in page scope. Once
+ * imported, an attribute can be used as any other beans from jsp contexts.
+ * </p>
+ */
+public class ImportAttributeDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.ImportAttributeModel model = new org.apache.tiles.template.ImportAttributeModel();
+
+    @Override
+    public String getName() {
+        return "tiles_importAttribute";
+    }
+
+    @Override
+    public int getType() {
+        return LINE;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("scope", java.lang.String.class, null),
+                runtime.getParameter("toName", java.lang.String.class, null),
+                runtime.getParameter("ignore", java.lang.Boolean.class, false), request
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertAttributeDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertAttributeDirective.java
new file mode 100644
index 000000000..4a980cd1d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertAttributeDirective.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Inserts the value of an attribute into the page.
+ * </p>
+ * <p>
+ * This tag can be flexibly used to insert the value of an attribute into a
+ * page. As in other usages in Tiles, every attribute can be determined to have
+ * a "type", either set explicitly when it was defined, or "computed". If the
+ * type is not explicit, then if the attribute value is a valid definition, it
+ * will be inserted as such. Otherwise, if it begins with a "/" character, it
+ * will be treated as a "template". Finally, if it has not otherwise been
+ * assigned a type, it will be treated as a String and included without any
+ * special handling.
+ * </p>
+ * 
+ * <p>
+ * Example :
+ * </p>
+ * 
+ * <pre>
+ *     &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
+ * </pre>
+ */
+public class InsertAttributeDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.InsertAttributeModel model = new org.apache.tiles.template.InsertAttributeModel();
+
+    @Override
+    public String getName() {
+        return "tiles_insertAttribute";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("ignore", java.lang.Boolean.class, false),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("defaultValue", java.lang.Object.class, null),
+                runtime.getParameter("defaultValueRole", java.lang.String.class, null),
+                runtime.getParameter("defaultValueType", java.lang.String.class, null),
+                runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("value", org.apache.tiles.api.Attribute.class, null),
+                runtime.getParameter("flush", java.lang.Boolean.class, false), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertDefinitionDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertDefinitionDirective.java
new file mode 100644
index 000000000..51a098882
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertDefinitionDirective.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Insert a definition.
+ * </p>
+ * <p>
+ * Insert a definition with the possibility to override and specify parameters
+ * (called attributes). A definition can be seen as a (partially or totally)
+ * filled template that can override or complete attribute values.
+ * &lt;tiles:insertDefinition&gt; allows to define these attributes and pass
+ * them to the inserted jsp page, called template. Attributes are defined using
+ * nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+ * </p>
+ * <p>
+ * You must specify name tag attribute, for inserting a definition from
+ * definitions factory.
+ * </p>
+ * <p>
+ * Example :
+ * </p>
+ * 
+ * <pre>
+ *     &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
+ *         &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;/tiles:insertDefinition&gt;
+ * </pre>
+ */
+public class InsertDefinitionDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.InsertDefinitionModel model = new org.apache.tiles.template.InsertDefinitionModel();
+
+    @Override
+    public String getName() {
+        return "tiles_insertDefinition";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("template", java.lang.String.class, null),
+                runtime.getParameter("templateType", java.lang.String.class, null),
+                runtime.getParameter("templateExpression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("flush", java.lang.Boolean.class, false), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertTemplateDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertTemplateDirective.java
new file mode 100644
index 000000000..1ce0e53df
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/InsertTemplateDirective.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Insert a template.
+ * </p>
+ * <p>
+ * Insert a template with the possibility to pass parameters (called
+ * attributes). A template can be seen as a procedure that can take parameters
+ * or attributes. &lt;tiles:insertTemplate&gt; allows to define these attributes
+ * and pass them to the inserted jsp page, called template. Attributes are
+ * defined using nested tag &lt;tiles:putAttribute&gt; or
+ * &lt;tiles:putListAttribute&gt;.
+ * </p>
+ * <p>
+ * You must specify template attribute, for inserting a template
+ * </p>
+ * 
+ * <p>
+ * Example :
+ * </p>
+ * 
+ * <pre>
+ *     &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
+ *         &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;/tiles:insertTemplate&gt;
+ * </pre>
+ */
+public class InsertTemplateDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.InsertTemplateModel model = new org.apache.tiles.template.InsertTemplateModel();
+
+    @Override
+    public String getName() {
+        return "tiles_insertTemplate";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("template", java.lang.String.class, null),
+                runtime.getParameter("templateType", java.lang.String.class, null),
+                runtime.getParameter("templateExpression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("flush", java.lang.Boolean.class, false), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/PutAttributeDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/PutAttributeDirective.java
new file mode 100644
index 000000000..acac9b1fa
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/PutAttributeDirective.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Put an attribute in enclosing attribute container tag.
+ * </p>
+ * <p>
+ * Enclosing attribute container tag can be :
+ * <ul>
+ * <li>&lt;initContainer&gt;</li>
+ * <li>&lt;definition&gt;</li>
+ * <li>&lt;insertAttribute&gt;</li>
+ * <li>&lt;insertDefinition&gt;</li>
+ * <li>&lt;putListAttribute&gt;</li>
+ * </ul>
+ * (or any other tag which implements the PutAttributeTagParent interface.
+ * Exception is thrown if no appropriate tag can be found.
+ * </p>
+ * <p>
+ * Put tag can have following atributes :
+ * <ul>
+ * <li>name : Name of the attribute</li>
+ * <li>value : value to put as attribute</li>
+ * <li>type : value type. Possible type are : string (value is used as direct
+ * string), template (value is used as a page url to insert), definition (value
+ * is used as a definition name to insert), object (value is used as it is)</li>
+ * <li>role : Role to check when 'insertAttribute' will be called.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Value can also come from tag body. Tag body is taken into account only if
+ * value is not set by one of the tag attributes. In this case Attribute type is
+ * "string", unless tag body define another type.
+ * </p>
+ */
+public class PutAttributeDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.PutAttributeModel model = new org.apache.tiles.template.PutAttributeModel();
+
+    @Override
+    public String getName() {
+        return "tiles_putAttribute";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("value", java.lang.Object.class, null),
+                runtime.getParameter("expression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("type", java.lang.String.class, null),
+                runtime.getParameter("cascade", java.lang.Boolean.class, false), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/PutListAttributeDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/PutListAttributeDirective.java
new file mode 100644
index 000000000..c55dd9274
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/PutListAttributeDirective.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * <p>
+ * Declare a list that will be pass as attribute to tile.
+ * </p>
+ * <p>
+ * Declare a list that will be pass as attribute to tile. List elements are
+ * added using the tags 'addAttribute' or 'addListAttribute'. This tag can only
+ * be used inside 'insertTemplate', 'insertDefinition', 'definition' tags.
+ * </p>
+ */
+public class PutListAttributeDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.PutListAttributeModel model = new org.apache.tiles.template.PutListAttributeModel();
+
+    @Override
+    public String getName() {
+        return "tiles_putListAttribute";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("inherit", java.lang.Boolean.class, false),
+                runtime.getParameter("cascade", java.lang.Boolean.class, false), request, modelBody
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/SetCurrentContainerDirective.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/SetCurrentContainerDirective.java
new file mode 100644
index 000000000..d7ff03e80
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/SetCurrentContainerDirective.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * Selects a container to be used as the "current" container.
+ */
+public class SetCurrentContainerDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.SetCurrentContainerModel model = new org.apache.tiles.template.SetCurrentContainerModel();
+
+    @Override
+    public String getName() {
+        return "tiles_setCurrentContainer";
+    }
+
+    @Override
+    public int getType() {
+        return LINE;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.velocity.autotag.VelocityAutotagRuntime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        model.execute(runtime.getParameter("containerKey", java.lang.String.class, null), request
+
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/VelocityStyleTilesTool.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/VelocityStyleTilesTool.java
new file mode 100644
index 000000000..e9c3852ac
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/VelocityStyleTilesTool.java
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.velocity.template;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.servlet.ServletUtil;
+import org.apache.tiles.request.velocity.VelocityRequest;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.Renderable;
+
+/**
+ * Tiles Tool to be used "the classic way".
+ *
+ * @since 2.2.0
+ */
+public class VelocityStyleTilesTool extends ContextHolder {
+
+    /**
+     * Returns an attribute.
+     *
+     * @param key The name of the attribute to get.
+     * @return The Attribute.
+     * @since 2.2.0
+     */
+    public Attribute get(String key) {
+        Request velocityRequest = createVelocityRequest(getServletContext(), null);
+        TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+        AttributeContext attributeContext = container.getAttributeContext(velocityRequest);
+        Attribute attribute = attributeContext.getAttribute(key);
+        return attribute;
+    }
+
+    /**
+     * Creates a new empty attribute.
+     *
+     * @return The created attribute.
+     * @since 2.2.0
+     */
+    public Attribute createAttribute() {
+        return new Attribute();
+    }
+
+    /**
+     * Creates an attribute that is a copy of the one passed as a parameter.
+     *
+     * @param attribute The attribute to copy.
+     * @return The copied attribute.
+     * @since 2.2.0
+     */
+    public Attribute clone(Attribute attribute) {
+        return new Attribute(attribute);
+    }
+
+    /**
+     * Creates an attribute that represents a template.
+     *
+     * @param template The template.
+     * @return The attribute.
+     * @since 2.2.0
+     */
+    public Attribute createTemplateAttribute(String template) {
+        return Attribute.createTemplateAttribute(template);
+    }
+
+    /**
+     * Renders an attribute.
+     *
+     * @param attribute The attribute to render.
+     * @return The renderable object, ready to be rendered.
+     * @since 2.2.0
+     */
+    public Renderable render(final Attribute attribute) {
+        return new AbstractDefaultToStringRenderable(getVelocityContext(), null, getResponse(), getRequest()) {
+
+            public boolean render(InternalContextAdapter context, Writer writer) throws IOException {
+                Request velocityRequest = createVelocityRequest(getServletContext(), writer);
+                TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+                container.render(attribute, velocityRequest);
+                return true;
+            }
+
+        };
+    }
+
+    /**
+     * Renders a definition. It can be used in conjunction with
+     * {@link #startAttributeContext()} and {@link #endAttributeContext()} to
+     * customize appearance.
+     *
+     * @param definitionName The name of the definition to render.
+     * @return The renderable that renders the definition.
+     * @since 2.2.0
+     */
+    public Renderable renderDefinition(final String definitionName) {
+        return new AbstractDefaultToStringRenderable(getVelocityContext(), null, getResponse(), getRequest()) {
+
+            public boolean render(InternalContextAdapter context, Writer writer) {
+                Request velocityRequest = createVelocityRequest(getServletContext(), writer);
+                TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+                container.render(definitionName, velocityRequest);
+                return true;
+            }
+
+        };
+    }
+
+    /**
+     * Renders the current attribute context. It can be used in conjunction with
+     * {@link #startAttributeContext()} and {@link #endAttributeContext()} to
+     * customize appearance.
+     *
+     * @return The renderable that renders the current attribute context.
+     * @since 2.2.0
+     */
+    public Renderable renderAttributeContext() {
+        return new AbstractDefaultToStringRenderable(getVelocityContext(), null, getResponse(), getRequest()) {
+
+            public boolean render(InternalContextAdapter context, Writer writer) {
+                Request velocityRequest = createVelocityRequest(getServletContext(), writer);
+                TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+                container.renderContext(velocityRequest);
+                return true;
+            }
+
+        };
+    }
+
+    /**
+     * Starts the attribute context. Remember to call {@link #endAttributeContext()}
+     * when finished!
+     *
+     * @return The started attribute context, ready to be customized.
+     * @since 2.2.0
+     */
+    public AttributeContext startAttributeContext() {
+        Request velocityRequest = createVelocityRequest(getServletContext(), null);
+        TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+        return container.startContext(velocityRequest);
+    }
+
+    /**
+     * Ends the current attribute context. To be called after
+     * {@link #startAttributeContext()}.
+     *
+     * @return The tool itself.
+     * @since 2.2.0
+     */
+    public VelocityStyleTilesTool endAttributeContext() {
+        Request velocityRequest = createVelocityRequest(getServletContext(), null);
+        TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+        container.endContext(velocityRequest);
+        return this;
+    }
+
+    /**
+     * Returns the current attribute context.
+     *
+     * @return The current attribute context.
+     * @since 2.2.0
+     */
+    public AttributeContext getAttributeContext() {
+        Request velocityRequest = createVelocityRequest(getServletContext(), null);
+        TilesContainer container = TilesAccess.getCurrentContainer(velocityRequest);
+        return container.getAttributeContext(velocityRequest);
+    }
+
+    /**
+     * Sets the current container for the current request.
+     *
+     * @param containerKey The key of the container to set as "current" for the
+     *                     current request.
+     * @return The tool itself.
+     * @since 2.2.0
+     */
+    public VelocityStyleTilesTool setCurrentContainer(String containerKey) {
+        Request velocityRequest = createVelocityRequest(getServletContext(), null);
+        TilesAccess.setCurrentContainer(velocityRequest, containerKey);
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "";
+    }
+
+    /**
+     * Creates a Velocity request.
+     *
+     * @param servletContext The servlet context.
+     * @param writer         The writer.
+     * @return The created request.
+     */
+    protected Request createVelocityRequest(ServletContext servletContext, Writer writer) {
+        return VelocityRequest.createVelocityRequest(ServletUtil.getApplicationContext(servletContext), getRequest(),
+                getResponse(), getVelocityContext(), writer);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/package-info.java
new file mode 100644
index 000000000..eeb9e3a27
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/velocity/template/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Classes that allow the use of "Tiles template" as a Velocity tool.
+ */
+package org.apache.tiles.velocity.template;
diff --git a/plugins/tiles/src/main/resources/META-INF/velocity.properties b/plugins/tiles/src/main/resources/META-INF/velocity.properties
new file mode 100644
index 000000000..4887c6cc3
--- /dev/null
+++ b/plugins/tiles/src/main/resources/META-INF/velocity.properties
@@ -0,0 +1,30 @@
+# 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.
+#
+# This file was automatically generated by Autotag.  Please do not edit it manually.
+
+userdirective=org.apache.tiles.velocity.template.InsertDefinitionDirective,\
+org.apache.tiles.velocity.template.ImportAttributeDirective,\
+org.apache.tiles.velocity.template.SetCurrentContainerDirective,\
+org.apache.tiles.velocity.template.AddListAttributeDirective,\
+org.apache.tiles.velocity.template.GetAsStringDirective,\
+org.apache.tiles.velocity.template.InsertAttributeDirective,\
+org.apache.tiles.velocity.template.PutAttributeDirective,\
+org.apache.tiles.velocity.template.DefinitionDirective,\
+org.apache.tiles.velocity.template.AddAttributeDirective,\
+org.apache.tiles.velocity.template.PutListAttributeDirective,\
+org.apache.tiles.velocity.template.InsertTemplateDirective
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties
index 29ae759db..821c6d762 100644
--- a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties
@@ -44,19 +44,6 @@ input.encoding=ISO-8859-1
 output.encoding=ISO-8859-1
 
 
-# ----------------------------------------------------------------------------
-# F O R E A C H  P R O P E R T I E S
-# ----------------------------------------------------------------------------
-# These properties control how the counter is accessed in the #foreach
-# directive. By default the reference $velocityCount will be available
-# in the body of the #foreach directive. The default starting value
-# for this reference is 1.
-# ----------------------------------------------------------------------------
-
-directive.foreach.counter.name = velocityCount
-directive.foreach.counter.initial.value = 1
-
-
 # ----------------------------------------------------------------------------
 # I N C L U D E  P R O P E R T I E S
 # ----------------------------------------------------------------------------
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity/velocityDirective.vm b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity/velocityDirective.vm
new file mode 100644
index 000000000..0528affab
--- /dev/null
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity/velocityDirective.vm
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+ /*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package ${packageName};
+
+import java.io.IOException;
+import java.io.Writer;
+
+#if(${clazz.hasBody()})
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+#end
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+#foreach($line in $stringTool.splitOnNewlines(${clazz.documentation}))
+ * ${line}
+#end
+ */
+public class ${clazz.tagClassPrefix}Directive extends Directive {
+
+    /**
+     * The template model.
+     */
+    private ${clazz.name} model = new ${clazz.name}();
+
+    @Override
+    public String getName() {
+        return "${suite.name}_${clazz.tagName}";
+    }
+
+    @Override
+    public int getType() {
+        return #if(${clazz.hasBody()})BLOCK#{else}LINE#{end};
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node)
+            throws IOException {
+        AutotagRuntime<${requestClass}> runtime = new ${runtimeClass}();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        ${requestClass} request = runtime.createRequest();
+#if(${clazz.hasBody()})
+        ModelBody modelBody = runtime.createModelBody();
+#end
+        model.execute(
+#foreach($parameter in ${clazz.parameters})
+            runtime.getParameter("${parameter.exportedName}", ${stringTool.getClassToCast(${parameter.type})}.class, $stringTool.getDefaultValue(${parameter.type}, ${parameter.defaultValue})),
+#end
+            request#if(${clazz.hasBody()}), modelBody#end
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity/velocityProperties.vm b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity/velocityProperties.vm
new file mode 100644
index 000000000..6360d64f4
--- /dev/null
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity/velocityProperties.vm
@@ -0,0 +1,21 @@
+# 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.
+#
+# This file was automatically generated by Autotag.  Please do not edit it manually.
+
+userdirective=#foreach($clazz in ${suite.getTemplateClasses()})#if($foreach.count > 1),\
+  #{end}${packageName}.${clazz.tagClassPrefix}Directive#end
\ No newline at end of file
diff --git a/plugins/tiles/src/main/resources/tools.xml b/plugins/tiles/src/main/resources/tools.xml
new file mode 100644
index 000000000..65d673763
--- /dev/null
+++ b/plugins/tiles/src/main/resources/tools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<tools>
+  <toolbox scope="request">
+    <tool key="tiles" class="org.apache.tiles.velocity.template.VelocityStyleTilesTool"/>
+  </toolbox>
+</tools>
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityDirectiveGeneratorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityDirectiveGeneratorTest.java
new file mode 100644
index 000000000..b9854bf1c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityDirectiveGeneratorTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.velocity;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateMethod;
+import org.apache.tiles.autotag.model.TemplateParameter;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests VelocityDirectiveGenerator.
+ */
+public class VelocityDirectiveGeneratorTest {
+
+    public static final String REQUEST_CLASS = "org.apache.tiles.autotag.velocity.Request";
+
+    /**
+     * Test method for VelocityDirectiveGenerator#generate(File, String,
+     * TemplateSuite, TemplateClass, java.util.Map).
+     * 
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void testGenerate() throws Exception {
+        Properties props = new Properties();
+        InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+        props.load(propsStream);
+        propsStream.close();
+        VelocityEngine velocityEngine = new VelocityEngine(props);
+
+        VelocityDirectiveGenerator generator = new VelocityDirectiveGenerator(velocityEngine);
+        File file = File.createTempFile("autotag", null);
+        file.delete();
+        file.mkdir();
+        file.deleteOnExit();
+        TemplateSuite suite = new TemplateSuite("tldtest", "Test for TLD docs.");
+
+        List<TemplateParameter> params = new ArrayList<TemplateParameter>();
+        TemplateParameter param = new TemplateParameter("one", "one", "java.lang.String", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "int", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "boolean", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        param = new TemplateParameter("modelBody", "modelBody", ModelBody.class.getName(), null, false, false);
+        param.setDocumentation("The body.");
+        params.add(param);
+        TemplateMethod executeMethod = new TemplateMethod("execute", params);
+
+        TemplateClass clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffTemplate", "doStuff",
+                "DoStuff", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuff class.");
+
+        generator.generate(file, "org.apache.tiles.autotag.velocity.test", suite, clazz, null,
+                "org.apache.tiles.autotag.velocity.test.Runtime", REQUEST_CLASS);
+
+        InputStream expected = getClass()
+                .getResourceAsStream("/org/apache/tiles/autotag/velocity/test/DoStuffDirective.javat");
+        File effectiveFile = new File(file, "/org/apache/tiles/autotag/velocity/test/DoStuffDirective.java");
+        assertTrue(effectiveFile.exists());
+        InputStream effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        suite.addTemplateClass(clazz);
+        params = new ArrayList<TemplateParameter>();
+        param = new TemplateParameter("one", "one", "java.lang.Double", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "float", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "java.util.Date", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        executeMethod = new TemplateMethod("execute", params);
+
+        clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffNoBodyTemplate", "doStuffNoBody",
+                "DoStuffNoBody", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuffNoBody class.");
+
+        suite.addTemplateClass(clazz);
+
+        generator.generate(file, "org.apache.tiles.autotag.velocity.test", suite, clazz, null,
+                "org.apache.tiles.autotag.velocity.test.Runtime", REQUEST_CLASS);
+
+        expected = getClass()
+                .getResourceAsStream("/org/apache/tiles/autotag/velocity/test/DoStuffNoBodyDirective.javat");
+        effectiveFile = new File(file, "/org/apache/tiles/autotag/velocity/test/DoStuffNoBodyDirective.java");
+        assertTrue(effectiveFile.exists());
+        effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        FileUtils.deleteDirectory(file);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityPropertiesGeneratorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityPropertiesGeneratorTest.java
new file mode 100644
index 000000000..1ea2b37fc
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityPropertiesGeneratorTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.velocity;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateMethod;
+import org.apache.tiles.autotag.model.TemplateParameter;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests VelocityPropertiesGenerator.
+ */
+public class VelocityPropertiesGeneratorTest {
+
+    public static final String REQUEST_CLASS = "org.apache.tiles.autotag.velocity.Request";
+
+    /**
+     * Test method for org.apache.tiles.autotag.velocity.VelocityPropertiesGenerator
+     * #generate(File, String, TemplateSuite, java.util.Map).
+     * 
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void testGenerate() throws Exception {
+        Properties props = new Properties();
+        InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+        props.load(propsStream);
+        propsStream.close();
+        VelocityEngine velocityEngine = new VelocityEngine(props);
+
+        VelocityPropertiesGenerator generator = new VelocityPropertiesGenerator(velocityEngine);
+        File file = File.createTempFile("autotag", null);
+        file.delete();
+        file.mkdir();
+        file.deleteOnExit();
+        TemplateSuite suite = new TemplateSuite("tldtest", "Test for TLD docs.");
+
+        List<TemplateParameter> params = new ArrayList<TemplateParameter>();
+        TemplateParameter param = new TemplateParameter("one", "one", "java.lang.String", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "int", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "long", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        param = new TemplateParameter("modelBody", "modelBody", ModelBody.class.getName(), null, false, false);
+        param.setDocumentation("The body.");
+        params.add(param);
+        TemplateMethod executeMethod = new TemplateMethod("execute", params);
+
+        TemplateClass clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffTemplate", "doStuff",
+                "DoStuff", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuff class");
+
+        suite.addTemplateClass(clazz);
+        params = new ArrayList<TemplateParameter>();
+        param = new TemplateParameter("one", "one", "java.lang.Double", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "float", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "java.util.Date", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        executeMethod = new TemplateMethod("execute", params);
+
+        clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffNoBodyTemplate", "doStuffNoBody",
+                "DoStuffNoBody", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuffNoBody class");
+
+        suite.addTemplateClass(clazz);
+
+        generator.generate(file, "org.apache.tiles.autotag.velocity.test", suite, null);
+
+        InputStream expected = getClass().getResourceAsStream("/velocity.properties.test");
+        File effectiveFile = new File(file, "META-INF/velocity.properties");
+        assertTrue(effectiveFile.exists());
+        InputStream effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        FileUtils.deleteDirectory(file);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityTemplateGeneratorFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityTemplateGeneratorFactoryTest.java
new file mode 100644
index 000000000..e0924178a
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/velocity/VelocityTemplateGeneratorFactoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.velocity;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests JspTemplateGeneratorFactory.
+ */
+public class VelocityTemplateGeneratorFactoryTest {
+
+    /**
+     * Test method for VelocityTemplateGeneratorFactory#createTemplateGenerator().
+     */
+    @Test
+    public void testCreateTemplateGenerator() {
+        File classesOutputDirectory = createMock(File.class);
+        File resourcesOutputDirectory = createMock(File.class);
+        VelocityEngine velocityEngine = createMock(VelocityEngine.class);
+        TemplateGeneratorBuilder builder = createMock(TemplateGeneratorBuilder.class);
+        TemplateGenerator generator = createMock(TemplateGenerator.class);
+
+        expect(builder.setClassesOutputDirectory(classesOutputDirectory)).andReturn(builder);
+        expect(builder.setResourcesOutputDirectory(resourcesOutputDirectory)).andReturn(builder);
+        expect(builder.addResourcesTemplateSuiteGenerator(isA(VelocityPropertiesGenerator.class))).andReturn(builder);
+        expect(builder.addClassesTemplateClassGenerator(isA(VelocityDirectiveGenerator.class))).andReturn(builder);
+        expect(builder.build()).andReturn(generator);
+
+        replay(classesOutputDirectory, resourcesOutputDirectory, velocityEngine, builder, generator);
+        VelocityTemplateGeneratorFactory factory = new VelocityTemplateGeneratorFactory(classesOutputDirectory,
+                resourcesOutputDirectory, velocityEngine, builder);
+        assertSame(generator, factory.createTemplateGenerator());
+        verify(classesOutputDirectory, resourcesOutputDirectory, velocityEngine, builder, generator);
+    }
+
+}
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/velocity/test/DoStuffDirective.javat b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/velocity/test/DoStuffDirective.javat
new file mode 100644
index 000000000..8ae29b34a
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/velocity/test/DoStuffDirective.javat
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+ /*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.autotag.velocity.test;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * Documentation of the DoStuff class.
+ */
+public class DoStuffDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.autotag.template.DoStuffTemplate model = new org.apache.tiles.autotag.template.DoStuffTemplate();
+
+    @Override
+    public String getName() {
+        return "tldtest_doStuff";
+    }
+
+    @Override
+    public int getType() {
+        return BLOCK;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node)
+            throws IOException {
+        AutotagRuntime<org.apache.tiles.autotag.velocity.Request> runtime = new org.apache.tiles.autotag.velocity.test.Runtime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.autotag.velocity.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(
+            runtime.getParameter("one", java.lang.String.class, null),
+            runtime.getParameter("two", java.lang.Integer.class, 0),
+            runtime.getParameter("three", java.lang.Boolean.class, false),
+            request, modelBody
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/velocity/test/DoStuffNoBodyDirective.javat b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/velocity/test/DoStuffNoBodyDirective.javat
new file mode 100644
index 000000000..6ed645a66
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/velocity/test/DoStuffNoBodyDirective.javat
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+ /*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.autotag.velocity.test;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * Documentation of the DoStuffNoBody class.
+ */
+public class DoStuffNoBodyDirective extends Directive {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.autotag.template.DoStuffNoBodyTemplate model = new org.apache.tiles.autotag.template.DoStuffNoBodyTemplate();
+
+    @Override
+    public String getName() {
+        return "tldtest_doStuffNoBody";
+    }
+
+    @Override
+    public int getType() {
+        return LINE;
+    }
+
+    @Override
+    public boolean render(InternalContextAdapter context, Writer writer, Node node)
+            throws IOException {
+        AutotagRuntime<org.apache.tiles.autotag.velocity.Request> runtime = new org.apache.tiles.autotag.velocity.test.Runtime();
+        if (runtime instanceof Directive) {
+            ((Directive) runtime).render(context, writer, node);
+        }
+        org.apache.tiles.autotag.velocity.Request request = runtime.createRequest();
+        model.execute(
+            runtime.getParameter("one", java.lang.Double.class, null),
+            runtime.getParameter("two", java.lang.Float.class, 0.0f),
+            runtime.getParameter("three", java.util.Date.class, null),
+            request
+        );
+        return true;
+    }
+}
diff --git a/plugins/tiles/src/test/resources/velocity.properties.test b/plugins/tiles/src/test/resources/velocity.properties.test
new file mode 100644
index 000000000..3ee9deeb8
--- /dev/null
+++ b/plugins/tiles/src/test/resources/velocity.properties.test
@@ -0,0 +1,21 @@
+# 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.
+#
+# This file was automatically generated by Autotag.  Please do not edit it manually.
+
+userdirective=org.apache.tiles.autotag.velocity.test.DoStuffDirective,\
+org.apache.tiles.autotag.velocity.test.DoStuffNoBodyDirective
\ No newline at end of file


[struts] 07/23: WW-5233 Copies Tiles Template related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 1d36a148b7bab12fe2ceb1c67a611d4282454027
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 13:41:49 2022 +0200

    WW-5233 Copies Tiles Template related tests
---
 .../tiles/template/AddAttributeModelTest.java      | 111 ++++++++
 .../tiles/template/AddListAttributeModelTest.java  |  86 ++++++
 .../tiles/template/ComposeStackUtilTest.java       | 123 ++++++++
 .../template/DefaultAttributeResolverTest.java     | 155 ++++++++++
 .../apache/tiles/template/DefinitionModelTest.java |  98 +++++++
 .../tiles/template/GetAsStringModelTest.java       | 140 +++++++++
 .../tiles/template/ImportAttributeModelTest.java   | 316 +++++++++++++++++++++
 .../tiles/template/InsertAttributeModelTest.java   | 131 +++++++++
 .../tiles/template/InsertDefinitionModelTest.java  |  90 ++++++
 .../tiles/template/InsertTemplateModelTest.java    |  89 ++++++
 .../tiles/template/PutAttributeModelTest.java      |  93 ++++++
 .../tiles/template/PutListAttributeModelTest.java  |  93 ++++++
 .../template/SetCurrentContainerModelTest.java     |  84 ++++++
 13 files changed, 1609 insertions(+)

diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/AddAttributeModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/AddAttributeModelTest.java
new file mode 100644
index 000000000..86da99995
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/AddAttributeModelTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link AddAttributeModel}.
+ */
+public class AddAttributeModelTest {
+
+    /**
+     * The model to test.
+     */
+    private AddAttributeModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new AddAttributeModel();
+    }
+
+    /**
+     * Test method for {@link AddAttributeModel
+     * #execute(java.lang.Object, java.lang.String, java.lang.String, java.lang.String,
+     * Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        Request request = createMock(Request.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+        Deque<Object> composeStack = new ArrayDeque<>();
+        ListAttribute listAttribute = new ListAttribute();
+        Attribute attribute;
+        composeStack.push(listAttribute);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+
+        expect(request.getContext("request")).andReturn(requestScope).times(2);
+        expect(modelBody.evaluateAsString()).andReturn(null);
+        expect(modelBody.evaluateAsString()).andReturn("myBody");
+
+        replay(request, modelBody);
+        model.execute("myValue", "myExpression", "myRole", "myType",
+            request, modelBody);
+        List<Attribute> attributes = listAttribute.getValue();
+        assertEquals(1, attributes.size());
+        attribute = attributes.iterator().next();
+        assertEquals("myValue", attribute.getValue());
+        assertEquals("myExpression", attribute.getExpressionObject().getExpression());
+        assertEquals("myRole", attribute.getRole());
+        assertEquals("myType", attribute.getRenderer());
+
+        composeStack.clear();
+        listAttribute = new ListAttribute();
+        attribute = new Attribute();
+        composeStack.push(listAttribute);
+        composeStack.push(attribute);
+
+        model.execute(null, "myExpression", "myRole", "myType", request,
+            modelBody);
+        attributes = listAttribute.getValue();
+        assertEquals(1, attributes.size());
+        attribute = attributes.iterator().next();
+        assertEquals("myBody", attribute.getValue());
+        assertEquals("myExpression", attribute.getExpressionObject()
+            .getExpression());
+        assertEquals("myRole", attribute.getRole());
+        assertEquals("myType", attribute.getRenderer());
+        verify(request, modelBody);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/AddListAttributeModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/AddListAttributeModelTest.java
new file mode 100644
index 000000000..3bdf11f5f
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/AddListAttributeModelTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link AddListAttributeModel}.
+ */
+public class AddListAttributeModelTest {
+
+    /**
+     * The model to test.
+     */
+    private AddListAttributeModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new AddListAttributeModel();
+    }
+
+    /**
+     * Test method for
+     * {@link AddListAttributeModel#execute(String, Request, ModelBody)}
+     * .
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        Deque<Object> composeStack = new ArrayDeque<>();
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request, modelBody);
+        ListAttribute parent = new ListAttribute();
+        composeStack.push(parent);
+        model.execute("myRole", request, modelBody);
+        assertEquals(1, composeStack.size());
+        assertEquals(parent, composeStack.pop());
+        assertEquals(1, parent.getValue().size());
+        ListAttribute listAttribute = (ListAttribute) parent.getValue().get(0);
+        assertEquals("myRole", listAttribute.getRole());
+        verify(request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/ComposeStackUtilTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/ComposeStackUtilTest.java
new file mode 100644
index 000000000..cdfbab26e
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/ComposeStackUtilTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import java.util.ArrayDeque;
+import java.util.Date;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests {@link ComposeStackUtil}.
+ */
+public class ComposeStackUtilTest {
+
+    /**
+     * An integer value.
+     */
+    private static final int INT_VALUE = 3;
+
+    /**
+     * A long value.
+     */
+    private static final long LONG_VALUE = 2L;
+
+    /**
+     * Test method for {@link ComposeStackUtil
+     * #findAncestorWithClass(java.util.Stack, java.lang.Class)}.
+     */
+    @Test
+    public void testFindAncestorWithClass() {
+        Deque<Object> composeStack = new ArrayDeque<>();
+        Integer integerValue = 1;
+        Long longValue = LONG_VALUE;
+        String stringValue = "my value";
+        Integer integerValue2 = INT_VALUE;
+        composeStack.push(integerValue);
+        composeStack.push(longValue);
+        composeStack.push(stringValue);
+        composeStack.push(integerValue2);
+        assertEquals(integerValue2, ComposeStackUtil.findAncestorWithClass(composeStack, Integer.class));
+        assertEquals(longValue, ComposeStackUtil.findAncestorWithClass(composeStack, Long.class));
+        assertEquals(stringValue, ComposeStackUtil.findAncestorWithClass(composeStack, String.class));
+        assertEquals(integerValue2, ComposeStackUtil.findAncestorWithClass(composeStack, Object.class));
+        assertNull(ComposeStackUtil.findAncestorWithClass(composeStack, Date.class));
+    }
+
+    /**
+     * Tests {@link ComposeStackUtil#getComposeStack(Request)}.
+     */
+    @Test
+    public void testGetComposeStackNull() {
+        Request request = createMock(Request.class);
+
+        Map<String, Object> requestScope = new HashMap<>();
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request);
+        assertSame(ComposeStackUtil.getComposeStack(request),
+            requestScope.get(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME));
+        verify(request);
+    }
+
+    /**
+     * Tests {@link ComposeStackUtil#getComposeStack(Request)}.
+     */
+    @Test
+    public void testGetComposeStackNotNull() {
+        Request request = createMock(Request.class);
+        Deque<Object> composeStack = createMock(Deque.class);
+
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request, composeStack);
+        assertSame(composeStack, ComposeStackUtil.getComposeStack(request));
+        verify(request, composeStack);
+    }
+
+    /**
+     * Tests {@link ComposeStackUtil#getComposeStack(Request)}.
+     */
+    @Test
+    public void testGetComposeStackNoNull() {
+        Request request = createMock(Request.class);
+
+        Map<String, Object> requestScope = new HashMap<>();
+        expect(request.getContext("request")).andReturn(requestScope);
+
+        replay(request);
+        assertSame(ComposeStackUtil.getComposeStack(request),
+            requestScope.get(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME));
+        verify(request);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/DefaultAttributeResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/DefaultAttributeResolverTest.java
new file mode 100644
index 000000000..ad51c1f70
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/DefaultAttributeResolverTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link DefaultAttributeResolver}.
+ */
+public class DefaultAttributeResolverTest {
+
+    /**
+     * The resolver to test.
+     */
+    private DefaultAttributeResolver resolver;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        resolver = new DefaultAttributeResolver();
+    }
+
+    /**
+     * Test method for {@link DefaultAttributeResolver
+     * #computeAttribute(org.apache.tiles.TilesContainer, org.apache.tiles.Attribute,
+     * java.lang.String, java.lang.String, boolean, java.lang.Object, java.lang.String,
+     * java.lang.String, Request)}.
+     */
+    @Test
+    public void testComputeAttributeInContext() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Request request = createMock(Request.class);
+        Attribute attribute = new Attribute("myValue", Expression.createExpression("myExpression", null), "myRole", "myRenderer");
+
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+
+        replay(container, attributeContext, request);
+        assertEquals(attribute, resolver.computeAttribute(container, null, "myName", null, false, null, null, null, request));
+        verify(container, attributeContext, request);
+    }
+
+    /**
+     * Test method for {@link DefaultAttributeResolver
+     * #computeAttribute(org.apache.tiles.TilesContainer, org.apache.tiles.Attribute,
+     * java.lang.String, java.lang.String, boolean, java.lang.Object, java.lang.String,
+     * java.lang.String, Request)}.
+     */
+    @Test
+    public void testComputeAttributeInCall() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        Attribute attribute = new Attribute("myValue", Expression.createExpression("myExpression", null), "myRole", "myRenderer");
+
+        replay(container, request);
+        assertEquals(attribute, resolver.computeAttribute(container, attribute, null, null, false, null, null, null, request));
+        verify(container, request);
+    }
+
+    /**
+     * Test method for {@link DefaultAttributeResolver
+     * #computeAttribute(org.apache.tiles.TilesContainer, org.apache.tiles.Attribute,
+     * java.lang.String, java.lang.String, boolean, java.lang.Object, java.lang.String,
+     * java.lang.String, Request)}.
+     */
+    @Test
+    public void testComputeAttributeDefault() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(null);
+
+        replay(container, attributeContext, request);
+        Attribute attribute = resolver.computeAttribute(container, null, "myName", null, false, "defaultValue", "defaultRole", "defaultType", request);
+        assertEquals("defaultValue", attribute.getValue());
+        assertEquals("defaultRole", attribute.getRole());
+        assertEquals("defaultType", attribute.getRenderer());
+        verify(container, attributeContext, request);
+    }
+
+    /**
+     * Test method for {@link DefaultAttributeResolver
+     * #computeAttribute(org.apache.tiles.TilesContainer, org.apache.tiles.Attribute,
+     * java.lang.String, java.lang.String, boolean, java.lang.Object, java.lang.String,
+     * java.lang.String, Request)}.
+     */
+    @Test(expected = NoSuchAttributeException.class)
+    public void testComputeAttributeException() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Request request = createMock(Request.class);
+
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(null);
+
+        replay(container, attributeContext, request);
+        resolver.computeAttribute(container, null, "myName", null, false, null, "defaultRole", "defaultType", request);
+        verify(container, attributeContext, request);
+    }
+
+    /**
+     * Test method for {@link DefaultAttributeResolver
+     * #computeAttribute(org.apache.tiles.TilesContainer, org.apache.tiles.Attribute,
+     * java.lang.String, java.lang.String, boolean, java.lang.Object, java.lang.String,
+     * java.lang.String, Request)}.
+     */
+    @Test
+    public void testComputeAttributeIgnore() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Request request = createMock(Request.class);
+
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(null);
+
+        replay(container, attributeContext, request);
+        assertNull(resolver.computeAttribute(container, null, "myName", null, true, null, "defaultRole", "defaultType", request));
+        verify(container, attributeContext, request);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/DefinitionModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/DefinitionModelTest.java
new file mode 100644
index 000000000..44511452f
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/DefinitionModelTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.api.mgmt.MutableTilesContainer;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.notNull;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests {@link DefinitionModel}.
+ */
+public class DefinitionModelTest {
+
+    /**
+     * The model to test.
+     */
+    private DefinitionModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new DefinitionModel();
+    }
+
+    /**
+     * Test method for {@link DefinitionModel
+     * #execute(java.lang.String, java.lang.String,
+     * java.lang.String, java.lang.String, java.lang.String, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        MutableTilesContainer container = createMock(MutableTilesContainer.class);
+        Request request = createMock(Request.class);
+        Deque<Object> composeStack = new ArrayDeque<>();
+        Attribute attribute = new Attribute();
+        composeStack.push(attribute);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        container.register(notNull(), eq(request));
+
+        replay(container, request, modelBody, applicationContext);
+        model.execute("myName", "myTemplate", "myRole", "myExtends",
+            "myPreparer", request, modelBody);
+        assertEquals(1, composeStack.size());
+        attribute = (Attribute) composeStack.peek();
+        assertNotNull(attribute);
+        assertEquals("definition", attribute.getRenderer());
+        verify(container, request, modelBody, applicationContext);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/GetAsStringModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/GetAsStringModelTest.java
new file mode 100644
index 000000000..8a8bbeee1
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/GetAsStringModelTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link GetAsStringModel}.
+ */
+public class GetAsStringModelTest {
+
+    /**
+     * The mock resolver.
+     */
+    private AttributeResolver resolver;
+
+    /**
+     * The model to test.
+     */
+    private GetAsStringModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        resolver = createMock(AttributeResolver.class);
+        model = new GetAsStringModel(resolver);
+    }
+
+    /**
+     * Test method for {@link GetAsStringModel
+     * #execute(boolean, java.lang.String, java.lang.String,
+     * java.lang.Object, java.lang.String, java.lang.String, java.lang.String,
+     * org.apache.tiles.Attribute, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        Attribute attribute = createMock(Attribute.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Request request = createMock(Request.class);
+        Writer writer = createMock(Writer.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        Deque<Object> composeStack = new ArrayDeque<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext).times(2);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(request.getWriter()).andReturn(writer);
+        container.prepare("myPreparer", request);
+        expect(resolver.computeAttribute(container, attribute, "myName", "myRole", false, "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", request)).andReturn(attribute);
+        expect(container.startContext(request)).andReturn(attributeContext);
+        expect(container.evaluate(attribute, request)).andReturn("myValue");
+        writer.write("myValue");
+        container.endContext(request);
+
+        replay(resolver, container, writer, request, applicationContext, modelBody);
+        model.execute(false, "myPreparer", "myRole", "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", "myName", attribute, request, modelBody);
+        verify(resolver, container, writer, request, applicationContext, modelBody);
+    }
+
+    /**
+     * Test method for {@link GetAsStringModel
+     * #execute(boolean, java.lang.String, java.lang.String,
+     * java.lang.Object, java.lang.String, java.lang.String, java.lang.String,
+     * org.apache.tiles.Attribute, Request, ModelBody)} when ignore flag is set.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecuteIgnore() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Request request = createMock(Request.class);
+        Writer writer = createMock(Writer.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        Deque<Object> composeStack = new ArrayDeque<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext).times(2);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(request.getWriter()).andReturn(writer);
+        container.prepare("myPreparer", request);
+        expect(resolver.computeAttribute(container, null, "myName", "myRole", true, "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", request)).andReturn(null);
+        expect(container.startContext(request)).andReturn(attributeContext);
+        container.endContext(request);
+
+        replay(resolver, container, writer, request, applicationContext, modelBody);
+        model.execute(true, "myPreparer", "myRole", "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", "myName", null, request, modelBody);
+        verify(resolver, container, writer, request, applicationContext, modelBody);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/ImportAttributeModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/ImportAttributeModelTest.java
new file mode 100644
index 000000000..73a10121e
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/ImportAttributeModelTest.java
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link ImportAttributeModel}.
+ */
+public class ImportAttributeModelTest {
+
+    /**
+     * The size of the attributes collection.
+     */
+    private static final int ATTRIBUTES_SIZE = 4;
+
+    /**
+     * The model to test.
+     */
+    private ImportAttributeModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new ImportAttributeModel();
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test
+    public void testExecuteSingle() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = new Attribute();
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+        expect(container.evaluate(attribute, request)).andReturn("myEvaluatedValue");
+
+        replay(container, attributeContext, request, applicationContext);
+        model.execute("myName", "request", null, false, request);
+        assertEquals(2, requestScope.size());
+        assertEquals("myEvaluatedValue", requestScope.get("myName"));
+        verify(container, attributeContext, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test
+    public void testExecuteSingleToName() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = new Attribute();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+        expect(container.evaluate(attribute, request)).andReturn("myEvaluatedValue");
+
+        replay(container, attributeContext, request, applicationContext);
+        model.execute("myName", "request", "myToName", false, request);
+        assertEquals(2, requestScope.size());
+        assertEquals("myEvaluatedValue", requestScope.get("myToName"));
+        verify(container, attributeContext, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test
+    public void testExecuteAll() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute1 = new Attribute("myValue1");
+        Attribute attribute2 = new Attribute("myValue2");
+        Attribute attribute3 = new Attribute("myValue3");
+        Set<String> cascadedNames = new HashSet<>();
+        cascadedNames.add("myName1");
+        cascadedNames.add("myName2");
+        Set<String> localNames = new HashSet<>();
+        localNames.add("myName1");
+        localNames.add("myName3");
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getCascadedAttributeNames()).andReturn(cascadedNames);
+        expect(attributeContext.getLocalAttributeNames()).andReturn(localNames);
+        expect(attributeContext.getAttribute("myName1")).andReturn(attribute1).times(2);
+        expect(attributeContext.getAttribute("myName2")).andReturn(attribute2);
+        expect(attributeContext.getAttribute("myName3")).andReturn(attribute3);
+        expect(container.evaluate(attribute1, request)).andReturn("myEvaluatedValue1").times(2);
+        expect(container.evaluate(attribute2, request)).andReturn("myEvaluatedValue2");
+        expect(container.evaluate(attribute3, request)).andReturn("myEvaluatedValue3");
+
+        replay(container, attributeContext, request, applicationContext);
+        model.execute(null, "request", null, false, request);
+        assertEquals(ATTRIBUTES_SIZE, requestScope.size());
+        assertEquals("myEvaluatedValue1", requestScope.get("myName1"));
+        assertEquals("myEvaluatedValue2", requestScope.get("myName2"));
+        assertEquals("myEvaluatedValue3", requestScope.get("myName3"));
+        verify(container, attributeContext, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test(expected = NoSuchAttributeException.class)
+    public void testExecuteSingleNullAttributeException() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(null);
+
+        replay(container, attributeContext, request, applicationContext);
+        try {
+            model.execute("myName", "request", null, false, request);
+        } finally {
+            verify(container, attributeContext, request, applicationContext);
+        }
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test(expected = NoSuchAttributeException.class)
+    public void testExecuteSingleNullAttributeValueException() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = new Attribute();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+        expect(container.evaluate(attribute, request)).andReturn(null);
+
+        replay(container, attributeContext, request, applicationContext);
+        try {
+            model.execute("myName", "request", null, false, request);
+        } finally {
+            verify(container, attributeContext, request, applicationContext);
+        }
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test(expected = RuntimeException.class)
+    public void testExecuteSingleRuntimeException() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = new Attribute();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+        expect(container.evaluate(attribute, request)).andThrow(new RuntimeException());
+
+        replay(container, attributeContext, request, applicationContext);
+        try {
+            model.execute("myName", "request", null, false, request);
+        } finally {
+            verify(container, attributeContext, request, applicationContext);
+        }
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test
+    public void testExecuteSingleNullAttributeIgnore() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(null);
+
+        replay(container, attributeContext, request, applicationContext);
+        model.execute("myName", "request", null, true, request);
+        verify(container, attributeContext, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test
+    public void testExecuteSingleNullAttributeValueIgnore() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = new Attribute();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+        expect(container.evaluate(attribute, request)).andReturn(null);
+
+        replay(container, attributeContext, request, applicationContext);
+        model.execute("myName", "request", null, true, request);
+        verify(container, attributeContext, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link ImportAttributeModel
+     * #execute(String, String, String, boolean, Request).
+     */
+    @Test
+    public void testExecuteSingleRuntimeIgnore() {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = new Attribute();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("myName")).andReturn(attribute);
+        expect(container.evaluate(attribute, request)).andThrow(new RuntimeException());
+
+        replay(container, attributeContext, request, applicationContext);
+        model.execute("myName", "request", null, true, request);
+        verify(container, attributeContext, request, applicationContext);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/InsertAttributeModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/InsertAttributeModelTest.java
new file mode 100644
index 000000000..e8a997ac0
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/InsertAttributeModelTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link InsertAttributeModel}.
+ */
+public class InsertAttributeModelTest {
+
+    /**
+     * The mock resolver.
+     */
+    private AttributeResolver resolver;
+
+    /**
+     * The model to test.
+     */
+    private InsertAttributeModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        resolver = createMock(AttributeResolver.class);
+        model = new InsertAttributeModel(resolver);
+    }
+
+    /**
+     * Test method for {@link InsertAttributeModel
+     * #execute(boolean, String, String, Object, String, String, String,
+     * Attribute, boolean, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        Attribute attribute = new Attribute("myValue");
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext).times(2);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+
+        container.prepare("myPreparer", request);
+        expect(resolver.computeAttribute(container, attribute, "myName", "myRole", false, "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", request)).andReturn(attribute);
+        expect(container.startContext(request)).andReturn(attributeContext);
+        container.endContext(request);
+        container.render(attribute, request);
+
+        replay(resolver, container, request, applicationContext, modelBody);
+        model.execute(false, "myPreparer", "myRole", "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", "myName", attribute, false, request, modelBody);
+        verify(resolver, container, request, applicationContext, modelBody);
+    }
+
+    /**
+     * Test method for {@link InsertAttributeModel
+     * #execute(boolean, String, String, Object, String, String, String,
+     * Attribute, boolean, Request, ModelBody)} when ignore flag is set.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecuteIgnore() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        Deque<Object> composeStack = new ArrayDeque<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext).times(2);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+
+        container.prepare("myPreparer", request);
+        expect(resolver.computeAttribute(container, null, "myName", "myRole", true, "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", request)).andReturn(null);
+        expect(container.startContext(request)).andReturn(attributeContext);
+        container.endContext(request);
+
+        replay(resolver, container, request, applicationContext, modelBody);
+        model.execute(true, "myPreparer", "myRole", "myDefaultValue", "myDefaultValueRole", "myDefaultValueType", "myName", null, false, request, modelBody);
+        verify(resolver, container, request, applicationContext, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/InsertDefinitionModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/InsertDefinitionModelTest.java
new file mode 100644
index 000000000..48d3fb492
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/InsertDefinitionModelTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.notNull;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link InsertDefinitionModel}.
+ */
+public class InsertDefinitionModelTest {
+
+    /**
+     * The model to test.
+     */
+    private InsertDefinitionModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new InsertDefinitionModel();
+    }
+
+    /**
+     * Test method for {@link InsertDefinitionModel
+     * #execute(java.lang.String, java.lang.String, String,
+     * String, java.lang.String, java.lang.String, boolean, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext).times(2);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.startContext(request)).andReturn(attributeContext);
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        container.endContext(request);
+        attributeContext.setPreparer("myPreparer");
+        attributeContext.setTemplateAttribute(notNull());
+        container.render("myDefinitionName", request);
+
+        replay(container, attributeContext, request, applicationContext, modelBody);
+        model.execute("myDefinitionName", "myTemplate", "myTemplateType", "myTemplateExpression", "myRole", "myPreparer", false, request, modelBody);
+        verify(container, attributeContext, request, applicationContext, modelBody);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/InsertTemplateModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/InsertTemplateModelTest.java
new file mode 100644
index 000000000..840593d7e
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/InsertTemplateModelTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.notNull;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link InsertTemplateModel}.
+ */
+public class InsertTemplateModelTest {
+
+    /**
+     * The model to test.
+     */
+    private InsertTemplateModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new InsertTemplateModel();
+    }
+
+    /**
+     * Test method for {@link InsertTemplateModel
+     * #execute(String, String, String, String, String, boolean, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext).times(2);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.startContext(request)).andReturn(attributeContext);
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        container.endContext(request);
+        attributeContext.setPreparer("myPreparer");
+        attributeContext.setTemplateAttribute(notNull());
+        container.renderContext(request);
+
+        replay(container, attributeContext, request, applicationContext, modelBody);
+        model.execute("myTemplate", "myTemplateType", "myTemplateExpression", "myRole", "myPreparer", false, request, modelBody);
+        verify(container, attributeContext, request, applicationContext, modelBody);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/PutAttributeModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/PutAttributeModelTest.java
new file mode 100644
index 000000000..572dcad59
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/PutAttributeModelTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.notNull;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link PutAttributeModel}.
+ */
+public class PutAttributeModelTest {
+
+    /**
+     * The model to test.
+     */
+    private PutAttributeModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new PutAttributeModel();
+    }
+
+    /**
+     * Test method for {@link PutAttributeModel
+     * #execute(String, Object, String, String, String,
+     * boolean, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecuteListAttribute() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        Request request = createMock(Request.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Deque<Object> composeStack = new ArrayDeque<>();
+        ListAttribute listAttribute = new ListAttribute();
+        composeStack.push(listAttribute);
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        attributeContext.putAttribute(eq("myName"), notNull(), eq(false));
+        expect(modelBody.evaluateAsString()).andReturn(null);
+
+        replay(container, attributeContext, request, applicationContext, modelBody);
+        model.execute("myName", "myValue", "myExpression", "myRole", "myType", false, request, modelBody);
+        verify(container, attributeContext, request, applicationContext, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/PutListAttributeModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/PutListAttributeModelTest.java
new file mode 100644
index 000000000..cd4708afc
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/PutListAttributeModelTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link PutListAttributeModel}.
+ */
+public class PutListAttributeModelTest {
+
+    /**
+     * The model to test.
+     */
+    private PutListAttributeModel model;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        model = new PutListAttributeModel();
+    }
+
+    /**
+     * Test method for {@link PutListAttributeModel
+     * #execute(String, String, boolean, boolean, Request, ModelBody)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testExecute() throws IOException {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Request request = createMock(Request.class);
+        Deque<Object> composeStack = new ArrayDeque<>();
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put(ComposeStackUtil.COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
+        requestScope.put(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ModelBody modelBody = createMock(ModelBody.class);
+
+        modelBody.evaluateWithoutWriting();
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+        expect(request.getContext("request")).andReturn(requestScope).anyTimes();
+        expect(container.getAttributeContext(request)).andReturn(attributeContext);
+        attributeContext.putAttribute(eq("myName"), isA(ListAttribute.class), eq(false));
+
+        replay(container, attributeContext, request, modelBody);
+        model.execute("myName", "myRole", false, false, request, modelBody);
+        assertEquals(0, composeStack.size());
+        verify(container, attributeContext, request, modelBody);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/template/SetCurrentContainerModelTest.java b/plugins/tiles/src/test/java/org/apache/tiles/template/SetCurrentContainerModelTest.java
new file mode 100644
index 000000000..2ecda504f
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/template/SetCurrentContainerModelTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.template;
+
+import org.apache.tiles.api.NoSuchContainerException;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link SetCurrentContainerModel}.
+ */
+public class SetCurrentContainerModelTest {
+
+    /**
+     * Test method for {@link SetCurrentContainerModel#execute(String, Request)}.
+     */
+    @Test
+    public void testSetCurrentContainer() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> attribs = new HashMap<>();
+        attribs.put("myKey", container);
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(request.getApplicationContext()).andReturn(context);
+        replay(request, context, container);
+        SetCurrentContainerModel model = new SetCurrentContainerModel();
+        model.execute("myKey", request);
+        assertEquals(container, requestScope.get(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME));
+        verify(request, context, container);
+    }
+
+    /**
+     * Test method for {@link SetCurrentContainerModel#execute(String, Request)}.
+     */
+    @Test(expected = NoSuchContainerException.class)
+    public void testSetCurrentContainerException() {
+        Request request = createMock(Request.class);
+        ApplicationContext context = createMock(ApplicationContext.class);
+        Map<String, Object> attribs = new HashMap<>();
+
+        expect(request.getApplicationContext()).andReturn(context);
+        expect(context.getApplicationScope()).andReturn(attribs).anyTimes();
+        replay(request, context);
+        try {
+            SetCurrentContainerModel model = new SetCurrentContainerModel();
+            model.execute("myKey", request);
+        } finally {
+            verify(request, context);
+        }
+    }
+
+}


[struts] 06/23: WW-5233 Copies Tiles OGNL related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit fe815e8795e3beb5fd499ffdc611572946c02fca
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 13:27:34 2022 +0200

    WW-5233 Copies Tiles OGNL related tests
---
 .../tiles/ognl/AnyScopePropertyAccessorTest.java   | 152 ++++++++++++++
 .../tiles/ognl/DelegatePropertyAccessorTest.java   | 111 ++++++++++
 .../NestedObjectDelegatePropertyAccessorTest.java  | 106 ++++++++++
 .../tiles/ognl/OGNLAttributeEvaluatorTest.java     | 229 +++++++++++++++++++++
 .../tiles/ognl/ScopePropertyAccessorTest.java      |  91 ++++++++
 ...pplicationContextNestedObjectExtractorTest.java |  51 +++++
 ...ContextPropertyAccessorDelegateFactoryTest.java | 189 +++++++++++++++++
 7 files changed, 929 insertions(+)

diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/AnyScopePropertyAccessorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/AnyScopePropertyAccessorTest.java
new file mode 100644
index 000000000..c7f3465cc
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/AnyScopePropertyAccessorTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.ognl;
+
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link AnyScopePropertyAccessor}.
+ */
+public class AnyScopePropertyAccessorTest {
+
+    /**
+     * The accessor to test.
+     */
+    private AnyScopePropertyAccessor accessor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        accessor = new AnyScopePropertyAccessor();
+    }
+
+    /**
+     * Test method for {@link AnyScopePropertyAccessor#getProperty(Map, Object, Object)}.
+     */
+    @Test
+    public void testGetProperty() {
+        Request request = createMock(Request.class);
+        Map<String, Object> oneScope = createMock(Map.class);
+        Map<String, Object> twoScope = createMock(Map.class);
+
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList("one", "two")).anyTimes();
+        expect(request.getContext("one")).andReturn(oneScope).anyTimes();
+        expect(request.getContext("two")).andReturn(twoScope).anyTimes();
+        expect(oneScope.containsKey("name1")).andReturn(true);
+        expect(oneScope.get("name1")).andReturn("value1");
+        expect(oneScope.containsKey("name2")).andReturn(false);
+        expect(oneScope.containsKey("name3")).andReturn(false);
+        expect(twoScope.containsKey("name2")).andReturn(true);
+        expect(twoScope.get("name2")).andReturn("value2");
+        expect(twoScope.containsKey("name3")).andReturn(false);
+
+        replay(request, oneScope, twoScope);
+        assertEquals("value1", accessor.getProperty(null, request, "name1"));
+        assertEquals("value2", accessor.getProperty(null, request, "name2"));
+        assertNull(accessor.getProperty(null, request, "name3"));
+        verify(request, oneScope, twoScope);
+    }
+
+    @Test
+    public void testGetSourceAccessor() {
+        Request request = createMock(Request.class);
+        Map<String, Object> oneScope = createMock(Map.class);
+        Map<String, Object> twoScope = createMock(Map.class);
+
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList("one", "two")).anyTimes();
+        expect(request.getContext("one")).andReturn(oneScope).anyTimes();
+        expect(request.getContext("two")).andReturn(twoScope).anyTimes();
+        expect(oneScope.containsKey("name1")).andReturn(true);
+        expect(oneScope.containsKey("name2")).andReturn(false);
+        expect(oneScope.containsKey("name3")).andReturn(false);
+        expect(twoScope.containsKey("name2")).andReturn(true);
+        expect(twoScope.containsKey("name3")).andReturn(false);
+
+        replay(request, oneScope, twoScope);
+        assertEquals(".getContext(\"one\").get(index)", accessor.getSourceAccessor(null, request, "name1"));
+        assertEquals(".getContext(\"two\").get(index)", accessor.getSourceAccessor(null, request, "name2"));
+        assertNull(accessor.getSourceAccessor(null, request, "name3"));
+        verify(request, oneScope, twoScope);
+    }
+
+    @Test
+    public void testGetSourceSetter() {
+        Request request = createMock(Request.class);
+        Map<String, Object> oneScope = createMock(Map.class);
+        Map<String, Object> twoScope = createMock(Map.class);
+
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList("one", "two")).anyTimes();
+        expect(request.getContext("one")).andReturn(oneScope).anyTimes();
+        expect(request.getContext("two")).andReturn(twoScope).anyTimes();
+        expect(oneScope.containsKey("name1")).andReturn(true);
+        expect(oneScope.containsKey("name2")).andReturn(false);
+        expect(oneScope.containsKey("name3")).andReturn(false);
+        expect(twoScope.containsKey("name2")).andReturn(true);
+        expect(twoScope.containsKey("name3")).andReturn(false);
+
+        replay(request, oneScope, twoScope);
+        assertEquals(".getContext(\"one\").put(index, target)", accessor.getSourceSetter(null, request, "name1"));
+        assertEquals(".getContext(\"two\").put(index, target)", accessor.getSourceSetter(null, request, "name2"));
+        assertEquals(".getContext(\"one\").put(index, target)", accessor.getSourceSetter(null, request, "name3"));
+        verify(request, oneScope, twoScope);
+    }
+
+    /**
+     * Test method for {@link AnyScopePropertyAccessor#setProperty(Map, Object, Object, Object)}.
+     */
+    @Test
+    public void testSetProperty() {
+        Request request = createMock(Request.class);
+        Map<String, Object> oneScope = createMock(Map.class);
+        Map<String, Object> twoScope = createMock(Map.class);
+
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList("one", "two")).anyTimes();
+        expect(request.getContext("one")).andReturn(oneScope).anyTimes();
+        expect(request.getContext("two")).andReturn(twoScope).anyTimes();
+        expect(oneScope.containsKey("name1")).andReturn(true);
+        expect(oneScope.put("name1", "otherValue1")).andReturn("value1");
+        expect(oneScope.containsKey("name2")).andReturn(false);
+        expect(oneScope.containsKey("name3")).andReturn(false);
+        expect(twoScope.containsKey("name2")).andReturn(true);
+        expect(twoScope.put("name2", "otherValue2")).andReturn("value2");
+        expect(twoScope.containsKey("name3")).andReturn(false);
+        expect(oneScope.put("name3", "otherValue3")).andReturn(null);
+
+        replay(request, oneScope, twoScope);
+        accessor.setProperty(null, request, "name1", "otherValue1");
+        accessor.setProperty(null, request, "name2", "otherValue2");
+        accessor.setProperty(null, request, "name3", "otherValue3");
+        verify(request, oneScope, twoScope);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/DelegatePropertyAccessorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/DelegatePropertyAccessorTest.java
new file mode 100644
index 000000000..fc5470d74
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/DelegatePropertyAccessorTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.ognl;
+
+import ognl.OgnlContext;
+import ognl.OgnlException;
+import ognl.PropertyAccessor;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link DelegatePropertyAccessor}.
+ */
+public class DelegatePropertyAccessorTest {
+
+    /**
+     * Test method for {@link DelegatePropertyAccessor#getProperty(Map, Object, Object)}.
+     *
+     * @throws OgnlException If something goes wrong.
+     */
+    @Test
+    public void testGetProperty() throws OgnlException {
+        PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
+        PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
+        Map<String, Object> context = createMock(Map.class);
+        expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
+        expect(mockAccessor.getProperty(context, 1, "property")).andReturn("value");
+
+        replay(factory, mockAccessor, context);
+        PropertyAccessor accessor = new DelegatePropertyAccessor<>(factory);
+        assertEquals("value", accessor.getProperty(context, 1, "property"));
+        verify(factory, mockAccessor, context);
+    }
+
+    /**
+     * Test method for {@link DelegatePropertyAccessor#setProperty(Map, Object, Object, Object)}.
+     *
+     * @throws OgnlException If something goes wrong.
+     */
+    @Test
+    public void testSetProperty() throws OgnlException {
+        PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
+        PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
+        Map<String, Object> context = createMock(Map.class);
+        expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
+        mockAccessor.setProperty(context, 1, "property", "value");
+
+        replay(factory, mockAccessor, context);
+        PropertyAccessor accessor = new DelegatePropertyAccessor<>(factory);
+        accessor.setProperty(context, 1, "property", "value");
+        verify(factory, mockAccessor, context);
+    }
+
+    /**
+     * Test method for {@link DelegatePropertyAccessor#getSourceAccessor(OgnlContext, Object, Object)}.
+     */
+    @Test
+    public void testGetSourceAccessor() {
+        PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
+        PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
+        OgnlContext context = createMock(OgnlContext.class);
+        expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
+        expect(mockAccessor.getSourceAccessor(context, 1, "property")).andReturn("method");
+
+        replay(factory, mockAccessor, context);
+        PropertyAccessor accessor = new DelegatePropertyAccessor<>(factory);
+        assertEquals("method", accessor.getSourceAccessor(context, 1, "property"));
+        verify(factory, mockAccessor, context);
+    }
+
+    /**
+     * Test method for {@link DelegatePropertyAccessor#getSourceSetter(OgnlContext, Object, Object)}.
+     */
+    @Test
+    public void testGetSourceSetter() {
+        PropertyAccessorDelegateFactory<Integer> factory = createMock(PropertyAccessorDelegateFactory.class);
+        PropertyAccessor mockAccessor = createMock(PropertyAccessor.class);
+        OgnlContext context = createMock(OgnlContext.class);
+        expect(factory.getPropertyAccessor("property", 1)).andReturn(mockAccessor);
+        expect(mockAccessor.getSourceSetter(context, 1, "property")).andReturn("method");
+
+        replay(factory, mockAccessor, context);
+        PropertyAccessor accessor = new DelegatePropertyAccessor<>(factory);
+        assertEquals("method", accessor.getSourceSetter(context, 1, "property"));
+        verify(factory, mockAccessor, context);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessorTest.java
new file mode 100644
index 000000000..0425d3c1c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessorTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.ognl;
+
+import ognl.OgnlContext;
+import ognl.OgnlException;
+import ognl.PropertyAccessor;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link NestedObjectDelegatePropertyAccessor}.
+ */
+public class NestedObjectDelegatePropertyAccessorTest {
+
+    /**
+     * Test method for {@link NestedObjectDelegatePropertyAccessor#getProperty(Map, Object, Object)}.
+     * @throws OgnlException If something goes wrong.
+     */
+    @Test
+    public void testGetProperty() throws OgnlException {
+        NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
+        PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
+        Map<String, Object> context = createMock(Map.class);
+        expect(propertyAccessor.getProperty(context, "nested", "property")).andReturn("value");
+        expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
+
+        replay(nestedObjectExtractor, propertyAccessor, context);
+        PropertyAccessor accessor = new NestedObjectDelegatePropertyAccessor<>(nestedObjectExtractor, propertyAccessor);
+        assertEquals("value", accessor.getProperty(context, 1, "property"));
+        verify(nestedObjectExtractor, propertyAccessor, context);
+    }
+
+    /**
+     * Test method for {@link NestedObjectDelegatePropertyAccessor#setProperty(Map, Object, Object, Object)}.
+     * @throws OgnlException If something goes wrong.
+     */
+    @Test
+    public void testSetProperty() throws OgnlException {
+        NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
+        PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
+        Map<String, Object> context = createMock(Map.class);
+        propertyAccessor.setProperty(context, "nested", "property", "value");
+        expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
+
+        replay(nestedObjectExtractor, propertyAccessor, context);
+        PropertyAccessor accessor = new NestedObjectDelegatePropertyAccessor<>(nestedObjectExtractor, propertyAccessor);
+        accessor.setProperty(context, 1, "property", "value");
+        verify(nestedObjectExtractor, propertyAccessor, context);
+    }
+
+    /**
+     * Test method for {@link NestedObjectDelegatePropertyAccessor#getSourceAccessor(OgnlContext, Object, Object)}.
+     */
+    @Test
+    public void testGetSourceAccessor() {
+        NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
+        PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
+        OgnlContext context = createMock(OgnlContext.class);
+        expect(propertyAccessor.getSourceAccessor(context, "nested", "property")).andReturn("method");
+        expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
+
+        replay(nestedObjectExtractor, propertyAccessor, context);
+        PropertyAccessor accessor = new NestedObjectDelegatePropertyAccessor<>(nestedObjectExtractor, propertyAccessor);
+        assertEquals("method", accessor.getSourceAccessor(context, 1, "property"));
+        verify(nestedObjectExtractor, propertyAccessor, context);
+    }
+
+    /**
+     * Test method for {@link NestedObjectDelegatePropertyAccessor#getSourceSetter(OgnlContext, Object, Object)}.
+     */
+    @Test
+    public void testGetSourceSetter() {
+        NestedObjectExtractor<Integer> nestedObjectExtractor = createMock(NestedObjectExtractor.class);
+        PropertyAccessor propertyAccessor = createMock(PropertyAccessor.class);
+        OgnlContext context = createMock(OgnlContext.class);
+        expect(propertyAccessor.getSourceSetter(context, "nested", "property")).andReturn("method");
+        expect(nestedObjectExtractor.getNestedObject(1)).andReturn("nested");
+
+        replay(nestedObjectExtractor, propertyAccessor, context);
+        PropertyAccessor accessor = new NestedObjectDelegatePropertyAccessor<>(nestedObjectExtractor, propertyAccessor);
+        assertEquals("method", accessor.getSourceSetter(context, 1, "property"));
+        verify(nestedObjectExtractor, propertyAccessor, context);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/OGNLAttributeEvaluatorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/OGNLAttributeEvaluatorTest.java
new file mode 100644
index 000000000..fbfe2081b
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/OGNLAttributeEvaluatorTest.java
@@ -0,0 +1,229 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.ognl;
+
+import ognl.OgnlException;
+import ognl.OgnlRuntime;
+import ognl.PropertyAccessor;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.core.evaluator.EvaluationException;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link OGNLAttributeEvaluator}.
+ *
+ * @version $Rev$ $Date$$
+ */
+public class OGNLAttributeEvaluatorTest {
+
+    /**
+     * The evaluator to test.
+     */
+    private OGNLAttributeEvaluator evaluator;
+
+    /**
+     * The request object to use.
+     */
+    private Request request;
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * Sets up the test.
+     *
+     * @throws OgnlException If something goes wrong.
+     */
+    @Before
+    public void setUp() throws OgnlException {
+        PropertyAccessor objectPropertyAccessor = OgnlRuntime.getPropertyAccessor(Object.class);
+        PropertyAccessor applicationContextPropertyAccessor = new NestedObjectDelegatePropertyAccessor<>(
+            new TilesApplicationContextNestedObjectExtractor(),
+            objectPropertyAccessor
+        );
+        PropertyAccessor anyScopePropertyAccessor = new AnyScopePropertyAccessor();
+        PropertyAccessor scopePropertyAccessor = new ScopePropertyAccessor();
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor,
+            applicationContextPropertyAccessor,
+            anyScopePropertyAccessor,
+            scopePropertyAccessor
+        );
+        PropertyAccessor tilesRequestAccessor = new DelegatePropertyAccessor<>(factory);
+        OgnlRuntime.setPropertyAccessor(Request.class, tilesRequestAccessor);
+        evaluator = new OGNLAttributeEvaluator();
+        Map<String, Object> requestScope = new HashMap<>();
+        Map<String, Object> sessionScope = new HashMap<>();
+        Map<String, Object> applicationScope = new HashMap<>();
+        requestScope.put("object1", "value");
+        sessionScope.put("object2", 1);
+        applicationScope.put("object3", 2.0F);
+        requestScope.put("paulaBean", new PaulaBean());
+        request = createMock(Request.class);
+        expect(request.getContext("request")).andReturn(requestScope)
+            .anyTimes();
+        expect(request.getContext("session")).andReturn(sessionScope)
+            .anyTimes();
+        expect(request.getContext("application")).andReturn(applicationScope)
+            .anyTimes();
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList("request", "session", "application"))
+            .anyTimes();
+        applicationContext = createMock(ApplicationContext.class);
+        expect(request.getApplicationContext()).andReturn(applicationContext)
+            .anyTimes();
+        expect(applicationContext.getApplicationScope()).andReturn(applicationScope)
+            .anyTimes();
+        replay(request, applicationContext);
+    }
+
+    /**
+     * Tears down the test.
+     */
+    @After
+    public void tearDown() {
+        verify(request, applicationContext);
+    }
+
+    /**
+     * Tests
+     * {@link OGNLAttributeEvaluator#evaluate(Attribute, Request)}.
+     */
+    @Test
+    public void testEvaluate() {
+        Attribute attribute = new Attribute();
+        attribute.setExpressionObject(new Expression("requestScope.object1"));
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+            attribute, request));
+        attribute.setExpressionObject(new Expression("sessionScope.object2"));
+        assertEquals("The value is not correct", 1, evaluator
+            .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("applicationScope.object3"));
+        assertEquals("The value is not correct", 2.0F, evaluator
+            .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("object1"));
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+            attribute, request));
+        attribute.setExpressionObject(new Expression("object2"));
+        assertEquals("The value is not correct", 1, evaluator
+            .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("object3"));
+        assertEquals("The value is not correct", 2.0F, evaluator
+            .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("paulaBean.paula"));
+        assertEquals("The value is not correct", "Brillant", evaluator
+            .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("'String literal'"));
+        assertEquals("The value is not correct", "String literal", evaluator
+            .evaluate(attribute, request));
+        attribute.setValue(2);
+        assertEquals("The value is not correct", 2, evaluator
+            .evaluate(attribute, request));
+        attribute.setValue("object1");
+        assertEquals("The value has been evaluated", "object1", evaluator
+            .evaluate(attribute, request));
+    }
+
+    /**
+     * Tests {@link OGNLAttributeEvaluator#evaluate(String, Request)}.
+     */
+    @Test
+    public void testEvaluateString() {
+        String expression = "requestScope.object1";
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+            expression, request));
+        expression = "sessionScope.object2";
+        assertEquals("The value is not correct", 1, evaluator
+            .evaluate(expression, request));
+        expression = "applicationScope.object3";
+        assertEquals("The value is not correct", 2.0F, evaluator
+            .evaluate(expression, request));
+        expression = "object1";
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+            expression, request));
+        expression = "object2";
+        assertEquals("The value is not correct", 1, evaluator
+            .evaluate(expression, request));
+        expression = "object3";
+        assertEquals("The value is not correct", 2.0F, evaluator
+            .evaluate(expression, request));
+        expression = "paulaBean.paula";
+        assertEquals("The value is not correct", "Brillant", evaluator
+            .evaluate(expression, request));
+        expression = "'String literal'";
+        assertEquals("The value is not correct", "String literal", evaluator
+            .evaluate(expression, request));
+    }
+
+    /**
+     * Tests {@link OGNLAttributeEvaluator#evaluate(String, Request)}.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testEvaluateNull() {
+        evaluator.evaluate((String) null, request);
+    }
+
+    /**
+     * Tests {@link OGNLAttributeEvaluator#evaluate(String, Request)}.
+     */
+    @Test(expected = EvaluationException.class)
+    public void testEvaluateOgnlException() {
+        evaluator.evaluate("wrong|||!!!!yes###", request);
+    }
+
+    /**
+     * This is The Brillant Paula Bean (sic) just like it was posted to:
+     * http://thedailywtf.com/Articles/The_Brillant_Paula_Bean.aspx I hope that
+     * there is no copyright on it.
+     */
+    public static class PaulaBean {
+
+        /**
+         * Paula is brillant, really.
+         */
+        private final String paula = "Brillant";
+
+        /**
+         * Returns brillant.
+         *
+         * @return "Brillant".
+         */
+        public String getPaula() {
+            return paula;
+        }
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/ScopePropertyAccessorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/ScopePropertyAccessorTest.java
new file mode 100644
index 000000000..86b29449c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/ScopePropertyAccessorTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.ognl;
+
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link ScopePropertyAccessor}.
+ */
+public class ScopePropertyAccessorTest {
+
+    /**
+     * The accessor to test.
+     */
+    private ScopePropertyAccessor accessor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        accessor = new ScopePropertyAccessor();
+    }
+
+    /**
+     * Test method for {@link ScopePropertyAccessor#getProperty(Map, Object, Object)}.
+     */
+    @Test
+    public void testGetProperty() {
+        Request request = createMock(Request.class);
+        Map<String, Object> oneScope = createMock(Map.class);
+
+        expect(request.getContext("one")).andReturn(oneScope);
+
+        replay(request);
+        assertEquals(oneScope, accessor.getProperty(null, request, "oneScope"));
+        assertNull(accessor.getProperty(null, request, "whatever"));
+        verify(request);
+    }
+
+    @Test
+    public void testGetSourceAccessor() {
+        Request request = createMock(Request.class);
+
+        replay(request);
+        assertEquals(".getContext(\"one\")", accessor.getSourceAccessor(null, request, "oneScope"));
+        assertNull(accessor.getSourceAccessor(null, request, "whatever"));
+        verify(request);
+    }
+
+    @Test
+    public void testGetSourceSetter() {
+        assertNull(accessor.getSourceSetter(null, null, "whatever"));
+    }
+
+    /**
+     * Test method for {@link ScopePropertyAccessor#setProperty(Map, Object, Object, Object)}.
+     */
+    @Test
+    public void testSetProperty() {
+        accessor.setProperty(null, null, "whatever", "whateverValue");
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractorTest.java
new file mode 100644
index 000000000..b791a646c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractorTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.ognl;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link TilesApplicationContextNestedObjectExtractor}.
+ */
+public class TilesApplicationContextNestedObjectExtractorTest {
+
+    /**
+     * Tests {@link TilesApplicationContextNestedObjectExtractor#getNestedObject(Request)}.
+     */
+    @Test
+    public void testGetNestedObject() {
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(request.getApplicationContext()).andReturn(applicationContext);
+
+        replay(request, applicationContext);
+        NestedObjectExtractor<Request> extractor = new TilesApplicationContextNestedObjectExtractor();
+        assertEquals(applicationContext, extractor.getNestedObject(request));
+        verify(request, applicationContext);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactoryTest.java
new file mode 100644
index 000000000..8a70ae220
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactoryTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.ognl;
+
+import ognl.PropertyAccessor;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link TilesContextPropertyAccessorDelegateFactory}.
+ */
+public class TilesContextPropertyAccessorDelegateFactoryTest {
+
+    /**
+     * Test method for
+     * {@link TilesContextPropertyAccessorDelegateFactory#getPropertyAccessor(String, Request)}
+     * .
+     */
+    @Test
+    public void testGetPropertyAccessorRequest() {
+        PropertyAccessor objectPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationContextPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor requestScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor sessionScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationScopePropertyAccessor = createMock(PropertyAccessor.class);
+        Request request = createMock(Request.class);
+
+        replay(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor, applicationContextPropertyAccessor,
+            requestScopePropertyAccessor, sessionScopePropertyAccessor);
+        assertEquals(objectPropertyAccessor, factory.getPropertyAccessor("writer", request));
+
+        verify(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextPropertyAccessorDelegateFactory#getPropertyAccessor(String, Request)}
+     * .
+     */
+    @Test
+    public void testGetPropertyAccessorApplication() {
+        PropertyAccessor objectPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationContextPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor requestScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor sessionScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationScopePropertyAccessor = createMock(PropertyAccessor.class);
+        Request request = createMock(Request.class);
+
+        replay(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor, applicationContextPropertyAccessor,
+            requestScopePropertyAccessor, sessionScopePropertyAccessor);
+        assertEquals(applicationContextPropertyAccessor, factory.getPropertyAccessor("initParams", request));
+
+        verify(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextPropertyAccessorDelegateFactory#getPropertyAccessor(String, Request)}
+     * .
+     */
+    @Test
+    public void testGetPropertyAccessorRequestScope() {
+        PropertyAccessor objectPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationContextPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor requestScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor sessionScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationScopePropertyAccessor = createMock(PropertyAccessor.class);
+        Request request = createMock(Request.class);
+
+        replay(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor, applicationContextPropertyAccessor,
+            requestScopePropertyAccessor, sessionScopePropertyAccessor);
+        assertEquals(requestScopePropertyAccessor, factory.getPropertyAccessor("attribute", request));
+
+        verify(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextPropertyAccessorDelegateFactory#getPropertyAccessor(String, Request)}
+     * .
+     */
+    @Test
+    public void testGetPropertyAccessorSessionScope() {
+        PropertyAccessor objectPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationContextPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor requestScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor sessionScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationScopePropertyAccessor = createMock(PropertyAccessor.class);
+        Request request = createMock(Request.class);
+
+        replay(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor, applicationContextPropertyAccessor,
+            requestScopePropertyAccessor, sessionScopePropertyAccessor);
+        assertEquals(requestScopePropertyAccessor, factory.getPropertyAccessor("attribute", request));
+
+        verify(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextPropertyAccessorDelegateFactory#getPropertyAccessor(String, Request)}
+     * .
+     */
+    @Test
+    public void testGetPropertyAccessorApplicationScope() {
+        PropertyAccessor objectPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationContextPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor requestScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor sessionScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationScopePropertyAccessor = createMock(PropertyAccessor.class);
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        replay(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request, applicationContext);
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor, applicationContextPropertyAccessor,
+            requestScopePropertyAccessor, sessionScopePropertyAccessor);
+        assertEquals(requestScopePropertyAccessor, factory.getPropertyAccessor("attribute", request));
+
+        verify(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request, applicationContext);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextPropertyAccessorDelegateFactory#getPropertyAccessor(String, Request)}
+     * .
+     */
+    @Test
+    public void testGetPropertyAccessorRequestScopeDefault() {
+        PropertyAccessor objectPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationContextPropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor requestScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor sessionScopePropertyAccessor = createMock(PropertyAccessor.class);
+        PropertyAccessor applicationScopePropertyAccessor = createMock(PropertyAccessor.class);
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        replay(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request, applicationContext);
+        PropertyAccessorDelegateFactory<Request> factory = new TilesContextPropertyAccessorDelegateFactory(
+            objectPropertyAccessor, applicationContextPropertyAccessor,
+            requestScopePropertyAccessor, sessionScopePropertyAccessor);
+        assertEquals(requestScopePropertyAccessor, factory.getPropertyAccessor("attribute", request));
+
+        verify(objectPropertyAccessor, applicationContextPropertyAccessor, requestScopePropertyAccessor,
+            sessionScopePropertyAccessor, applicationScopePropertyAccessor, request, applicationContext);
+    }
+
+}


[struts] 17/23: WW-5233 Adds Tiles DTD definition

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit add505a3bafb5b221ed96437abb6dcb4514eaf53
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Oct 3 10:58:02 2022 +0200

    WW-5233 Adds Tiles DTD definition
---
 .../apache/tiles/resources/tiles-config_3_0.dtd    | 245 +++++++++++++++++++++
 1 file changed, 245 insertions(+)

diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/resources/tiles-config_3_0.dtd b/plugins/tiles/src/main/resources/org/apache/tiles/resources/tiles-config_3_0.dtd
new file mode 100644
index 000000000..dab8d7857
--- /dev/null
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/resources/tiles-config_3_0.dtd
@@ -0,0 +1,245 @@
+<!--
+%
+
+   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.
+
+%
+
+@hidden $Id$
+@title DTD for the Tiles Definition File, Version 3.0
+@doctype tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd"
+@root tiles-definitions
+-->
+
+
+<!-- ========== Defined Types ============================================= -->
+
+
+<!-- A "Boolean" is the string representation of a boolean (true or false)
+     variable.
+-->
+<!ENTITY % Boolean "(true|false)">
+
+
+<!-- A "ContentType" is the content type of attribute passed to a template.
+-->
+<!ENTITY % ContentType "CDATA">
+
+<!-- A "ClassName" is the fully qualified name of a Java class which is
+     instantiated to provide the functionality of the enclosing element.
+-->
+<!ENTITY % ClassName "CDATA">
+
+<!-- A "RequestPath" is a module-relative URI path, beginning with a
+     slash, that identifies a mapped resource (such as a JSP page or a servlet)
+     within this web application.
+-->
+<!ENTITY % RequestPath "CDATA">
+
+<!-- A "DefinitionName" is the unique identifier of a definition. This identifier
+     is a logical name used to reference the definition.
+-->
+<!ENTITY % DefinitionName "CDATA">
+
+<!-- A "Location" is a relative path, delimited by "/" characters, that
+     defines the location of a resource relative to the location of the
+     configuration file itself.
+-->
+<!ENTITY % Location "#PCDATA">
+
+
+
+<!-- ========== Top Level Elements ======================================== -->
+
+
+<!-- The "tiles-definitions" element is the root of the configuration file
+     hierarchy, and contains nested elements for all the other
+     configuration settings.
+-->
+<!ELEMENT tiles-definitions (definition+)>
+
+<!-- The "definition" element describes a definition that can be inserted in a jsp
+     page. This definition is identified by its logical name. A definition allows
+     to define all the attributes that can be set in <insert> tag from a jsp page.
+-->
+<!ELEMENT definition (put-attribute*, put-list-attribute*)>
+<!ATTLIST definition       id               ID               #IMPLIED>
+<!--
+@attr preparer       The fully qualified Java class name of the preparer
+                     subclass to call immediately before the tiles is inserted.
+                     Only one of preparerClass or preparerUrl should be
+                     specified.
+-->
+<!ATTLIST definition       preparer         %ClassName;      #IMPLIED>
+<!--
+@attr extends        Name of a definition that is used as ancestor of this definition.
+                     All attributes from the ancestor are available to the new
+                     definition. Any attribute inherited from the ancestor can
+                     be overloaded by providing a new value.
+-->
+<!ATTLIST definition       extends          %DefinitionName; #IMPLIED>
+<!--
+@attr name           The unique identifier for this definition. Required when
+                     it is a root definition, while it is implied in nested
+                     definitions.
+-->
+<!ATTLIST definition       name             %DefinitionName; #IMPLIED>
+<!--
+@attr role           Security role name that is allowed access to this definition
+                     object. The definition is inserted only if the role name is
+                     allowed.
+-->
+<!ATTLIST definition       role             CDATA            #IMPLIED>
+<!--
+@attr template       The context-relative path to the resource used as tiles to
+                     insert. This tiles will be inserted and a tiles context
+                     containing appropriate attributes will be available.
+-->
+<!ATTLIST definition       template         %RequestPath;    #IMPLIED>
+<!--
+@attr templateExpression The expression that will evaluate to a template for this definition.
+               This attribute will be ignored if template is specified.
+
+-->
+<!ATTLIST definition       templateExpression       CDATA    #IMPLIED>
+<!--
+@attr templateType   The type of the template attribute. Can be: string,
+           template or definition.
+                     By default, the type is "template". If a type is
+                     associated, the desired renderer will be invoked.
+-->
+<!ATTLIST definition       templateType             %ContentType;   #IMPLIED>
+
+<!-- The "put-attribute" element describes an attribute of a definition. It allows to
+     specify the tiles attribute name and its value. The tiles value can be
+     specified as a xml attribute, or in the body of the <put-attribute> tag.
+-->
+<!ELEMENT put-attribute ( (definition*) )>
+<!ATTLIST put-attribute     id               ID              #IMPLIED>
+<!--
+@attr name           The unique identifier for this put-attribute.
+-->
+<!ATTLIST put-attribute     name             CDATA           #REQUIRED>
+<!--
+@attr type           The type of the value. Can be: string, template or definition.
+                     By default, no type is associated to a value. If a type is
+                     associated, it will be used as a hint to process the value
+                     when the attribute will be used in the inserted tiles.
+-->
+<!ATTLIST put-attribute     type             %ContentType;   #IMPLIED>
+<!--
+@attr value          The value associated to this tiles attribute. The value should
+                     be specified with this tag attribute, or in the body of the tag.
+-->
+<!ATTLIST put-attribute     value            CDATA           #IMPLIED>
+<!--
+@attr expression     The expression associated to this tiles attribute. This
+           attribute will be ignored if value is specified.
+
+-->
+<!ATTLIST put-attribute     expression       CDATA           #IMPLIED>
+<!--
+@attr role           Security role name that is allowed access to this attribute
+                     object. The attribute is inserted only if the role name is
+                     allowed.
+-->
+<!ATTLIST put-attribute     role             CDATA            #IMPLIED>
+<!--
+@attr cascade        If true, the attribute will be cascaded to all inner
+                     definitions. By default, cascade is false.
+-->
+<!ATTLIST put-attribute     cascade          %Boolean;    #IMPLIED>
+
+
+<!-- The "put-list-attribute" element describes a list attribute of a definition. It allows to
+     specify an attribute that is a java List containing any kind of values. In
+     the config file, the list elements are specified by nested <add-attribute> or
+     <add-list-attribute>.
+-->
+<!ELEMENT put-list-attribute ( (add-attribute* | add-list-attribute*)+) >
+<!ATTLIST put-list-attribute id               ID              #IMPLIED>
+<!--
+@attr name           The unique identifier for this put attribute list.
+-->
+<!ATTLIST put-list-attribute name             CDATA           #REQUIRED>
+<!--
+@attr role           Security role name that is allowed access to this attribute
+                     object. The attribute is inserted only if the role name is
+                     allowed.
+-->
+<!ATTLIST put-list-attribute role             CDATA            #IMPLIED>
+<!--
+@attr inherit        If true, the attribute will put the elements of the attribute
+                     with the same name of the parent definition before the ones
+                     specified here. By default, it is 'false'.
+-->
+<!ATTLIST put-list-attribute inherit          %Boolean;        #IMPLIED>
+<!--
+@attr cascade        If true, the attribute will be cascaded to all inner
+                     definitions. By default, cascade is false.
+-->
+<!ATTLIST put-list-attribute cascade          %Boolean;        #IMPLIED>
+
+<!-- ========== Subordinate Elements ====================================== -->
+
+
+<!-- The "add-attribute" element describes an element of a list. It is similar to the
+     <put> element.
+-->
+<!ELEMENT add-attribute ( (definition*) )>
+<!ATTLIST add-attribute              id               ID              #IMPLIED>
+<!--
+@attr type           The type of the value. Can be: string, template or definition.
+                     By default, no type is associated to a value. If a type is
+                     associated, it will be used as a hint to process the value
+                     when the attribute will be used in the inserted tiles.
+-->
+<!ATTLIST add-attribute              type             %ContentType;   #IMPLIED>
+<!--
+@attr value          The value associated to this tiles attribute. The value should
+                     be specified with this tag attribute, or in the body of the tag.
+-->
+<!ATTLIST add-attribute              value            CDATA           #IMPLIED>
+<!--
+@attr expression     The expression associated to this tiles attribute. This
+           attribute will be ignored if value is specified.
+
+-->
+<!ATTLIST add-attribute              expression       CDATA           #IMPLIED>
+<!--
+@attr role           Security role name that is allowed access to this attribute
+                     object. The attribute will be added to the parent list
+                     anyway. It is delegated to the user of this attribute to
+                     use it or not depending on the role of the user.
+-->
+<!ATTLIST add-attribute              role             CDATA            #IMPLIED>
+
+<!-- The "add-list-attribute" element describes a list attribute subordinate to another
+     list attribute. It allows to specify an attribute value that is a java List
+     containing any kind of values. In the config file, the list elements are specified
+     by nested <add-attribute> or <add-list-attribute>.
+-->
+<!ELEMENT add-list-attribute ( (add-attribute* | add-list-attribute*)+) >
+<!ATTLIST add-list-attribute id               ID              #IMPLIED>
+<!--
+@attr role           Security role name that is allowed access to this attribute
+                     object. The attribute will be added to the parent list
+                     anyway. It is delegated to the user of this attribute to
+                     use it or not depending on the role of the user.
+-->
+<!ATTLIST add-list-attribute role             CDATA            #IMPLIED>


[struts] 10/23: WW-5233 Copies Tiles Request related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit c912c4eea03bf0fad34164654626b2661ce0d59e
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 14:47:34 2022 +0200

    WW-5233 Copies Tiles Request related tests
---
 .../request/locale/URLApplicationResource.java     |  40 ++-
 .../tiles/request/AbstractClientRequestTest.java   | 155 ++++++++
 .../apache/tiles/request/AbstractRequestTest.java  |  54 +++
 .../tiles/request/AbstractViewRequestTest.java     | 119 ++++++
 .../tiles/request/ApplicationAccessTest.java       |  51 +++
 .../tiles/request/DispatchRequestWrapperTest.java  |  90 +++++
 .../request/NotAvailableFeatureExceptionTest.java  |  41 +++
 .../apache/tiles/request/RequestExceptionTest.java |  53 +++
 .../collection/AddableParameterMapTest.java        | 112 ++++++
 .../request/collection/CollectionUtilTest.java     |  59 +++
 .../collection/HeaderValuesCollectionTest.java     | 398 +++++++++++++++++++++
 .../collection/HeaderValuesMapEntrySetTest.java    | 337 +++++++++++++++++
 .../request/collection/HeaderValuesMapTest.java    | 337 +++++++++++++++++
 .../tiles/request/collection/KeySetTest.java       | 283 +++++++++++++++
 .../collection/MapEntryArrayValuesTest.java        |  76 ++++
 .../tiles/request/collection/MapEntryTest.java     | 106 ++++++
 .../ReadOnlyEnumerationMapEntrySetTest.java        | 293 +++++++++++++++
 .../collection/ReadOnlyEnumerationMapTest.java     | 306 ++++++++++++++++
 ...ReadOnlyEnumerationMapValuesCollectionTest.java | 310 ++++++++++++++++
 .../request/collection/RemovableKeySetTest.java    | 129 +++++++
 .../request/collection/ScopeMapEntrySetTest.java   | 234 ++++++++++++
 .../tiles/request/collection/ScopeMapTest.java     | 135 +++++++
 .../tiles/request/locale/LocaleUtilTest.java       |  42 +++
 .../locale/PostfixedApplicationResourceTest.java   | 131 +++++++
 .../request/locale/URLApplicationResourceTest.java | 201 +++++++++++
 .../CannotInstantiateObjectExceptionTest.java      |  41 +++
 .../tiles/request/reflect/ClassUtilTest.java       | 175 +++++++++
 .../request/render/BasicRendererFactoryTest.java   | 100 ++++++
 .../render/ChainedDelegateRendererTest.java        | 178 +++++++++
 .../tiles/request/render/DispatchRendererTest.java |  74 ++++
 .../render/NoSuchRendererExceptionTest.java        |  42 +++
 .../tiles/request/render/StringRendererTest.java   |  79 ++++
 .../tiles/request/locale/resource with space.txt   |  17 +
 .../org/apache/tiles/request/locale/resource.txt   |  17 +
 34 files changed, 4803 insertions(+), 12 deletions(-)

diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
index 8f867b7fb..e88b25db7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
@@ -98,22 +98,28 @@ public class URLApplicationResource extends PostfixedApplicationResource {
         return Collections.unmodifiableSet(remoteProtocols);
     }
 
-    private static boolean isLocal(URL url) {
+    private boolean isLocal(URL url) {
         return !REMOTE_PROTOCOLS.contains(url.getProtocol());
     }
 
-    /** the URL where the contents can be found. */
+    /**
+     * the URL where the contents can be found.
+     */
     private final URL url;
-    /** if the URL matches a file, this is the file. */
+    /**
+     * if the URL matches a file, this is the file.
+     */
     private File file;
-    /** if the URL points to a local resource */
+    /**
+     * if the URL points to a local resource
+     */
     private final boolean local;
 
     /**
      * Creates a URLApplicationResource for the specified path that can be accessed through the specified URL.
      *
      * @param localePath the path including localization.
-     * @param url the URL where the contents can be found.
+     * @param url        the URL where the contents can be found.
      */
     public URLApplicationResource(String localePath, URL url) {
         super(localePath);
@@ -127,9 +133,9 @@ public class URLApplicationResource extends PostfixedApplicationResource {
     /**
      * Creates a URLApplicationResource for the specified path that can be accessed through the specified URL.
      *
-     * @param path the path excluding localization.
+     * @param path   the path excluding localization.
      * @param locale the Locale.
-     * @param url the URL where the contents can be found.
+     * @param url    the URL where the contents can be found.
      */
     public URLApplicationResource(String path, Locale locale, URL url) {
         super(path, locale);
@@ -156,7 +162,7 @@ public class URLApplicationResource extends PostfixedApplicationResource {
         }
     }
 
-    private static File getFile(URL url) {
+    private File getFile(URL url) {
         try {
             return new File(new URI(url.toExternalForm()).getSchemeSpecificPart());
         } catch (URISyntaxException e) {
@@ -165,17 +171,25 @@ public class URLApplicationResource extends PostfixedApplicationResource {
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public InputStream getInputStream() throws IOException {
         if (file != null) {
-            return Files.newInputStream(file.toPath());
+            if (file.exists()) {
+                return Files.newInputStream(file.toPath());
+            } else {
+                throw new FileNotFoundException("File does not exist: " + file);
+            }
         } else {
             return openConnection().getInputStream();
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public long getLastModified() throws IOException {
         if (file != null) {
@@ -190,7 +204,9 @@ public class URLApplicationResource extends PostfixedApplicationResource {
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public String toString() {
         return "Resource " + getLocalePath() + " at " + url.toString();
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractClientRequestTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractClientRequestTest.java
new file mode 100644
index 000000000..338270d11
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractClientRequestTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link AbstractClientRequest}.
+ */
+public class AbstractClientRequestTest {
+
+    /**
+     * The request to test.
+     */
+    private AbstractClientRequest request;
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * The application scope.
+     */
+    private Map<String, Object> applicationScope;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        applicationContext = createMock(ApplicationContext.class);
+        applicationScope = new HashMap<>();
+        request = createMockBuilder(AbstractClientRequest.class).withConstructor(applicationContext).createMock();
+
+        expect(applicationContext.getApplicationScope()).andReturn(applicationScope).anyTimes();
+    }
+
+    /**
+     * Test method for {@link AbstractClientRequest#dispatch(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testDispatch() throws IOException {
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(request.getContext(Request.REQUEST_SCOPE)).andReturn(requestScope).anyTimes();
+        request.doForward("/my/path.html");
+        request.doInclude("/my/path2.html");
+
+        replay(request, applicationContext);
+        request.dispatch("/my/path.html");
+        request.dispatch("/my/path2.html");
+        verify(request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link AbstractClientRequest#include(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testInclude() throws IOException {
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(request.getContext(Request.REQUEST_SCOPE)).andReturn(requestScope).anyTimes();
+        request.doInclude("/my/path2.html");
+
+        replay(request, applicationContext);
+        request.include("/my/path2.html");
+        assertTrue((Boolean) request.getContext(Request.REQUEST_SCOPE).get(AbstractRequest.FORCE_INCLUDE_ATTRIBUTE_NAME));
+        verify(request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link AbstractClientRequest#getApplicationContext()}.
+     */
+    @Test
+    public void testGetApplicationContext() {
+        replay(request, applicationContext);
+        assertEquals(applicationContext, request.getApplicationContext());
+        verify(request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link AbstractClientRequest#getContext(String)}.
+     */
+    @Test
+    public void testGetContext() {
+        Map<String, Object> scope = createMock(Map.class);
+
+        expect(request.getContext("myScope")).andReturn(scope);
+
+        replay(request, applicationContext, scope);
+        assertEquals(scope, request.getContext("myScope"));
+        verify(request, applicationContext, scope);
+    }
+
+    /**
+     * Test method for {@link AbstractClientRequest#getAvailableScopes()}.
+     */
+    @Test
+    public void testGetAvailableScopes() {
+        String[] scopes = new String[]{"one", "two", "three"};
+
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList(scopes));
+
+        replay(request, applicationContext);
+        assertArrayEquals(scopes, request.getAvailableScopes().toArray());
+        verify(request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link AbstractClientRequest#getApplicationScope()}.
+     */
+    @Test
+    public void testGetApplicationScope() {
+        replay(request, applicationContext);
+        assertEquals(applicationScope, request.getApplicationScope());
+        verify(request, applicationContext);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractRequestTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractRequestTest.java
new file mode 100644
index 000000000..e0e3dd0c3
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractRequestTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link AbstractRequest}.
+ */
+public class AbstractRequestTest {
+
+    /**
+     * Test method for {@link AbstractRequest#setForceInclude(boolean)}.
+     */
+    @Test
+    public void testSetForceInclude() {
+        AbstractRequest request = createMockBuilder(AbstractRequest.class).createMock();
+        Map<String, Object> scope = new HashMap<>();
+
+        expect(request.getContext(Request.REQUEST_SCOPE)).andReturn(scope).anyTimes();
+
+        replay(request);
+        assertFalse(request.isForceInclude());
+        request.setForceInclude(true);
+        assertTrue(request.isForceInclude());
+        verify(request);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractViewRequestTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractViewRequestTest.java
new file mode 100644
index 000000000..bf650240d
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/AbstractViewRequestTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link AbstractViewRequest}.
+ */
+public class AbstractViewRequestTest {
+
+    /**
+     * The request to test.
+     */
+    private AbstractViewRequest request;
+
+    /**
+     * The internal request.
+     */
+    private DispatchRequest wrappedRequest;
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        wrappedRequest = createMock(DispatchRequest.class);
+        request = createMockBuilder(AbstractViewRequest.class).withConstructor(wrappedRequest).createMock();
+        applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> applicationScope = new HashMap<>();
+
+        expect(wrappedRequest.getApplicationContext()).andReturn(applicationContext).anyTimes();
+        expect(applicationContext.getApplicationScope()).andReturn(applicationScope).anyTimes();
+    }
+
+    /**
+     * Test method for {@link AbstractViewRequest#dispatch(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testDispatch() throws IOException {
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(request.getContext(Request.REQUEST_SCOPE)).andReturn(requestScope);
+        wrappedRequest.include("/my/path.html");
+
+        replay(wrappedRequest, request, applicationContext);
+        request.dispatch("/my/path.html");
+        assertTrue((Boolean) requestScope.get(AbstractRequest.FORCE_INCLUDE_ATTRIBUTE_NAME));
+        verify(wrappedRequest, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link AbstractViewRequest#include(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testInclude() throws IOException {
+        Map<String, Object> requestScope = new HashMap<>();
+
+        expect(request.getContext(Request.REQUEST_SCOPE)).andReturn(requestScope);
+        wrappedRequest.include("/my/path.html");
+
+        replay(wrappedRequest, request, applicationContext);
+        request.include("/my/path.html");
+        assertTrue((Boolean) requestScope.get(AbstractRequest.FORCE_INCLUDE_ATTRIBUTE_NAME));
+        verify(wrappedRequest, request, applicationContext);
+    }
+
+    /**
+     * Test method for {@link AbstractViewRequest#doInclude(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testDoInclude() throws IOException {
+        wrappedRequest.include("/my/path.html");
+
+        replay(wrappedRequest, request, applicationContext);
+        request.doInclude("/my/path.html");
+        verify(wrappedRequest, request, applicationContext);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/ApplicationAccessTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/ApplicationAccessTest.java
new file mode 100644
index 000000000..08b5ec27f
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/ApplicationAccessTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request;
+
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link ApplicationAccess}.
+ */
+public class ApplicationAccessTest {
+
+    /**
+     * Test method for {@link ApplicationAccess#register(ApplicationContext)}.
+     */
+    @Test
+    public void testRegister() {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Map<String, Object> applicationScope = createMock(Map.class);
+
+        expect(applicationContext.getApplicationScope()).andReturn(applicationScope);
+        expect(applicationScope.put(ApplicationAccess.APPLICATION_CONTEXT_ATTRIBUTE, applicationContext)).andReturn(null);
+
+        replay(applicationContext, applicationScope);
+        ApplicationAccess.register(applicationContext);
+        verify(applicationContext, applicationScope);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/DispatchRequestWrapperTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/DispatchRequestWrapperTest.java
new file mode 100644
index 000000000..2fa6a96d0
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/DispatchRequestWrapperTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link DispatchRequestWrapper}.
+ */
+public class DispatchRequestWrapperTest {
+
+    protected DispatchRequest createMockRequest() {
+        return createMock(DispatchRequest.class);
+    }
+
+    protected DispatchRequestWrapper createRequestWrapper(Request wrappedRequest) {
+        return new DispatchRequestWrapper((DispatchRequest) wrappedRequest);
+    }
+
+    /**
+     * Test method for {@link DispatchRequestWrapper#dispatch(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testDispatch() throws IOException {
+        DispatchRequest wrappedRequest = createMockRequest();
+
+        wrappedRequest.dispatch("/my/path.html");
+
+        replay(wrappedRequest);
+        DispatchRequestWrapper request = createRequestWrapper(wrappedRequest);
+        request.dispatch("/my/path.html");
+        verify(wrappedRequest);
+    }
+
+    /**
+     * Test method for {@link DispatchRequestWrapper#include(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testInclude() throws IOException {
+        DispatchRequest wrappedRequest = createMockRequest();
+
+        wrappedRequest.include("/my/path.html");
+
+        replay(wrappedRequest);
+        DispatchRequestWrapper request = createRequestWrapper(wrappedRequest);
+        request.include("/my/path.html");
+        verify(wrappedRequest);
+    }
+
+    /**
+     * Test method for {@link DispatchRequestWrapper#setContentType(String)}.
+     */
+    @Test
+    public void testSetContentType() {
+        DispatchRequest wrappedRequest = createMockRequest();
+
+        wrappedRequest.setContentType("text/html");
+
+        replay(wrappedRequest);
+        DispatchRequestWrapper request = createRequestWrapper(wrappedRequest);
+        request.setContentType("text/html");
+        verify(wrappedRequest);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/NotAvailableFeatureExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/NotAvailableFeatureExceptionTest.java
new file mode 100644
index 000000000..f1d6caf51
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/NotAvailableFeatureExceptionTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link NotAvailableFeatureException}.
+ */
+public class NotAvailableFeatureExceptionTest {
+
+    /**
+     * Test method for {@link NotAvailableFeatureException#NotAvailableFeatureException(String, Throwable)}.
+     */
+    @Test
+    public void testNotAvailableFeatureExceptionStringThrowable() {
+        Throwable cause = new Throwable();
+        NotAvailableFeatureException exception = new NotAvailableFeatureException("my message", cause);
+        assertEquals("my message", exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/RequestExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/RequestExceptionTest.java
new file mode 100644
index 000000000..b8a699c45
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/RequestExceptionTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.request;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link RequestException}.
+ */
+public class RequestExceptionTest {
+
+    /**
+     * Test method for {@link RequestException#RequestException(String)}.
+     */
+    @Test
+    public void testRequestExceptionString() {
+        RequestException exception = new RequestException("my message");
+        assertEquals("my message", exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+    /**
+     * Test method for {@link RequestException#RequestException(String, Throwable)}.
+     */
+    @Test
+    public void testRequestExceptionStringThrowable() {
+        Throwable cause = new Throwable();
+        RequestException exception = new RequestException("my message", cause);
+        assertEquals("my message", exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/AddableParameterMapTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/AddableParameterMapTest.java
new file mode 100644
index 000000000..a06d9bb81
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/AddableParameterMapTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasAddableKeys;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link AddableParameterMap}.
+ */
+public class AddableParameterMapTest {
+
+    /**
+     * The object to test.
+     */
+    private AddableParameterMap map;
+
+    /**
+     * The extractor to use.
+     */
+    private HasAddableKeys<String> extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(HasAddableKeys.class);
+        map = new AddableParameterMap(extractor);
+    }
+
+    /**
+     * Test method for {@link AddableParameterMap#entrySet()}.
+     */
+    @Test
+    public void testEntrySet() {
+        Set<Map.Entry<String, String>> entrySet = map.entrySet();
+        MapEntry<String, String> entry1 = new MapEntry<>("one", "value1", false);
+        MapEntry<String, String> entry2 = new MapEntry<>("two", "value2", false);
+        List<Map.Entry<String, String>> entries = new ArrayList<>(2);
+        entries.add(entry1);
+        entries.add(entry2);
+
+        extractor.setValue("one", "value1");
+        expectLastCall().times(2);
+        extractor.setValue("two", "value2");
+        replay(extractor);
+        entrySet.add(entry1);
+        entrySet.addAll(entries);
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link AddableParameterMap#put(String, String)}.
+     */
+    @Test
+    public void testPut() {
+        expect(extractor.getValue("one")).andReturn(null);
+        extractor.setValue("one", "value1");
+
+        replay(extractor);
+        assertNull(map.put("one", "value1"));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link AddableParameterMap#putAll(Map)}.
+     */
+    @Test
+    public void testPutAll() {
+        Map<String, String> map = new HashMap<>();
+        map.put("one", "value1");
+        map.put("two", "value2");
+
+        extractor.setValue("one", "value1");
+        extractor.setValue("two", "value2");
+
+        replay(extractor);
+        this.map.putAll(map);
+        verify(extractor);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/CollectionUtilTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/CollectionUtilTest.java
new file mode 100644
index 000000000..39f286760
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/CollectionUtilTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.junit.Test;
+
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+public class CollectionUtilTest {
+
+    @Test
+    public void testKey() {
+        assertEquals("1", CollectionUtil.key(1));
+        assertEquals("hello", CollectionUtil.key("hello"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testKeyException() {
+        CollectionUtil.key(null);
+    }
+
+    @Test
+    public void testEnumerationSize() {
+        Enumeration<Object> enumeration = createMock(Enumeration.class);
+
+        expect(enumeration.hasMoreElements()).andReturn(true);
+        expect(enumeration.nextElement()).andReturn(1);
+        expect(enumeration.hasMoreElements()).andReturn(true);
+        expect(enumeration.nextElement()).andReturn(1);
+        expect(enumeration.hasMoreElements()).andReturn(false);
+
+        replay(enumeration);
+        assertEquals(2, CollectionUtil.enumerationSize(enumeration));
+        verify(enumeration);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java
new file mode 100644
index 000000000..8a4069171
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.EnumeratedValuesExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link HeaderValuesMap#values()}.
+ */
+public class HeaderValuesCollectionTest {
+
+
+    /**
+     * The extractor to use.
+     */
+    private EnumeratedValuesExtractor extractor;
+
+    /**
+     * The map to test.
+     */
+    private HeaderValuesMap map;
+
+    /**
+     * The collection.
+     */
+    private Collection<String[]> coll;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(EnumeratedValuesExtractor.class);
+        map = new HeaderValuesMap(extractor);
+        coll = map.values();
+    }
+
+    /**
+     * Tests {@link Collection#add(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAdd() {
+        coll.add(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAddAll() {
+        coll.addAll(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        coll.clear();
+    }
+
+    /**
+     * Tests {@link Collection#contains(Object)}.
+     */
+    @Test
+    public void testContainsValue() {
+        assertFalse(map.containsValue(1));
+
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        assertTrue(coll.contains(new String[]{"value2", "value3"}));
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Tests {@link Collection#contains(Object)}.
+     */
+    @Test
+    public void testContainsValueFalse() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        assertFalse(coll.contains(new String[]{"value2", "value4"}));
+        verify(extractor, keys, values1, values2);
+    }
+
+    @Test
+    public void testContainsAll() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys).times(2);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValues("one")).andReturn(values1).times(2);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        List<String[]> coll = new ArrayList<>();
+        coll.add(new String[]{"value1"});
+        coll.add(new String[]{"value2", "value3"});
+        assertTrue(this.coll.containsAll(coll));
+        verify(extractor, keys, values1, values2);
+    }
+
+    @Test
+    public void testContainsAllFalse() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys, values1, values2);
+        List<String[]> coll = new ArrayList<>();
+        coll.add(new String[]{"value4"});
+        assertFalse(this.coll.containsAll(coll));
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link Collection#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(coll.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#iterator()}.
+     */
+    @Test
+    public void testIterator() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values2);
+        Iterator<String[]> entryIt = coll.iterator();
+        assertTrue(entryIt.hasNext());
+        assertArrayEquals(new String[]{"value2", "value3"}, entryIt.next());
+        verify(extractor, keys, values2);
+    }
+
+    /**
+     * Test method for {@link Collection#iterator()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testIteratorRemove() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+
+        try {
+            replay(extractor, keys);
+            coll.iterator().remove();
+        } finally {
+            verify(extractor, keys);
+        }
+    }
+
+    /**
+     * Tests {@link Collection#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        coll.remove(null);
+    }
+
+    /**
+     * Tests {@link Collection#removeAll(Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveAll() {
+        coll.removeAll(null);
+    }
+
+    /**
+     * Tests {@link Collection#retainAll(Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRetainAll() {
+        coll.retainAll(null);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, coll.size());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#toArray()}.
+     */
+    @Test
+    public void testToArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        String[][] entryArray = new String[2][];
+        entryArray[0] = new String[]{"value1"};
+        entryArray[1] = new String[]{"value2", "value3"};
+
+        replay(extractor, keys, values1, values2);
+        assertArrayEquals(entryArray, coll.toArray());
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link Collection#toArray(Object[])}.
+     */
+    @Test
+    public void testToArrayTArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        String[][] entryArray = new String[2][];
+        entryArray[0] = new String[]{"value1"};
+        entryArray[1] = new String[]{"value2", "value3"};
+        String[][] realArray = new String[2][];
+
+        replay(extractor, keys, values1, values2);
+        assertArrayEquals(entryArray, coll.toArray(realArray));
+        verify(extractor, keys, values1, values2);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java
new file mode 100644
index 000000000..344151c52
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.EnumeratedValuesExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link HeaderValuesMap entry set}.
+ */
+public class HeaderValuesMapEntrySetTest {
+
+    /**
+     * The extractor to use.
+     */
+    private EnumeratedValuesExtractor extractor;
+
+    /**
+     * The set to test.
+     */
+    private Set<Map.Entry<String, String[]>> entrySet;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(EnumeratedValuesExtractor.class);
+        HeaderValuesMap map = new HeaderValuesMap(extractor);
+        entrySet = map.entrySet();
+    }
+
+    /**
+     * Tests {@link Set#add(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAdd() {
+        entrySet.add(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAddAll() {
+        entrySet.addAll(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        entrySet.clear();
+    }
+
+    /**
+     * Tests {@link Set#contains(Object)}.
+     */
+    @Test
+    public void testContains() {
+        Map.Entry<String, String[]> entry = createMock(Map.Entry.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(entry.getKey()).andReturn("two");
+        expect(entry.getValue()).andReturn(new String[]{"value2", "value3"});
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, entry, values2);
+        assertTrue(entrySet.contains(entry));
+        verify(extractor, entry, values2);
+    }
+
+    @Test
+    public void testContainsAll() {
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+        Map.Entry<String, String[]> entry1 = createMock(Map.Entry.class);
+        Map.Entry<String, String[]> entry2 = createMock(Map.Entry.class);
+
+        expect(entry1.getKey()).andReturn("one");
+        expect(entry1.getValue()).andReturn(new String[]{"value1"});
+        expect(entry2.getKey()).andReturn("two");
+        expect(entry2.getValue()).andReturn(new String[]{"value2", "value3"});
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, values1, values2, entry1, entry2);
+        List<Map.Entry<String, String[]>> coll = new ArrayList<>();
+        coll.add(entry1);
+        coll.add(entry2);
+        assertTrue(entrySet.containsAll(coll));
+        verify(extractor, values1, values2, entry1, entry2);
+    }
+
+    @Test
+    public void testContainsAllFalse() {
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Map.Entry<String, String[]> entry1 = createMock(Map.Entry.class);
+
+        expect(entry1.getKey()).andReturn("one");
+        expect(entry1.getValue()).andReturn(new String[]{"value4"});
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+
+        replay(extractor, values1, entry1);
+        List<Map.Entry<String, String[]>> coll = new ArrayList<>();
+        coll.add(entry1);
+        assertFalse(entrySet.containsAll(coll));
+        verify(extractor, values1, entry1);
+    }
+
+    /**
+     * Test method for {@link Set#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(entrySet.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#iterator()}.
+     */
+    @Test
+    public void testIterator() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values2);
+        Iterator<Map.Entry<String, String[]>> entryIt = entrySet.iterator();
+        assertTrue(entryIt.hasNext());
+        MapEntryArrayValues<String, String> entry = new MapEntryArrayValues<>(
+            "two", new String[]{"value2", "value3"}, false);
+        assertEquals(entry, entryIt.next());
+        verify(extractor, keys, values2);
+    }
+
+    /**
+     * Test method for {@link Set#iterator()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testIteratorRemove() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+
+        try {
+            replay(extractor, keys);
+            entrySet.iterator().remove();
+        } finally {
+            verify(extractor, keys);
+        }
+    }
+
+    /**
+     * Tests {@link Set#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        entrySet.remove(null);
+    }
+
+    /**
+     * Tests {@link Set#removeAll(java.util.Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveAll() {
+        entrySet.removeAll(null);
+    }
+
+    /**
+     * Tests {@link Set#retainAll(java.util.Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRetainAll() {
+        entrySet.retainAll(null);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, entrySet.size());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#toArray()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testToArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        MapEntryArrayValues<String, String>[] entryArray = new MapEntryArrayValues[2];
+        entryArray[0] = new MapEntryArrayValues<>("one", new String[]{"value1"}, false);
+        entryArray[1] = new MapEntryArrayValues<>("two", new String[]{"value2", "value3"}, false);
+
+        replay(extractor, keys, values1, values2);
+        assertArrayEquals(entryArray, entrySet.toArray());
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link Set#toArray(Object[])}.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testToArrayTArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        MapEntryArrayValues<String, String>[] entryArray = new MapEntryArrayValues[2];
+        entryArray[0] = new MapEntryArrayValues<>("one", new String[]{"value1"}, false);
+        entryArray[1] = new MapEntryArrayValues<>("two", new String[]{"value2", "value3"}, false);
+        MapEntryArrayValues<String, String>[] realArray = new MapEntryArrayValues[2];
+
+        replay(extractor, keys, values1, values2);
+        assertArrayEquals(entryArray, entrySet.toArray(realArray));
+        verify(extractor, keys, values1, values2);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapTest.java
new file mode 100644
index 000000000..aaf0ef602
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapTest.java
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.EnumeratedValuesExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link HeaderValuesMap}.
+ */
+public class HeaderValuesMapTest {
+
+    /**
+     * The extractor to use.
+     */
+    private EnumeratedValuesExtractor extractor;
+
+    /**
+     * The map to test.
+     */
+    private HeaderValuesMap map;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(EnumeratedValuesExtractor.class);
+        map = new HeaderValuesMap(extractor);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#hashCode()}.
+     */
+    @Test
+    public void testHashCode() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        assertEquals(
+            ("one".hashCode() ^ "value1".hashCode())
+                + ("two".hashCode() ^ ("value2".hashCode() + "value3"
+                .hashCode())),
+            map.hashCode());
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#clear()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        map.clear();
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#containsKey(Object)}.
+     */
+    @Test
+    public void testContainsKey() {
+        expect(extractor.getValue("one")).andReturn("value1");
+        expect(extractor.getValue("two")).andReturn(null);
+
+        replay(extractor);
+        assertTrue(map.containsKey("one"));
+        assertFalse(map.containsKey("two"));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#containsValue(Object)}.
+     */
+    @Test
+    public void testContainsValue() {
+        assertFalse(map.containsValue(1));
+
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        assertTrue(map.containsValue(new String[]{"value2", "value3"}));
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#containsValue(Object)}.
+     */
+    @Test
+    public void testContainsValueFalse() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        assertFalse(map.containsValue(new String[]{"value2", "value4"}));
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#equals(Object)}.
+     */
+    @Test
+    public void testEqualsObject() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+        EnumeratedValuesExtractor otherExtractor = createMock(EnumeratedValuesExtractor.class);
+        Enumeration<String> otherValues1 = createMock(Enumeration.class);
+        Enumeration<String> otherValues2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("one")).andReturn(values1);
+        expect(values1.hasMoreElements()).andReturn(true);
+        expect(values1.nextElement()).andReturn("value1");
+        expect(values1.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        expect(otherExtractor.getValues("one")).andReturn(otherValues1);
+        expect(otherValues1.hasMoreElements()).andReturn(true);
+        expect(otherValues1.nextElement()).andReturn("value1");
+        expect(otherValues1.hasMoreElements()).andReturn(false);
+
+        expect(otherExtractor.getValues("two")).andReturn(otherValues2);
+        expect(otherValues2.hasMoreElements()).andReturn(true);
+        expect(otherValues2.nextElement()).andReturn("value2");
+        expect(otherValues2.hasMoreElements()).andReturn(true);
+        expect(otherValues2.nextElement()).andReturn("value3");
+        expect(otherValues2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, otherExtractor, keys, values1, values2, otherValues1, otherValues2);
+        HeaderValuesMap otherMap = new HeaderValuesMap(otherExtractor);
+        assertTrue(map.equals(otherMap));
+        verify(extractor, otherExtractor, keys, values1, values2, otherValues1, otherValues2);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#get(Object)}.
+     */
+    @Test
+    public void testGet() {
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getValues("two")).andReturn(values2);
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value2");
+        expect(values2.hasMoreElements()).andReturn(true);
+        expect(values2.nextElement()).andReturn("value3");
+        expect(values2.hasMoreElements()).andReturn(false);
+
+        replay(extractor, values2);
+        assertArrayEquals(new String[]{"value2", "value3"}, map.get("two"));
+        verify(extractor, values2);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(map.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#isEmpty()}.
+     */
+    @Test
+    public void testIsEmptyTrue() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertTrue(map.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#keySet()}.
+     */
+    @Test
+    public void testKeySet() {
+        replay(extractor);
+        assertTrue(map.keySet() instanceof KeySet);
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#put(String, String[])}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPut() {
+        map.put("one", new String[]{"value1", "value2"});
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#putAll(java.util.Map)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPutAll() {
+        map.putAll(new HashMap<>());
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        map.remove("one");
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, map.size());
+        verify(extractor, keys);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java
new file mode 100644
index 000000000..f8fe60a31
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java
@@ -0,0 +1,283 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasKeys;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link KeySet}.
+ */
+public class KeySetTest {
+
+
+    /**
+     * The extractor to use.
+     */
+    private HasKeys<Integer> extractor;
+
+    /**
+     * The key set.
+     */
+    private Set<String> entrySet;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(HasKeys.class);
+        entrySet = new KeySet(extractor);
+    }
+
+    /**
+     * Tests {@link Set#add(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAdd() {
+        entrySet.add(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAddAll() {
+        entrySet.addAll(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        entrySet.clear();
+    }
+
+    /**
+     * Tests {@link Set#contains(Object)}.
+     */
+    @Test
+    public void testContains() {
+        expect(extractor.getValue("one")).andReturn(1);
+
+        replay(extractor);
+        assertTrue(entrySet.contains("one"));
+        verify(extractor);
+    }
+
+    /**
+     * Tests {@link Set#contains(Object)}.
+     */
+    @Test
+    public void testContainsFalse() {
+        expect(extractor.getValue("one")).andReturn(null);
+
+        replay(extractor);
+        assertFalse(entrySet.contains("one"));
+        verify(extractor);
+    }
+
+    @Test
+    public void testContainsAll() {
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(1);
+
+        replay(extractor);
+        List<String> coll = new ArrayList<String>();
+        coll.add("one");
+        coll.add("two");
+        assertTrue(entrySet.containsAll(coll));
+        verify(extractor);
+    }
+
+    @Test
+    public void testContainsAllFalse() {
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(null);
+
+        replay(extractor);
+        List<String> coll = new ArrayList<>();
+        coll.add("one");
+        coll.add("two");
+        assertFalse(entrySet.containsAll(coll));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link Set#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(entrySet.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#isEmpty()}.
+     */
+    @Test
+    public void testIsEmptyTrue() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertTrue(entrySet.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#iterator()}.
+     */
+    @Test
+    public void testIterator() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        replay(extractor, keys, values2);
+        Iterator<String> entryIt = entrySet.iterator();
+        assertTrue(entryIt.hasNext());
+        assertEquals("two", entryIt.next());
+        verify(extractor, keys, values2);
+    }
+
+    /**
+     * Test method for {@link Set#iterator()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testIteratorRemove() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+
+        try {
+            replay(extractor, keys);
+            entrySet.iterator().remove();
+        } finally {
+            verify(extractor, keys);
+        }
+    }
+
+    /**
+     * Tests {@link Set#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        entrySet.remove(null);
+    }
+
+    /**
+     * Tests {@link Set#removeAll(java.util.Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveAll() {
+        entrySet.removeAll(null);
+    }
+
+    /**
+     * Tests {@link Set#retainAll(java.util.Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRetainAll() {
+        entrySet.retainAll(null);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, entrySet.size());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#toArray()}.
+     */
+    @Test
+    public void testToArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+        replay(extractor, keys, values1, values2);
+        assertArrayEquals(new String[]{"one", "two"}, entrySet.toArray());
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link Set#toArray(Object[])}.
+     */
+    @Test
+    public void testToArrayTArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys, values1, values2);
+        String[] realArray = new String[2];
+        assertArrayEquals(new String[]{"one", "two"}, entrySet.toArray(realArray));
+        verify(extractor, keys, values1, values2);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/MapEntryArrayValuesTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/MapEntryArrayValuesTest.java
new file mode 100644
index 000000000..97045cd10
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/MapEntryArrayValuesTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests {@link MapEntryArrayValues}.
+ */
+public class MapEntryArrayValuesTest {
+
+    /**
+     * Test method for {@link MapEntryArrayValues#hashCode()}.
+     */
+    @Test
+    public void testHashCode() {
+        MapEntryArrayValues<String, String> entry = new MapEntryArrayValues<>("key", new String[]{"value1", "value2"}, false);
+        assertEquals("key".hashCode() ^ ("value1".hashCode() + "value2".hashCode()), entry.hashCode());
+        entry = new MapEntryArrayValues<>(null, new String[]{"value1", "value2"}, false);
+        assertEquals(("value1".hashCode() + "value2".hashCode()), entry.hashCode());
+        entry = new MapEntryArrayValues<>("key", null, false);
+        assertEquals("key".hashCode(), entry.hashCode());
+        entry = new MapEntryArrayValues<>(null, null, false);
+        assertEquals(0, entry.hashCode());
+    }
+
+    /**
+     * Test method for {@link MapEntryArrayValues#equals(Object)}.
+     */
+    @Test
+    public void testEqualsObject() {
+        MapEntryArrayValues<String, String> entry = new MapEntryArrayValues<>("key", new String[]{"value1", "value2"}, false);
+        assertNotEquals(null, entry);
+        MapEntryArrayValues<String, String> entry2 = new MapEntryArrayValues<>("key", new String[]{"value1", "value2"}, false);
+        assertEquals(entry, entry2);
+        entry2 = new MapEntryArrayValues<>("key", null, false);
+        assertNotEquals(entry, entry2);
+        entry2 = new MapEntryArrayValues<>("key2", new String[]{"value1", "value2"}, false);
+        assertNotEquals(entry, entry2);
+        entry2 = new MapEntryArrayValues<>("key", new String[]{"value1", "value3"}, false);
+        assertNotEquals(entry, entry2);
+        entry = new MapEntryArrayValues<>(null, new String[]{"value1", "value2"}, false);
+        entry2 = new MapEntryArrayValues<>(null, new String[]{"value1", "value2"}, false);
+        assertEquals(entry, entry2);
+        entry = new MapEntryArrayValues<>("key", null, false);
+        entry2 = new MapEntryArrayValues<>("key", null, false);
+        assertEquals(entry, entry2);
+        entry2 = new MapEntryArrayValues<>("key", new String[]{"value1", "value2"}, false);
+        assertNotEquals(entry, entry2);
+        entry = new MapEntryArrayValues<>(null, new String[]{null, "value2"}, false);
+        entry2 = new MapEntryArrayValues<>(null, new String[]{null, "value2"}, false);
+        assertEquals(entry, entry2);
+        entry2 = new MapEntryArrayValues<>(null, new String[]{"value1", "value2"}, false);
+        assertNotEquals(entry, entry2);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/MapEntryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/MapEntryTest.java
new file mode 100644
index 000000000..31406b057
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/MapEntryTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests {@link MapEntry}.
+ */
+public class MapEntryTest {
+
+    /**
+     * Test method for {@link MapEntry#hashCode()}.
+     */
+    @Test
+    public void testHashCode() {
+        MapEntry<String, String> entry = new MapEntry<>("key", "value", false);
+        assertEquals("key".hashCode() ^ "value".hashCode(), entry.hashCode());
+        entry = new MapEntry<>(null, "value", false);
+        assertEquals("value".hashCode(), entry.hashCode());
+        entry = new MapEntry<>("key", null, false);
+        assertEquals("key".hashCode(), entry.hashCode());
+        entry = new MapEntry<>(null, null, false);
+        assertEquals(0, entry.hashCode());
+    }
+
+    /**
+     * Test method for {@link MapEntry#getKey()}.
+     */
+    @Test
+    public void testGetKey() {
+        MapEntry<String, String> entry = new MapEntry<>("key", "value", false);
+        assertEquals("key", entry.getKey());
+    }
+
+    /**
+     * Test method for {@link MapEntry#getValue()}.
+     */
+    @Test
+    public void testGetValue() {
+        MapEntry<String, String> entry = new MapEntry<>("key", "value", false);
+        assertEquals("value", entry.getValue());
+    }
+
+    /**
+     * Test method for {@link MapEntry#setValue(Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        MapEntry<String, String> entry = new MapEntry<>("key", "value", true);
+        assertEquals("value", entry.getValue());
+        entry.setValue("value2");
+        assertEquals("value2", entry.getValue());
+    }
+
+    /**
+     * Test method for {@link MapEntry#setValue(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSetValueException() {
+        MapEntry<String, String> entry = new MapEntry<>("key", "value", false);
+        assertEquals("value", entry.getValue());
+        entry.setValue("value2");
+    }
+
+    /**
+     * Test method for {@link MapEntry#equals(Object)}.
+     */
+    @Test
+    public void testEqualsObject() {
+        MapEntry<String, String> entry = new MapEntry<>("key", "value", false);
+        assertNotEquals(null, entry);
+        MapEntry<String, String> entry2 = new MapEntry<>("key", "value", false);
+        assertEquals(entry, entry2);
+        entry2 = new MapEntry<>("key2", "value", false);
+        assertNotEquals(entry, entry2);
+        entry2 = new MapEntry<>("key", "value2", false);
+        assertNotEquals(entry, entry2);
+        entry = new MapEntry<>(null, "value", false);
+        entry2 = new MapEntry<>(null, "value", false);
+        assertEquals(entry, entry2);
+        entry = new MapEntry<>("key", null, false);
+        entry2 = new MapEntry<>("key", null, false);
+        assertEquals(entry, entry2);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java
new file mode 100644
index 000000000..a77d6bd82
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasKeys;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ReadOnlyEnumerationMap#entrySet()}.
+ */
+public class ReadOnlyEnumerationMapEntrySetTest {
+
+    /**
+     * The extractor to use.
+     */
+    private HasKeys<Integer> extractor;
+
+    /**
+     * The set to test.
+     */
+    private Set<Map.Entry<String, Integer>> entrySet;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(HasKeys.class);
+        ReadOnlyEnumerationMap<Integer> map = new ReadOnlyEnumerationMap<>(extractor);
+        entrySet = map.entrySet();
+    }
+
+    /**
+     * Tests {@link Set#add(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAdd() {
+        entrySet.add(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAddAll() {
+        entrySet.addAll(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        entrySet.clear();
+    }
+
+    /**
+     * Tests {@link Set#contains(Object)}.
+     */
+    @Test
+    public void testContains() {
+        Map.Entry<String, Integer> entry = createMock(Map.Entry.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(entry.getKey()).andReturn("two");
+        expect(entry.getValue()).andReturn(2);
+
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, entry, values2);
+        assertTrue(entrySet.contains(entry));
+        verify(extractor, entry, values2);
+    }
+
+    @Test
+    public void testContainsAll() {
+        Map.Entry<String, Integer> entry1 = createMock(Map.Entry.class);
+        Map.Entry<String, Integer> entry2 = createMock(Map.Entry.class);
+
+        expect(entry1.getKey()).andReturn("one");
+        expect(entry1.getValue()).andReturn(1);
+        expect(entry2.getKey()).andReturn("two");
+        expect(entry2.getValue()).andReturn(2);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, entry1, entry2);
+        List<Map.Entry<String, Integer>> coll = new ArrayList<>();
+        coll.add(entry1);
+        coll.add(entry2);
+        assertTrue(entrySet.containsAll(coll));
+        verify(extractor, entry1, entry2);
+    }
+
+    @Test
+    public void testContainsAllFalse() {
+        Map.Entry<String, String> entry1 = createMock(Map.Entry.class);
+
+        expect(entry1.getKey()).andReturn("one");
+        expect(entry1.getValue()).andReturn("value4");
+
+        expect(extractor.getValue("one")).andReturn(1);
+
+        replay(extractor, entry1);
+        List<Map.Entry<String, String>> coll = new ArrayList<>();
+        coll.add(entry1);
+        assertFalse(entrySet.containsAll(coll));
+        verify(extractor, entry1);
+    }
+
+    /**
+     * Test method for {@link Set#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(entrySet.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#iterator()}.
+     */
+    @Test
+    public void testIterator() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        Iterator<Map.Entry<String, Integer>> entryIt = entrySet.iterator();
+        assertTrue(entryIt.hasNext());
+        MapEntry<String, Integer> entry = new MapEntry<>("two", 2, false);
+        assertEquals(entry, entryIt.next());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#iterator()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testIteratorRemove() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+
+        try {
+            replay(extractor, keys);
+            entrySet.iterator().remove();
+        } finally {
+            verify(extractor, keys);
+        }
+    }
+
+    /**
+     * Tests {@link Set#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        entrySet.remove(null);
+    }
+
+    /**
+     * Tests {@link Set#removeAll(java.util.Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveAll() {
+        entrySet.removeAll(null);
+    }
+
+    /**
+     * Tests {@link Set#retainAll(java.util.Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRetainAll() {
+        entrySet.retainAll(null);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, entrySet.size());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Set#toArray()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testToArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        MapEntry<String, Integer>[] entryArray = new MapEntry[2];
+        entryArray[0] = new MapEntry<>("one", 1, false);
+        entryArray[1] = new MapEntry<>("two", 2, false);
+
+        replay(extractor, keys, values1, values2);
+        assertArrayEquals(entryArray, entrySet.toArray());
+        verify(extractor, keys, values1, values2);
+    }
+
+    /**
+     * Test method for {@link Set#toArray(Object[])}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testToArrayTArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> values1 = createMock(Enumeration.class);
+        Enumeration<String> values2 = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        MapEntry<String, Integer>[] entryArray = new MapEntry[2];
+        entryArray[0] = new MapEntry<>("one", 1, false);
+        entryArray[1] = new MapEntry<>("two", 2, false);
+
+        replay(extractor, keys, values1, values2);
+        MapEntry<String, String>[] realArray = new MapEntry[2];
+        assertArrayEquals(entryArray, entrySet.toArray(realArray));
+        verify(extractor, keys, values1, values2);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapTest.java
new file mode 100644
index 000000000..be3245691
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapTest.java
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasKeys;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ReadOnlyEnumerationMap}.
+ */
+public class ReadOnlyEnumerationMapTest {
+
+    /**
+     * The extractor to use.
+     */
+    private HasKeys<Integer> extractor;
+
+    /**
+     * The map to test.
+     */
+    private ReadOnlyEnumerationMap<Integer> map;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(HasKeys.class);
+        map = new ReadOnlyEnumerationMap<>(extractor);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#clear()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        map.clear();
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#containsKey(Object)}.
+     */
+    @Test
+    public void testContainsKey() {
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(null);
+
+        replay(extractor);
+        assertTrue(map.containsKey("one"));
+        assertFalse(map.containsKey("two"));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#containsValue(Object)}.
+     */
+    @Test
+    public void testContainsValue() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        assertTrue(map.containsValue(2));
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#containsValue(Object)}.
+     */
+    @Test
+    public void testContainsValueFalse() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(1);
+
+        replay(extractor, keys);
+        assertFalse(map.containsValue(3));
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#get(Object)}.
+     */
+    @Test
+    public void testGet() {
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor);
+        assertEquals(new Integer(2), map.get("two"));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(map.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#isEmpty()}.
+     */
+    @Test
+    public void testIsEmptyTrue() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertTrue(map.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#keySet()}.
+     */
+    @Test
+    public void testKeySet() {
+        replay(extractor);
+        assertTrue(map.keySet() instanceof KeySet);
+        verify(extractor);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPut() {
+        map.put("one", 1);
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#putAll(java.util.Map)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPutAll() {
+        map.putAll(new HashMap<>());
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        map.remove("one");
+    }
+
+    /**
+     * Test method for {@link ReadOnlyEnumerationMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, map.size());
+        verify(extractor, keys);
+    }
+
+    @Test
+    public void testHashCode() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("first");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("second");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        Integer value1 = 1;
+
+        expect(extractor.getValue("first")).andReturn(value1);
+        expect(extractor.getValue("second")).andReturn(null);
+
+        replay(extractor, keys);
+        assertEquals(("first".hashCode() ^ value1.hashCode()) + ("second".hashCode()), map.hashCode());
+        verify(extractor, keys);
+    }
+
+    @Test
+    public void testEqualsObject() {
+        HasKeys<Integer> otherRequest = createMock(HasKeys.class);
+        ReadOnlyEnumerationMap<Integer> otherMap = createMockBuilder(ReadOnlyEnumerationMap.class).withConstructor(otherRequest).createMock();
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> otherKeys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(otherRequest.getKeys()).andReturn(otherKeys);
+
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("first");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("second");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("first")).andReturn(1);
+        expect(extractor.getValue("second")).andReturn(2);
+
+        expect(otherKeys.hasMoreElements()).andReturn(true);
+        expect(otherKeys.nextElement()).andReturn("first");
+        expect(otherKeys.hasMoreElements()).andReturn(true);
+        expect(otherKeys.nextElement()).andReturn("second");
+        expect(otherKeys.hasMoreElements()).andReturn(false);
+
+        expect(otherRequest.getValue("first")).andReturn(1);
+        expect(otherRequest.getValue("second")).andReturn(2);
+
+        replay(extractor, otherRequest, otherMap, keys, otherKeys);
+        assertEquals(map, otherMap);
+        verify(extractor, otherRequest, otherMap, keys, otherKeys);
+    }
+
+    @Test
+    public void testEqualsObjectFalse() {
+        HasKeys<Integer> otherRequest = createMock(HasKeys.class);
+        ReadOnlyEnumerationMap<Integer> otherMap = createMockBuilder(ReadOnlyEnumerationMap.class).withConstructor(otherRequest).createMock();
+        Enumeration<String> keys = createMock(Enumeration.class);
+        Enumeration<String> otherKeys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(otherRequest.getKeys()).andReturn(otherKeys);
+
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("first");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("second");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("first")).andReturn(1);
+        expect(extractor.getValue("second")).andReturn(2);
+
+        expect(otherKeys.hasMoreElements()).andReturn(true);
+        expect(otherKeys.nextElement()).andReturn("first");
+        expect(otherKeys.hasMoreElements()).andReturn(true);
+        expect(otherKeys.nextElement()).andReturn("second");
+        expect(otherKeys.hasMoreElements()).andReturn(false);
+
+        expect(otherRequest.getValue("first")).andReturn(1);
+        expect(otherRequest.getValue("second")).andReturn(3);
+
+        replay(extractor, otherRequest, otherMap, keys, otherKeys);
+        assertNotEquals(map, otherMap);
+        verify(extractor, otherRequest, otherMap, keys, otherKeys);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java
new file mode 100644
index 000000000..4a9862f82
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasKeys;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ReadOnlyEnumerationMap#values()}.
+ */
+public class ReadOnlyEnumerationMapValuesCollectionTest {
+    /**
+     * The extractor to use.
+     */
+    private HasKeys<Integer> extractor;
+
+    /**
+     * The collection to test.
+     */
+    private Collection<Integer> coll;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(HasKeys.class);
+        ReadOnlyEnumerationMap<Integer> map = new ReadOnlyEnumerationMap<>(extractor);
+        coll = map.values();
+    }
+
+    /**
+     * Tests {@link Collection#add(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAdd() {
+        coll.add(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAddAll() {
+        coll.addAll(null);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        coll.clear();
+    }
+
+    /**
+     * Tests {@link Collection#contains(Object)}.
+     */
+    @Test
+    public void testContainsValue() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        assertTrue(coll.contains(2));
+        verify(extractor, keys);
+    }
+
+    /**
+     * Tests {@link Collection#contains(Object)}.
+     */
+    @Test
+    public void testContainsValueFalse() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        assertFalse(coll.contains(3));
+        verify(extractor, keys);
+    }
+
+    @Test
+    public void testContainsAll() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        List<Integer> coll = new ArrayList<>();
+        coll.add(1);
+        coll.add(2);
+        assertTrue(this.coll.containsAll(coll));
+        verify(extractor, keys);
+    }
+
+    @Test
+    public void testContainsAllFalse() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        List<Integer> coll = new ArrayList<>();
+        coll.add(3);
+        assertFalse(this.coll.containsAll(coll));
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#isEmpty()}.
+     */
+    @Test
+    public void testIsEmpty() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+
+        replay(extractor, keys);
+        assertFalse(coll.isEmpty());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#iterator()}.
+     */
+    @Test
+    public void testIterator() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+
+        expect(extractor.getValue("two")).andReturn(2);
+
+        replay(extractor, keys);
+        Iterator<Integer> entryIt = coll.iterator();
+        assertTrue(entryIt.hasNext());
+        assertEquals(new Integer(2), entryIt.next());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#iterator()}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testIteratorRemove() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+
+        try {
+            replay(extractor, keys);
+            coll.iterator().remove();
+        } finally {
+            verify(extractor, keys);
+        }
+    }
+
+    /**
+     * Tests {@link Collection#remove(Object)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        coll.remove(null);
+    }
+
+    /**
+     * Tests {@link Collection#removeAll(Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveAll() {
+        coll.removeAll(null);
+    }
+
+    /**
+     * Tests {@link Collection#retainAll(Collection)}.
+     */
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRetainAll() {
+        coll.retainAll(null);
+    }
+
+    /**
+     * Test method for {@link HeaderValuesMap#size()}.
+     */
+    @Test
+    public void testSize() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        replay(extractor, keys);
+        assertEquals(2, coll.size());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#toArray()}.
+     */
+    @Test
+    public void testToArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        Integer[] entryArray = new Integer[] {1, 2};
+
+        replay(extractor, keys);
+        assertArrayEquals(entryArray, coll.toArray());
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link Collection#toArray(Object[])}.
+     */
+    @Test
+    public void testToArrayTArray() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+
+        Integer[] entryArray = new Integer[] {1, 2};
+
+        replay(extractor, keys);
+        Integer[] realArray = new Integer[2];
+        assertArrayEquals(entryArray, coll.toArray(realArray));
+        verify(extractor, keys);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/RemovableKeySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/RemovableKeySetTest.java
new file mode 100644
index 000000000..e60b02ed6
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/RemovableKeySetTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasRemovableKeys;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link RemovableKeySet}.
+ */
+public class RemovableKeySetTest {
+
+    /**
+     * The extractor to use.
+     */
+    private HasRemovableKeys<Integer> extractor;
+
+    /**
+     * The key set to test.
+     */
+    private RemovableKeySet entrySet;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(HasRemovableKeys.class);
+        entrySet = new RemovableKeySet(extractor);
+    }
+
+    /**
+     * Test method for {@link RemovableKeySet#remove(Object)}.
+     */
+    @Test
+    public void testRemove() {
+        expect(extractor.getValue("one")).andReturn(1);
+        extractor.removeValue("one");
+
+        replay(extractor);
+        assertTrue(entrySet.remove("one"));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link RemovableKeySet#remove(Object)}.
+     */
+    @Test
+    public void testRemoveNoEffect() {
+        expect(extractor.getValue("one")).andReturn(null);
+
+        replay(extractor);
+        assertFalse(entrySet.remove("one"));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link RemovableKeySet#removeAll(java.util.Collection)}.
+     */
+    @Test
+    public void testRemoveAll() {
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+        extractor.removeValue("one");
+        extractor.removeValue("two");
+
+        replay(extractor);
+        List<String> coll = new ArrayList<>();
+        coll.add("one");
+        coll.add("two");
+        assertTrue(entrySet.removeAll(coll));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link RemovableKeySet#retainAll(java.util.Collection)}.
+     */
+    @Test
+    public void testRetainAll() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("three");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        extractor.removeValue("three");
+
+        replay(extractor, keys);
+        List<String> coll = new ArrayList<>();
+        coll.add("one");
+        coll.add("two");
+        assertTrue(entrySet.retainAll(coll));
+        verify(extractor, keys);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ScopeMapEntrySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ScopeMapEntrySetTest.java
new file mode 100644
index 000000000..c8ceea437
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ScopeMapEntrySetTest.java
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.AttributeExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ScopeMap#entrySet()}.
+ */
+public class ScopeMapEntrySetTest {
+
+    /**
+     * The extractor to use.
+     */
+    private AttributeExtractor extractor;
+
+    /**
+     * The entry set to test.
+     */
+    private Set<Map.Entry<String, Object>> entrySet;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(AttributeExtractor.class);
+        ScopeMap map = new ScopeMap(extractor);
+        entrySet = map.entrySet();
+    }
+
+    /**
+     * Tests {@link Set#add(Object)}.
+     */
+    @Test
+    public void testAdd() {
+        Map.Entry<String, Object> entry = createMock(Map.Entry.class);
+
+        expect(entry.getKey()).andReturn("one");
+        expect(entry.getValue()).andReturn(1);
+        expect(extractor.getValue("one")).andReturn(null);
+
+        extractor.setValue("one", 1);
+
+        replay(extractor, entry);
+        assertTrue(entrySet.add(entry));
+        verify(extractor, entry);
+    }
+
+    /**
+     * Tests {@link Set#add(Object)}.
+     */
+    @Test
+    public void testAddNoEffect() {
+        Map.Entry<String, Object> entry = createMock(Map.Entry.class);
+
+        expect(entry.getKey()).andReturn("one");
+        expect(entry.getValue()).andReturn(1);
+        expect(extractor.getValue("one")).andReturn(1);
+
+        replay(extractor, entry);
+        assertFalse(entrySet.add(entry));
+        verify(extractor, entry);
+    }
+
+    /**
+     * Tests {@link Set#addAll(java.util.Collection)}.
+     */
+    @Test
+    public void testAddAll() {
+        Map.Entry<String, Object> entry1 = createMock(Map.Entry.class);
+        Map.Entry<String, Object> entry2 = createMock(Map.Entry.class);
+
+        expect(entry1.getKey()).andReturn("one");
+        expect(entry1.getValue()).andReturn(1);
+        expect(entry2.getKey()).andReturn("two");
+        expect(entry2.getValue()).andReturn(2);
+        expect(extractor.getValue("one")).andReturn(null);
+        expect(extractor.getValue("two")).andReturn(null);
+
+        extractor.setValue("one", 1);
+        extractor.setValue("two", 2);
+
+        replay(extractor, entry1, entry2);
+        List<Map.Entry<String, Object>> coll = new ArrayList<>();
+        coll.add(entry1);
+        coll.add(entry2);
+        assertTrue(entrySet.addAll(coll));
+        verify(extractor, entry1, entry2);
+    }
+
+    /**
+     * Test method for {@link ScopeMap#clear()}.
+     */
+    @Test
+    public void testClear() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        extractor.removeValue("one");
+        extractor.removeValue("two");
+
+        replay(extractor, keys);
+        entrySet.clear();
+        verify(extractor, keys);
+    }
+
+    /**
+     * Tests {@link Set#remove(Object)}.
+     */
+    @Test
+    public void testRemove() {
+        Map.Entry<String, Object> entry = createMock(Map.Entry.class);
+
+        expect(entry.getKey()).andReturn("one");
+        expect(entry.getValue()).andReturn(1);
+        expect(extractor.getValue("one")).andReturn(1);
+        extractor.removeValue("one");
+
+        replay(extractor, entry);
+        assertTrue(entrySet.remove(entry));
+        verify(extractor, entry);
+    }
+
+    /**
+     * Tests {@link Set#remove(Object)}.
+     */
+    @Test
+    public void testRemoveNoEffect() {
+        Map.Entry<String, Object> entry = createMock(Map.Entry.class);
+
+        expect(entry.getKey()).andReturn("one");
+        expect(extractor.getValue("one")).andReturn(null);
+
+        replay(extractor, entry);
+        assertFalse(entrySet.remove(entry));
+        verify(extractor, entry);
+    }
+
+    /**
+     * Tests {@link Set#addAll(java.util.Collection)}.
+     */
+    @Test
+    public void testRemoveAll() {
+        Map.Entry<String, Object> entry1 = createMock(Map.Entry.class);
+        Map.Entry<String, Object> entry2 = createMock(Map.Entry.class);
+
+        expect(entry1.getKey()).andReturn("one");
+        expect(entry1.getValue()).andReturn(1);
+        expect(entry2.getKey()).andReturn("two");
+        expect(entry2.getValue()).andReturn(2);
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(2);
+        extractor.removeValue("one");
+        extractor.removeValue("two");
+
+        replay(extractor, entry1, entry2);
+        List<Map.Entry<String, Object>> coll = new ArrayList<>();
+        coll.add(entry1);
+        coll.add(entry2);
+        assertTrue(entrySet.removeAll(coll));
+        verify(extractor, entry1, entry2);
+    }
+
+    /**
+     * Tests {@link Set#addAll(java.util.Collection)}.
+     */
+    @Test
+    public void testRetainAll() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("three");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        Map.Entry<String, Object> entry1 = new MapEntry<>("one", 1, false);
+        Map.Entry<String, Object> entry2 = new MapEntry<>("two", 2, false);
+
+        expect(extractor.getValue("one")).andReturn(1);
+        expect(extractor.getValue("two")).andReturn(3);
+        expect(extractor.getValue("three")).andReturn(4);
+        extractor.removeValue("two");
+        extractor.removeValue("three");
+
+        replay(extractor, keys);
+        List<Map.Entry<String, Object>> coll = new ArrayList<>();
+        coll.add(entry1);
+        coll.add(entry2);
+        assertTrue(entrySet.retainAll(coll));
+        verify(extractor, keys);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ScopeMapTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ScopeMapTest.java
new file mode 100644
index 000000000..09853bcae
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ScopeMapTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.AttributeExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ScopeMap}.
+ */
+public class ScopeMapTest {
+
+    /**
+     * The map tot est.
+     */
+    private ScopeMap map;
+
+    /**
+     * The extractor to use.
+     */
+    private AttributeExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        extractor = createMock(AttributeExtractor.class);
+        map = new ScopeMap(extractor);
+    }
+
+    /**
+     * Test method for {@link ScopeMap#clear()}.
+     */
+    @Test
+    public void testClear() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(extractor.getKeys()).andReturn(keys);
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("one");
+        expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.nextElement()).andReturn("two");
+        expect(keys.hasMoreElements()).andReturn(false);
+
+        extractor.removeValue("one");
+        extractor.removeValue("two");
+
+        replay(extractor, keys);
+        map.clear();
+        verify(extractor, keys);
+    }
+
+    /**
+     * Test method for {@link ScopeMap#keySet()}.
+     */
+    @Test
+    public void testKeySet() {
+        replay(extractor);
+        assertTrue(map.keySet() instanceof RemovableKeySet);
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link ScopeMap#put(String, Object)}.
+     */
+    @Test
+    public void testPutStringObject() {
+        expect(extractor.getValue("one")).andReturn(null);
+        extractor.setValue("one", 1);
+
+        replay(extractor);
+        assertNull(map.put("one", 1));
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link ScopeMap#putAll(Map)}.
+     */
+    @Test
+    public void testPutAllMapOfQextendsStringQextendsObject() {
+        Map<String, Object> items = new LinkedHashMap<>();
+        items.put("one", 1);
+        items.put("two", 2);
+
+        extractor.setValue("one", 1);
+        extractor.setValue("two", 2);
+
+        replay(extractor);
+        map.putAll(items);
+        verify(extractor);
+    }
+
+    /**
+     * Test method for {@link ScopeMap#remove(Object)}.
+     */
+    @Test
+    public void testRemoveObject() {
+        expect(extractor.getValue("one")).andReturn(1);
+        extractor.removeValue("one");
+
+        replay(extractor);
+        assertEquals(1, map.remove("one"));
+        verify(extractor);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/locale/LocaleUtilTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/locale/LocaleUtilTest.java
new file mode 100644
index 000000000..202a68c48
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/locale/LocaleUtilTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.request.locale;
+
+import junit.framework.TestCase;
+
+import java.util.Locale;
+
+/**
+ * Tests {@link LocaleUtil}.
+ */
+public class LocaleUtilTest extends TestCase {
+
+    /**
+     * Test method for {@link LocaleUtil#getParentLocale(Locale)}.
+     */
+    public void testGetParentLocale() {
+        assertNull("The parent locale of NULL_LOCALE is not correct", LocaleUtil.getParentLocale(Locale.ROOT));
+        assertEquals("The parent locale of 'en' is not correct", Locale.ROOT, LocaleUtil.getParentLocale(Locale.ENGLISH));
+        assertEquals("The parent locale of 'en_US' is not correct", Locale.ENGLISH, LocaleUtil.getParentLocale(Locale.US));
+        Locale locale = new Locale("es", "ES", "Traditional_WIN");
+        Locale parentLocale = new Locale("es", "ES");
+        assertEquals("The parent locale of 'es_ES_Traditional_WIN' is not correct", parentLocale, LocaleUtil.getParentLocale(locale));
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java
new file mode 100644
index 000000000..48bd0a21b
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/locale/PostfixedApplicationResourceTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.locale;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests PostfixedApplicationResource.
+ */
+public class PostfixedApplicationResourceTest {
+
+    private static class TestApplicationResource extends PostfixedApplicationResource {
+        public TestApplicationResource(String path, Locale locale) {
+            super(path, locale);
+        }
+
+        public TestApplicationResource(String localePath) {
+            super(localePath);
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return null;
+        }
+
+        @Override
+        public long getLastModified() throws IOException {
+            return 0;
+        }
+
+    }
+
+    /**
+     * Test getLocalePath(String path, Locale locale).
+     */
+    @Test
+    public void testGetLocalePath() {
+        TestApplicationResource resource = new TestApplicationResource("/my test/path_fr.html");
+        assertEquals("/my test/path.html", resource.getLocalePath(null));
+        assertEquals("/my test/path.html", resource.getLocalePath(Locale.ROOT));
+        assertEquals("/my test/path_it.html", resource.getLocalePath(Locale.ITALIAN));
+        assertEquals("/my test/path_it_IT.html", resource.getLocalePath(Locale.ITALY));
+        assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath(new Locale("en", "GB", "scotland")));
+    }
+
+    @Test
+    public void testBuildFromString() {
+        TestApplicationResource resource = new TestApplicationResource("/my test/path_en_GB_scotland.html");
+        assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en", "GB", "scotland"), resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_it_IT.html");
+        assertEquals("/my test/path_it_IT.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALY, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_it.html");
+        assertEquals("/my test/path_it.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALIAN, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path.html");
+        assertEquals("/my test/path.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_zz.html");
+        assertEquals("/my test/path_zz.html", resource.getLocalePath());
+        assertEquals("/my test/path_zz.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_en_ZZ.html");
+        assertEquals("/my test/path_en.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_tiles.html");
+        assertEquals("/my test/path_tiles.html", resource.getLocalePath());
+        assertEquals("/my test/path_tiles.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_longwordthatbreaksISO639.html");
+        assertEquals("/my test/path_longwordthatbreaksISO639.html", resource.getLocalePath());
+        assertEquals("/my test/path_longwordthatbreaksISO639.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_en_tiles.html");
+        assertEquals("/my test/path_en.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new TestApplicationResource("/my test/path_en_longwordthatbreaksISO3166.html");
+        assertEquals("/my test/path_en.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+    }
+
+    @Test
+    public void testBuildFromStringAndLocale() {
+        TestApplicationResource resource = new TestApplicationResource("/my test/path.html", new Locale("en", "GB", "scotland"));
+        assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en", "GB", "scotland"), resource.getLocale());
+        resource = new TestApplicationResource("/my test/path.html", Locale.ITALY);
+        assertEquals("/my test/path_it_IT.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALY, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path.html", Locale.ITALIAN);
+        assertEquals("/my test/path_it.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALIAN, resource.getLocale());
+        resource = new TestApplicationResource("/my test/path.html", Locale.ROOT);
+        assertEquals("/my test/path.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
new file mode 100644
index 000000000..964ca1b73
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.locale;
+
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.util.Locale;
+
+import static java.lang.System.setProperty;
+import static java.lang.reflect.Modifier.FINAL;
+import static org.apache.tiles.request.locale.URLApplicationResource.REMOTE_PROTOCOLS_PROPERTY;
+import static org.apache.tiles.request.locale.URLApplicationResource.initRemoteProtocols;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests URLApplicationResource.
+ */
+public class URLApplicationResourceTest {
+
+    private static final String EXPECTED_MESSAGE = "aMessage";
+
+    private static class TestUrlStreamHandler extends URLStreamHandler {
+
+        @Override
+        protected URLConnection openConnection(final URL u) throws IOException {
+            throw new IOException(EXPECTED_MESSAGE);
+        }
+    }
+
+    private static class TestURLStreamHandlerFactory implements URLStreamHandlerFactory {
+
+        @Override
+        public URLStreamHandler createURLStreamHandler(final String protocol) {
+            if ("test1".equals(protocol) || "test2".equals(protocol)) {
+                return new TestUrlStreamHandler();
+            }
+            return null;
+        }
+    }
+
+    @BeforeClass
+    public static void setURLStreamHandlerFactory() {
+        URL.setURLStreamHandlerFactory(new TestURLStreamHandlerFactory());
+    }
+
+    @After
+    public void tearDown() {
+        setProperty(REMOTE_PROTOCOLS_PROPERTY, "");
+    }
+
+    /**
+     * Test getLocalePath(String path, Locale locale).
+     */
+    @Test
+    public void testGetLocalePath() throws MalformedURLException {
+        URLApplicationResource resource = new URLApplicationResource("/my test/path_fr.html", new URL("file:///"));
+        assertEquals("/my test/path.html", resource.getLocalePath(null));
+        assertEquals("/my test/path.html", resource.getLocalePath(Locale.ROOT));
+        assertEquals("/my test/path_it.html", resource.getLocalePath(Locale.ITALIAN));
+        assertEquals("/my test/path_it_IT.html", resource.getLocalePath(Locale.ITALY));
+        assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath(new Locale("en", "GB", "scotland")));
+    }
+
+    @Test
+    public void testBuildFromString() throws MalformedURLException {
+        URLApplicationResource resource = new URLApplicationResource("/my test/path_en_GB_scotland.html", new URL("file:///"));
+        assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en", "GB", "scotland"), resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_it_IT.html", new URL("file:///"));
+        assertEquals("/my test/path_it_IT.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALY, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_it.html", new URL("file:///"));
+        assertEquals("/my test/path_it.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALIAN, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path.html", new URL("file:///"));
+        assertEquals("/my test/path.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_zz.html", new URL("file:///"));
+        assertEquals("/my test/path_zz.html", resource.getLocalePath());
+        assertEquals("/my test/path_zz.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_en_ZZ.html", new URL("file:///"));
+        assertEquals("/my test/path_en.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_tiles.html", new URL("file:///"));
+        assertEquals("/my test/path_tiles.html", resource.getLocalePath());
+        assertEquals("/my test/path_tiles.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_longwordthatbreaksISO639.html", new URL("file:///"));
+        assertEquals("/my test/path_longwordthatbreaksISO639.html", resource.getLocalePath());
+        assertEquals("/my test/path_longwordthatbreaksISO639.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_en_tiles.html", new URL("file:///"));
+        assertEquals("/my test/path_en.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+        resource = new URLApplicationResource("/my test/path_en_longwordthatbreaksISO3166.html", new URL("file:///"));
+        assertEquals("/my test/path_en.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en"), resource.getLocale());
+    }
+
+    @Test
+    public void testBuildFromStringAndLocale() throws MalformedURLException {
+        URLApplicationResource resource = new URLApplicationResource("/my test/path.html", new Locale("en", "GB", "scotland"), new URL("file:///"));
+        assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(new Locale("en", "GB", "scotland"), resource.getLocale());
+        resource = new URLApplicationResource("/my test/path.html", Locale.ITALY, new URL("file:///"));
+        assertEquals("/my test/path_it_IT.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALY, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path.html", Locale.ITALIAN, new URL("file:///"));
+        assertEquals("/my test/path_it.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ITALIAN, resource.getLocale());
+        resource = new URLApplicationResource("/my test/path.html", Locale.ROOT, new URL("file:///"));
+        assertEquals("/my test/path.html", resource.getLocalePath());
+        assertEquals("/my test/path.html", resource.getPath());
+        assertEquals(Locale.ROOT, resource.getLocale());
+    }
+
+    @Test
+    public void testGetLastModified() throws IOException {
+        URL url = getClass().getClassLoader().getResource("org/apache/tiles/request/locale/resource.txt");
+        assertNotNull(url);
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/locale/resource.txt", url);
+        assertTrue(resource.getLastModified() > 0);
+    }
+
+    @Test
+    public void testGetLastModifiedWithSpace() throws IOException {
+        URL url = getClass().getClassLoader().getResource("org/apache/tiles/request/locale/resource with space.txt");
+        assertNotNull(url);
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/locale/resource with space.txt", url);
+        assertTrue(resource.getLastModified() > 0);
+    }
+
+    @Test
+    public void testGetInputStream() throws IOException {
+        URL url = getClass().getClassLoader().getResource("org/apache/tiles/request/locale/resource.txt");
+        assertNotNull(url);
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/locale/resource.txt", url);
+        InputStream is = resource.getInputStream();
+        assertNotNull(is);
+        is.close();
+    }
+
+    @Test
+    public void testGetInputStreamWithSpace() throws IOException {
+        URL url = getClass().getClassLoader().getResource("org/apache/tiles/request/locale/resource with space.txt");
+        assertNotNull(url);
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/locale/resource with space.txt", url);
+        InputStream is = resource.getInputStream();
+        assertNotNull(is);
+        is.close();
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void testLocalProtocol() throws IOException {
+        URL url = new URL("file://foo/bar.txt");
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/locale/resource.txt", url);
+        resource.getInputStream();
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/reflect/CannotInstantiateObjectExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/reflect/CannotInstantiateObjectExceptionTest.java
new file mode 100644
index 000000000..b170ca4e7
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/reflect/CannotInstantiateObjectExceptionTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.reflect;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link CannotInstantiateObjectException}.
+ */
+public class CannotInstantiateObjectExceptionTest {
+
+    /**
+     * Test method for {@link CannotInstantiateObjectException#CannotInstantiateObjectException(String, Throwable)}.
+     */
+    @Test
+    public void testCannotInstantiateObjectExceptionStringThrowable() {
+        Throwable cause = new Throwable();
+        CannotInstantiateObjectException exception = new CannotInstantiateObjectException("my message", cause);
+        assertEquals("my message", exception.getMessage());
+        assertEquals(cause, exception.getCause());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/reflect/ClassUtilTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/reflect/ClassUtilTest.java
new file mode 100644
index 000000000..db01a2414
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/reflect/ClassUtilTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.request.reflect;
+
+import org.junit.Test;
+
+import java.beans.PropertyDescriptor;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link ClassUtil}.
+ */
+public class ClassUtilTest {
+
+    /**
+     * The size of descriptor map.
+     */
+    private static final int MAP_SIZE = 3;
+
+    /**
+     * Test method for {@link ClassUtil#collectBeanInfo(Class, Map)}.
+     */
+    @Test
+    public void testCollectBeanInfo() {
+        Map<String, PropertyDescriptor> name2descriptor = new HashMap<>();
+        ClassUtil.collectBeanInfo(TestInterface.class, name2descriptor);
+        assertEquals(MAP_SIZE, name2descriptor.size());
+        PropertyDescriptor descriptor = name2descriptor.get("value");
+        assertEquals("value", descriptor.getName());
+        assertEquals(int.class, descriptor.getPropertyType());
+        assertNotNull(descriptor.getReadMethod());
+        assertNotNull(descriptor.getWriteMethod());
+        descriptor = name2descriptor.get("value2");
+        assertEquals("value2", descriptor.getName());
+        assertEquals(long.class, descriptor.getPropertyType());
+        assertNotNull(descriptor.getReadMethod());
+        assertNull(descriptor.getWriteMethod());
+        descriptor = name2descriptor.get("value3");
+        assertEquals("value3", descriptor.getName());
+        assertEquals(String.class, descriptor.getPropertyType());
+        assertNull(descriptor.getReadMethod());
+        assertNotNull(descriptor.getWriteMethod());
+    }
+
+    /**
+     * Test method for {@link ClassUtil#getClass(String, Class)}.
+     * @throws ClassNotFoundException If something goes wrong.
+     */
+    @Test
+    public void testGetClass() throws ClassNotFoundException {
+        assertEquals(TestInterface.class, ClassUtil.getClass(
+                TestInterface.class.getName(), Object.class));
+    }
+
+    /**
+     * Test method for {@link ClassUtil#getClass(String, Class)}.
+     * @throws ClassNotFoundException If something goes wrong.
+     */
+    @Test(expected = ClassNotFoundException.class)
+    public void testGetClassException() throws ClassNotFoundException {
+        ClassUtil.getClass("this.class.does.not.Exist", Object.class);
+    }
+
+    /**
+     * Test method for {@link ClassUtil#instantiate(String, boolean)}.
+     */
+    @Test
+    public void testInstantiate() {
+        assertNotNull(ClassUtil.instantiate(TestClass.class.getName(), true));
+        assertNull(ClassUtil.instantiate("this.class.does.not.Exist", true));
+    }
+
+    /**
+     * Test method for {@link ClassUtil#instantiate(String, boolean)}.
+     */
+    @Test
+    public void testInstantiateOneParameter() {
+        assertNotNull(ClassUtil.instantiate(TestClass.class.getName()));
+    }
+
+    /**
+     * Test method for {@link ClassUtil#instantiate(String)}.
+     */
+    @Test(expected = CannotInstantiateObjectException.class)
+    public void testInstantiateOneParameterException() {
+        assertNotNull(ClassUtil.instantiate("this.class.does.not.Exist"));
+    }
+
+    /**
+     * Test method for {@link ClassUtil#instantiate(String)}.
+     */
+    @Test(expected = CannotInstantiateObjectException.class)
+    public void testInstantiateInstantiationException() {
+        ClassUtil.instantiate(TestInterface.class.getName());
+    }
+
+    /**
+     * Test method for {@link ClassUtil#instantiate(String)}.
+     */
+    @Test(expected = CannotInstantiateObjectException.class)
+    public void testInstantiateIllegalAccessException() {
+        ClassUtil.instantiate(TestPrivateClass.class.getName());
+    }
+
+    /**
+     * Interface to be used as test.
+     *
+     * @version $Rev$ $Date$
+     */
+    public interface TestInterface {
+
+        /**
+         * The value.
+         *
+         * @return The value.
+         */
+        int getValue();
+
+        /**
+         * The value.
+         *
+         * @param value The value.
+         */
+        void setValue(int value);
+
+        /**
+         * The value.
+         *
+         * @return The value.
+         */
+        long getValue2();
+
+        /**
+         * The value.
+         *
+         * @param value3 The value.
+         */
+        @SuppressWarnings("unused")
+        void setValue3(String value3);
+    }
+
+    /**
+     * A test static class.
+     */
+    public static class TestClass {
+    }
+
+    /**
+     * A test static private class.
+     */
+    private static class TestPrivateClass {
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/render/BasicRendererFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/render/BasicRendererFactoryTest.java
new file mode 100644
index 000000000..c133b4cb2
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/render/BasicRendererFactoryTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.render;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Basic renderer factory implementation.
+ */
+public class BasicRendererFactoryTest {
+
+    /**
+     * The renderer factory.
+     */
+    private BasicRendererFactory rendererFactory;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        rendererFactory = new BasicRendererFactory();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        replay(applicationContext);
+    }
+
+    /**
+     * Tests execution and
+     * {@link BasicRendererFactory#getRenderer(String)}.
+     */
+    @Test
+    public void testInitAndGetRenderer() {
+        Renderer renderer1 = createMock(Renderer.class);
+        Renderer renderer2 = createMock(Renderer.class);
+        Renderer renderer3 = createMock(Renderer.class);
+        Renderer renderer4 = createMock(Renderer.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        replay(renderer1, renderer2, renderer3, renderer4, applicationContext);
+        rendererFactory.registerRenderer("string", renderer1);
+        rendererFactory.registerRenderer("test", renderer2);
+        rendererFactory.registerRenderer("test2", renderer3);
+        rendererFactory.setDefaultRenderer(renderer4);
+        Renderer renderer = rendererFactory.getRenderer("string");
+        assertSame(renderer1, renderer);
+        renderer = rendererFactory.getRenderer("test");
+        assertSame(renderer2, renderer);
+        renderer = rendererFactory.getRenderer("test2");
+        assertSame(renderer3, renderer);
+        renderer = rendererFactory.getRenderer(null);
+        assertSame(renderer4, renderer);
+        verify(renderer1, renderer2, renderer3, renderer4, applicationContext);
+    }
+
+    /**
+     * Tests execution and
+     * {@link BasicRendererFactory#getRenderer(String)}.
+     */
+    @Test(expected = NoSuchRendererException.class)
+    public void testGetRendererException() {
+        Renderer renderer1 = createMock(Renderer.class);
+        Renderer renderer2 = createMock(Renderer.class);
+        Renderer renderer3 = createMock(Renderer.class);
+        Renderer renderer4 = createMock(Renderer.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        replay(renderer1, renderer2, renderer3, renderer4, applicationContext);
+        rendererFactory.registerRenderer("string", renderer1);
+        rendererFactory.registerRenderer("test", renderer2);
+        rendererFactory.registerRenderer("test2", renderer3);
+        rendererFactory.setDefaultRenderer(renderer4);
+        try {
+            rendererFactory.getRenderer("nothing");
+        } finally {
+            verify(renderer1, renderer2, renderer3, renderer4, applicationContext);
+        }
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/render/ChainedDelegateRendererTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/render/ChainedDelegateRendererTest.java
new file mode 100644
index 000000000..31daf7fe1
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/render/ChainedDelegateRendererTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.render;
+
+import org.apache.tiles.request.Request;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link ChainedDelegateRenderer}.
+ */
+public class ChainedDelegateRendererTest {
+
+    /**
+     * The renderer.
+     */
+    private ChainedDelegateRenderer renderer;
+
+    /**
+     * A mock string attribute renderer.
+     */
+    private Renderer stringRenderer;
+
+    /**
+     * A mock template attribute renderer.
+     */
+    private Renderer templateRenderer;
+
+    /**
+     * A mock definition attribute renderer.
+     */
+    private Renderer definitionRenderer;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        stringRenderer = createMock(Renderer.class);
+        templateRenderer = createMock(Renderer.class);
+        definitionRenderer = createMock(Renderer.class);
+        renderer = new ChainedDelegateRenderer();
+        renderer.addAttributeRenderer(definitionRenderer);
+        renderer.addAttributeRenderer(templateRenderer);
+        renderer.addAttributeRenderer(stringRenderer);
+    }
+
+    /**
+     * Tests
+     * {@link ChainedDelegateRenderer#render(String, Request)}
+     * writing a definition.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test
+    public void testWriteDefinition() throws IOException {
+        Request requestContext = EasyMock.createMock(Request.class);
+
+        expect(definitionRenderer.isRenderable("my.definition", requestContext)).andReturn(Boolean.TRUE);
+        definitionRenderer.render("my.definition", requestContext);
+
+        replay(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        renderer.render("my.definition", requestContext);
+        verify(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+    }
+
+    /**
+     * Tests
+     * {@link ChainedDelegateRenderer#render(String, Request)}
+     * writing a definition.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testWriteNull() throws IOException {
+        StringWriter writer = new StringWriter();
+        Request requestContext = EasyMock.createMock(Request.class);
+
+        replay(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        try {
+            renderer.render(null, requestContext);
+        } finally {
+            writer.close();
+            verify(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        }
+    }
+
+    /**
+     * Tests
+     * {@link ChainedDelegateRenderer#render(String, Request)}
+     * writing a definition.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test(expected = CannotRenderException.class)
+    public void testWriteNotRenderable() throws IOException {
+        StringWriter writer = new StringWriter();
+        Request requestContext = EasyMock.createMock(Request.class);
+
+        expect(definitionRenderer.isRenderable("Result", requestContext)).andReturn(Boolean.FALSE);
+        expect(templateRenderer.isRenderable("Result", requestContext)).andReturn(Boolean.FALSE);
+        expect(stringRenderer.isRenderable("Result", requestContext)).andReturn(Boolean.FALSE);
+
+        replay(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        try {
+            renderer.render("Result", requestContext);
+        } finally {
+            writer.close();
+            verify(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        }
+    }
+
+    /**
+     * Tests
+     * {@link ChainedDelegateRenderer#render(String, Request)}
+     * writing a string.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test
+    public void testWriteString() throws IOException {
+        Request requestContext = EasyMock.createMock(Request.class);
+        expect(definitionRenderer.isRenderable("Result", requestContext)).andReturn(Boolean.FALSE);
+        expect(templateRenderer.isRenderable("Result", requestContext)).andReturn(Boolean.FALSE);
+        expect(stringRenderer.isRenderable("Result", requestContext)).andReturn(Boolean.TRUE);
+        stringRenderer.render("Result", requestContext);
+
+        replay(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        renderer.render("Result", requestContext);
+        verify(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+    }
+
+    /**
+     * Tests
+     * {@link ChainedDelegateRenderer#render(String, Request)}
+     * writing a template.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test
+    public void testWriteTemplate() throws IOException {
+        StringWriter writer = new StringWriter();
+        Request requestContext = EasyMock.createMock(Request.class);
+        templateRenderer.render("/myTemplate.jsp", requestContext);
+        expect(definitionRenderer.isRenderable("/myTemplate.jsp", requestContext)).andReturn(Boolean.FALSE);
+        expect(templateRenderer.isRenderable("/myTemplate.jsp", requestContext)).andReturn(Boolean.TRUE);
+
+        replay(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+        renderer.render("/myTemplate.jsp", requestContext);
+        writer.close();
+        verify(requestContext, stringRenderer, templateRenderer, definitionRenderer);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/render/DispatchRendererTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/render/DispatchRendererTest.java
new file mode 100644
index 000000000..7f158ce69
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/render/DispatchRendererTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.render;
+
+import org.apache.tiles.request.DispatchRequest;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link DispatchRenderer}.
+ */
+public class DispatchRendererTest {
+
+    /**
+     * The renderer.
+     */
+    private DispatchRenderer renderer;
+
+    @Before
+    public void setUp() {
+        renderer = new DispatchRenderer();
+    }
+
+    @Test
+    public void testWrite() throws IOException {
+        DispatchRequest requestContext = createMock(DispatchRequest.class);
+        requestContext.dispatch("/myTemplate.jsp");
+        replay(requestContext);
+        renderer.render("/myTemplate.jsp", requestContext);
+        verify(requestContext);
+    }
+
+    @Test(expected = CannotRenderException.class)
+    public void testWriteNull() throws IOException {
+        DispatchRequest requestContext = createMock(DispatchRequest.class);
+        replay(requestContext);
+        renderer.render(null, requestContext);
+        verify(requestContext);
+    }
+
+    @Test
+    public void testIsRenderable() {
+        Request requestContext = createMock(DispatchRequest.class);
+        replay(requestContext);
+        assertTrue(renderer.isRenderable("/myTemplate.jsp", requestContext));
+        assertFalse(renderer.isRenderable(null, requestContext));
+        verify(requestContext);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/render/NoSuchRendererExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/render/NoSuchRendererExceptionTest.java
new file mode 100644
index 000000000..5c51a730c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/render/NoSuchRendererExceptionTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.request.render;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link NoSuchRendererException}.
+ */
+public class NoSuchRendererExceptionTest {
+
+    /**
+     * Test method for {@link NoSuchRendererException#NoSuchRendererException(String)}.
+     */
+    @Test
+    public void testNoSuchRendererExceptionString() {
+        NoSuchRendererException exception = new NoSuchRendererException("my message");
+        assertEquals("my message", exception.getMessage());
+        assertNull(exception.getCause());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/render/StringRendererTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/render/StringRendererTest.java
new file mode 100644
index 000000000..cce4710af
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/render/StringRendererTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.render;
+
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link StringRenderer}.
+ */
+public class StringRendererTest {
+
+    /**
+     * The renderer.
+     */
+    private StringRenderer renderer;
+
+    @Before
+    public void setUp() {
+        renderer = new StringRenderer();
+    }
+
+    /**
+     * Tests
+     * {@link StringRenderer#render(String, Request)}.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test
+    public void testWrite() throws IOException {
+        StringWriter writer = new StringWriter();
+        Request requestContext = createMock(Request.class);
+        expect(requestContext.getWriter()).andReturn(writer);
+        replay(requestContext);
+        renderer.render("Result", requestContext);
+        writer.close();
+        assertEquals("Not written 'Result'", "Result", writer.toString());
+        verify(requestContext);
+    }
+
+    /**
+     * Tests
+     * {@link StringRenderer#isRenderable(String, Request)}.
+     */
+    @Test
+    public void testIsRenderable() {
+        Request requestContext = createMock(Request.class);
+        replay(requestContext);
+        assertTrue(renderer.isRenderable("Result", requestContext));
+        verify(requestContext);
+    }
+}
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/request/locale/resource with space.txt b/plugins/tiles/src/test/resources/org/apache/tiles/request/locale/resource with space.txt
new file mode 100644
index 000000000..82cb4afe8
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/request/locale/resource with space.txt	
@@ -0,0 +1,17 @@
+ * 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.
+test
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/request/locale/resource.txt b/plugins/tiles/src/test/resources/org/apache/tiles/request/locale/resource.txt
new file mode 100644
index 000000000..82cb4afe8
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/request/locale/resource.txt
@@ -0,0 +1,17 @@
+ * 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.
+test


[struts] 02/23: WW-5233 Copies Portlet related Tiles code base

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 2fd075271de8b8a7c52c6cca868478232abe319c
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sat Oct 1 17:51:38 2022 +0200

    WW-5233 Copies Portlet related Tiles code base
---
 .../tiles/request/portlet/PortletRequest.java      | 344 +++++++++++++++++++++
 .../request/portlet/RenderPortletRequest.java      |  47 +++
 .../portlet/delegate/MimeResponseDelegate.java     |  72 +++++
 .../portlet/delegate/PortletRequestDelegate.java   |  79 +++++
 .../request/portlet/delegate/RequestDelegate.java  |  43 +++
 .../request/portlet/delegate/ResponseDelegate.java |  70 +++++
 .../portlet/delegate/StateAwareParameterMap.java   | 112 +++++++
 .../delegate/StateAwareRequestDelegate.java        |  83 +++++
 .../delegate/StateAwareResponseDelegate.java       |  57 ++++
 .../request/portlet/delegate/package-info.java     |  24 ++
 .../extractor/ApplicationScopeExtractor.java       |  66 ++++
 .../request/portlet/extractor/HeaderExtractor.java |  74 +++++
 .../portlet/extractor/InitParameterExtractor.java  |  57 ++++
 .../portlet/extractor/ParameterExtractor.java      |  56 ++++
 .../portlet/extractor/RequestScopeExtractor.java   |  66 ++++
 .../portlet/extractor/SessionScopeExtractor.java   |  88 ++++++
 .../extractor/StateAwareParameterExtractor.java    |  53 ++++
 .../request/portlet/extractor/package-info.java    |  24 ++
 .../apache/tiles/request/portlet/package-info.java |  24 ++
 .../request/collection/AddableParameterMap.java    |  95 ++++++
 20 files changed, 1534 insertions(+)

diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/PortletRequest.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/PortletRequest.java
new file mode 100644
index 000000000..6946776e4
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/PortletRequest.java
@@ -0,0 +1,344 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet;
+
+import org.apache.tiles.request.AbstractClientRequest;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.attribute.Addable;
+import org.apache.tiles.request.collection.HeaderValuesMap;
+import org.apache.tiles.request.collection.ReadOnlyEnumerationMap;
+import org.apache.tiles.request.collection.ScopeMap;
+import org.apache.tiles.request.portlet.delegate.RequestDelegate;
+import org.apache.tiles.request.portlet.delegate.ResponseDelegate;
+import org.apache.tiles.request.portlet.extractor.HeaderExtractor;
+import org.apache.tiles.request.portlet.extractor.RequestScopeExtractor;
+import org.apache.tiles.request.portlet.extractor.SessionScopeExtractor;
+
+import javax.portlet.PortletContext;
+import javax.portlet.PortletException;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.PortletResponse;
+import javax.portlet.PortletSession;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Portlet-based TilesApplicationContext implementation.
+ */
+public class PortletRequest extends AbstractClientRequest {
+
+    /**
+     * The native available scopes.
+     */
+    private static final List<String> SCOPES = Collections.unmodifiableList(Arrays.asList(REQUEST_SCOPE, "portletSession", "session", APPLICATION_SCOPE));
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of header name-value
+     * combinations (immutable).</p>
+     */
+    private Map<String, String> header = null;
+
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of header name-value
+     * combinations (write-only).</p>
+     */
+    private Addable<String> responseHeaders = null;
+
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of header name-values
+     * combinations (immutable).</p>
+     */
+    private Map<String, String[]> headerValues = null;
+
+    /**
+     * The <code>PortletContext</code> for this application.
+     */
+    protected PortletContext context;
+
+    /**
+     * <p>The <code>PortletRequest</code> for this request.</p>
+     */
+    protected javax.portlet.PortletRequest request;
+
+    /**
+     * The delegate to get information about parameters.
+     */
+    protected RequestDelegate requestDelegate;
+
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request scope
+     * attributes.</p>
+     */
+    private Map<String, Object> requestScope = null;
+
+
+    /**
+     * <p>The <code>PortletResponse</code> for this request.</p>
+     */
+    protected PortletResponse response;
+
+    /**
+     * The delegate to get information from a response (output stream, writer, etc.).
+     */
+    protected ResponseDelegate responseDelegate;
+
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of session scope
+     * attributes.</p>
+     */
+    private Map<String, Object> sessionScope = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of portlet session scope
+     * attributes.</p>
+     */
+    private Map<String, Object> portletSessionScope = null;
+
+
+    /**
+     * Creates a new instance of PortletTilesRequestContext.
+     *
+     * @param applicationContext The Tiles application context.
+     * @param context            The portlet context to use.
+     * @param request            The request object to use.
+     * @param response           The response object to use.
+     * @param requestDelegate    The request delegate.
+     * @param responseDelegate   The response delegate.
+     */
+    public PortletRequest(ApplicationContext applicationContext,
+                          PortletContext context, javax.portlet.PortletRequest request,
+                          PortletResponse response, RequestDelegate requestDelegate, ResponseDelegate responseDelegate) {
+        super(applicationContext);
+
+        // Save the specified Portlet API object references
+        this.context = context;
+        this.request = request;
+        this.response = response;
+        this.requestDelegate = requestDelegate;
+        this.responseDelegate = responseDelegate;
+    }
+
+    /**
+     * <p>Return the {@link PortletRequest} for this context.</p>
+     *
+     * @return The used portlet request.
+     */
+    public javax.portlet.PortletRequest getRequest() {
+        return (this.request);
+    }
+
+    /**
+     * Returns the portlet context.
+     *
+     * @return The portlet context.
+     */
+    public PortletContext getPortletContext() {
+        return context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String> getHeader() {
+        if ((header == null) && (request != null)) {
+            header = new ReadOnlyEnumerationMap<>(new HeaderExtractor(request, null));
+        }
+        return (header);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Addable<String> getResponseHeaders() {
+        if ((responseHeaders == null) && (request != null)) {
+            responseHeaders = new HeaderExtractor(null, response);
+        }
+        return (responseHeaders);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String[]> getHeaderValues() {
+        if ((headerValues == null) && (request != null)) {
+            headerValues = new HeaderValuesMap(new HeaderExtractor(request, response));
+        }
+        return (headerValues);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Object> getRequestScope() {
+        if ((requestScope == null) && (request != null)) {
+            requestScope = new ScopeMap(new RequestScopeExtractor(request));
+        }
+        return (requestScope);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Object> getSessionScope() {
+        if ((sessionScope == null) && (request != null)) {
+            sessionScope = new ScopeMap(new SessionScopeExtractor(request,
+                PortletSession.APPLICATION_SCOPE));
+        }
+        return (sessionScope);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Object> getPortletSessionScope() {
+        if ((portletSessionScope == null) && (request != null)) {
+            portletSessionScope = new ScopeMap(new SessionScopeExtractor(
+                request, PortletSession.APPLICATION_SCOPE));
+        }
+        return (portletSessionScope);
+    }
+
+    @Override
+    public List<String> getAvailableScopes() {
+        return SCOPES;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Locale getRequestLocale() {
+        return request.getLocale();
+    }
+
+    @Override
+    public Map<String, String> getParam() {
+        return requestDelegate.getParam();
+    }
+
+    @Override
+    public Map<String, String[]> getParamValues() {
+        return requestDelegate.getParamValues();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isUserInRole(String role) {
+        return request.isUserInRole(role);
+    }
+
+    @Override
+    public OutputStream getOutputStream() throws IOException {
+        return responseDelegate.getOutputStream();
+    }
+
+    @Override
+    public PrintWriter getPrintWriter() throws IOException {
+        return responseDelegate.getPrintWriter();
+    }
+
+    @Override
+    public Writer getWriter() throws IOException {
+        return responseDelegate.getWriter();
+    }
+
+    @Override
+    public boolean isResponseCommitted() {
+        return responseDelegate.isResponseCommitted();
+    }
+
+    @Override
+    public void setContentType(String contentType) {
+        responseDelegate.setContentType(contentType);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void doForward(String path) throws IOException {
+        if (responseDelegate.isResponseCommitted()) {
+            doInclude(path);
+            return;
+        }
+
+        try {
+            PortletRequestDispatcher rd = getPortletContext()
+                .getRequestDispatcher(path);
+
+            if (rd == null) {
+                throw new IOException(
+                    "No portlet request dispatcher returned for path '"
+                        + path + "'");
+            }
+
+            rd.forward(request, response);
+        } catch (PortletException e) {
+            throw new IOException("PortletException while including path '"
+                + path + "'.", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void doInclude(String path) throws IOException {
+        try {
+            PortletRequestDispatcher rd = getPortletContext()
+                .getRequestDispatcher(path);
+
+            if (rd == null) {
+                throw new IOException(
+                    "No portlet request dispatcher returned for path '"
+                        + path + "'");
+            }
+
+            rd.include(request, response);
+        } catch (PortletException e) {
+            throw new IOException("PortletException while including path '"
+                + path + "'.", e);
+        }
+    }
+
+    @Override
+    public Map<String, Object> getContext(String scope) {
+        if (REQUEST_SCOPE.equals(scope)) {
+            return getRequestScope();
+        } else if ("session".equals(scope)) {
+            return getSessionScope();
+        } else if ("portletSession".equals(scope)) {
+            return getPortletSessionScope();
+        } else if (APPLICATION_SCOPE.equals(scope)) {
+            return getApplicationScope();
+        }
+        throw new IllegalArgumentException(scope + " does not exist. Call getAvailableScopes() first to check.");
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/RenderPortletRequest.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/RenderPortletRequest.java
new file mode 100644
index 000000000..ea22c38a2
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/RenderPortletRequest.java
@@ -0,0 +1,47 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.portlet.delegate.MimeResponseDelegate;
+import org.apache.tiles.request.portlet.delegate.PortletRequestDelegate;
+
+import javax.portlet.PortletContext;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+
+/**
+ * Portlet request for a {@link RenderRequest}.
+ */
+public class RenderPortletRequest extends PortletRequest {
+
+    /**
+     * Constructor.
+     *
+     * @param applicationContext The application context.
+     * @param context            The portlet context.
+     * @param request            The portlet request.
+     * @param response           The portlet response.
+     */
+    public RenderPortletRequest(ApplicationContext applicationContext, PortletContext context, RenderRequest request, RenderResponse response) {
+        super(applicationContext, context, request, response, new PortletRequestDelegate(request), new MimeResponseDelegate(response));
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/MimeResponseDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/MimeResponseDelegate.java
new file mode 100644
index 000000000..347873cf1
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/MimeResponseDelegate.java
@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import javax.portlet.MimeResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Response delegate in case of {@link MimeResponse}.
+ */
+public class MimeResponseDelegate implements ResponseDelegate {
+
+    /**
+     * The response.
+     */
+    private final MimeResponse response;
+
+    /**
+     * Constructor.
+     *
+     * @param response The response.
+     */
+    public MimeResponseDelegate(MimeResponse response) {
+        this.response = response;
+    }
+
+    /** {@inheritDoc} */
+    public OutputStream getOutputStream() throws IOException {
+        return response.getPortletOutputStream();
+    }
+
+    /** {@inheritDoc} */
+    public PrintWriter getPrintWriter() throws IOException {
+        return response.getWriter();
+    }
+
+    /** {@inheritDoc} */
+    public Writer getWriter() throws IOException {
+        return response.getWriter();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isResponseCommitted() {
+        return response.isCommitted();
+    }
+
+    /** {@inheritDoc} */
+    public void setContentType(String contentType) {
+        response.setContentType(contentType);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/PortletRequestDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/PortletRequestDelegate.java
new file mode 100644
index 000000000..e5683d5a0
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/PortletRequestDelegate.java
@@ -0,0 +1,79 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import org.apache.tiles.request.collection.ReadOnlyEnumerationMap;
+import org.apache.tiles.request.portlet.extractor.ParameterExtractor;
+
+import javax.portlet.PortletRequest;
+import java.util.Map;
+
+/**
+ * Request delegate in case of simple Portlet request.
+ */
+public class PortletRequestDelegate implements RequestDelegate {
+
+    /**
+     * The request.
+     */
+    private final PortletRequest request;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request
+     * parameter name-value.</p>
+     */
+    private Map<String, String> param = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request
+     * parameter name-values.</p>
+     */
+    private Map<String, String[]> paramValues = null;
+
+    /**
+     * Constructor.
+     *
+     * @param request The request.
+     */
+    public PortletRequestDelegate(PortletRequest request) {
+        this.request = request;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String> getParam() {
+        if ((param == null) && (request != null)) {
+            param = new ReadOnlyEnumerationMap<>(new ParameterExtractor(request));
+        }
+        return (param);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String[]> getParamValues() {
+        if ((paramValues == null) && (request != null)) {
+            paramValues = request.getParameterMap();
+        }
+        return (paramValues);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/RequestDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/RequestDelegate.java
new file mode 100644
index 000000000..03846cc72
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/RequestDelegate.java
@@ -0,0 +1,43 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import java.util.Map;
+
+/**
+ * Exposes the parameters of a portlet request, if available.
+ */
+public interface RequestDelegate {
+
+    /**
+     * The parameters, as single values.
+     *
+     * @return The parameters.
+     */
+    Map<String, String> getParam();
+
+    /**
+     * The parameters, with values as array of strings.
+     *
+     * @return The parameters.
+     */
+    Map<String, String[]> getParamValues();
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/ResponseDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/ResponseDelegate.java
new file mode 100644
index 000000000..92f46cef6
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/ResponseDelegate.java
@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Exposes features of a response, if they are available.
+ */
+public interface ResponseDelegate {
+
+    /**
+     * Returns the output stream.
+     *
+     * @return The output stream.
+     * @throws IOException If the underlying response causes a problem.
+     */
+    OutputStream getOutputStream() throws IOException;
+
+    /**
+     * Returns the print writer.
+     *
+     * @return The print writer.
+     * @throws IOException If the underlying response causes a problem.
+     */
+    PrintWriter getPrintWriter() throws IOException;
+
+    /**
+     * Returns the writer.
+     *
+     * @return The writer.
+     * @throws IOException If the underlying response causes a problem.
+     */
+    Writer getWriter() throws IOException;
+
+    /**
+     * Sets the content type of the response.
+     *
+     * @param contentType The content type.
+     */
+    void setContentType(String contentType);
+
+    /**
+     * Checks if the response is committed.
+     *
+     * @return <code>true</code> if the response is committed.
+     */
+    boolean isResponseCommitted();
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareParameterMap.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareParameterMap.java
new file mode 100644
index 000000000..34e36bb31
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareParameterMap.java
@@ -0,0 +1,112 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Parameter map to be used when the response is a {@link javax.portlet.StateAwareResponse}.
+ */
+public class StateAwareParameterMap implements Map<String, String[]> {
+
+    /**
+     * The request parameter map.
+     */
+    private final Map<String, String[]> requestMap;
+
+    /**
+     * The response parameter map.
+     */
+    private final Map<String, String[]> responseMap;
+
+    /**
+     * Constructor.
+     *
+     * @param requestMap The request parameter map.
+     * @param responseMap The response parameter map.
+     */
+    public StateAwareParameterMap(Map<String, String[]> requestMap, Map<String, String[]> responseMap) {
+        this.requestMap = requestMap;
+        this.responseMap = responseMap;
+    }
+
+    @Override
+    public void clear() {
+        responseMap.clear();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return requestMap.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return requestMap.containsValue(value);
+    }
+
+    @Override
+    public Set<Entry<String, String[]>> entrySet() {
+        return requestMap.entrySet();
+    }
+
+    @Override
+    public String[] get(Object key) {
+        return requestMap.get(key);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return requestMap.isEmpty();
+    }
+
+    @Override
+    public Set<String> keySet() {
+        return requestMap.keySet();
+    }
+
+    @Override
+    public String[] put(String key, String[] value) {
+        return responseMap.put(key, value);
+    }
+
+    @Override
+    public void putAll(Map<? extends String, ? extends String[]> m) {
+        responseMap.putAll(m);
+    }
+
+    @Override
+    public String[] remove(Object key) {
+        return responseMap.remove(key);
+    }
+
+    @Override
+    public int size() {
+        return requestMap.size();
+    }
+
+    @Override
+    public Collection<String[]> values() {
+        return requestMap.values();
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareRequestDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareRequestDelegate.java
new file mode 100644
index 000000000..ede98a745
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareRequestDelegate.java
@@ -0,0 +1,83 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import org.apache.tiles.request.collection.AddableParameterMap;
+import org.apache.tiles.request.portlet.extractor.StateAwareParameterExtractor;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.StateAwareResponse;
+import java.util.Map;
+
+/**
+ * Exposes parameters getting them from a portlet reques and allowing to be put into a {@link StateAwareResponse}.
+ */
+public class StateAwareRequestDelegate implements RequestDelegate {
+
+    /**
+     * The request.
+     */
+    private final PortletRequest request;
+
+    /**
+     * The response.
+     */
+    private final StateAwareResponse response;
+
+    /**
+     * Constructor.
+     *
+     * @param request The request.
+     * @param response The response.
+     */
+    public StateAwareRequestDelegate(PortletRequest request, StateAwareResponse response) {
+        this.request = request;
+        this.response = response;
+    }
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request
+     * parameter name-value.</p>
+     */
+    private Map<String, String> param = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request
+     * parameter name-values.</p>
+     */
+    private Map<String, String[]> paramValues = null;
+
+    /** {@inheritDoc} */
+    public Map<String, String> getParam() {
+        if ((param == null) && (request != null)) {
+            param = new AddableParameterMap(new StateAwareParameterExtractor(request, response));
+        }
+        return (param);
+    }
+
+    /** {@inheritDoc} */
+    public Map<String, String[]> getParamValues() {
+        if ((paramValues == null) && (request != null)) {
+            paramValues = new StateAwareParameterMap(request.getParameterMap(), response.getRenderParameterMap());
+        }
+        return (paramValues);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareResponseDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareResponseDelegate.java
new file mode 100644
index 000000000..20e05cbcb
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareResponseDelegate.java
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * A state aware response does not allow to access to the output stream and similar, so it is, essentially,
+ * a feature blocker.
+ */
+public class StateAwareResponseDelegate implements ResponseDelegate {
+
+    @Override
+    public OutputStream getOutputStream() {
+        throw new UnsupportedOperationException("No outputstream available for state-aware response");
+    }
+
+    @Override
+    public PrintWriter getPrintWriter() {
+        throw new UnsupportedOperationException("No outputstream available for state-aware response");
+    }
+
+    @Override
+    public Writer getWriter() {
+        throw new UnsupportedOperationException("No outputstream available for state-aware response");
+    }
+
+    @Override
+    public boolean isResponseCommitted() {
+        return false;
+    }
+
+    @Override
+    public void setContentType(String contentType) {
+        throw new UnsupportedOperationException("No outputstream available for state-aware response");
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/package-info.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/package-info.java
new file mode 100644
index 000000000..5080dc3e0
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * $Id: package-info.java 1049711 2010-12-15 21:12:00Z apetrelli $
+ *
+ * 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.
+ */
+/**
+ * Delegations to map all the different types of request and responses.
+ */
+package org.apache.tiles.request.portlet.delegate;
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ApplicationScopeExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ApplicationScopeExtractor.java
new file mode 100644
index 000000000..590046cff
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ApplicationScopeExtractor.java
@@ -0,0 +1,66 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.AttributeExtractor;
+
+import javax.portlet.PortletContext;
+import java.util.Enumeration;
+
+/**
+ * Extracts attributes from portlet application scope.
+ */
+public class ApplicationScopeExtractor implements AttributeExtractor {
+
+    /**
+     * The portlet context.
+     */
+    private final PortletContext context;
+
+    /**
+     * Constructor.
+     *
+     * @param context The portlet context.
+     */
+    public ApplicationScopeExtractor(PortletContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public void setValue(String name, Object value) {
+        context.setAttribute(name, value);
+    }
+
+    @Override
+    public void removeValue(String name) {
+        context.removeAttribute(name);
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return context.getAttributeNames();
+    }
+
+    @Override
+    public Object getValue(String key) {
+        return context.getAttribute(key);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/HeaderExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/HeaderExtractor.java
new file mode 100644
index 000000000..0c94fa90f
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/HeaderExtractor.java
@@ -0,0 +1,74 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.EnumeratedValuesExtractor;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import java.util.Enumeration;
+
+/**
+ * Extracts and puts headers in portlet requests and responses.
+ */
+public class HeaderExtractor implements EnumeratedValuesExtractor {
+
+    /**
+     * The request.
+     */
+    private final PortletRequest request;
+
+    /**
+     * The response.
+     */
+    private final PortletResponse response;
+
+    /**
+     * Constructor.
+     *
+     * @param request The request.
+     * @param response The response.
+     */
+    public HeaderExtractor(PortletRequest request, PortletResponse response) {
+        this.request = request;
+        this.response = response;
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return request.getPropertyNames();
+   }
+
+    @Override
+    public String getValue(String key) {
+        return request.getProperty(key);
+    }
+
+    @Override
+    public Enumeration<String> getValues(String key) {
+        return request.getProperties(key);
+    }
+
+    @Override
+    public void setValue(String key, String value) {
+        response.setProperty(key, value);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/InitParameterExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/InitParameterExtractor.java
new file mode 100644
index 000000000..f27fdf4f1
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/InitParameterExtractor.java
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.HasKeys;
+
+import javax.portlet.PortletContext;
+import java.util.Enumeration;
+
+/**
+ * Extracts init parameters from a portlet context.
+ */
+public class InitParameterExtractor implements HasKeys<String> {
+
+    /**
+     * The portlet context.
+     */
+    private final PortletContext context;
+
+    /**
+     * Constructor.
+     *
+     * @param context The portlet context.
+     */
+    public InitParameterExtractor(PortletContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return context.getInitParameterNames();
+    }
+
+    @Override
+    public String getValue(String key) {
+        return context.getInitParameter(key);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ParameterExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ParameterExtractor.java
new file mode 100644
index 000000000..e412a84c6
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ParameterExtractor.java
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.HasKeys;
+
+import javax.portlet.PortletRequest;
+import java.util.Enumeration;
+
+/**
+ * Extracts parameters from a portlet request.
+ */
+public class ParameterExtractor implements HasKeys<String> {
+
+    /**
+     * The portlet request.
+     */
+    private final PortletRequest request;
+
+    /**
+     * Constructor.
+     *
+     * @param request The portlet request.
+     */
+    public ParameterExtractor(PortletRequest request) {
+        this.request = request;
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return request.getParameterNames();
+    }
+
+    @Override
+    public String getValue(String key) {
+        return request.getParameter(key);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/RequestScopeExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/RequestScopeExtractor.java
new file mode 100644
index 000000000..edc72bc9e
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/RequestScopeExtractor.java
@@ -0,0 +1,66 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.AttributeExtractor;
+
+import javax.portlet.PortletRequest;
+import java.util.Enumeration;
+
+/**
+ * Extracts attributes from request scope of a portlet request.
+ */
+public class RequestScopeExtractor implements AttributeExtractor {
+
+    /**
+     * The portlet request.
+     */
+    private final PortletRequest request;
+
+    /**
+     * Constructor.
+     *
+     * @param request The portlet request.
+     */
+    public RequestScopeExtractor(PortletRequest request) {
+        this.request = request;
+    }
+
+    @Override
+    public void setValue(String name, Object value) {
+        request.setAttribute(name, value);
+    }
+
+    @Override
+    public void removeValue(String name) {
+        request.removeAttribute(name);
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return request.getAttributeNames();
+    }
+
+    @Override
+    public Object getValue(String key) {
+        return request.getAttribute(key);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/SessionScopeExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/SessionScopeExtractor.java
new file mode 100644
index 000000000..9801454fa
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/SessionScopeExtractor.java
@@ -0,0 +1,88 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.AttributeExtractor;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
+import java.util.Enumeration;
+
+/**
+ * Extracts attributes from the session scope of a portlet request.
+ */
+public class SessionScopeExtractor implements AttributeExtractor {
+
+    /**
+     * The portlet request.
+     */
+    private final PortletRequest request;
+
+    /**
+     * The subscope (application or portlet).
+     */
+    private final int scope;
+
+    /**
+     * Constructor.
+     *
+     * @param request The request.
+     * @param scope The subscope (application or portlet).
+     */
+    public SessionScopeExtractor(PortletRequest request, int scope) {
+        this.request = request;
+        if (scope != PortletSession.APPLICATION_SCOPE && scope != PortletSession.PORTLET_SCOPE) {
+            throw new IllegalArgumentException("The scope must be either APPLICATION_SCOPE or PORTLET_SCOPE");
+        }
+        this.scope = scope;
+    }
+
+    @Override
+    public void setValue(String name, Object value) {
+        request.getPortletSession().setAttribute(name, value, scope);
+    }
+
+    @Override
+    public void removeValue(String name) {
+        PortletSession session = request.getPortletSession(false);
+        if (session != null) {
+            session.removeAttribute(name, scope);
+        }
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        PortletSession session = request.getPortletSession(false);
+        if (session != null) {
+            return session.getAttributeNames(scope);
+        }
+        return null;
+    }
+
+    @Override
+    public Object getValue(String key) {
+        PortletSession session = request.getPortletSession(false);
+        if (session != null) {
+            return session.getAttribute(key, scope);
+        }
+        return null;
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
new file mode 100644
index 000000000..3b18b7343
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.HasAddableKeys;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.StateAwareResponse;
+
+/**
+ * Extracts parameters from a request and allows putting render parameters in a state aware response.
+ */
+public class StateAwareParameterExtractor extends ParameterExtractor implements HasAddableKeys<String> {
+
+    /**
+     * The portlet response.
+     */
+    private StateAwareResponse response;
+
+    /**
+     * Constructor.
+     *
+     * @param request The portlet request.
+     * @param response The portlet response.
+     */
+    public StateAwareParameterExtractor(PortletRequest request, StateAwareResponse response) {
+        super(request);
+        this.response = response;
+    }
+
+    @Override
+    public void setValue(String key, String value) {
+        response.setRenderParameter(key, value);
+    }
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/package-info.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/package-info.java
new file mode 100644
index 000000000..a37ccbb9e
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * $Id: package-info.java 1049711 2010-12-15 21:12:00Z apetrelli $
+ *
+ * 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.
+ */
+/**
+ * Extractors to get scopes from Portlet requests.
+ */
+package org.apache.tiles.request.portlet.extractor;
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/package-info.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/package-info.java
new file mode 100644
index 000000000..b9eb0d168
--- /dev/null
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * $Id: package-info.java 1049711 2010-12-15 21:12:00Z apetrelli $
+ *
+ * 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.
+ */
+/**
+ * Support of Tiles requests to portlets.
+ */
+package org.apache.tiles.request.portlet;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/AddableParameterMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/AddableParameterMap.java
new file mode 100644
index 000000000..d88b90503
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/AddableParameterMap.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.collection;
+
+import org.apache.tiles.request.attribute.HasAddableKeys;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Exposes an {@link HasAddableKeys} object as a put/get (no remove) map.
+ */
+public class AddableParameterMap extends ReadOnlyEnumerationMap<String> {
+
+    /**
+     * The request.
+     */
+    private final HasAddableKeys<String> request;
+
+    /**
+     * Constructor.
+     *
+     * @param request The request object to use.
+     */
+    public AddableParameterMap(HasAddableKeys<String> request) {
+        super(request);
+        this.request = request;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<Entry<String, String>> entrySet() {
+        return new AddableParameterEntrySet();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String put(String key, String value) {
+        String oldValue = request.getValue(key);
+        request.setValue(key, value);
+        return oldValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void putAll(Map<? extends String, ? extends String> map) {
+        for (Entry<? extends String, ? extends String> entry : map
+            .entrySet()) {
+            request.setValue(entry.getKey(), entry.getValue());
+        }
+    }
+
+
+    /**
+     * Entry set implementation for {@link AddableParameterMap}.
+     */
+    private class AddableParameterEntrySet extends ReadOnlyEnumerationMap<String>.ReadOnlyEnumerationMapEntrySet {
+
+        @Override
+        public boolean add(Entry<String, String> e) {
+            request.setValue(e.getKey(), e.getValue());
+            return true;
+        }
+
+        @Override
+        public boolean addAll(
+            Collection<? extends Entry<String, String>> c) {
+            for (Entry<String, String> entry : c) {
+                request.setValue(entry.getKey(), entry.getValue());
+            }
+            return true;
+        }
+    }
+}


[struts] 16/23: WW-5233 Fixes broken test

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit d694cce7c938741dcb626e54fe47c343723ab063
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Oct 3 09:01:58 2022 +0200

    WW-5233 Fixes broken test
---
 .../tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java     | 1 +
 1 file changed, 1 insertion(+)

diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java
index a77d6bd82..ad44d0379 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapEntrySetTest.java
@@ -160,6 +160,7 @@ public class ReadOnlyEnumerationMapEntrySetTest {
 
         expect(extractor.getKeys()).andReturn(keys);
         expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.hasMoreElements()).andReturn(true);
         expect(keys.nextElement()).andReturn("two");
 
         expect(extractor.getValue("two")).andReturn(2);


[struts] 15/23: WW-5233 Copies Tiles Portal related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 55987963a933fe0faaf76a4329ec7ef17da50316
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Oct 3 08:52:41 2022 +0200

    WW-5233 Copies Tiles Portal related tests
---
 plugins/portlet-tiles/pom.xml                      |   5 +
 .../portlet/delegate/StateAwareParameterMap.java   | 112 ------
 .../delegate/StateAwareRequestDelegate.java        |  83 ----
 .../delegate/StateAwareResponseDelegate.java       |  57 ---
 .../extractor/StateAwareParameterExtractor.java    |   2 +-
 .../tiles/request/portlet/PortletRequestTest.java  | 424 +++++++++++++++++++++
 .../request/portlet/RenderPortletRequestTest.java  |  69 ++++
 .../portlet/delegate/MimeResponseDelegateTest.java | 132 +++++++
 .../delegate/PortletRequestDelegateTest.java       |  83 ++++
 .../extractor/ApplicationScopeExtractorTest.java   | 106 ++++++
 .../portlet/extractor/HeaderExtractorTest.java     | 117 ++++++
 .../extractor/InitParameterExtractorTest.java      |  83 ++++
 .../portlet/extractor/ParameterExtractorTest.java  |  83 ++++
 .../extractor/RequestScopeExtractorTest.java       | 107 ++++++
 .../extractor/SessionScopeExtractorTest.java       | 154 ++++++++
 .../StateAwareParameterExtractorTest.java}         |  37 +-
 .../request/collection/ReadOnlyEnumerationMap.java |   5 +-
 17 files changed, 1385 insertions(+), 274 deletions(-)

diff --git a/plugins/portlet-tiles/pom.xml b/plugins/portlet-tiles/pom.xml
index 3ce787962..1ea145562 100644
--- a/plugins/portlet-tiles/pom.xml
+++ b/plugins/portlet-tiles/pom.xml
@@ -50,6 +50,11 @@
             <artifactId>portlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <properties>
     	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareParameterMap.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareParameterMap.java
deleted file mode 100644
index 34e36bb31..000000000
--- a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareParameterMap.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * $Id$
- *
- * 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.
- */
-package org.apache.tiles.request.portlet.delegate;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Parameter map to be used when the response is a {@link javax.portlet.StateAwareResponse}.
- */
-public class StateAwareParameterMap implements Map<String, String[]> {
-
-    /**
-     * The request parameter map.
-     */
-    private final Map<String, String[]> requestMap;
-
-    /**
-     * The response parameter map.
-     */
-    private final Map<String, String[]> responseMap;
-
-    /**
-     * Constructor.
-     *
-     * @param requestMap The request parameter map.
-     * @param responseMap The response parameter map.
-     */
-    public StateAwareParameterMap(Map<String, String[]> requestMap, Map<String, String[]> responseMap) {
-        this.requestMap = requestMap;
-        this.responseMap = responseMap;
-    }
-
-    @Override
-    public void clear() {
-        responseMap.clear();
-    }
-
-    @Override
-    public boolean containsKey(Object key) {
-        return requestMap.containsKey(key);
-    }
-
-    @Override
-    public boolean containsValue(Object value) {
-        return requestMap.containsValue(value);
-    }
-
-    @Override
-    public Set<Entry<String, String[]>> entrySet() {
-        return requestMap.entrySet();
-    }
-
-    @Override
-    public String[] get(Object key) {
-        return requestMap.get(key);
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return requestMap.isEmpty();
-    }
-
-    @Override
-    public Set<String> keySet() {
-        return requestMap.keySet();
-    }
-
-    @Override
-    public String[] put(String key, String[] value) {
-        return responseMap.put(key, value);
-    }
-
-    @Override
-    public void putAll(Map<? extends String, ? extends String[]> m) {
-        responseMap.putAll(m);
-    }
-
-    @Override
-    public String[] remove(Object key) {
-        return responseMap.remove(key);
-    }
-
-    @Override
-    public int size() {
-        return requestMap.size();
-    }
-
-    @Override
-    public Collection<String[]> values() {
-        return requestMap.values();
-    }
-}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareRequestDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareRequestDelegate.java
deleted file mode 100644
index ede98a745..000000000
--- a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareRequestDelegate.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * $Id$
- *
- * 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.
- */
-package org.apache.tiles.request.portlet.delegate;
-
-import org.apache.tiles.request.collection.AddableParameterMap;
-import org.apache.tiles.request.portlet.extractor.StateAwareParameterExtractor;
-
-import javax.portlet.PortletRequest;
-import javax.portlet.StateAwareResponse;
-import java.util.Map;
-
-/**
- * Exposes parameters getting them from a portlet reques and allowing to be put into a {@link StateAwareResponse}.
- */
-public class StateAwareRequestDelegate implements RequestDelegate {
-
-    /**
-     * The request.
-     */
-    private final PortletRequest request;
-
-    /**
-     * The response.
-     */
-    private final StateAwareResponse response;
-
-    /**
-     * Constructor.
-     *
-     * @param request The request.
-     * @param response The response.
-     */
-    public StateAwareRequestDelegate(PortletRequest request, StateAwareResponse response) {
-        this.request = request;
-        this.response = response;
-    }
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of request
-     * parameter name-value.</p>
-     */
-    private Map<String, String> param = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of request
-     * parameter name-values.</p>
-     */
-    private Map<String, String[]> paramValues = null;
-
-    /** {@inheritDoc} */
-    public Map<String, String> getParam() {
-        if ((param == null) && (request != null)) {
-            param = new AddableParameterMap(new StateAwareParameterExtractor(request, response));
-        }
-        return (param);
-    }
-
-    /** {@inheritDoc} */
-    public Map<String, String[]> getParamValues() {
-        if ((paramValues == null) && (request != null)) {
-            paramValues = new StateAwareParameterMap(request.getParameterMap(), response.getRenderParameterMap());
-        }
-        return (paramValues);
-    }
-}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareResponseDelegate.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareResponseDelegate.java
deleted file mode 100644
index 20e05cbcb..000000000
--- a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/StateAwareResponseDelegate.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * $Id$
- *
- * 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.
- */
-package org.apache.tiles.request.portlet.delegate;
-
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.Writer;
-
-/**
- * A state aware response does not allow to access to the output stream and similar, so it is, essentially,
- * a feature blocker.
- */
-public class StateAwareResponseDelegate implements ResponseDelegate {
-
-    @Override
-    public OutputStream getOutputStream() {
-        throw new UnsupportedOperationException("No outputstream available for state-aware response");
-    }
-
-    @Override
-    public PrintWriter getPrintWriter() {
-        throw new UnsupportedOperationException("No outputstream available for state-aware response");
-    }
-
-    @Override
-    public Writer getWriter() {
-        throw new UnsupportedOperationException("No outputstream available for state-aware response");
-    }
-
-    @Override
-    public boolean isResponseCommitted() {
-        return false;
-    }
-
-    @Override
-    public void setContentType(String contentType) {
-        throw new UnsupportedOperationException("No outputstream available for state-aware response");
-    }
-}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
index 3b18b7343..a14f53a7b 100644
--- a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
@@ -33,7 +33,7 @@ public class StateAwareParameterExtractor extends ParameterExtractor implements
     /**
      * The portlet response.
      */
-    private StateAwareResponse response;
+    private final StateAwareResponse response;
 
     /**
      * Constructor.
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/PortletRequestTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/PortletRequestTest.java
new file mode 100644
index 000000000..53a6bf856
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/PortletRequestTest.java
@@ -0,0 +1,424 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.collection.HeaderValuesMap;
+import org.apache.tiles.request.collection.ReadOnlyEnumerationMap;
+import org.apache.tiles.request.collection.ScopeMap;
+import org.apache.tiles.request.portlet.delegate.RequestDelegate;
+import org.apache.tiles.request.portlet.delegate.ResponseDelegate;
+import org.apache.tiles.request.portlet.extractor.HeaderExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletContext;
+import javax.portlet.PortletException;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.PortletResponse;
+import javax.servlet.ServletOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link PortletRequest}.
+ */
+public class PortletRequestTest {
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * The portlet context.
+     */
+    private PortletContext portletContext;
+
+    /**
+     * The request.
+     */
+    private javax.portlet.PortletRequest request;
+
+    /**
+     * The response.
+     */
+    private PortletResponse response;
+
+    /**
+     * The request to test.
+     */
+    private PortletRequest req;
+
+    /**
+     * The request delegate.
+     */
+    private RequestDelegate requestDelegate;
+
+    /**
+     * The response delegate.
+     */
+    private ResponseDelegate responseDelegate;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        applicationContext = createMock(ApplicationContext.class);
+        portletContext = createMock(PortletContext.class);
+        request = createMock(javax.portlet.PortletRequest.class);
+        response = createMock(PortletResponse.class);
+        requestDelegate = createMock(RequestDelegate.class);
+        responseDelegate = createMock(ResponseDelegate.class);
+        req = new PortletRequest(applicationContext, portletContext, request,
+            response, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doForward(String)}.
+     *
+     * @throws IOException      If something goes wrong.
+     * @throws PortletException If something goes wrong.
+     */
+    @Test
+    public void testDoForward() throws PortletException, IOException {
+        PortletRequestDispatcher rd = createMock(PortletRequestDispatcher.class);
+
+        expect(responseDelegate.isResponseCommitted()).andReturn(false);
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(rd);
+        rd.forward(request, response);
+
+        replay(applicationContext, portletContext, request, response, rd);
+        req.doForward("/my/path");
+        verify(applicationContext, portletContext, request, response, rd);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doForward(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test(expected = IOException.class)
+    public void testDoForwardNoDispatcher() throws IOException {
+        expect(responseDelegate.isResponseCommitted()).andReturn(false);
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(null);
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        try {
+            req.doForward("/my/path");
+        } finally {
+            verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        }
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doForward(String)}.
+     *
+     * @throws IOException      If something goes wrong.
+     * @throws PortletException If something goes wrong.
+     */
+    @Test(expected = IOException.class)
+    public void testDoForwardPortletException() throws PortletException, IOException {
+        PortletRequestDispatcher rd = createMock(PortletRequestDispatcher.class);
+
+        expect(responseDelegate.isResponseCommitted()).andReturn(false);
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(rd);
+        rd.forward(request, response);
+        expectLastCall().andThrow(new PortletException());
+
+        replay(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+        try {
+            req.doForward("/my/path");
+        } finally {
+            verify(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+        }
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doForward(String)}.
+     *
+     * @throws IOException      If something goes wrong.
+     * @throws PortletException If something goes wrong.
+     */
+    @Test
+    public void testDoForwardInclude() throws PortletException, IOException {
+        PortletRequestDispatcher rd = createMock(PortletRequestDispatcher.class);
+
+        expect(responseDelegate.isResponseCommitted()).andReturn(true);
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(rd);
+        rd.include(request, response);
+
+        replay(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+        req.doForward("/my/path");
+        verify(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doInclude(String)}.
+     *
+     * @throws IOException      If something goes wrong.
+     * @throws PortletException If something goes wrong.
+     */
+    @Test
+    public void testDoInclude() throws IOException, PortletException {
+        PortletRequestDispatcher rd = createMock(PortletRequestDispatcher.class);
+
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(rd);
+        rd.include(request, response);
+
+        replay(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+        req.doInclude("/my/path");
+        verify(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doInclude(String)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test(expected = IOException.class)
+    public void testDoIncludeNoDispatcher() throws IOException {
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(null);
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        try {
+            req.doInclude("/my/path");
+        } finally {
+            verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        }
+    }
+
+    /**
+     * Test method for {@link PortletRequest#doInclude(String)}.
+     *
+     * @throws IOException      If something goes wrong.
+     * @throws PortletException If something goes wrong.
+     */
+    @Test(expected = IOException.class)
+    public void testDoIncludePortletException() throws IOException, PortletException {
+        PortletRequestDispatcher rd = createMock(PortletRequestDispatcher.class);
+
+        expect(portletContext.getRequestDispatcher("/my/path")).andReturn(rd);
+        rd.include(request, response);
+        expectLastCall().andThrow(new PortletException());
+
+        replay(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+        try {
+            req.doInclude("/my/path");
+        } finally {
+            verify(applicationContext, request, response, rd, portletContext, requestDelegate, responseDelegate);
+        }
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getHeader()}.
+     */
+    @Test
+    public void testGetHeader() {
+        assertTrue(req.getHeader() instanceof ReadOnlyEnumerationMap);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getResponseHeaders()}.
+     */
+    @Test
+    public void testGetResponseHeaders() {
+        assertTrue(req.getResponseHeaders() instanceof HeaderExtractor);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getHeaderValues()}.
+     */
+    @Test
+    public void testGetHeaderValues() {
+        assertTrue(req.getHeaderValues() instanceof HeaderValuesMap);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getParam()}.
+     */
+    @Test
+    public void testGetParam() {
+        Map<String, String> map = createMock(Map.class);
+
+        expect(requestDelegate.getParam()).andReturn(map);
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        assertEquals(map, req.getParam());
+        verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getParamValues()}.
+     */
+    @Test
+    public void testGetParamValues() {
+        Map<String, String[]> paramMap = createMock(Map.class);
+
+        expect(requestDelegate.getParamValues()).andReturn(paramMap);
+
+        replay(applicationContext, request, response, paramMap, portletContext, requestDelegate, responseDelegate);
+        assertEquals(paramMap, req.getParamValues());
+        verify(applicationContext, request, response, paramMap, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getRequestScope()}.
+     */
+    @Test
+    public void testGetRequestScope() {
+        assertTrue(req.getRequestScope() instanceof ScopeMap);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getSessionScope()}.
+     */
+    @Test
+    public void testGetSessionScope() {
+        assertTrue(req.getSessionScope() instanceof ScopeMap);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getPortletSessionScope()}.
+     */
+    @Test
+    public void testGetPortletSessionScope() {
+        assertTrue(req.getPortletSessionScope() instanceof ScopeMap);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getOutputStream()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testGetOutputStream() throws IOException {
+        ServletOutputStream os = createMock(ServletOutputStream.class);
+
+        expect(responseDelegate.getOutputStream()).andReturn(os);
+
+        replay(applicationContext, request, response, os, portletContext, requestDelegate, responseDelegate);
+        assertEquals(req.getOutputStream(), os);
+        verify(applicationContext, request, response, os, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getWriter()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testGetWriter() throws IOException {
+        PrintWriter os = createMock(PrintWriter.class);
+
+        expect(responseDelegate.getWriter()).andReturn(os);
+
+        replay(applicationContext, request, response, os, portletContext, requestDelegate, responseDelegate);
+        assertEquals(req.getWriter(), os);
+        verify(applicationContext, request, response, os, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getPrintWriter()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testGetPrintWriter() throws IOException {
+        PrintWriter os = createMock(PrintWriter.class);
+
+        expect(responseDelegate.getPrintWriter()).andReturn(os);
+
+        replay(applicationContext, request, response, os, portletContext, requestDelegate, responseDelegate);
+        assertEquals(req.getPrintWriter(), os);
+        verify(applicationContext, request, response, os, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#isResponseCommitted()}.
+     */
+    @Test
+    public void testIsResponseCommitted() {
+        expect(responseDelegate.isResponseCommitted()).andReturn(true);
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        assertTrue(req.isResponseCommitted());
+        verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#setContentType(String)}.
+     */
+    @Test
+    public void testSetContentType() {
+        responseDelegate.setContentType("text/html");
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        req.setContentType("text/html");
+        verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getRequestLocale()}.
+     */
+    @Test
+    public void testGetRequestLocale() {
+        Locale locale = Locale.ITALY;
+
+        expect(request.getLocale()).andReturn(locale);
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        assertEquals(locale, req.getRequestLocale());
+        verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#getRequest()}.
+     */
+    @Test
+    public void testGetRequest() {
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        assertEquals(request, req.getRequest());
+        verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+    }
+
+    /**
+     * Test method for {@link PortletRequest#isUserInRole(String)}.
+     */
+    @Test
+    public void testIsUserInRole() {
+        expect(request.isUserInRole("myrole")).andReturn(true);
+
+        replay(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+        assertTrue(req.isUserInRole("myrole"));
+        verify(applicationContext, request, response, portletContext, requestDelegate, responseDelegate);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/RenderPortletRequestTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/RenderPortletRequestTest.java
new file mode 100644
index 000000000..5bba700fb
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/RenderPortletRequestTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.portlet.delegate.MimeResponseDelegate;
+import org.apache.tiles.request.portlet.delegate.PortletRequestDelegate;
+import org.junit.Test;
+
+import javax.portlet.PortletContext;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import java.lang.reflect.Field;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link RenderPortletRequest}.
+ */
+public class RenderPortletRequestTest {
+
+    /**
+     * Test method for
+     * {@link RenderPortletRequest#RenderPortletRequest(ApplicationContext, PortletContext,
+     * RenderRequest, RenderResponse)}.
+     *
+     * @throws NoSuchFieldException     If something goes wrong.
+     * @throws SecurityException        If something goes wrong.
+     * @throws IllegalAccessException   If something goes wrong.
+     * @throws IllegalArgumentException If something goes wrong.
+     */
+    @Test
+    public void testRenderPortletRequest() throws NoSuchFieldException, IllegalAccessException {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        PortletContext portletContext = createMock(PortletContext.class);
+        RenderRequest request = createMock(RenderRequest.class);
+        RenderResponse response = createMock(RenderResponse.class);
+
+        replay(applicationContext, portletContext, request, response);
+        RenderPortletRequest req = new RenderPortletRequest(applicationContext,
+            portletContext, request, response);
+        Class<? extends RenderPortletRequest> clazz = req.getClass();
+        Field field = clazz.getSuperclass().getDeclaredField("requestDelegate");
+        assertTrue(field.get(req) instanceof PortletRequestDelegate);
+        field = clazz.getSuperclass().getDeclaredField("responseDelegate");
+        assertTrue(field.get(req) instanceof MimeResponseDelegate);
+        verify(applicationContext, portletContext, request, response);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/delegate/MimeResponseDelegateTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/delegate/MimeResponseDelegateTest.java
new file mode 100644
index 000000000..25d653456
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/delegate/MimeResponseDelegateTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.MimeResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link MimeResponseDelegate}.
+ */
+public class MimeResponseDelegateTest {
+
+    /**
+     * The response.
+     */
+    private MimeResponse response;
+
+    /**
+     * The delegate to test.
+     */
+    private MimeResponseDelegate delegate;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        response = createMock(MimeResponse.class);
+        delegate = new MimeResponseDelegate(response);
+    }
+
+    /**
+     * Test method for {@link MimeResponseDelegate#getOutputStream()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testGetOutputStream() throws IOException {
+        OutputStream os = createMock(OutputStream.class);
+
+        expect(response.getPortletOutputStream()).andReturn(os);
+
+        replay(response, os);
+        assertEquals(os, delegate.getOutputStream());
+        verify(response, os);
+    }
+
+    /**
+     * Test method for {@link MimeResponseDelegate#getPrintWriter()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testGetPrintWriter() throws IOException {
+        PrintWriter os = createMock(PrintWriter.class);
+
+        expect(response.getWriter()).andReturn(os);
+
+        replay(response, os);
+        assertEquals(os, delegate.getPrintWriter());
+        verify(response, os);
+    }
+
+    /**
+     * Test method for {@link MimeResponseDelegate#getWriter()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testGetWriter() throws IOException {
+        PrintWriter os = createMock(PrintWriter.class);
+
+        expect(response.getWriter()).andReturn(os);
+
+        replay(response, os);
+        assertEquals(os, delegate.getWriter());
+        verify(response, os);
+    }
+
+    /**
+     * Test method for {@link MimeResponseDelegate#isResponseCommitted()}.
+     */
+    @Test
+    public void testIsResponseCommitted() {
+        expect(response.isCommitted()).andReturn(true);
+
+        replay(response);
+        assertTrue(delegate.isResponseCommitted());
+        verify(response);
+    }
+
+    /**
+     * Test method for {@link MimeResponseDelegate#setContentType(String)}.
+     */
+    @Test
+    public void testSetContentType() {
+        response.setContentType("text/html");
+
+        replay(response);
+        delegate.setContentType("text/html");
+        verify(response);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/delegate/PortletRequestDelegateTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/delegate/PortletRequestDelegateTest.java
new file mode 100644
index 000000000..ce6d4e849
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/delegate/PortletRequestDelegateTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.delegate;
+
+import org.apache.tiles.request.collection.ReadOnlyEnumerationMap;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletRequest;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link PortletRequestDelegate}.
+ */
+public class PortletRequestDelegateTest {
+
+    /**
+     * The request.
+     */
+    private PortletRequest request;
+
+    /**
+     * The delegate to test.
+     */
+    private PortletRequestDelegate delegate;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        request = createMock(PortletRequest.class);
+        delegate = new PortletRequestDelegate(request);
+    }
+
+    /**
+     * Test method for {@link PortletRequestDelegate#getParam()}.
+     */
+    @Test
+    public void testGetParam() {
+        replay(request);
+        assertTrue(delegate.getParam() instanceof ReadOnlyEnumerationMap);
+        verify(request);
+    }
+
+    /**
+     * Test method for {@link PortletRequestDelegate#getParamValues()}.
+     */
+    @Test
+    public void testGetParamValues() {
+        Map<String, String[]> params = createMock(Map.class);
+
+        expect(request.getParameterMap()).andReturn(params);
+
+        replay(request, params);
+        assertEquals(params, delegate.getParamValues());
+        verify(request, params);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/ApplicationScopeExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/ApplicationScopeExtractorTest.java
new file mode 100644
index 000000000..5ede84f69
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/ApplicationScopeExtractorTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.portlet.extractor.ApplicationScopeExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletContext;
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link ApplicationScopeExtractor}.
+ */
+public class ApplicationScopeExtractorTest {
+
+    /**
+     * The portlet context.
+     */
+    private PortletContext context;
+
+    /**
+     * The extractot to test.
+     */
+    private ApplicationScopeExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        context = createMock(PortletContext.class);
+        extractor = new ApplicationScopeExtractor(context);
+    }
+
+    /**
+     * Test method for {@link ApplicationScopeExtractor#setValue(String, Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        context.setAttribute("attribute", "value");
+
+        replay(context);
+        extractor.setValue("attribute", "value");
+        verify(context);
+    }
+
+    /**
+     * Test method for {@link ApplicationScopeExtractor#removeValue(String)}.
+     */
+    @Test
+    public void testRemoveValue() {
+        context.removeAttribute("attribute");
+
+        replay(context);
+        extractor.removeValue("attribute");
+        verify(context);
+    }
+
+    /**
+     * Test method for {@link ApplicationScopeExtractor#getKeys()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetKeys() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+        expect(context.getAttributeNames()).andReturn(keys);
+
+        replay(context, keys);
+        assertEquals(keys, extractor.getKeys());
+        verify(context, keys);
+    }
+
+    /**
+     * Test method for {@link ApplicationScopeExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValue() {
+        expect(context.getAttribute("attribute")).andReturn("value");
+
+        replay(context);
+        assertEquals("value", extractor.getValue("attribute"));
+        verify(context);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/HeaderExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/HeaderExtractorTest.java
new file mode 100644
index 000000000..7f5054c02
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/HeaderExtractorTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.portlet.extractor.HeaderExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link HeaderExtractor}.
+ */
+public class HeaderExtractorTest {
+
+    /**
+     * The request.
+     */
+    private PortletRequest request;
+
+    /**
+     * The response.
+     */
+    private PortletResponse response;
+
+    /**
+     * The extractor to test.
+     */
+    private HeaderExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        request = createMock(PortletRequest.class);
+        response = createMock(PortletResponse.class);
+        extractor = new HeaderExtractor(request, response);
+    }
+
+    /**
+     * Test method for {@link HeaderExtractor#getKeys()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetKeys() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(request.getPropertyNames()).andReturn(keys);
+
+        replay(request, response, keys);
+        assertEquals(keys, extractor.getKeys());
+        verify(request, response, keys);
+    }
+
+    /**
+     * Test method for {@link HeaderExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValue() {
+        expect(request.getProperty("name")).andReturn("value");
+
+        replay(request, response);
+        assertEquals("value", extractor.getValue("name"));
+        verify(request, response);
+    }
+
+    /**
+     * Test method for {@link HeaderExtractor#getValues(String)}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetValues() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(request.getProperties("name")).andReturn(keys);
+
+        replay(request, response, keys);
+        assertEquals(keys, extractor.getValues("name"));
+        verify(request, response, keys);
+    }
+
+    /**
+     * Test method for {@link HeaderExtractor#setValue(String, String)}.
+     */
+    @Test
+    public void testSetValue() {
+        response.setProperty("name", "value");
+
+        replay(request, response);
+        extractor.setValue("name", "value");
+        verify(request, response);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/InitParameterExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/InitParameterExtractorTest.java
new file mode 100644
index 000000000..66a1f9ea7
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/InitParameterExtractorTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.portlet.extractor.InitParameterExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletContext;
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link InitParameterExtractor}.
+ */
+public class InitParameterExtractorTest {
+
+    /**
+     * The portlet context.
+     */
+    private PortletContext context;
+
+    /**
+     * The extractor to test.
+     */
+    private InitParameterExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        context = createMock(PortletContext.class);
+        extractor = new InitParameterExtractor(context);
+    }
+
+    /**
+     * Test method for {@link InitParameterExtractor#getKeys()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetKeys() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(context.getInitParameterNames()).andReturn(keys);
+
+        replay(context, keys);
+        assertEquals(keys, extractor.getKeys());
+        verify(context, keys);
+    }
+
+    /**
+     * Test method for {@link InitParameterExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValue() {
+        expect(context.getInitParameter("name")).andReturn("value");
+
+        replay(context);
+        assertEquals("value", extractor.getValue("name"));
+        verify(context);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/ParameterExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/ParameterExtractorTest.java
new file mode 100644
index 000000000..0e8005325
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/ParameterExtractorTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.portlet.extractor.ParameterExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletRequest;
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link ParameterExtractor}.
+ */
+public class ParameterExtractorTest {
+
+    /**
+     * The request.
+     */
+    private PortletRequest request;
+
+    /**
+     * The extractor to test.
+     */
+    private ParameterExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        request = createMock(PortletRequest.class);
+        extractor = new ParameterExtractor(request);
+    }
+
+    /**
+     * Test method for {@link ParameterExtractor#getKeys()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetKeys() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(request.getParameterNames()).andReturn(keys);
+
+        replay(request, keys);
+        assertEquals(keys, extractor.getKeys());
+        verify(request, keys);
+    }
+
+    /**
+     * Test method for {@link ParameterExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValue() {
+        expect(request.getParameter("name")).andReturn("value");
+
+        replay(request);
+        assertEquals("value", extractor.getValue("name"));
+        verify(request);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/RequestScopeExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/RequestScopeExtractorTest.java
new file mode 100644
index 000000000..df76a515e
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/RequestScopeExtractorTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.portlet.extractor.RequestScopeExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletRequest;
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link RequestScopeExtractor}.
+ */
+public class RequestScopeExtractorTest {
+
+    /**
+     * The request to test.
+     */
+    private PortletRequest request;
+
+    /**
+     * The extractor to test.
+     */
+    private RequestScopeExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        request = createMock(PortletRequest.class);
+        extractor = new RequestScopeExtractor(request);
+    }
+
+    /**
+     * Test method for {@link RequestScopeExtractor#setValue(String, Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        request.setAttribute("name", "value");
+
+        replay(request);
+        extractor.setValue("name", "value");
+        verify(request);
+    }
+
+    /**
+     * Test method for {@link RequestScopeExtractor#removeValue(String)}.
+     */
+    @Test
+    public void testRemoveValue() {
+        request.removeAttribute("name");
+
+        replay(request);
+        extractor.removeValue("name");
+        verify(request);
+    }
+
+    /**
+     * Test method for {@link RequestScopeExtractor#getKeys()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetKeys() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(request.getAttributeNames()).andReturn(keys);
+
+        replay(request, keys);
+        assertEquals(keys, extractor.getKeys());
+        verify(request, keys);
+    }
+
+    /**
+     * Test method for {@link RequestScopeExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValue() {
+        expect(request.getAttribute("name")).andReturn("value");
+
+        replay(request);
+        assertEquals("value", extractor.getValue("name"));
+        verify(request);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/SessionScopeExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/SessionScopeExtractorTest.java
new file mode 100644
index 000000000..09010ff0c
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/SessionScopeExtractorTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.portlet.extractor.SessionScopeExtractor;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
+import java.util.Enumeration;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link SessionScopeExtractor}.
+ */
+public class SessionScopeExtractorTest {
+
+    /**
+     * The request.
+     */
+    private PortletRequest request;
+
+    /**
+     * The session.
+     */
+    private PortletSession session;
+
+    /**
+     * The scope to test.
+     */
+    private SessionScopeExtractor extractor;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        request = createMock(PortletRequest.class);
+        session = createMock(PortletSession.class);
+        extractor = new SessionScopeExtractor(request, PortletSession.PORTLET_SCOPE);
+    }
+
+
+    /**
+     * Tests {@link SessionScopeExtractor#SessionScopeExtractor(PortletRequest, int)}.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalScope() {
+        replay(request, session);
+        new SessionScopeExtractor(request, 0);
+        verify(request, session);
+    }
+
+    /**
+     * Test method for {@link SessionScopeExtractor#setValue(String, Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        expect(request.getPortletSession()).andReturn(session);
+        session.setAttribute("name", "value", PortletSession.PORTLET_SCOPE);
+
+        replay(request, session);
+        extractor.setValue("name", "value");
+        verify(request, session);
+    }
+
+    /**
+     * Test method for {@link SessionScopeExtractor#removeValue(String)}.
+     */
+    @Test
+    public void testRemoveValue() {
+        expect(request.getPortletSession(false)).andReturn(session);
+        session.removeAttribute("name", PortletSession.PORTLET_SCOPE);
+
+        replay(request, session);
+        extractor.removeValue("name");
+        verify(request, session);
+    }
+
+    /**
+     * Test method for {@link SessionScopeExtractor#getKeys()}.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGetKeys() {
+        Enumeration<String> keys = createMock(Enumeration.class);
+
+        expect(request.getPortletSession(false)).andReturn(session);
+        expect(session.getAttributeNames(PortletSession.PORTLET_SCOPE)).andReturn(keys);
+
+        replay(request, session, keys);
+        assertEquals(keys, extractor.getKeys());
+        verify(request, session, keys);
+    }
+
+    /**
+     * Test method for {@link SessionScopeExtractor#getKeys()}.
+     */
+    @Test
+    public void testGetKeysNoSession() {
+        expect(request.getPortletSession(false)).andReturn(null);
+
+        replay(request, session);
+        assertNull(extractor.getKeys());
+        verify(request, session);
+    }
+
+    /**
+     * Test method for {@link SessionScopeExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValue() {
+        expect(request.getPortletSession(false)).andReturn(session);
+        expect(session.getAttribute("name", PortletSession.PORTLET_SCOPE)).andReturn("value");
+
+        replay(request, session);
+        assertEquals("value", extractor.getValue("name"));
+        verify(request, session);
+    }
+
+    /**
+     * Test method for {@link SessionScopeExtractor#getValue(String)}.
+     */
+    @Test
+    public void testGetValueNoSession() {
+        expect(request.getPortletSession(false)).andReturn(null);
+
+        replay(request, session);
+        assertNull(extractor.getValue("name"));
+        verify(request, session);
+    }
+
+}
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractorTest.java
similarity index 55%
copy from plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
copy to plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractorTest.java
index 3b18b7343..5157b6fe6 100644
--- a/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractor.java
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractorTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -20,34 +18,33 @@
  */
 package org.apache.tiles.request.portlet.extractor;
 
-import org.apache.tiles.request.attribute.HasAddableKeys;
+import org.apache.tiles.request.portlet.extractor.StateAwareParameterExtractor;
+import org.junit.Test;
 
 import javax.portlet.PortletRequest;
 import javax.portlet.StateAwareResponse;
 
+import static org.easymock.EasyMock.*;
+
 /**
- * Extracts parameters from a request and allows putting render parameters in a state aware response.
+ * Tests {@link StateAwareParameterExtractor}.
  */
-public class StateAwareParameterExtractor extends ParameterExtractor implements HasAddableKeys<String> {
+public class StateAwareParameterExtractorTest {
 
     /**
-     * The portlet response.
+     * Test method for {@link StateAwareParameterExtractor#setValue(String, String)}.
      */
-    private StateAwareResponse response;
+    @Test
+    public void testSetValue() {
+        PortletRequest request = createMock(PortletRequest.class);
+        StateAwareResponse response = createMock(StateAwareResponse.class);
 
-    /**
-     * Constructor.
-     *
-     * @param request The portlet request.
-     * @param response The portlet response.
-     */
-    public StateAwareParameterExtractor(PortletRequest request, StateAwareResponse response) {
-        super(request);
-        this.response = response;
-    }
+        response.setRenderParameter("name", "value");
 
-    @Override
-    public void setValue(String key, String value) {
-        response.setRenderParameter(key, value);
+        replay(request, response);
+        StateAwareParameterExtractor extractor = new StateAwareParameterExtractor(request, response);
+        extractor.setValue("name", "value");
+        verify(request, response);
     }
+
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
index 2db0e83ae..d5cc16978 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
@@ -322,7 +322,10 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
 
             @Override
             public Entry<String, V> next() {
-                return extractNextEntry(namesEnumeration);
+                if (namesEnumeration.hasMoreElements()) {
+                    return extractNextEntry(namesEnumeration);
+                }
+                throw new NoSuchElementException();
             }
 
             @Override


[struts] 23/23: WW-5233 Marks Velocity dependencies as optional

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 6fc1b9c972822cb115b6bdc1982a03cdb37f64ae
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Wed Oct 19 09:06:54 2022 +0200

    WW-5233 Marks Velocity dependencies as optional
---
 plugins/tiles/pom.xml | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 55759a642..d29ad9f93 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -30,7 +30,7 @@
     <artifactId>struts2-tiles-plugin</artifactId>
     <packaging>jar</packaging>
     <name>Struts 2 Tiles Plugin</name>
-    
+
     <!-- mvn -P build-autotags exec:java -->
     <profiles>
         <profile>
@@ -80,29 +80,35 @@
             <artifactId>jsp-api</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.easymock</groupId>
-            <artifactId>easymock</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.logging.log4j</groupId>
-            <artifactId>log4j-jcl</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.apache.velocity</groupId>
             <artifactId>velocity-engine-core</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity-tools</artifactId>
-            <version>2.0</version>
-            <scope>provided</scope>
+            <groupId>org.apache.velocity.tools</groupId>
+            <artifactId>velocity-tools-view</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.velocity.tools</groupId>
+            <artifactId>velocity-tools-view-jsp</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>com.thoughtworks.xstream</groupId>
             <artifactId>xstream</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-jcl</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
     <properties>


[struts] 12/23: WW-5233 Drops useless @version tag and addresses some potential RegEx vulnerabilities

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 6d1f60ae1e25146bd2907b42ddca5b8483f47862
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 18:43:45 2022 +0200

    WW-5233 Drops useless @version tag and addresses some potential RegEx vulnerabilities
---
 .../main/java/org/apache/tiles/api/Attribute.java  |   5 +-
 .../apache/tiles/api/preparer/ViewPreparer.java    |   2 -
 .../autotag/core/runtime/AbstractModelBody.java    |   2 -
 .../tiles/autotag/core/runtime/ModelBody.java      |   2 -
 .../autotag/core/runtime/annotation/Parameter.java |   2 -
 .../autotag/core/runtime/util/NullWriter.java      |   2 -
 .../apache/tiles/autotag/model/TemplateClass.java  |   2 -
 .../apache/tiles/autotag/model/TemplateMethod.java |   2 -
 .../tiles/autotag/model/TemplateParameter.java     |   2 -
 .../apache/tiles/autotag/model/TemplateSuite.java  |   2 -
 .../tiles/core/definition/DefinitionsFactory.java  |   2 -
 .../core/definition/NoSuchDefinitionException.java |   2 -
 .../UnresolvingLocaleDefinitionsFactory.java       |   2 -
 .../digester/DigesterDefinitionsReader.java        |   2 -
 .../DigesterDefinitionsReaderException.java        |   2 -
 .../pattern/DefinitionPatternMatcher.java          |   2 -
 .../pattern/DefinitionPatternMatcherFactory.java   |   2 -
 .../org/apache/tiles/request/RequestException.java |   2 -
 .../NotAvailableFreemarkerServletException.java    |   2 -
 .../autotag/FreemarkerAutotagException.java        |   2 -
 .../render/AttributeValueFreemarkerServlet.java    |  51 ------
 .../request/freemarker/render/package-info.java    |  24 ---
 .../SharedVariableLoaderFreemarkerServlet.java     | 200 ---------------------
 .../servlet/WebappClassTemplateLoader.java         |   2 -
 .../tiles/request/jsp/JspPrintWriterAdapter.java   |   2 -
 .../request/locale/URLApplicationResource.java     |   2 -
 .../reflect/CannotInstantiateObjectException.java  |   2 -
 .../tiles/request/render/DispatchRenderer.java     |   2 -
 .../tiles/template/InsertAttributeModel.java       |   2 -
 .../tiles/template/InsertDefinitionModel.java      |   2 -
 30 files changed, 2 insertions(+), 330 deletions(-)

diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
index c49f07a96..e84039c73 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -19,6 +19,7 @@
 
 package org.apache.tiles.api;
 
+import com.opensymphony.xwork2.util.TextParseUtil;
 import org.apache.tiles.request.Request;
 
 import java.io.Serializable;
@@ -205,9 +206,7 @@ public class Attribute implements Serializable, Cloneable {
      */
     public void setRole(String role) {
         if (role != null && role.trim().length() > 0) {
-            String[] rolesStrings = role.split("\\s*,\\s*");
-            roles = new HashSet<>();
-            Collections.addAll(roles, rolesStrings);
+            roles = TextParseUtil.commaDelimitedStringToSet(role);
         } else {
             roles = null;
         }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
index 94527a45b..9abf720a6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
@@ -38,8 +38,6 @@ import org.apache.tiles.request.Request;
  * <li>&lt;insert&gt;</li>
  * <li>&lt;definition&gt;</li>
  * </ul>>
- *
- * @version $Rev$ $Date$
  */
 public interface ViewPreparer {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
index 1054f338a..72b3a9938 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
@@ -27,8 +27,6 @@ import java.util.regex.Pattern;
 
 /**
  * Base class for the abstraction of the body.
- *
- * @version $Rev$ $Date$
  */
 public abstract class AbstractModelBody implements ModelBody {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
index feedca8c8..0f97ec0d0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
@@ -23,8 +23,6 @@ import java.io.Writer;
 
 /**
  * Abstracts a tag/directive body.
- *
- * @version $Rev$ $Date$
  */
 public interface ModelBody {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
index 1c6373f7f..8833eddeb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
@@ -25,8 +25,6 @@ import java.lang.annotation.Target;
 
 /**
  * Specifies behaviour for a parameter of the "execute" method of a template class.
- *
- * @version $Rev$ $Date$
  */
 @Retention(RetentionPolicy.SOURCE)
 @Target(ElementType.PARAMETER)
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
index 76a19b6b4..4905e6c63 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
@@ -23,8 +23,6 @@ import java.io.Writer;
 
 /**
  * A writer that does not write anything.
- *
- * @version $Rev$ $Date$
  */
 public class NullWriter extends Writer {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
index f130fa9d1..0aeb990ce 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
@@ -24,8 +24,6 @@ import java.util.Map;
 
 /**
  * It represents a parsed template class.
- *
- * @version $Rev$ $Date$
  */
 public class TemplateClass {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
index 2390c2119..2bccf2ddd 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
@@ -24,8 +24,6 @@ import java.util.Map;
 
 /**
  * It represents a parsed method in a parsed template class.
- *
- * @version $Rev$ $Date$
  */
 public class TemplateMethod {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
index ab4e8dc58..0540954c1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
@@ -22,8 +22,6 @@ import org.apache.tiles.autotag.core.runtime.ModelBody;
 
 /**
  * It represents a parameter in a method in a parsed template class.
- *
- * @version $Rev$ $Date$
  */
 public class TemplateParameter {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
index ff96b9eda..de14b466f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
@@ -24,8 +24,6 @@ import java.util.Map;
 
 /**
  * It represents a suite of template classes.
- *
- * @version $Rev$ $Date$
  */
 public class TemplateSuite {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
index a7165a981..8f0dcc7aa 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
@@ -31,8 +31,6 @@ import org.apache.tiles.request.Request;
  * sets. Implementations also know how to append locale-specific configuration
  * data to an existing Definitions set.
  * </p>
- *
- * @version $Rev$ $Date$
  */
 public interface DefinitionsFactory {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
index aa78661bd..6815f2db9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
@@ -20,8 +20,6 @@ package org.apache.tiles.core.definition;
 
 /**
  * Exception thrown when a definition is not found.
- *
- * @version $Rev$ $Date$
  */
 public class NoSuchDefinitionException extends DefinitionsFactoryException {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
index ca69310f4..5a35e4825 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
@@ -35,8 +35,6 @@ import java.util.Locale;
  * {@link org.apache.tiles.core.definition.digester.DigesterDefinitionsReader}
  * class unless another implementation is specified.
  * </p>
- *
- * @version $Rev$ $Date$
  * @since 2.2.1
  */
 public class UnresolvingLocaleDefinitionsFactory implements DefinitionsFactory {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
index b751c5607..4d756bbb2 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
@@ -61,8 +61,6 @@ import java.util.Map;
  * method. This means that instances of this class are <strong>not</strong>
  * thread-safe and access by multiple threads must be synchronized.
  * </p>
- *
- * @version $Rev$ $Date$
  */
 public class DigesterDefinitionsReader implements DefinitionsReader {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
index 0aeb324bc..ca501e089 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
@@ -23,8 +23,6 @@ import org.apache.tiles.api.TilesException;
 /**
  * Indicates that something went wrong during the use of
  * {@link DigesterDefinitionsReader}.
- *
- * @version $Rev$ $Date$
  * @since 2.1.0
  */
 public class DigesterDefinitionsReaderException extends TilesException {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
index 8e913bca1..657780650 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
@@ -23,8 +23,6 @@ import org.apache.tiles.api.Definition;
 /**
  * Matches a definition name to a definition, through pattern-matching. The
  * matched pattern should be a single one.
- *
- * @version $Rev$ $Date$
  * @since 2.2.0
  */
 public interface DefinitionPatternMatcher {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
index d58858a50..df5890744 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
@@ -23,8 +23,6 @@ import org.apache.tiles.api.Definition;
 /**
  * Creates a new definition pattern matcher for the given pattern and the given
  * base definition with pattern expressions.
- *
- * @version $Rev$ $Date$
  * @since 2.2.0
  */
 public interface DefinitionPatternMatcherFactory {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java
index 192dff6b7..dcd8daeae 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java
@@ -20,8 +20,6 @@ package org.apache.tiles.request;
 
 /**
  * Thrown when something related to a request fails.
- *
- * @version $Rev$ $Date$
  */
 public class RequestException extends RuntimeException {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java
index 13c5dd0f8..c34b91168 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java
@@ -22,8 +22,6 @@ import org.apache.tiles.request.NotAvailableFeatureException;
 
 /**
  * Thrown when the Freemarker servlet is not available.
- *
- * @version $Rev$ $Date$
  */
 public class NotAvailableFreemarkerServletException extends NotAvailableFeatureException {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java
index dfd95cd06..9ba13c882 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java
@@ -20,8 +20,6 @@ package org.apache.tiles.request.freemarker.autotag;
 
 /**
  * Thrown when a Freemarker problem under Autotag runtime part happens.
- *
- * @version $Rev$ $Date$
  */
 public class FreemarkerAutotagException extends RuntimeException {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java
deleted file mode 100644
index 8162c815d..000000000
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-package org.apache.tiles.request.freemarker.render;
-
-import org.apache.tiles.request.freemarker.servlet.SharedVariableLoaderFreemarkerServlet;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * Extends {@link SharedVariableLoaderFreemarkerServlet} to use the attribute value as the template name.
- */
-public class AttributeValueFreemarkerServlet extends SharedVariableLoaderFreemarkerServlet {
-
-    /**
-     * Holds the value that should be used as the template name.
-     */
-    private final ThreadLocal<String> valueHolder = new ThreadLocal<>();
-
-    /**
-     * Sets the value to use as the template name.
-     *
-     * @param value The template name.
-     */
-    public void setValue(String value) {
-        valueHolder.set(value);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected String requestUrlToTemplatePath(HttpServletRequest request) {
-        return valueHolder.get();
-    }
-}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/package-info.java
deleted file mode 100644
index 925f6a2f7..000000000
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * $Id: package-info.java 1049711 2010-12-15 21:12:00Z apetrelli $
- *
- * 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.
- */
-/**
- * Rendering of Freemarker templates.
- */
-package org.apache.tiles.request.freemarker.render;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java
deleted file mode 100644
index 8cec74b1f..000000000
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.tiles.request.freemarker.servlet;
-
-import freemarker.cache.TemplateLoader;
-import freemarker.ext.servlet.FreemarkerServlet;
-import freemarker.template.Configuration;
-import org.apache.tiles.request.reflect.ClassUtil;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import java.util.Enumeration;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * Extends FreemarkerServlet to load Tiles directives as a shared variable.
- */
-public class SharedVariableLoaderFreemarkerServlet extends FreemarkerServlet {
-
-    /**
-     * The init parameter under which the factories will be put. The value of the parameter
-     * must be a semicolon (;) separated list of couples, each member of the couple must
-     * be separated by commas (,).
-     */
-    public static final String CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM =
-        "org.apache.tiles.request.freemarker.CUSTOM_SHARED_VARIABLE_FACTORIES";
-
-    /**
-     * Maps a name of a shared variable to its factory.
-     */
-    private final Map<String, SharedVariableFactory> name2variableFactory = new LinkedHashMap<>();
-
-    @Override
-    public void init(ServletConfig config) throws ServletException {
-        String param = config.getInitParameter(CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM);
-        if (param != null) {
-            String[] couples = param.split("\\s*;\\s*");
-            for (String s : couples) {
-                String[] couple = s.split("\\s*,\\s*");
-                if (couple.length != 2) {
-                    throw new ServletException("Cannot parse custom shared variable partial init param: '" + s + "'");
-                }
-                name2variableFactory.put(couple[0], (SharedVariableFactory) ClassUtil.instantiate(couple[1]));
-            }
-        }
-        super.init(new ExcludingParameterServletConfig(config));
-    }
-
-    /**
-     * Adds anew shared variable factory in a manual way.
-     *
-     * @param variableName The name of the shared variable.
-     * @param factory The shared variable factory.
-     */
-    public void addSharedVariableFactory(String variableName, SharedVariableFactory factory) {
-        name2variableFactory.put(variableName, factory);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected Configuration createConfiguration() {
-        Configuration configuration = super.createConfiguration();
-
-        for (Map.Entry<String, SharedVariableFactory> entry : name2variableFactory.entrySet()) {
-            configuration.setSharedVariable(entry.getKey(), entry.getValue().create());
-        }
-        return configuration;
-    }
-
-    /** {@inheritDoc} */
-
-    @Override
-    protected TemplateLoader createTemplateLoader(String templatePath) {
-        return new WebappClassTemplateLoader(getServletContext());
-    }
-
-    /**
-     * Servlet configuration that excludes some parameters. It is useful to adapt to
-     * FreemarkerServlet behaviour, because it gets angry if it sees some extra
-     * parameters that it does not recognize.
-     */
-    private static class ExcludingParameterServletConfig implements ServletConfig {
-
-        /**
-         * The servlet configuration.
-         */
-        private final ServletConfig config;
-
-        /**
-         * Constructor.
-         *
-         * @param config The servlet configuration.
-         */
-        public ExcludingParameterServletConfig(ServletConfig config) {
-            this.config = config;
-        }
-
-        @Override
-        public String getServletName() {
-            return config.getServletName();
-        }
-
-        @Override
-        public ServletContext getServletContext() {
-            return config.getServletContext();
-        }
-
-        @Override
-        public String getInitParameter(String name) {
-            if (CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM.equals(name)) {
-                return null;
-            }
-            return config.getInitParameter(name);
-        }
-
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        @Override
-        public Enumeration getInitParameterNames() {
-            return new SkippingEnumeration(config.getInitParameterNames());
-        }
-
-    }
-
-    /**
-     * An enumeration that skip just
-     * {@link SharedVariableLoaderFreemarkerServlet#CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM},
-     * again not to let the FreemarkerServlet be angry about it.
-     */
-    private static class SkippingEnumeration implements Enumeration<String> {
-
-        /**
-         * The original enumeration.
-         */
-        private final Enumeration<String> enumeration;
-
-        /**
-         * The next element.
-         */
-        private String next = null;
-
-        /**
-         * Constructor.
-         *
-         * @param enumeration The original enumeration.
-         */
-        public SkippingEnumeration(Enumeration<String> enumeration) {
-            this.enumeration = enumeration;
-            updateNextElement();
-        }
-
-        @Override
-        public boolean hasMoreElements() {
-            return next != null;
-        }
-
-        @Override
-        public String nextElement() {
-            String retValue = next;
-            updateNextElement();
-            return retValue;
-        }
-
-        /**
-         * Updates the next element that will be passed.
-         */
-        private void updateNextElement() {
-            String value = null;
-            boolean done = false;
-            while (this.enumeration.hasMoreElements() && !done) {
-                value = this.enumeration.nextElement();
-                if (value.equals(CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM)) {
-                    value = null;
-                } else {
-                    done = true;
-                }
-            }
-            next = value;
-        }
-
-    }
-}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java
index ce5629fa7..5103903a5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java
@@ -31,8 +31,6 @@ import java.io.Reader;
  * Delegates loading templates using a {@link WebappTemplateLoader} and, if not
  * found, a {@link ClassTemplateLoader}. The resources are loaded from the
  * webapp root and from the classpath root.
- *
- * @version $Rev$ $Date$
  */
 public class WebappClassTemplateLoader implements TemplateLoader {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java
index 81c6e579f..a7b2e2629 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java
@@ -27,8 +27,6 @@ import java.io.PrintWriter;
 
 /**
  * Adapts a {@link JspWriter} to a {@link PrintWriter}, swallowing {@link IOException}.
- *
- * @version $Rev$ $Date$
  */
 public class JspPrintWriterAdapter extends PrintWriter {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
index e88b25db7..a4e71a818 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
@@ -38,8 +38,6 @@ import java.util.Set;
 
 /**
  * A {@link PostfixedApplicationResource} that can be accessed through a URL.
- *
- * @version $Rev$ $Date$
  */
 
 public class URLApplicationResource extends PostfixedApplicationResource {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java
index 953ae68c4..7b922fd8f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java
@@ -22,8 +22,6 @@ import org.apache.tiles.request.RequestException;
 
 /**
  * Indicates that an object cannot be instantiated.
- *
- * @version $Rev$ $Date$
  */
 public class CannotInstantiateObjectException extends RequestException {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java
index fa5b78749..b1db6a09e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java
@@ -26,8 +26,6 @@ import org.apache.tiles.request.RequestWrapper;
 
 /**
  * Renders an attribute that contains a reference to a template.
- *
- * @version $Rev$ $Date$
  */
 public class DispatchRenderer implements Renderer {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java
index 2ee9bb396..4c2ea7ef1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java
@@ -53,8 +53,6 @@ import java.util.Deque;
  *           &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
  *         &lt;/code&gt;
  * </pre>
- *
- * @version $Rev$ $Date$
  * @since 2.2.0
  */
 public class InsertAttributeModel {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java
index cff71b65f..a34bb3760 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java
@@ -61,8 +61,6 @@ import java.io.IOException;
  *           &lt;/tiles:insertDefinition&gt;
  *         &lt;/code&gt;
  * </pre>
- *
- * @version $Rev$ $Date$
  * @since 2.2.0
  */
 public class InsertDefinitionModel {


[struts] 11/23: WW-5233 Copies Tiles Autotag related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 3eeb2885bf84c223dbcceb6c9ae3a7b24c68ab97
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 14:53:17 2022 +0200

    WW-5233 Copies Tiles Autotag related tests
---
 .../tiles/autotag/model/TemplateClassTest.java     | 153 +++++++++++++++++++
 .../tiles/autotag/model/TemplateMethodTest.java    | 132 +++++++++++++++++
 .../tiles/autotag/model/TemplateParameterTest.java |  88 +++++++++++
 .../tiles/autotag/model/TemplateSuiteTest.java     | 112 ++++++++++++++
 .../autotag/runtime/AbstractModelBodyTest.java     | 164 +++++++++++++++++++++
 .../tiles/autotag/runtime/util/NullWriterTest.java |  71 +++++++++
 6 files changed, 720 insertions(+)

diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateClassTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateClassTest.java
new file mode 100644
index 000000000..1b875c37d
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateClassTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class TemplateClassTest {
+
+    /**
+     * Test method for {@link TemplateClass#TemplateClass(String)}.
+     */
+    @Test
+    public void testTemplateConstructor1() {
+        TemplateClass templateClass = new TemplateClass("name");
+        assertEquals("name", templateClass.getName());
+        assertNull(templateClass.getTagName());
+        assertNull(templateClass.getTagClassPrefix());
+        assertNull(templateClass.getExecuteMethod());
+        Collection<TemplateParameter> params = templateClass.getParameters();
+        assertTrue(params.isEmpty());
+    }
+
+    /**
+     * Test method for {@link TemplateClass#TemplateClass(String, String, String, TemplateMethod)}.
+     */
+    @Test
+    public void testTemplateConstructor2() {
+        TemplateMethod method = createMock(TemplateMethod.class);
+
+        replay(method);
+        TemplateClass templateClass = new TemplateClass("name", "tagName", "tagClassPrefix", method);
+        assertEquals("name", templateClass.getName());
+        assertEquals("tagName", templateClass.getTagName());
+        assertEquals("tagClassPrefix", templateClass.getTagClassPrefix());
+        assertEquals(method, templateClass.getExecuteMethod());
+        verify(method);
+    }
+
+    /**
+     * Test method for {@link TemplateClass#getSimpleName()}.
+     */
+    @Test
+    public void testGetSimpleName() {
+        TemplateClass templateClass = new TemplateClass("name");
+        assertEquals("name", templateClass.getSimpleName());
+        templateClass = new TemplateClass("org.whatever.Hello");
+        assertEquals("Hello", templateClass.getSimpleName());
+    }
+
+    /**
+     * Test method for {@link TemplateClass#setDocumentation(String)}.
+     */
+    @Test
+    public void testSetDocumentation() {
+        TemplateClass templateClass = new TemplateClass("name");
+        templateClass.setDocumentation("docs");
+        assertEquals("docs", templateClass.getDocumentation());
+    }
+
+    /**
+     * Test method for {@link TemplateClass#getParameters()}.
+     */
+    @Test
+    public void testGetParameters() {
+        TemplateParameter param1 = createMock(TemplateParameter.class);
+        TemplateParameter param2 = createMock(TemplateParameter.class);
+        TemplateParameter param3 = createMock(TemplateParameter.class);
+        TemplateParameter param4 = createMock(TemplateParameter.class);
+        TemplateMethod method = createMock(TemplateMethod.class);
+        List<TemplateParameter> params = new ArrayList<>();
+
+        expect(method.getParameters()).andReturn(params);
+        expect(param1.isRequest()).andReturn(true);
+        expect(param2.isRequest()).andReturn(false);
+        expect(param2.isBody()).andReturn(true);
+        expect(param3.isRequest()).andReturn(false);
+        expect(param3.isBody()).andReturn(false);
+        expect(param4.isRequest()).andReturn(false);
+        expect(param4.isBody()).andReturn(false);
+        expect(param3.getName()).andReturn("param1");
+        expect(param4.getName()).andReturn("param2");
+
+        replay(param1, param2, param3, param4, method);
+        params.add(param1);
+        params.add(param2);
+        params.add(param3);
+        params.add(param4);
+
+        TemplateClass templateClass = new TemplateClass("name", "tagName", "tagClassPrefix", method);
+        Collection<TemplateParameter> returnedParams = templateClass.getParameters();
+        Iterator<TemplateParameter> paramIt = returnedParams.iterator();
+        assertSame(param3, paramIt.next());
+        assertSame(param4, paramIt.next());
+        assertFalse(paramIt.hasNext());
+        verify(param1, param2, param3, param4, method);
+    }
+
+    /**
+     * Test method for {@link TemplateClass#hasBody()}.
+     */
+    @Test
+    public void testHasBody() {
+        TemplateMethod method = createMock(TemplateMethod.class);
+        expect(method.hasBody()).andReturn(true);
+
+        replay(method);
+        TemplateClass templateClass = new TemplateClass("name", "tagName", "tagClassPrefix", method);
+        assertTrue(templateClass.hasBody());
+        verify(method);
+    }
+
+    /**
+     * Test method for {@link TemplateClass#toString()}.
+     */
+    @Test
+    public void testToString() {
+        TemplateMethod method = new TemplateMethod("method", new ArrayList<>());
+        TemplateClass templateClass = new TemplateClass("name", "tagName", "tagClassPrefix", method);
+        assertEquals("TemplateClass [name=name, tagName=tagName, tagClassPrefix=tagClassPrefix, " + "documentation=null, executeMethod=TemplateMethod " + "[name=method, documentation=null, parameters={}]]", templateClass.toString());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateMethodTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateMethodTest.java
new file mode 100644
index 000000000..e6ad8b181
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateMethodTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link TemplateMethod}.
+ */
+public class TemplateMethodTest {
+
+    /**
+     * Tests {@link TemplateMethod#TemplateMethod(String, Iterable)}.
+     */
+    @Test
+    public void testTemplateMethod() {
+        TemplateParameter param1 = createMock(TemplateParameter.class);
+        TemplateParameter param2 = createMock(TemplateParameter.class);
+
+        expect(param1.getName()).andReturn("param1");
+        expect(param2.getName()).andReturn("param2");
+
+        replay(param1, param2);
+        List<TemplateParameter> parameters = new ArrayList<>();
+        parameters.add(param1);
+        parameters.add(param2);
+
+        TemplateMethod method = new TemplateMethod("method", parameters);
+        assertEquals("method", method.getName());
+        Iterator<TemplateParameter> params = method.getParameters().iterator();
+        assertSame(param1, params.next());
+        assertSame(param2, params.next());
+        assertFalse(params.hasNext());
+        assertSame(param1, method.getParameterByName("param1"));
+        assertSame(param2, method.getParameterByName("param2"));
+        verify(param1, param2);
+    }
+
+    /**
+     * Tests {@link TemplateMethod#setDocumentation(String)}.
+     */
+    @Test
+    public void testSetDocumentation() {
+        TemplateMethod method = new TemplateMethod("method", new ArrayList<>());
+        method.setDocumentation("docs");
+        assertEquals("docs", method.getDocumentation());
+    }
+
+    /**
+     * Tests {@link TemplateMethod#hasBody()}.
+     */
+    @Test
+    public void testHasBody() {
+        TemplateParameter param1 = createMock(TemplateParameter.class);
+        TemplateParameter param2 = createMock(TemplateParameter.class);
+
+        expect(param1.getName()).andReturn("param1");
+        expect(param2.getName()).andReturn("param2");
+        expect(param1.isBody()).andReturn(true);
+
+        replay(param1, param2);
+        List<TemplateParameter> parameters = new ArrayList<>();
+        parameters.add(param1);
+        parameters.add(param2);
+
+        TemplateMethod method = new TemplateMethod("method", parameters);
+        assertTrue(method.hasBody());
+        verify(param1, param2);
+    }
+
+    /**
+     * Tests {@link TemplateMethod#hasBody()}.
+     */
+    @Test
+    public void testHasBody2() {
+        TemplateParameter param1 = createMock(TemplateParameter.class);
+        TemplateParameter param2 = createMock(TemplateParameter.class);
+
+        expect(param1.getName()).andReturn("param1");
+        expect(param2.getName()).andReturn("param2");
+        expect(param1.isBody()).andReturn(false);
+        expect(param2.isBody()).andReturn(false);
+
+        replay(param1, param2);
+        List<TemplateParameter> parameters = new ArrayList<>();
+        parameters.add(param1);
+        parameters.add(param2);
+
+        TemplateMethod method = new TemplateMethod("method", parameters);
+        assertFalse(method.hasBody());
+        verify(param1, param2);
+    }
+
+    /**
+     * Tests {@link TemplateMethod#toString()}.
+     */
+    @Test
+    public void testToString() {
+        TemplateMethod method = new TemplateMethod("method", new ArrayList<>());
+        assertEquals("TemplateMethod [name=method, documentation=null, parameters={}]", method.toString());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateParameterTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateParameterTest.java
new file mode 100644
index 000000000..efa486950
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateParameterTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link TemplateParameter}.
+ */
+public class TemplateParameterTest {
+
+    @Test
+    public void testTemplateParameter() {
+        TemplateParameter parameter = new TemplateParameter("name", "exportedName", "type", "defaultValue", true, false);
+        assertEquals("name", parameter.getName());
+        assertEquals("exportedName", parameter.getExportedName());
+        assertEquals("type", parameter.getType());
+        assertEquals("defaultValue", parameter.getDefaultValue());
+        assertTrue(parameter.isRequired());
+        assertEquals("ExportedName", parameter.getGetterSetterSuffix());
+        assertFalse(parameter.isBody());
+        assertFalse(parameter.isRequest());
+
+        parameter = new TemplateParameter("name", "exportedName", "my.Request", "defaultValue", false, true);
+        assertEquals("name", parameter.getName());
+        assertEquals("exportedName", parameter.getExportedName());
+        assertEquals("my.Request", parameter.getType());
+        assertEquals("defaultValue", parameter.getDefaultValue());
+        assertFalse(parameter.isRequired());
+        assertEquals("ExportedName", parameter.getGetterSetterSuffix());
+        assertFalse(parameter.isBody());
+        assertTrue(parameter.isRequest());
+
+        parameter = new TemplateParameter("name", "exportedName", ModelBody.class.getName(), "defaultValue", false, false);
+        assertEquals("name", parameter.getName());
+        assertEquals("exportedName", parameter.getExportedName());
+        assertEquals(ModelBody.class.getName(), parameter.getType());
+        assertEquals("defaultValue", parameter.getDefaultValue());
+        assertFalse(parameter.isRequired());
+        assertEquals("ExportedName", parameter.getGetterSetterSuffix());
+        assertTrue(parameter.isBody());
+        assertFalse(parameter.isRequest());
+    }
+
+    /**
+     * Tests {@link TemplateParameter#setDocumentation(String)}.
+     */
+    @Test
+    public void testSetDocumentation() {
+        TemplateParameter parameter = new TemplateParameter("name", "exportedName", "type", "defaultValue", true, false);
+        parameter.setDocumentation("docs");
+        assertEquals("docs", parameter.getDocumentation());
+    }
+
+    /**
+     * Tests {@link TemplateParameter#toString()}.
+     */
+    @Test
+    public void testToString() {
+        TemplateParameter parameter = new TemplateParameter("name", "exportedName", "type", "defaultValue", true, false);
+        assertEquals(
+            "TemplateParameter [name=name, exportedName=exportedName, "
+                + "documentation=null, type=type, defaultValue=defaultValue, required=true, request=false]",
+            parameter.toString());
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateSuiteTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateSuiteTest.java
new file mode 100644
index 000000000..cdb5c5216
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/model/TemplateSuiteTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link TemplateSuite}.
+ */
+public class TemplateSuiteTest {
+
+    /**
+     * Test method for {@link TemplateSuite#TemplateSuite(String, String)}.
+     */
+    @Test
+    public void testTemplateSuiteConstructor1() {
+        TemplateSuite suite = new TemplateSuite("name", "docs");
+        assertEquals("name", suite.getName());
+        assertEquals("docs", suite.getDocumentation());
+        assertTrue(suite.getTemplateClasses().isEmpty());
+    }
+
+    /**
+     * Test method for {@link TemplateSuite#TemplateSuite(String, String, Iterable)}.
+     */
+    @Test
+    public void testTemplateSuiteConstructor2() {
+        TemplateClass class1 = createMock(TemplateClass.class);
+        TemplateClass class2 = createMock(TemplateClass.class);
+        expect(class1.getName()).andReturn("class1");
+        expect(class2.getName()).andReturn("class2");
+
+        replay(class1, class2);
+        List<TemplateClass> classes = new ArrayList<>();
+        classes.add(class1);
+        classes.add(class2);
+        TemplateSuite suite = new TemplateSuite("name", "docs", classes);
+        assertEquals("name", suite.getName());
+        assertEquals("docs", suite.getDocumentation());
+        Iterator<TemplateClass> clazzes = suite.getTemplateClasses().iterator();
+        assertSame(class1, clazzes.next());
+        assertSame(class2, clazzes.next());
+        assertFalse(clazzes.hasNext());
+        assertSame(class1, suite.getTemplateClassByName("class1"));
+        assertSame(class2, suite.getTemplateClassByName("class2"));
+        verify(class1, class2);
+    }
+
+    /**
+     * Test method for {@link TemplateSuite#addTemplateClass(TemplateClass)}.
+     */
+    @Test
+    public void testAddTemplateClass() {
+        TemplateClass class1 = createMock(TemplateClass.class);
+        TemplateClass class2 = createMock(TemplateClass.class);
+        expect(class1.getName()).andReturn("class1");
+        expect(class2.getName()).andReturn("class2");
+
+        replay(class1, class2);
+        TemplateSuite suite = new TemplateSuite("name", "docs");
+        assertEquals("name", suite.getName());
+        assertEquals("docs", suite.getDocumentation());
+        assertTrue(suite.getTemplateClasses().isEmpty());
+        suite.addTemplateClass(class1);
+        suite.addTemplateClass(class2);
+        Iterator<TemplateClass> clazzes = suite.getTemplateClasses().iterator();
+        assertSame(class1, clazzes.next());
+        assertSame(class2, clazzes.next());
+        assertFalse(clazzes.hasNext());
+        assertSame(class1, suite.getTemplateClassByName("class1"));
+        assertSame(class2, suite.getTemplateClassByName("class2"));
+        verify(class1, class2);
+    }
+
+    /**
+     * Test method for {@link TemplateSuite#toString()}.
+     */
+    @Test
+    public void testToString() {
+        TemplateSuite suite = new TemplateSuite("name", "docs");
+        assertEquals("TemplateSuite [name=name, documentation=docs, templateClasses={}]", suite.toString());
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java
new file mode 100644
index 000000000..08e4d9011
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.runtime;
+
+import org.apache.tiles.autotag.core.runtime.AbstractModelBody;
+import org.apache.tiles.autotag.core.runtime.util.NullWriter;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link AbstractModelBody}.
+ *
+ * @version $Rev$ $Date$
+ */
+public class AbstractModelBodyTest {
+
+    /**
+     * Test method for {@link AbstractModelBody#evaluate()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testEvaluate() throws IOException {
+        Writer writer = createMock(Writer.class);
+        AbstractModelBody modelBody = createMockBuilder(AbstractModelBody.class).withConstructor(writer).createMock();
+
+        modelBody.evaluate(writer);
+
+        replay(writer, modelBody);
+        modelBody.evaluate();
+        verify(writer, modelBody);
+    }
+
+    /**
+     * Test method for {@link AbstractModelBody#evaluateAsString()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testEvaluateAsString() throws IOException {
+        AbstractModelBody modelBody = new MockModelBody(null, "return me");
+        assertEquals("return me", modelBody.evaluateAsString());
+
+        modelBody = new MockModelBody(null, "\n   \n");
+        assertNull(modelBody.evaluateAsString());
+    }
+
+    /**
+     * Test method for {@link AbstractModelBody#evaluateAsString()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test(expected = IOException.class)
+    public void testEvaluateAsStringException() throws IOException {
+        Writer writer = createMock(Writer.class);
+        AbstractModelBody modelBody = createMockBuilder(AbstractModelBody.class).withConstructor(writer).createMock();
+
+        modelBody.evaluate(isA(StringWriter.class));
+        expectLastCall().andThrow(new IOException());
+
+        replay(writer, modelBody);
+        try {
+            modelBody.evaluateAsString();
+        } finally {
+            verify(writer, modelBody);
+        }
+    }
+
+    /**
+     * Test method for {@link AbstractModelBody#evaluateWithoutWriting()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testEvaluateWithoutWriting() throws IOException {
+        Writer writer = createMock(Writer.class);
+        AbstractModelBody modelBody = createMockBuilder(AbstractModelBody.class).withConstructor(writer).createMock();
+
+        modelBody.evaluate(isA(NullWriter.class));
+
+        replay(writer, modelBody);
+        modelBody.evaluateWithoutWriting();
+        verify(writer, modelBody);
+    }
+
+    /**
+     * Test method for {@link AbstractModelBody#evaluateWithoutWriting()}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test(expected = IOException.class)
+    public void testEvaluateWithoutWritingException() throws IOException {
+        Writer writer = createMock(Writer.class);
+        AbstractModelBody modelBody = createMockBuilder(AbstractModelBody.class).withConstructor(writer).createMock();
+
+        modelBody.evaluate(isA(NullWriter.class));
+        expectLastCall().andThrow(new IOException());
+
+        replay(writer, modelBody);
+        try {
+            modelBody.evaluateWithoutWriting();
+        } finally {
+            verify(writer, modelBody);
+        }
+    }
+
+    /**
+     * A mock model body.
+     *
+     * @version $Rev$ $Date$
+     */
+    public static class MockModelBody extends AbstractModelBody {
+
+        /**
+         * The result to return.
+         */
+        private final String toReturn;
+
+        /**
+         * Constructor.
+         *
+         * @param defaultWriter The default writer.
+         * @param toReturn      The result to return.
+         */
+        public MockModelBody(Writer defaultWriter, String toReturn) {
+            super(defaultWriter);
+            this.toReturn = toReturn;
+        }
+
+        @Override
+        public void evaluate(Writer writer) throws IOException {
+            writer.write(toReturn);
+        }
+
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/util/NullWriterTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/util/NullWriterTest.java
new file mode 100644
index 000000000..00f6b452c
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/util/NullWriterTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.runtime.util;
+
+import org.apache.tiles.autotag.core.runtime.util.NullWriter;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests {@link NullWriter}.
+ */
+public class NullWriterTest {
+
+    /**
+     * A dummy size.
+     */
+    private static final int DUMMY_SIZE = 15;
+    /**
+     * The object to test.
+     */
+    private NullWriter writer;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        writer = new NullWriter();
+    }
+
+    /**
+     * Test method for {@link NullWriter#write(char[], int, int)}.
+     */
+    @Test
+    public void testWriteCharArrayIntInt() {
+        writer.write("Hello there".toCharArray(), 0, DUMMY_SIZE);
+    }
+
+    /**
+     * Test method for {@link NullWriter#flush()}.
+     */
+    @Test
+    public void testFlush() {
+        writer.flush();
+    }
+
+    /**
+     * Test method for {@link NullWriter#close()}.
+     */
+    @Test
+    public void testClose() {
+        writer.close();
+    }
+
+}


[struts] 14/23: WW-5233 Addresses a few code smells

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit c8d843e7093f922d41ff469b7efaada8cf1b08d2
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Oct 3 08:09:34 2022 +0200

    WW-5233 Addresses a few code smells
---
 .../src/main/java/org/apache/tiles/api/Attribute.java  | 18 ++++++------------
 .../org/apache/tiles/api/BasicAttributeContext.java    |  4 ++--
 .../main/java/org/apache/tiles/api/ListAttribute.java  |  9 ++++-----
 .../test/java/org/apache/tiles/api/AttributeTest.java  |  2 +-
 .../java/org/apache/tiles/api/ListAttributeTest.java   |  2 +-
 .../request/collection/HeaderValuesCollectionTest.java |  4 ++--
 .../collection/HeaderValuesMapEntrySetTest.java        |  4 ++--
 .../apache/tiles/request/collection/KeySetTest.java    |  2 +-
 .../ReadOnlyEnumerationMapValuesCollectionTest.java    |  6 ++++--
 9 files changed, 23 insertions(+), 28 deletions(-)

diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
index 69209e5d4..65be6537a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -22,7 +22,6 @@ package org.apache.tiles.api;
 import com.opensymphony.xwork2.util.TextParseUtil;
 import org.apache.tiles.request.Request;
 
-import java.io.Serializable;
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
@@ -30,7 +29,7 @@ import java.util.Set;
 /**
  * Common implementation of attribute definition.
  */
-public class Attribute implements Serializable, Cloneable {
+public class Attribute {
 
     /**
      * The name of the template renderer.
@@ -42,20 +41,19 @@ public class Attribute implements Serializable, Cloneable {
      *
      * @since 2.0.6
      */
-    protected Set<String> roles = null;
+    private Set<String> roles = null;
 
     /**
      * The value of the attribute.
      */
-    protected Object value = null;
+    private Object value = null;
 
     /**
-     * The expression to evaluate. Ignored if {@link #value} is not
-     * <code>null</code>.
+     * The expression to evaluate. Ignored if {@link #value} is not <code>null</code>.
      *
      * @since 2.2.0
      */
-    protected Expression expressionObject = null;
+    private Expression expressionObject = null;
 
     /**
      * The renderer name of the attribute. Default names are <code>string</code>,
@@ -362,11 +360,7 @@ public class Attribute implements Serializable, Cloneable {
             + Objects.hashCode(roles) + Objects.hashCode(expressionObject);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Attribute clone() {
+    public Attribute copy() {
         return new Attribute(this);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
index 9de064d6b..cd12ea860 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
@@ -232,7 +232,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
 
     /**
      * Add all attributes to this context.
-     * Copies all of the mappings from the specified attribute map to this context.
+     * Copies all the mappings from the specified attribute map to this context.
      * New attribute mappings will replace any mappings that this context had for any of the keys
      * currently in the specified attribute map.
      *
@@ -454,7 +454,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         for (Map.Entry<String, Attribute> entry : attributes.entrySet()) {
             Attribute toCopy = entry.getValue();
             if (toCopy != null) {
-                retValue.put(entry.getKey(), toCopy.clone());
+                retValue.put(entry.getKey(), toCopy.copy());
             }
         }
         return retValue;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
index 227380af0..67b329443 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
@@ -61,7 +61,7 @@ public class ListAttribute extends Attribute {
             List<Attribute> attributes = new ArrayList<>(attributesToCopy.size());
             for (Attribute attribute : attributesToCopy) {
                 if (attribute != null) {
-                    attributes.add(attribute.clone());
+                    attributes.add(attribute.copy());
                 } else {
                     attributes.add(null);
                 }
@@ -135,11 +135,10 @@ public class ListAttribute extends Attribute {
      * @param parent The parent list attribute.
      * @since 2.1.0
      */
-    @SuppressWarnings("unchecked")
     public void inherit(ListAttribute parent) {
         List<Attribute> tempList = new ArrayList<>();
-        tempList.addAll((List<Attribute>) parent.value);
-        tempList.addAll((List<Attribute>) value);
+        tempList.addAll(parent.getValue());
+        tempList.addAll(getValue());
         setValue(tempList);
     }
 
@@ -164,7 +163,7 @@ public class ListAttribute extends Attribute {
 
     /** {@inheritDoc} */
     @Override
-    public ListAttribute clone() {
+    public ListAttribute copy() {
         return new ListAttribute(this);
     }
 }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
index 5c46b42e0..703dde92b 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
@@ -225,7 +225,7 @@ public class AttributeTest {
     public void testClone() {
         Expression expression = new Expression("my.expression", "MYLANG");
         Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
-        attribute = attribute.clone();
+        attribute = attribute.copy();
         assertEquals("my.value", attribute.getValue());
         assertEquals("myrenderer", attribute.getRenderer());
         Set<String> roles = new HashSet<>();
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
index 582f041e8..baa41fd7a 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
@@ -103,7 +103,7 @@ public class ListAttributeTest {
         list.add(new Attribute("value2"));
         attribute.setValue(list);
         attribute.setInherit(true);
-        ListAttribute toCheck = attribute.clone();
+        ListAttribute toCheck = attribute.copy();
         assertEquals(attribute, toCheck);
     }
 }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java
index 8a4069171..36f9bd2e0 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesCollectionTest.java
@@ -42,7 +42,6 @@ import static org.junit.Assert.assertTrue;
  */
 public class HeaderValuesCollectionTest {
 
-
     /**
      * The extractor to use.
      */
@@ -245,9 +244,10 @@ public class HeaderValuesCollectionTest {
 
         expect(extractor.getKeys()).andReturn(keys);
         expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.hasMoreElements()).andReturn(true);
         expect(keys.nextElement()).andReturn("two");
-
         expect(extractor.getValues("two")).andReturn(values2);
+
         expect(values2.hasMoreElements()).andReturn(true);
         expect(values2.nextElement()).andReturn("value2");
         expect(values2.hasMoreElements()).andReturn(true);
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java
index 344151c52..77218414d 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/HeaderValuesMapEntrySetTest.java
@@ -180,6 +180,7 @@ public class HeaderValuesMapEntrySetTest {
 
         expect(extractor.getKeys()).andReturn(keys);
         expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.hasMoreElements()).andReturn(true);
         expect(keys.nextElement()).andReturn("two");
 
         expect(extractor.getValues("two")).andReturn(values2);
@@ -192,8 +193,7 @@ public class HeaderValuesMapEntrySetTest {
         replay(extractor, keys, values2);
         Iterator<Map.Entry<String, String[]>> entryIt = entrySet.iterator();
         assertTrue(entryIt.hasNext());
-        MapEntryArrayValues<String, String> entry = new MapEntryArrayValues<>(
-            "two", new String[]{"value2", "value3"}, false);
+        MapEntryArrayValues<String, String> entry = new MapEntryArrayValues<>("two", new String[]{"value2", "value3"}, false);
         assertEquals(entry, entryIt.next());
         verify(extractor, keys, values2);
     }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java
index f8fe60a31..452bb5123 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/KeySetTest.java
@@ -42,7 +42,6 @@ import static org.junit.Assert.assertTrue;
  */
 public class KeySetTest {
 
-
     /**
      * The extractor to use.
      */
@@ -170,6 +169,7 @@ public class KeySetTest {
 
         expect(extractor.getKeys()).andReturn(keys);
         expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.hasMoreElements()).andReturn(true);
         expect(keys.nextElement()).andReturn("two");
 
         replay(extractor, keys, values2);
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java
index 4a9862f82..b37dbdc03 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMapValuesCollectionTest.java
@@ -41,6 +41,7 @@ import static org.junit.Assert.assertTrue;
  * Tests {@link ReadOnlyEnumerationMap#values()}.
  */
 public class ReadOnlyEnumerationMapValuesCollectionTest {
+
     /**
      * The extractor to use.
      */
@@ -188,6 +189,7 @@ public class ReadOnlyEnumerationMapValuesCollectionTest {
 
         expect(extractor.getKeys()).andReturn(keys);
         expect(keys.hasMoreElements()).andReturn(true);
+        expect(keys.hasMoreElements()).andReturn(true);
         expect(keys.nextElement()).andReturn("two");
 
         expect(extractor.getValue("two")).andReturn(2);
@@ -276,7 +278,7 @@ public class ReadOnlyEnumerationMapValuesCollectionTest {
         expect(extractor.getValue("one")).andReturn(1);
         expect(extractor.getValue("two")).andReturn(2);
 
-        Integer[] entryArray = new Integer[] {1, 2};
+        Integer[] entryArray = new Integer[]{1, 2};
 
         replay(extractor, keys);
         assertArrayEquals(entryArray, coll.toArray());
@@ -300,7 +302,7 @@ public class ReadOnlyEnumerationMapValuesCollectionTest {
         expect(extractor.getValue("one")).andReturn(1);
         expect(extractor.getValue("two")).andReturn(2);
 
-        Integer[] entryArray = new Integer[] {1, 2};
+        Integer[] entryArray = new Integer[]{1, 2};
 
         replay(extractor, keys);
         Integer[] realArray = new Integer[2];


[struts] 04/23: WW-5233 Copies Tiles Core related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit c77dcb53044faeff751d539d148eb15addefbf82
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 12:58:25 2022 +0200

    WW-5233 Copies Tiles Core related tests
---
 bom/pom.xml                                        |   4 +-
 plugins/tiles/pom.xml                              |   5 +
 .../main/java/org/apache/tiles/api/Attribute.java  |   2 -
 .../org/apache/tiles/api/AttributeContext.java     |   2 -
 .../apache/tiles/api/BasicAttributeContext.java    |   2 -
 .../main/java/org/apache/tiles/api/Definition.java |   2 -
 .../main/java/org/apache/tiles/api/Expression.java |   2 -
 .../java/org/apache/tiles/api/ListAttribute.java   |   2 -
 .../apache/tiles/api/NoSuchContainerException.java |   2 -
 .../java/org/apache/tiles/api/TilesContainer.java  |   2 -
 .../apache/tiles/api/TilesContainerWrapper.java    |   2 -
 .../java/org/apache/tiles/api/TilesException.java  |   2 -
 .../org/apache/tiles/api/access/TilesAccess.java   |   2 -
 .../tiles/api/mgmt/MutableTilesContainer.java      |   2 -
 .../apache/tiles/api/preparer/ViewPreparer.java    |   2 -
 .../autotag/core/runtime/AbstractModelBody.java    |   2 -
 .../tiles/autotag/core/runtime/AutotagRuntime.java |   2 -
 .../tiles/autotag/core/runtime/ModelBody.java      |   2 -
 .../autotag/core/runtime/annotation/Parameter.java |   2 -
 .../core/runtime/annotation/package-info.java      |   2 -
 .../tiles/autotag/core/runtime/package-info.java   |   2 -
 .../autotag/core/runtime/util/NullWriter.java      |   2 -
 .../autotag/core/runtime/util/package-info.java    |   2 -
 .../apache/tiles/autotag/model/TemplateClass.java  |   2 -
 .../apache/tiles/autotag/model/TemplateMethod.java |   2 -
 .../tiles/autotag/model/TemplateParameter.java     |   2 -
 .../apache/tiles/autotag/model/TemplateSuite.java  |   2 -
 .../apache/tiles/autotag/model/package-info.java   |   2 -
 .../tiles/core/definition/DefinitionsFactory.java  |   2 -
 .../definition/DefinitionsFactoryException.java    |   2 -
 .../tiles/core/definition/DefinitionsReader.java   |   2 -
 .../core/definition/NoSuchDefinitionException.java |   2 -
 .../tiles/core/definition/RefreshMonitor.java      |   2 -
 .../UnresolvingLocaleDefinitionsFactory.java       |   2 -
 .../definition/dao/BaseLocaleUrlDefinitionDAO.java |   2 -
 .../dao/CachingLocaleUrlDefinitionDAO.java         |   5 +-
 .../tiles/core/definition/dao/DefinitionDAO.java   |   2 -
 .../dao/ResolvingLocaleUrlDefinitionDAO.java       |   2 -
 .../tiles/core/definition/dao/package-info.java    |   2 -
 .../digester/DigesterDefinitionsReader.java        |   2 -
 .../DigesterDefinitionsReaderException.java        |   2 -
 .../core/definition/digester/package-info.java     |   2 -
 .../apache/tiles/core/definition/package-info.java |   2 -
 .../pattern/AbstractPatternDefinitionResolver.java |   2 -
 .../pattern/BasicPatternDefinitionResolver.java    |   2 -
 .../pattern/DefinitionPatternMatcher.java          |   2 -
 .../pattern/DefinitionPatternMatcherFactory.java   |   2 -
 .../pattern/PatternDefinitionResolver.java         |   2 -
 .../pattern/PatternDefinitionResolverAware.java    |   2 -
 .../core/definition/pattern/PatternRecognizer.java |   2 -
 .../tiles/core/definition/pattern/PatternUtil.java |   2 -
 .../pattern/PrefixedPatternDefinitionResolver.java |   2 -
 .../core/definition/pattern/package-info.java      |   2 -
 .../regexp/RegexpDefinitionPatternMatcher.java     |   2 -
 .../RegexpDefinitionPatternMatcherFactory.java     |   2 -
 .../definition/pattern/regexp/package-info.java    |   2 -
 .../wildcard/WildcardDefinitionPatternMatcher.java |   2 -
 .../WildcardDefinitionPatternMatcherFactory.java   |   2 -
 .../definition/pattern/wildcard/package-info.java  |   2 -
 .../core/evaluator/AbstractAttributeEvaluator.java |   2 -
 .../tiles/core/evaluator/AttributeEvaluator.java   |   2 -
 .../core/evaluator/AttributeEvaluatorFactory.java  |   2 -
 .../evaluator/AttributeEvaluatorFactoryAware.java  |   2 -
 .../evaluator/BasicAttributeEvaluatorFactory.java  |   2 -
 .../tiles/core/evaluator/EvaluationException.java  |   2 -
 .../evaluator/impl/DirectAttributeEvaluator.java   |   2 -
 .../tiles/core/evaluator/impl/package-info.java    |   2 -
 .../apache/tiles/core/evaluator/package-info.java  |   2 -
 .../factory/AbstractTilesContainerFactory.java     |   2 -
 .../core/factory/BasicTilesContainerFactory.java   |   2 -
 .../factory/TilesContainerFactoryException.java    |   2 -
 .../apache/tiles/core/factory/package-info.java    |   2 -
 .../tiles/core/impl/BasicTilesContainer.java       |   2 -
 .../tiles/core/impl/InvalidTemplateException.java  |   2 -
 .../core/impl/mgmt/CachingTilesContainer.java      |   2 -
 .../apache/tiles/core/impl/mgmt/package-info.java  |   2 -
 .../org/apache/tiles/core/impl/package-info.java   |   2 -
 .../apache/tiles/core/locale/LocaleResolver.java   |   2 -
 .../core/locale/impl/DefaultLocaleResolver.java    |   2 -
 .../tiles/core/locale/impl/package-info.java       |   2 -
 .../org/apache/tiles/core/locale/package-info.java |   2 -
 .../core/prepare/factory/BasicPreparerFactory.java |   2 -
 .../prepare/factory/NoSuchPreparerException.java   |   2 -
 .../core/prepare/factory/PreparerFactory.java      |   2 -
 .../tiles/core/prepare/factory/package-info.java   |   2 -
 .../tiles/core/renderer/DefinitionRenderer.java    |   2 -
 .../apache/tiles/core/renderer/package-info.java   |   2 -
 .../core/startup/AbstractTilesInitializer.java     |   2 -
 .../tiles/core/startup/TilesInitializer.java       |   2 -
 .../apache/tiles/core/startup/package-info.java    |   2 -
 .../apache/tiles/core/util/CombinedBeanInfo.java   |   2 -
 .../org/apache/tiles/core/util/WildcardHelper.java |   2 -
 .../org/apache/tiles/core/util/package-info.java   |   2 -
 .../org/apache/tiles/el/ELAttributeEvaluator.java  |   2 -
 .../java/org/apache/tiles/el/ELContextImpl.java    |   2 -
 .../apache/tiles/el/ExpressionFactoryFactory.java  |   2 -
 .../tiles/el/JspExpressionFactoryFactory.java      |   2 -
 .../java/org/apache/tiles/el/ScopeELResolver.java  |   2 -
 .../tiles/el/TilesContextBeanELResolver.java       |   2 -
 .../java/org/apache/tiles/el/package-info.java     |   2 -
 .../org/apache/tiles/freemarker/package-info.java  |   2 -
 .../tiles/ognl/AnyScopePropertyAccessor.java       |   2 -
 .../tiles/ognl/DelegatePropertyAccessor.java       |   2 -
 .../ognl/NestedObjectDelegatePropertyAccessor.java |   2 -
 .../apache/tiles/ognl/NestedObjectExtractor.java   |   2 -
 .../apache/tiles/ognl/OGNLAttributeEvaluator.java  |   2 -
 .../ognl/PropertyAccessorDelegateFactory.java      |   2 -
 .../apache/tiles/ognl/ScopePropertyAccessor.java   |   2 -
 ...lesApplicationContextNestedObjectExtractor.java |   2 -
 ...ilesContextPropertyAccessorDelegateFactory.java |   2 -
 .../java/org/apache/tiles/ognl/package-info.java   |   2 -
 .../tiles/request/AbstractClientRequest.java       |   2 -
 .../org/apache/tiles/request/AbstractRequest.java  |   2 -
 .../apache/tiles/request/AbstractViewRequest.java  |   2 -
 .../apache/tiles/request/ApplicationAccess.java    |   2 -
 .../apache/tiles/request/ApplicationContext.java   |   2 -
 .../tiles/request/ApplicationContextAware.java     |   2 -
 .../apache/tiles/request/ApplicationResource.java  |   2 -
 .../org/apache/tiles/request/DispatchRequest.java  |   2 -
 .../tiles/request/DispatchRequestWrapper.java      |   2 -
 .../request/NotAvailableFeatureException.java      |   2 -
 .../java/org/apache/tiles/request/Request.java     |   2 -
 .../org/apache/tiles/request/RequestException.java |   2 -
 .../org/apache/tiles/request/RequestWrapper.java   |   2 -
 .../apache/tiles/request/attribute/Addable.java    |   2 -
 .../request/attribute/AttributeExtractor.java      |   2 -
 .../attribute/EnumeratedValuesExtractor.java       |   2 -
 .../tiles/request/attribute/HasAddableKeys.java    |   2 -
 .../apache/tiles/request/attribute/HasKeys.java    |   2 -
 .../tiles/request/attribute/HasRemovableKeys.java  |   2 -
 .../tiles/request/attribute/package-info.java      |   2 -
 .../tiles/request/collection/CollectionUtil.java   |   2 -
 .../tiles/request/collection/HeaderValuesMap.java  |   2 -
 .../apache/tiles/request/collection/KeySet.java    |   2 -
 .../apache/tiles/request/collection/MapEntry.java  |   2 -
 .../request/collection/MapEntryArrayValues.java    |   2 -
 .../request/collection/ReadOnlyEnumerationMap.java |   2 -
 .../tiles/request/collection/RemovableKeySet.java  |   2 -
 .../apache/tiles/request/collection/ScopeMap.java  |   2 -
 .../tiles/request/collection/package-info.java     |   2 -
 .../request/freemarker/EnvironmentScopeMap.java    |   2 -
 .../request/freemarker/FreemarkerRequest.java      |   2 -
 .../freemarker/FreemarkerRequestException.java     |   2 -
 .../request/freemarker/FreemarkerRequestUtil.java  |   2 -
 .../NotAvailableFreemarkerServletException.java    |   2 -
 .../autotag/FreemarkerAutotagException.java        |   2 -
 .../autotag/FreemarkerAutotagRuntime.java          |   2 -
 .../freemarker/autotag/FreemarkerModelBody.java    |   2 -
 .../request/freemarker/autotag/FreemarkerUtil.java |   2 -
 .../request/freemarker/autotag/package-info.java   |   2 -
 .../extractor/EnvironmentScopeExtractor.java       |   2 -
 .../render/AttributeValueFreemarkerServlet.java    |   2 -
 .../freemarker/servlet/SharedVariableFactory.java  |   2 -
 .../SharedVariableLoaderFreemarkerServlet.java     |   2 -
 .../servlet/WebappClassTemplateLoader.java         |   2 -
 .../tiles/request/jsp/JspPrintWriterAdapter.java   |   2 -
 .../org/apache/tiles/request/jsp/JspRequest.java   |   2 -
 .../java/org/apache/tiles/request/jsp/JspUtil.java |   2 -
 .../request/jsp/autotag/JspAutotagRuntime.java     |   2 -
 .../tiles/request/jsp/autotag/JspModelBody.java    |   2 -
 .../tiles/request/jsp/autotag/package-info.java    |   2 -
 .../request/jsp/extractor/ScopeExtractor.java      |   2 -
 .../jsp/extractor/SessionScopeExtractor.java       |   2 -
 .../apache/tiles/request/locale/LocaleUtil.java    |   2 -
 .../locale/PostfixedApplicationResource.java       |   2 -
 .../request/locale/URLApplicationResource.java     |   2 -
 .../reflect/CannotInstantiateObjectException.java  |   2 -
 .../apache/tiles/request/reflect/ClassUtil.java    |   2 -
 .../apache/tiles/request/reflect/package-info.java |   2 -
 .../tiles/request/render/BasicRendererFactory.java |   2 -
 .../request/render/CannotRenderException.java      |   2 -
 .../request/render/ChainedDelegateRenderer.java    |   2 -
 .../tiles/request/render/DispatchRenderer.java     |   2 -
 .../request/render/NoSuchRendererException.java    |   2 -
 .../tiles/request/render/RenderException.java      |   2 -
 .../org/apache/tiles/request/render/Renderer.java  |   2 -
 .../tiles/request/render/RendererFactory.java      |   2 -
 .../tiles/request/render/StringRenderer.java       |   2 -
 .../servlet/NotAServletEnvironmentException.java   |   2 -
 .../request/servlet/ServletApplicationContext.java |   2 -
 .../tiles/request/servlet/ServletRequest.java      |   2 -
 .../apache/tiles/request/servlet/ServletUtil.java  |   2 -
 .../extractor/ApplicationScopeExtractor.java       |   2 -
 .../request/servlet/extractor/HeaderExtractor.java |   2 -
 .../servlet/extractor/InitParameterExtractor.java  |   2 -
 .../servlet/extractor/ParameterExtractor.java      |   2 -
 .../servlet/extractor/RequestScopeExtractor.java   |   2 -
 .../servlet/extractor/SessionScopeExtractor.java   |   2 -
 .../tiles/template/AddListAttributeModel.java      |   2 -
 .../apache/tiles/template/AttributeResolver.java   |   2 -
 .../apache/tiles/template/ComposeStackUtil.java    |   2 -
 .../tiles/template/DefaultAttributeResolver.java   |   2 -
 .../org/apache/tiles/template/DefinitionModel.java |   2 -
 .../apache/tiles/template/GetAsStringModel.java    |   2 -
 .../tiles/template/ImportAttributeModel.java       |   2 -
 .../tiles/template/InsertAttributeModel.java       |   2 -
 .../tiles/template/InsertDefinitionModel.java      |   2 -
 .../apache/tiles/template/InsertTemplateModel.java |   2 -
 .../tiles/template/NoSuchAttributeException.java   |   2 -
 .../apache/tiles/template/PutAttributeModel.java   |   2 -
 .../tiles/template/PutListAttributeModel.java      |   2 -
 .../tiles/template/SetCurrentContainerModel.java   |   2 -
 .../tiles/web/jsp/taglib/UseAttributeTag.java      |   2 -
 .../apache/tiles/web/jsp/taglib/package-info.java  |   2 -
 .../tiles/web/startup/AbstractTilesListener.java   |   2 -
 .../tiles/web/util/AttributeContextMutator.java    |   2 -
 .../tiles/web/util/TilesDispatchServlet.java       |   2 -
 .../java/org/apache/tiles/api/AttributeTest.java   |   2 -
 .../tiles/api/BasicAttributeContextTest.java       |   2 -
 .../java/org/apache/tiles/api/ExpressionTest.java  |   2 -
 .../org/apache/tiles/api/ListAttributeTest.java    |   2 -
 .../tiles/api/NoSuchContainerExceptionTest.java    |   2 -
 .../java/org/apache/tiles/api/TestDefinition.java  |   2 -
 .../tiles/api/TilesContainerWrapperTest.java       |   2 -
 .../org/apache/tiles/api/TilesExceptionTest.java   |   2 -
 .../tiles/api/preparer/PreparerExceptionTest.java  |   2 -
 .../DefinitionsFactoryExceptionTest.java}          |  32 +-
 .../core/definition/MockDefinitionsReader.java}    |  26 +-
 .../definition/NoSuchDefinitionExceptionTest.java} |  15 +-
 .../UnresolvingLocaleDefinitionsFactoryTest.java   |  63 ++
 .../dao/BaseLocaleUrlDefinitionDAOTest.java        | 156 ++++
 .../dao/CachingLocaleUrlDefinitionDAOTest.java     | 371 +++++++++
 .../dao/ResolvingLocaleUrlDefinitionDAOTest.java   | 391 ++++++++++
 .../DigesterDefinitionsReaderExceptionTest.java}   |  16 +-
 .../digester/TestDigesterDefinitionsReader.java    | 279 +++++++
 .../AbstractPatternDefinitionResolverTest.java     | 119 +++
 .../BasicPatternDefinitionResolverTest.java        |  78 ++
 .../core/definition/pattern/PatternUtilTest.java   | 316 ++++++++
 .../PrefixedPatternDefinitionResolverTest.java     |  77 ++
 ...RegexpDefinitionPatternMatcherFactoryTest.java} |  29 +-
 .../regexp/RegexpDefinitionPatternMatcherTest.java |  47 ++
 ...ildcardDefinitionPatternMatcherFactoryTest.java |  61 ++
 .../WildcardDefinitionPatternMatcherTest.java      |  53 ++
 .../BasicAttributeEvaluatorFactoryTest.java        |  85 +++
 .../evaluator/EvaluatorExceptionTest.java}         |  37 +-
 .../impl/DirectAttributeEvaluatorTest.java         |  84 +++
 .../core/factory/BasicPreparerFactoryTest.java     |  72 ++
 .../factory/BasicTilesContainerFactoryTest.java    | 252 +++++++
 .../factory/NoSuchPreparerExceptionTest.java}      |  16 +-
 .../TilesContainerFactoryExceptionTest.java}       |  19 +-
 .../tiles/core/impl/BasicTilesContainerTest.java   | 126 ++++
 .../core/impl/BasicTilesContainerUnitTest.java     | 836 +++++++++++++++++++++
 .../impl/CannotRenderExceptionTest.java}           |  38 +-
 .../tiles/core/impl/DefaultLocaleResolverTest.java |  58 ++
 .../impl/InvalidTemplateExceptionTest.java}        |  37 +-
 .../core/impl/mgmt/CachingTilesContainerTest.java  | 305 ++++++++
 .../core/renderer/DefinitionRendererTest.java      | 106 +++
 .../core/startup/AbstractTilesInitializerTest.java | 130 ++++
 .../tiles/core/util/CombinedBeanInfoTest.java      |  93 +++
 .../apache/tiles/core/config/defs-tiles-513.xml    |  48 ++
 .../org/apache/tiles/core/config/defs-wildcard.xml |  62 ++
 .../org/apache/tiles/core/config/defs1.xml         |  75 ++
 .../org/apache/tiles/core/config/defs1_en_US.xml   |  45 ++
 .../org/apache/tiles/core/config/defs1_fr.xml      |  58 ++
 .../org/apache/tiles/core/config/defs1_fr_CA.xml   |  45 ++
 .../org/apache/tiles/core/config/defs2.xml         |  44 ++
 .../org/apache/tiles/core/config/defs3.xml         |  44 ++
 .../core/config/defs_regression_TILES-352.xml}     |  40 +-
 .../org/apache/tiles/core/config/invalid-defs.xml  |  44 ++
 .../apache/tiles/core/config/malformed-defs.xml    |  42 ++
 .../org/apache/tiles/core/config/temp-defs.xml     |  45 ++
 .../apache/tiles/core/config/tiles-defs-2.1.xml    |  88 +++
 .../tiles/core/config/tiles-defs-2.1_it.xml}       |  33 +-
 .../org/apache/tiles/core/config/tiles-defs.xml    | 143 ++++
 .../tiles/core/factory/test-defs-key-one.xml}      |  35 +-
 .../tiles/core/factory/test-defs-key-two.xml}      |  35 +-
 .../org/apache/tiles/core/factory/test-defs.xml}   |  35 +-
 pom.xml                                            |   6 +
 268 files changed, 5151 insertions(+), 679 deletions(-)

diff --git a/bom/pom.xml b/bom/pom.xml
index f1db01489..40b3934a2 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -24,8 +24,8 @@
 
     <parent>
         <groupId>org.apache.struts</groupId>
-        <artifactId>struts-master</artifactId>
-        <version>14</version>
+        <artifactId>struts2-parent</artifactId>
+        <version>6.1.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>struts2-bom</artifactId>
diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 1ee16c1f6..c92bd571c 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -51,6 +51,11 @@
             <artifactId>easymock</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-jcl</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <properties>
     	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
index 5a2df3e32..c49f07a96 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
index 23e4fc124..24c4fa5fa 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
index 0c13933b8..8fdc5b8aa 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
index 85f1d9220..3cd217b1c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
index d96a9f154..6efe6ce1b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
index d618b66ec..3daeff4f5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java b/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
index 858db324d..6d6d19307 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java
index 20199772d..00afe9dac 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java
index 28687c194..e8707e34f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java
index 77088c3d5..520c24419 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java b/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java
index cdfaa753e..81cf48864 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java
index 6e8765cc2..5348f239c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
index 14bd08308..94527a45b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
index 3e3f1ede7..1054f338a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java
index 4d5c818d7..f95e39d77 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
index 81178eedd..feedca8c8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
index 6f9c99b8c..1c6373f7f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java
index 261b48ebd..2b68de79d 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java
index 1e8324a66..8d7b72483 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
index 6a66fb3a3..76a19b6b4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java
index 7f2e35629..76efc98f1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
index f869c9526..f130fa9d1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
index d5703c54e..2390c2119 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
index 360e019ee..ab4e8dc58 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
index 25361c866..ff96b9eda 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java
index a1130d2aa..7eddcd1f5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
index 150d66294..a7165a981 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java
index cc7468e3f..3d07b20bb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
index 3369f6aa0..39d61a52b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
index 460dcd78b..aa78661bd 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java
index bcd5569d9..d5f62d8d2 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
index 4fac31f71..ca69310f4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
index d5766fc7d..45aa73840 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java
index 84c44f949..b280fc97b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -223,8 +221,7 @@ public class CachingLocaleUrlDefinitionDAO extends BaseLocaleUrlDefinitionDAO im
      * @return The loaded definitions.
      * @since 2.1.3
      */
-    protected Map<String, Definition> loadRawDefinitionsFromResources(
-        Locale customizationKey) {
+    protected Map<String, Definition> loadRawDefinitionsFromResources(Locale customizationKey) {
         Map<String, Definition> localeDefsMap;
 
         Locale parentLocale = LocaleUtil.getParentLocale(customizationKey);
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
index e42772fe6..45358a25a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java
index df7eef304..d6af2f87b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java
index 225d581ba..93cee8617 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
index 9fd3700f0..b751c5607 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
index cd9c1c6c5..0aeb324bc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java
index f76e46d68..49764f7cc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java
index 2e570e061..1dc51fc77 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java
index dae01776f..a960ec9bf 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java
index a2d5fbed7..541805c23 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
index 59461af25..8e913bca1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
index 454dada62..d58858a50 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
index 07c78157d..0e3d397a3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java
index 790a64e8c..e91945973 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java
index 3ae899f9e..0f3b23e66 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java
index d7894b922..6d3dc39bc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
index f50f4498b..42095e43f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java
index 13c53ec83..d23eb0cad 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java
index b575c2a27..f060d69a5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
index 3cbffaf99..77ae96c16 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java
index 15389afdb..dd679897a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java
index fe2d54349..265047159 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java
index 0804a9d21..34c1c793c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java
index dfbb05225..2b7f1231e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java
index 702ba5a6d..b035a0bbc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java
index 93feb168a..487c306c4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java
index efac52ed4..56725d065 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java
index 9e472c555..f7dee1eec 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java
index e6f8a47b4..7f87dc38d 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java
index 7f5cb9c80..f5073706f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java
index 35157812d..7900872ac 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java
index 40bc521ec..c8b19297c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java
index da5b4bc26..2285788b6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java
index fc5ca1f17..c64a30931 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java
index 311172e28..7a424d31c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java
index 24d927788..8f1bdd4e5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java
index c305b60c7..a9848e865 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java
index 400c3bc44..922d01613 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java
index 51c46b215..7b95722ff 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java
index 40e64c906..0a18c7333 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java
index ad44a742f..e63fbe3fb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java
index 638599c00..7b89ff86e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java
index e377fa8d6..de73dc17e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java
index b592978a0..57d63b597 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/package-info.java
index 93b2f96fb..d8bb3d6bc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/package-info.java
index aeed07e6b..0470b39df 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/BasicPreparerFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/BasicPreparerFactory.java
index 75c5fc8e6..b28151da2 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/BasicPreparerFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/BasicPreparerFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/NoSuchPreparerException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/NoSuchPreparerException.java
index 1430264ee..1d4b50282 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/NoSuchPreparerException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/NoSuchPreparerException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/PreparerFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/PreparerFactory.java
index 9e80c572b..073ab3fb6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/PreparerFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/PreparerFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/package-info.java
index f249ccdff..c228befe8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/prepare/factory/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/DefinitionRenderer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/DefinitionRenderer.java
index 976bf87da..9becc6e43 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/DefinitionRenderer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/DefinitionRenderer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/package-info.java
index 2485d3c31..089580e86 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/renderer/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/startup/AbstractTilesInitializer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/startup/AbstractTilesInitializer.java
index a74d4bb30..012665bf0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/startup/AbstractTilesInitializer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/startup/AbstractTilesInitializer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/startup/TilesInitializer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/startup/TilesInitializer.java
index 55d0292b3..d9bfc0f6e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/startup/TilesInitializer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/startup/TilesInitializer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/startup/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/startup/package-info.java
index 3410efe1d..3c06d86e3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/startup/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/startup/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/util/CombinedBeanInfo.java b/plugins/tiles/src/main/java/org/apache/tiles/core/util/CombinedBeanInfo.java
index 9854897a4..425a3d7bf 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/util/CombinedBeanInfo.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/util/CombinedBeanInfo.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/util/WildcardHelper.java b/plugins/tiles/src/main/java/org/apache/tiles/core/util/WildcardHelper.java
index 09c176144..35f54a064 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/util/WildcardHelper.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/util/WildcardHelper.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/util/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/core/util/package-info.java
index c6e6a4c68..9d03dc0e5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/util/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/util/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/ELAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/el/ELAttributeEvaluator.java
index 14f2e3e54..cfa68da8a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/ELAttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/ELAttributeEvaluator.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/ELContextImpl.java b/plugins/tiles/src/main/java/org/apache/tiles/el/ELContextImpl.java
index 7b62dd48a..8e162ae40 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/ELContextImpl.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/ELContextImpl.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/ExpressionFactoryFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/el/ExpressionFactoryFactory.java
index 99a99f81a..f19a9e0e8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/ExpressionFactoryFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/ExpressionFactoryFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/JspExpressionFactoryFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/el/JspExpressionFactoryFactory.java
index 3b822cef1..5b9bd108b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/JspExpressionFactoryFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/JspExpressionFactoryFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/ScopeELResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/el/ScopeELResolver.java
index bd304f1fc..8086e113a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/ScopeELResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/ScopeELResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/TilesContextBeanELResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/el/TilesContextBeanELResolver.java
index d69432fe9..117b4e614 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/TilesContextBeanELResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/TilesContextBeanELResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/el/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/el/package-info.java
index 01731df4c..f1886e81f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/el/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/el/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/package-info.java
index c64cec92f..7f77267d6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java
index 2f3d6d6cf..aca95ce5f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/AnyScopePropertyAccessor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java
index c23d2fd93..637823a9b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/DelegatePropertyAccessor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java
index 323f53169..dbafb66c7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectDelegatePropertyAccessor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectExtractor.java
index c11d19968..ba994d31b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/NestedObjectExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/OGNLAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/OGNLAttributeEvaluator.java
index 6f10d7f61..cac54fdcb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/OGNLAttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/OGNLAttributeEvaluator.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java
index 741e3f3ba..b781b402a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/PropertyAccessorDelegateFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java
index ea4841b23..bb45085b6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/ScopePropertyAccessor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractor.java
index 41ac16bae..60f4321af 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesApplicationContextNestedObjectExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactory.java
index 4c3431e86..5106f656a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/TilesContextPropertyAccessorDelegateFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/ognl/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/ognl/package-info.java
index 116082cdd..69d74a282 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/ognl/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/ognl/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractClientRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractClientRequest.java
index b013c11d1..459c54c1b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractClientRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractClientRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractRequest.java
index cbc7454ad..7fd52d9c6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractViewRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractViewRequest.java
index ae118f929..9cd74cd74 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractViewRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/AbstractViewRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationAccess.java b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationAccess.java
index 726b19ef3..35a1d29ed 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationAccess.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationAccess.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContext.java b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContext.java
index 67300e108..d45d90720 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContext.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContextAware.java b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContextAware.java
index 9eff28c21..5775c72e9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContextAware.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationContextAware.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationResource.java b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationResource.java
index d2adddfa6..cf868e888 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationResource.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/ApplicationResource.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequest.java
index 52b9bba20..30d208ca0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequestWrapper.java b/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequestWrapper.java
index 460500504..cc2ca6a1e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequestWrapper.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/DispatchRequestWrapper.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/NotAvailableFeatureException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/NotAvailableFeatureException.java
index 3c78faf9c..ded24acd9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/NotAvailableFeatureException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/NotAvailableFeatureException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/Request.java b/plugins/tiles/src/main/java/org/apache/tiles/request/Request.java
index acfd2158f..9a1709f15 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/Request.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/Request.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java
index ddabff9ed..192dff6b7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/RequestException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/RequestWrapper.java b/plugins/tiles/src/main/java/org/apache/tiles/request/RequestWrapper.java
index 2477e0eb7..a9826d369 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/RequestWrapper.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/RequestWrapper.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/Addable.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/Addable.java
index e827b21a2..0a6178a56 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/Addable.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/Addable.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/AttributeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/AttributeExtractor.java
index be61940f0..b855123f7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/AttributeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/AttributeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/EnumeratedValuesExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/EnumeratedValuesExtractor.java
index 0a252cb88..13240b044 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/EnumeratedValuesExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/EnumeratedValuesExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasAddableKeys.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasAddableKeys.java
index d8e399a42..1bff1f2c5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasAddableKeys.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasAddableKeys.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasKeys.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasKeys.java
index 9f88ee1bd..692cf61cb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasKeys.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasKeys.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasRemovableKeys.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasRemovableKeys.java
index 30b368d10..4cb31e317 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasRemovableKeys.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/HasRemovableKeys.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/package-info.java
index 0eebcc13a..054b0e4f9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/attribute/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/CollectionUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/CollectionUtil.java
index 54fa91aa1..54cc254a6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/CollectionUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/CollectionUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java
index 53f6e14d5..6c91895ad 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java
index 62ecfedb1..e89d60bdc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntry.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntry.java
index 38b930cb0..58e590816 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntry.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntry.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntryArrayValues.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntryArrayValues.java
index 21aeb131b..c9aff7fd3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntryArrayValues.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/MapEntryArrayValues.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
index 3ab475eae..85c17b656 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/RemovableKeySet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/RemovableKeySet.java
index feaefa568..1ce23f66b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/RemovableKeySet.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/RemovableKeySet.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ScopeMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ScopeMap.java
index de1d99a6b..a03ec1f3b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ScopeMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ScopeMap.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/package-info.java
index cfd47eb8e..e236964a8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/EnvironmentScopeMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/EnvironmentScopeMap.java
index 540a9d562..e55c38582 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/EnvironmentScopeMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/EnvironmentScopeMap.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequest.java
index d23b72608..cd82fccb0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestException.java
index 9b11d8591..a03ae300e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestUtil.java
index 366dd24b7..6c43f231e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/FreemarkerRequestUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java
index e35a3294d..13c5dd0f8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/NotAvailableFreemarkerServletException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java
index 467d0c0d4..dfd95cd06 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagRuntime.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagRuntime.java
index a0188ea8e..9fe1a7de6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagRuntime.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerAutotagRuntime.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerModelBody.java
index 78ecb1305..85f52b7e3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerModelBody.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerUtil.java
index 6eb862f53..37362edc3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/FreemarkerUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/package-info.java
index fb875dca7..af78d7b2d 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/autotag/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/extractor/EnvironmentScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/extractor/EnvironmentScopeExtractor.java
index 2ea117035..e7ce577d6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/extractor/EnvironmentScopeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/extractor/EnvironmentScopeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java
index 47cd991c4..8162c815d 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/render/AttributeValueFreemarkerServlet.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableFactory.java
index 788b0fbc7..18642640d 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java
index 340d5ed54..8cec74b1f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/SharedVariableLoaderFreemarkerServlet.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java
index b66e625d7..ce5629fa7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/freemarker/servlet/WebappClassTemplateLoader.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java
index 2a8778336..81c6e579f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspPrintWriterAdapter.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspRequest.java
index f338235de..7e94e331e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspUtil.java
index e282d6053..0a79145a0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/JspUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspAutotagRuntime.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspAutotagRuntime.java
index 9c2922fb3..ac15efa7e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspAutotagRuntime.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspAutotagRuntime.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspModelBody.java
index 683eff38e..ad9721575 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/JspModelBody.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/package-info.java
index 08adc1ba4..ce77fc427 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/autotag/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/ScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/ScopeExtractor.java
index ab90f3488..e3485226a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/ScopeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/ScopeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/SessionScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/SessionScopeExtractor.java
index 22099903c..73eec8df1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/SessionScopeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/jsp/extractor/SessionScopeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/LocaleUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/LocaleUtil.java
index 2b5fd4d53..0b3650480 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/LocaleUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/LocaleUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
index 4f854b5e3..85c44745b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/PostfixedApplicationResource.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
index f648945bf..8f867b7fb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java
index 067c73149..953ae68c4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/CannotInstantiateObjectException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/ClassUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/ClassUtil.java
index 60d9b6ca9..8211b3ac6 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/ClassUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/ClassUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/package-info.java
index 299c145d3..c7b0d3cdc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/reflect/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/BasicRendererFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/BasicRendererFactory.java
index 899e2d7b9..eb6b00fdf 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/BasicRendererFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/BasicRendererFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/CannotRenderException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/CannotRenderException.java
index 6c246ebf2..d2c5e39f8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/CannotRenderException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/CannotRenderException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/ChainedDelegateRenderer.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/ChainedDelegateRenderer.java
index 71abc2c59..ff0bdc136 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/ChainedDelegateRenderer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/ChainedDelegateRenderer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java
index 49a661eed..fa5b78749 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/DispatchRenderer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/NoSuchRendererException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/NoSuchRendererException.java
index 2f59a9ead..f3a71983f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/NoSuchRendererException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/NoSuchRendererException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/RenderException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/RenderException.java
index e159bfa8a..f99ee6024 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/RenderException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/RenderException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/Renderer.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/Renderer.java
index 8349507ba..076837240 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/Renderer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/Renderer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/RendererFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/RendererFactory.java
index 4b4bec1a5..7119d6455 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/RendererFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/RendererFactory.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/render/StringRenderer.java b/plugins/tiles/src/main/java/org/apache/tiles/request/render/StringRenderer.java
index 1b10e380e..309546a2f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/render/StringRenderer.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/render/StringRenderer.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/NotAServletEnvironmentException.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/NotAServletEnvironmentException.java
index a9830c5d3..ce4bf5471 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/NotAServletEnvironmentException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/NotAServletEnvironmentException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletApplicationContext.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletApplicationContext.java
index 540dec593..27f2b0e63 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletApplicationContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletApplicationContext.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletRequest.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletRequest.java
index 0a62722cd..a21a025d4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletRequest.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletRequest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletUtil.java
index 71c6fee29..0646774b0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/ServletUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ApplicationScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ApplicationScopeExtractor.java
index 178cbcdde..52af00a9c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ApplicationScopeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ApplicationScopeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/HeaderExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/HeaderExtractor.java
index 56cb68686..e7c366238 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/HeaderExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/HeaderExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/InitParameterExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/InitParameterExtractor.java
index bfaedd43f..6c67aaed9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/InitParameterExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/InitParameterExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ParameterExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ParameterExtractor.java
index 4e1e69c8b..6925d253f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ParameterExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/ParameterExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/RequestScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/RequestScopeExtractor.java
index dbac85608..8bb3682e8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/RequestScopeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/RequestScopeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/SessionScopeExtractor.java b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/SessionScopeExtractor.java
index 008dcb671..3753d9f2b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/SessionScopeExtractor.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/servlet/extractor/SessionScopeExtractor.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/AddListAttributeModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/AddListAttributeModel.java
index fac35511c..09e7433c1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/AddListAttributeModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/AddListAttributeModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/AttributeResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/template/AttributeResolver.java
index 82f3dd9de..786e258f8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/AttributeResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/AttributeResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/ComposeStackUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/template/ComposeStackUtil.java
index b425ac629..0b255e58e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/ComposeStackUtil.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/ComposeStackUtil.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/DefaultAttributeResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/template/DefaultAttributeResolver.java
index b3464ef4f..c1ee10ae1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/DefaultAttributeResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/DefaultAttributeResolver.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/DefinitionModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/DefinitionModel.java
index 760c33947..7302d2ea1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/DefinitionModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/DefinitionModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java
index c292aece9..b2d7db437 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/ImportAttributeModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/ImportAttributeModel.java
index 05f3a2f3b..ecf07bf7e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/ImportAttributeModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/ImportAttributeModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java
index a84ed4221..2ee9bb396 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertAttributeModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java
index 113977891..cff71b65f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertDefinitionModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertTemplateModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertTemplateModel.java
index bf80c73c5..0856e24d8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/InsertTemplateModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/InsertTemplateModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java b/plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java
index aaab7652c..5de6b0f18 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/PutAttributeModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/PutAttributeModel.java
index c83ff1d13..9391f14bf 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/PutAttributeModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/PutAttributeModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/PutListAttributeModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/PutListAttributeModel.java
index c61e0213f..30e858802 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/PutListAttributeModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/PutListAttributeModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/SetCurrentContainerModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/SetCurrentContainerModel.java
index 90412570e..80b7174ed 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/SetCurrentContainerModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/SetCurrentContainerModel.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java
index 21e17f2f6..0262029d8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java
index f20836b6e..c40a0a955 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/startup/AbstractTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/web/startup/AbstractTilesListener.java
index f6f363d0e..465431b06 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/startup/AbstractTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/startup/AbstractTilesListener.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/util/AttributeContextMutator.java b/plugins/tiles/src/main/java/org/apache/tiles/web/util/AttributeContextMutator.java
index b73e94bad..aa99ca099 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/util/AttributeContextMutator.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/util/AttributeContextMutator.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/util/TilesDispatchServlet.java b/plugins/tiles/src/main/java/org/apache/tiles/web/util/TilesDispatchServlet.java
index 67142ad40..d456848c8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/util/TilesDispatchServlet.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/util/TilesDispatchServlet.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
index d081e5634..875431c6f 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java
index 23f021491..8b60953b5 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/BasicAttributeContextTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java
index 2aa091fdd..6c2d618b1 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/ExpressionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
index 1bff6eb93..582f041e8 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/ListAttributeTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
index 777ecd57c..7634873b8 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java b/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java
index 2da936a3b..520fd997c 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/TestDefinition.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java
index c7a6f49c0..c4a3bb919 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesContainerWrapperTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
index fc26afeb0..cb6b8012b 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
index 61700f0b2..35cbc3bbb 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/DefinitionsFactoryExceptionTest.java
similarity index 57%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/definition/DefinitionsFactoryExceptionTest.java
index 61700f0b2..c9f4d5bd2 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/preparer/PreparerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/DefinitionsFactoryExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.tiles.api.preparer;
+package org.apache.tiles.core.definition;
 
 import org.junit.Test;
 
@@ -27,48 +25,48 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link PreparerException}.
+ * Tests {@link DefinitionsFactoryException}.
  */
-public class PreparerExceptionTest {
+public class DefinitionsFactoryExceptionTest {
 
     /**
-     * Test method for {@link PreparerException#PreparerException()}.
+     * Test method for {@link DefinitionsFactoryException#DefinitionsFactoryException()}.
      */
     @Test
-    public void testPreparerException() {
-        PreparerException exception = new PreparerException();
+    public void testDefinitionsFactoryException() {
+        DefinitionsFactoryException exception = new DefinitionsFactoryException();
         assertNull(exception.getMessage());
         assertNull(exception.getCause());
     }
 
     /**
-     * Test method for {@link PreparerException#PreparerException(String)}.
+     * Test method for {@link DefinitionsFactoryException#DefinitionsFactoryException(String)}.
      */
     @Test
-    public void testPreparerExceptionString() {
-        PreparerException exception = new PreparerException("my message");
+    public void testDefinitionsFactoryExceptionString() {
+        DefinitionsFactoryException exception = new DefinitionsFactoryException("my message");
         assertEquals("my message", exception.getMessage());
         assertNull(exception.getCause());
     }
 
     /**
-     * Test method for {@link PreparerException#PreparerException(Throwable)}.
+     * Test method for {@link DefinitionsFactoryException#DefinitionsFactoryException(Throwable)}.
      */
     @Test
-    public void testPreparerExceptionThrowable() {
+    public void testDefinitionsFactoryExceptionThrowable() {
         Throwable cause = new Throwable();
-        PreparerException exception = new PreparerException(cause);
+        DefinitionsFactoryException exception = new DefinitionsFactoryException(cause);
         assertEquals(cause.toString(), exception.getMessage());
         assertEquals(cause, exception.getCause());
     }
 
     /**
-     * Test method for {@link PreparerException#PreparerException(String, Throwable)}.
+     * Test method for {@link DefinitionsFactoryException#DefinitionsFactoryException(String, Throwable)}.
      */
     @Test
-    public void testPreparerExceptionStringThrowable() {
+    public void testDefinitionsFactoryExceptionStringThrowable() {
         Throwable cause = new Throwable();
-        PreparerException exception = new PreparerException("my message", cause);
+        DefinitionsFactoryException exception = new DefinitionsFactoryException("my message", cause);
         assertEquals("my message", exception.getMessage());
         assertEquals(cause, exception.getCause());
     }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/MockDefinitionsReader.java
similarity index 59%
copy from plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/definition/MockDefinitionsReader.java
index 3369f6aa0..865e2230f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/MockDefinitionsReader.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -18,37 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.tiles.core.definition;
 
 import org.apache.tiles.api.Definition;
 
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 /**
- * Interface for reading <code>{@link Definition}</code> from a source.
- * <p/>
- * <p>This interface provides a standard way to read
- * <code>{@link Definition}</code> objects from a source.  Implementations
- * should define what the source is, whether it be a persistent store such as a
- * configuration file or database, or something like a web service.  The
- * DefinitionsReader is responsible for reading from a single location.  It does
- * not perform any internationalization duties or inheritance of Definitions.
- * It only reads from the source and returns a Map of objects read.</p>
+ * Mock Definitions Reader implementation.  Stubs out all functionality.
  */
-public interface DefinitionsReader {
+public class MockDefinitionsReader implements DefinitionsReader {
 
     /**
      * Reads <code>{@link Definition}</code> objects from a source.
-     * <p/>
      * Implementations should publish what type of source object is expected.
      *
      * @param source The source from which definitions will be read.
      * @return a Map of <code>Definition</code> objects read from
      * the source.
-     * @throws DefinitionsFactoryException if the source is invalid or
-     *                                     an error occurs when reading definitions.
+     * @throws org.apache.tiles.core.definition.DefinitionsFactoryException if the source is invalid or
+     *                                                                      an error occurs when reading definitions.
      */
-    Map<String, Definition> read(Object source);
-
+    public Map<String, Definition> read(Object source) {
+        return new LinkedHashMap<>();
+    }
 }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/NoSuchDefinitionExceptionTest.java
similarity index 73%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/definition/NoSuchDefinitionExceptionTest.java
index 777ecd57c..9e2c2faab 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/NoSuchDefinitionExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.tiles.api;
+package org.apache.tiles.core.definition;
 
 import org.junit.Test;
 
@@ -27,13 +25,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link NoSuchContainerException}.
+ * Tests {@link NoSuchDefinitionException}.
  */
-public class NoSuchContainerExceptionTest {
+public class NoSuchDefinitionExceptionTest {
 
+    /**
+     * Test method for {@link NoSuchDefinitionException#NoSuchDefinitionException(String)}.
+     */
     @Test
-    public void testNoSuchContainerExceptionString() {
-        NoSuchContainerException exception = new NoSuchContainerException("my message");
+    public void testNoSuchDefinitionExceptionString() {
+        NoSuchDefinitionException exception = new NoSuchDefinitionException("my message");
         assertEquals("my message", exception.getMessage());
         assertNull(exception.getCause());
     }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactoryTest.java
new file mode 100644
index 000000000..1d136589f
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactoryTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.dao.DefinitionDAO;
+import org.apache.tiles.core.locale.LocaleResolver;
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import java.util.Locale;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link UnresolvingLocaleDefinitionsFactory}.
+ */
+public class UnresolvingLocaleDefinitionsFactoryTest {
+
+    /**
+     * Test method for {@link UnresolvingLocaleDefinitionsFactory#getDefinition(String, Request)}.
+     */
+    @Test
+    public void testGetDefinition() {
+        DefinitionDAO<Locale> dao = createMock(DefinitionDAO.class);
+        LocaleResolver localeResolver = createMock(LocaleResolver.class);
+        UnresolvingLocaleDefinitionsFactory factory = new UnresolvingLocaleDefinitionsFactory();
+        Request request = createMock(Request.class);
+        Definition definition = createMock(Definition.class);
+        Locale locale = Locale.ITALY;
+
+        expect(localeResolver.resolveLocale(request)).andReturn(locale);
+        expect(dao.getDefinition("myDefinition", locale)).andReturn(definition);
+
+        replay(dao, localeResolver, request, definition);
+        factory.setDefinitionDAO(dao);
+        factory.setLocaleResolver(localeResolver);
+        assertEquals(definition, factory.getDefinition("myDefinition", request));
+        verify(dao, localeResolver, request, definition);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAOTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAOTest.java
new file mode 100644
index 000000000..77dc4fba9
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAOTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.definition.dao;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.apache.tiles.core.definition.RefreshMonitor;
+import org.apache.tiles.core.definition.digester.DigesterDefinitionsReader;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.locale.PostfixedApplicationResource;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link BaseLocaleUrlDefinitionDAO}.
+ */
+public class BaseLocaleUrlDefinitionDAOTest {
+
+    private static final class MutableApplicationResource extends PostfixedApplicationResource {
+        private long lastModified = System.currentTimeMillis();
+        private String xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
+            + "<!DOCTYPE tiles-definitions PUBLIC "
+            + "\"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN\" "
+            + "\"http://tiles.apache.org/dtds/tiles-config_3_0.dtd\">\n\n" + "<tiles-definitions>"
+            + "<definition name=\"rewrite.test\" template=\"/test.jsp\">"
+            + "<put-attribute name=\"testparm\" value=\"testval\"/>" + "</definition>" //
+            + "</tiles-definitions>";
+
+        private MutableApplicationResource(String localePath) {
+            super(localePath);
+        }
+
+        public void modify(String xml) {
+            lastModified = System.currentTimeMillis();
+            this.xml = xml;
+        }
+
+        @Override
+        public long getLastModified() {
+            return lastModified;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return new ByteArrayInputStream(xml.getBytes(StandardCharsets.ISO_8859_1));
+        }
+    }
+
+    /**
+     * The time (in milliseconds) to wait to be sure that the system updates the
+     * modify date of a file.
+     */
+    private static final int SLEEP_MILLIS = 2000;
+
+    private BaseLocaleUrlDefinitionDAO dao;
+    private MutableApplicationResource resource;
+
+    @Before
+    public void setUp() throws IOException {
+        resource = new MutableApplicationResource("org/apache/tiles/core/config/temp-defs.xml");
+
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(applicationContext.getResource("org/apache/tiles/core/config/temp-defs.xml")).andReturn(resource).anyTimes();
+        replay(applicationContext);
+        dao = createMockBuilder(BaseLocaleUrlDefinitionDAO.class).withConstructor(applicationContext).createMock();
+    }
+
+    /**
+     * Test method for {@link org.apache.tiles.core.definition.dao.BaseLocaleUrlDefinitionDAO#refreshRequired()}.
+     *
+     * @throws InterruptedException If something goes wrong.
+     */
+    @Test
+    public void testRefreshRequired() throws InterruptedException {
+        // Set up multiple data sources.
+        Map<String, Attribute> attribs = new HashMap<>();
+        attribs.put("testparm", new Attribute("testval"));
+        Definition rewriteTest = new Definition("rewrite.test", Attribute.createTemplateAttribute("/test.jsp"), attribs);
+        expect(dao.getDefinition("rewrite.test", null)).andReturn(rewriteTest);
+
+        replay(dao);
+
+        List<ApplicationResource> sources = new ArrayList<>();
+        sources.add(resource);
+        dao.setSources(sources);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        dao.setReader(reader);
+
+        Request context = createMock(Request.class);
+        expect(context.getContext("session")).andReturn(new HashMap<>()).anyTimes();
+        expect(context.getRequestLocale()).andReturn(null).anyTimes();
+        replay(context);
+
+        Definition definition = dao.getDefinition("rewrite.test", null);
+        assertNotNull("rewrite.test definition not found.", definition);
+        assertEquals("Incorrect initial template value", "/test.jsp", definition.getTemplateAttribute().getValue());
+
+        RefreshMonitor reloadable = dao;
+        dao.loadDefinitionsFromResource(resource);
+        assertFalse("Factory should be fresh.", reloadable.refreshRequired());
+
+        // Make sure the system actually updates the timestamp.
+        Thread.sleep(SLEEP_MILLIS);
+
+        // Set up multiple data sources.
+        resource.modify("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n" + "<!DOCTYPE tiles-definitions PUBLIC "
+            + "\"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN\" "
+            + "\"http://tiles.apache.org/dtds/tiles-config_3_0.dtd\">\n\n" + "<tiles-definitions>"
+            + "<definition name=\"rewrite.test\" template=\"/newtest.jsp\">"
+            + "<put-attribute name=\"testparm\" value=\"testval\"/>" + "</definition>" //
+            + "</tiles-definitions>");
+
+        assertTrue("Factory should be stale.", reloadable.refreshRequired());
+
+        verify(context, dao);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAOTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAOTest.java
new file mode 100644
index 000000000..048577321
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAOTest.java
@@ -0,0 +1,371 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.dao;
+
+import junit.framework.TestCase;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.apache.tiles.core.definition.MockDefinitionsReader;
+import org.apache.tiles.core.definition.digester.DigesterDefinitionsReader;
+import org.apache.tiles.core.definition.pattern.BasicPatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.locale.URLApplicationResource;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link CachingLocaleUrlDefinitionDAO}.
+ *
+ * @version $Rev$ $Date$
+ */
+public class CachingLocaleUrlDefinitionDAOTest extends TestCase {
+
+    /**
+     * The object to test.
+     */
+    private CachingLocaleUrlDefinitionDAO definitionDao;
+
+    private ApplicationContext applicationContext;
+
+    private ApplicationResource url1;
+
+    private ApplicationResource url2;
+
+    private ApplicationResource url3;
+
+    private ApplicationResource urlWildcard;
+
+    private ApplicationResource url21;
+
+    private ApplicationResource setupUrl(String filename, Locale... locales) {
+        ApplicationResource url = new URLApplicationResource(
+            "org/apache/tiles/core/config/" + filename + ".xml",
+            Objects.requireNonNull(this.getClass().getClassLoader().getResource("org/apache/tiles/core/config/" + filename + ".xml"))
+        );
+        assertNotNull("Could not load " + filename + " file.", url);
+        expect(applicationContext.getResource(url.getLocalePath())).andReturn(url).anyTimes();
+        expect(applicationContext.getResource(url, Locale.ROOT)).andReturn(url).anyTimes();
+        Map<Locale, ApplicationResource> localeResources = new HashMap<Locale, ApplicationResource>();
+        for (Locale locale : locales) {
+            ApplicationResource urlLocale = new URLApplicationResource(
+                "org/apache/tiles/core/config/" + filename + "_" + locale.toString() + ".xml",
+                Objects.requireNonNull(this.getClass().getClassLoader().getResource("org/apache/tiles/core/config/" + filename + "_" + locale + ".xml"))
+            );
+            assertNotNull("Could not load " + filename + "_" + locale + " file.", urlLocale);
+            localeResources.put(locale, urlLocale);
+        }
+        for (Locale locale : new Locale[]{Locale.CANADA_FRENCH, Locale.FRENCH, Locale.US, Locale.ENGLISH,
+            Locale.CHINA, Locale.CHINESE, Locale.ITALY, Locale.ITALIAN}) {
+            ApplicationResource urlLocale = localeResources.get(locale);
+            expect(applicationContext.getResource(url, locale)).andReturn(urlLocale).anyTimes();
+        }
+        return url;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        applicationContext = createMock(ApplicationContext.class);
+        url1 = setupUrl("defs1", Locale.FRENCH, Locale.CANADA_FRENCH, Locale.US);
+        url2 = setupUrl("defs2");
+        url3 = setupUrl("defs3");
+        urlWildcard = setupUrl("defs-wildcard");
+        url21 = setupUrl("tiles-defs-2.1", Locale.ITALIAN);
+        replay(applicationContext);
+        definitionDao = new CachingLocaleUrlDefinitionDAO(applicationContext);
+        WildcardDefinitionPatternMatcherFactory definitionPatternMatcherFactory =
+            new WildcardDefinitionPatternMatcherFactory();
+        PatternDefinitionResolver<Locale> definitionResolver = new BasicPatternDefinitionResolver<>(
+            definitionPatternMatcherFactory,
+            definitionPatternMatcherFactory);
+        definitionDao.setPatternDefinitionResolver(definitionResolver);
+    }
+
+    public void testGetDefinition() {
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        definitionDao.setReader(reader);
+
+        assertNotNull("test.def1 definition not found.", definitionDao
+            .getDefinition("test.def1", null));
+        assertNotNull("test.def2 definition not found.", definitionDao
+            .getDefinition("test.def2", null));
+        assertNotNull("test.def3 definition not found.", definitionDao
+            .getDefinition("test.def3", null));
+        assertNotNull("test.common definition not found.", definitionDao
+            .getDefinition("test.common", null));
+        assertNotNull("test.common definition in US locale not found.",
+            definitionDao.getDefinition("test.common", Locale.US));
+        assertNotNull("test.common definition in FRENCH locale not found.",
+            definitionDao.getDefinition("test.common", Locale.FRENCH));
+        assertNotNull("test.common definition in CHINA locale not found.",
+            definitionDao.getDefinition("test.common", Locale.CHINA));
+        assertNotNull(
+            "test.common.french definition in FRENCH locale not found.",
+            definitionDao.getDefinition("test.common.french",
+                Locale.FRENCH));
+        assertNotNull(
+            "test.common.french definition in CANADA_FRENCH locale not found.",
+            definitionDao.getDefinition("test.common.french",
+                Locale.CANADA_FRENCH));
+        assertNotNull("test.def.toextend definition not found.", definitionDao
+            .getDefinition("test.def.toextend", null));
+        assertNotNull("test.def.overridden definition not found.",
+            definitionDao.getDefinition("test.def.overridden", null));
+        assertNotNull(
+            "test.def.overridden definition in FRENCH locale not found.",
+            definitionDao.getDefinition("test.def.overridden",
+                Locale.FRENCH));
+
+        assertEquals("Incorrect default country value", "default",
+            definitionDao.getDefinition("test.def1", null).getAttribute(
+                "country").getValue());
+        assertEquals("Incorrect US country value", "US", definitionDao
+            .getDefinition("test.def1", Locale.US).getAttribute("country")
+            .getValue());
+        assertEquals("Incorrect France country value", "France", definitionDao
+            .getDefinition("test.def1", Locale.FRENCH).getAttribute(
+                "country").getValue());
+        assertEquals("Incorrect Chinese country value (should be default)",
+            "default", definitionDao.getDefinition("test.def1",
+                Locale.CHINA).getAttribute("country").getValue());
+        assertEquals("Incorrect default country value", "default",
+            definitionDao.getDefinition("test.def.overridden", null)
+                .getAttribute("country").getValue());
+        assertEquals("Incorrect default title value",
+            "Definition to be overridden", definitionDao.getDefinition(
+                    "test.def.overridden", null).getAttribute("title")
+                .getValue());
+        assertEquals("Incorrect France country value", "France", definitionDao
+            .getDefinition("test.def.overridden", Locale.FRENCH)
+            .getAttribute("country").getValue());
+        assertNull("Definition in French not found", definitionDao
+            .getDefinition("test.def.overridden", Locale.FRENCH)
+            .getAttribute("title"));
+    }
+
+    public void testGetDefinitions() {
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        definitionDao.setReader(reader);
+
+        Map<String, Definition> defaultDefinitions = definitionDao
+            .getDefinitions(null);
+        Map<String, Definition> usDefinitions = definitionDao
+            .getDefinitions(Locale.US);
+        Map<String, Definition> frenchDefinitions = definitionDao
+            .getDefinitions(Locale.FRENCH);
+        Map<String, Definition> chinaDefinitions = definitionDao
+            .getDefinitions(Locale.CHINA);
+        Map<String, Definition> canadaFrenchDefinitions = definitionDao
+            .getDefinitions(Locale.CANADA_FRENCH);
+
+        assertNotNull("test.def1 definition not found.", defaultDefinitions
+            .get("test.def1"));
+        assertNotNull("test.def2 definition not found.", defaultDefinitions
+            .get("test.def2"));
+        assertNotNull("test.def3 definition not found.", defaultDefinitions
+            .get("test.def3"));
+        assertNotNull("test.common definition not found.", defaultDefinitions
+            .get("test.common"));
+        assertNotNull("test.common definition in US locale not found.",
+            usDefinitions.get("test.common"));
+        assertNotNull("test.common definition in FRENCH locale not found.",
+            frenchDefinitions.get("test.common"));
+        assertNotNull("test.common definition in CHINA locale not found.",
+            chinaDefinitions.get("test.common"));
+        assertNotNull(
+            "test.common.french definition in FRENCH locale not found.",
+            frenchDefinitions.get("test.common.french"));
+        assertNotNull(
+            "test.common.french definition in CANADA_FRENCH locale not found.",
+            canadaFrenchDefinitions.get("test.common.french"));
+        assertNotNull("test.def.toextend definition not found.",
+            defaultDefinitions.get("test.def.toextend"));
+        assertNotNull("test.def.overridden definition not found.",
+            defaultDefinitions.get("test.def.overridden"));
+        assertNotNull(
+            "test.def.overridden definition in FRENCH locale not found.",
+            frenchDefinitions.get("test.def.overridden"));
+
+        assertEquals("Incorrect default country value", "default",
+            defaultDefinitions.get("test.def1").getAttribute("country")
+                .getValue());
+        assertEquals("Incorrect US country value", "US", usDefinitions.get(
+            "test.def1").getAttribute("country").getValue());
+        assertEquals("Incorrect France country value", "France",
+            frenchDefinitions.get("test.def1").getAttribute("country")
+                .getValue());
+        assertEquals("Incorrect Chinese country value (should be default)",
+            "default", chinaDefinitions.get("test.def1").getAttribute(
+                "country").getValue());
+        assertEquals("Incorrect default country value", "default",
+            defaultDefinitions.get("test.def.overridden").getAttribute(
+                "country").getValue());
+        assertEquals("Incorrect default title value",
+            "Definition to be overridden", defaultDefinitions.get(
+                "test.def.overridden").getAttribute("title").getValue());
+        assertEquals("Incorrect France country value", "France",
+            frenchDefinitions.get("test.def.overridden").getAttribute(
+                "country").getValue());
+        assertNull("Definition in French not found", frenchDefinitions.get(
+            "test.def.overridden").getAttribute("title"));
+    }
+
+    public void testSetSourceURLs() {
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        assertEquals("The source URLs are not set correctly", sourceURLs,
+            definitionDao.sources);
+    }
+
+    public void testSetReader() {
+        DefinitionsReader reader = createMock(DefinitionsReader.class);
+        definitionDao.setReader(reader);
+        assertEquals("There reader has not been set correctly", reader,
+            definitionDao.reader);
+    }
+
+    public void testInit() {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Set<ApplicationResource> urlSet = new HashSet<>();
+        urlSet.add(url1);
+        expect(applicationContext.getResources("/WEB-INF/tiles.xml"))
+            .andReturn(urlSet);
+        replay(applicationContext);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        definitionDao.setReader(reader);
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        definitionDao.setSources(sourceURLs);
+        assertEquals("The reader is not of the correct class",
+            DigesterDefinitionsReader.class, definitionDao.reader
+                .getClass());
+        assertEquals("The source URLs are not correct", sourceURLs,
+            definitionDao.sources);
+        reset(applicationContext);
+
+        definitionDao.setReader(new MockDefinitionsReader());
+        assertEquals("The reader is not of the correct class",
+            MockDefinitionsReader.class, definitionDao.reader.getClass());
+        sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        assertEquals("The source URLs are not correct", sourceURLs,
+            definitionDao.sources);
+    }
+
+    /**
+     * Tests wildcard mappings.
+     */
+    public void testWildcardMapping() {
+        List<ApplicationResource> urls = new ArrayList<>();
+        urls.add(urlWildcard);
+        definitionDao.setSources(urls);
+        definitionDao.setReader(new DigesterDefinitionsReader());
+
+        Definition definition = definitionDao.getDefinition("test.defName.subLayered", Locale.ITALY);
+        assertEquals("The template is not correct", "/testName.jsp", definition
+            .getTemplateAttribute().getValue());
+        assertEquals("The header attribute is not correct",
+            "/common/headerLayered.jsp", definition.getAttribute("header")
+                .getValue());
+        definition = definitionDao.getDefinition("test.defName.subLayered", Locale.ITALIAN);
+        assertEquals("The template is not correct", "/testName.jsp", definition
+            .getTemplateAttribute().getValue());
+        assertEquals("The header attribute is not correct",
+            "/common/headerLayered.jsp", definition.getAttribute("header")
+                .getValue());
+        definition = definitionDao.getDefinition("test.defName.subLayered", null);
+        assertEquals("The template is not correct", "/testName.jsp", definition
+            .getTemplateAttribute().getValue());
+        assertEquals("The header attribute is not correct",
+            "/common/headerLayered.jsp", definition.getAttribute("header")
+                .getValue());
+        definition = definitionDao.getDefinition("test.defName.noAttribute", null);
+        assertEquals("/testName.jsp", definition.getTemplateAttribute().getValue());
+        assertNull(definition.getLocalAttributeNames());
+        definition = definitionDao.getDefinition("test.def3", null);
+        assertNotNull("The simple definition is null", definition);
+
+        definition = definitionDao.getDefinition("test.extended.defName.subLayered", null);
+        assertEquals("test.defName.subLayered", definition.getExtends());
+        assertNull(definition.getTemplateAttribute().getValue());
+        assertEquals(1, definition.getLocalAttributeNames().size());
+        assertEquals("Overridden Title", definition.getAttribute("title").getValue());
+    }
+
+    /**
+     * Tests
+     * {@link ResolvingLocaleUrlDefinitionDAO#getDefinition(String, Locale)}
+     * when loading multiple files for a locale.
+     */
+    public void testListAttributeLocaleInheritance() {
+        List<ApplicationResource> urls = new ArrayList<>();
+        urls.add(url21);
+        definitionDao.setSources(urls);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        definitionDao.setReader(new DigesterDefinitionsReader());
+        replay(applicationContext);
+
+        Definition definition = definitionDao.getDefinition(
+            "test.inherit.list", Locale.ITALIAN);
+        ListAttribute listAttribute = (ListAttribute) definition
+            .getAttribute("list");
+        List<Attribute> attributes = listAttribute.getValue();
+        // It is right not to resolve inheritance in this DAO.
+        assertEquals(1, attributes.size());
+        verify(applicationContext);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAOTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAOTest.java
new file mode 100644
index 000000000..727617b69
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAOTest.java
@@ -0,0 +1,391 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.dao;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.apache.tiles.core.definition.MockDefinitionsReader;
+import org.apache.tiles.core.definition.NoSuchDefinitionException;
+import org.apache.tiles.core.definition.digester.DigesterDefinitionsReader;
+import org.apache.tiles.core.definition.pattern.BasicPatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.locale.URLApplicationResource;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link ResolvingLocaleUrlDefinitionDAO}.
+ */
+public class ResolvingLocaleUrlDefinitionDAOTest {
+
+    /**
+     * The number of attribute names.
+     */
+    private static final int ATTRIBUTE_NAMES_COUNT = 6;
+
+    /**
+     * The object to test.
+     */
+    private ResolvingLocaleUrlDefinitionDAO definitionDao;
+
+    private ApplicationContext applicationContext;
+
+    private ApplicationResource url1;
+    private ApplicationResource url2;
+    private ApplicationResource url3;
+    private ApplicationResource urlWildcard;
+    private ApplicationResource url21;
+    private ApplicationResource url513;
+
+    private ApplicationResource setupUrl(String filename, Locale... locales) {
+        ApplicationResource url = new URLApplicationResource(
+            "org/apache/tiles/core/config/" + filename + ".xml",
+            Objects.requireNonNull(this.getClass().getClassLoader().getResource("org/apache/tiles/core/config/" + filename + ".xml"))
+        );
+        assertNotNull("Could not load " + filename + " file.", url);
+        expect(applicationContext.getResource(url.getLocalePath())).andReturn(url).anyTimes();
+        expect(applicationContext.getResource(url, Locale.ROOT)).andReturn(url).anyTimes();
+        Map<Locale, ApplicationResource> localeResources = new HashMap<>();
+        for (Locale locale : locales) {
+            ApplicationResource urlLocale = new URLApplicationResource(
+                "org/apache/tiles/core/config/" + filename + "_" + locale + ".xml",
+                Objects.requireNonNull(this.getClass().getClassLoader().getResource("org/apache/tiles/core/config/" + filename + "_" + locale.toString() + ".xml"))
+            );
+            assertNotNull("Could not load " + filename + "_" + locale + " file.", urlLocale);
+            localeResources.put(locale, urlLocale);
+        }
+        Locale[] supportedLocales = {
+            Locale.CANADA_FRENCH,
+            Locale.FRENCH,
+            Locale.US,
+            Locale.ENGLISH,
+            Locale.CHINA,
+            Locale.CHINESE,
+            Locale.ITALY,
+            Locale.ITALIAN,
+            new Locale("es"),
+            new Locale("es", "CO"),
+            new Locale("en", "CA")
+        };
+        for (Locale locale : supportedLocales) {
+            ApplicationResource urlLocale = localeResources.get(locale);
+            expect(applicationContext.getResource(url, locale)).andReturn(urlLocale).anyTimes();
+        }
+        return url;
+    }
+
+    @Before
+    public void setUp() throws IOException {
+        // Set up multiple data sources.
+        applicationContext = createMock(ApplicationContext.class);
+        url1 = setupUrl("defs1", Locale.FRENCH, Locale.CANADA_FRENCH, Locale.US);
+        url2 = setupUrl("defs2");
+        url3 = setupUrl("defs3");
+        urlWildcard = setupUrl("defs-wildcard");
+        url21 = setupUrl("tiles-defs-2.1", Locale.ITALIAN);
+        url513 = setupUrl("defs-tiles-513");
+        replay(applicationContext);
+
+        definitionDao = new ResolvingLocaleUrlDefinitionDAO(applicationContext);
+        WildcardDefinitionPatternMatcherFactory definitionPatternMatcherFactory = new WildcardDefinitionPatternMatcherFactory();
+        PatternDefinitionResolver<Locale> definitionResolver = new BasicPatternDefinitionResolver<>(
+            definitionPatternMatcherFactory, definitionPatternMatcherFactory);
+        definitionDao.setPatternDefinitionResolver(definitionResolver);
+    }
+
+    @Test
+    public void testGetDefinition() {
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        definitionDao.setReader(reader);
+
+        assertNotNull("test.def1 definition not found.", definitionDao.getDefinition("test.def1", null));
+        assertNotNull("test.def2 definition not found.", definitionDao.getDefinition("test.def2", null));
+        assertNotNull("test.def3 definition not found.", definitionDao.getDefinition("test.def3", null));
+        assertNotNull("test.common definition not found.", definitionDao.getDefinition("test.common", null));
+        assertNotNull("test.common definition in US locale not found.",
+            definitionDao.getDefinition("test.common", Locale.US));
+        assertNotNull("test.common definition in FRENCH locale not found.",
+            definitionDao.getDefinition("test.common", Locale.FRENCH));
+        assertNotNull("test.common definition in CHINA locale not found.",
+            definitionDao.getDefinition("test.common", Locale.CHINA));
+        assertNotNull("test.common.french definition in FRENCH locale not found.",
+            definitionDao.getDefinition("test.common.french", Locale.FRENCH));
+        assertNotNull("test.common.french definition in CANADA_FRENCH locale not found.",
+            definitionDao.getDefinition("test.common.french", Locale.CANADA_FRENCH));
+        assertNotNull("test.def.toextend definition not found.", definitionDao.getDefinition("test.def.toextend", null));
+        assertNotNull("test.def.overridden definition not found.",
+            definitionDao.getDefinition("test.def.overridden", null));
+        assertNotNull("test.def.overridden definition in FRENCH locale not found.",
+            definitionDao.getDefinition("test.def.overridden", Locale.FRENCH));
+
+        assertEquals("Incorrect default country value", "default", definitionDao.getDefinition("test.def1", null)
+            .getAttribute("country").getValue());
+        assertEquals("Incorrect US country value", "US", definitionDao.getDefinition("test.def1", Locale.US)
+            .getAttribute("country").getValue());
+        assertEquals("Incorrect France country value", "France", definitionDao
+            .getDefinition("test.def1", Locale.FRENCH).getAttribute("country").getValue());
+        assertEquals("Incorrect Chinese country value (should be default)", "default",
+            definitionDao.getDefinition("test.def1", Locale.CHINA).getAttribute("country").getValue());
+        assertEquals("Incorrect default country value", "default",
+            definitionDao.getDefinition("test.def.overridden", null).getAttribute("country").getValue());
+        assertEquals("Incorrect default title value", "Definition to be overridden",
+            definitionDao.getDefinition("test.def.overridden", null).getAttribute("title").getValue());
+        assertEquals("Incorrect France country value", "France",
+            definitionDao.getDefinition("test.def.overridden", Locale.FRENCH).getAttribute("country").getValue());
+        assertEquals("Incorrect France title value", "Definition to be extended",
+            definitionDao.getDefinition("test.def.overridden", Locale.FRENCH).getAttribute("title").getValue());
+    }
+
+    @Test
+    public void testGetDefinitions() {
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        definitionDao.setReader(reader);
+
+        Map<String, Definition> defaultDefinitions = definitionDao.getDefinitions(null);
+        Map<String, Definition> usDefinitions = definitionDao.getDefinitions(Locale.US);
+        Map<String, Definition> frenchDefinitions = definitionDao.getDefinitions(Locale.FRENCH);
+        Map<String, Definition> chinaDefinitions = definitionDao.getDefinitions(Locale.CHINA);
+        Map<String, Definition> canadaFrendDefinitions = definitionDao.getDefinitions(Locale.CANADA_FRENCH);
+
+        assertNotNull("test.def1 definition not found.", defaultDefinitions.get("test.def1"));
+        assertNotNull("test.def2 definition not found.", defaultDefinitions.get("test.def2"));
+        assertNotNull("test.def3 definition not found.", defaultDefinitions.get("test.def3"));
+        assertNotNull("test.common definition not found.", defaultDefinitions.get("test.common"));
+        assertNotNull("test.common definition in US locale not found.", usDefinitions.get("test.common"));
+        assertNotNull("test.common definition in FRENCH locale not found.", frenchDefinitions.get("test.common"));
+        assertNotNull("test.common definition in CHINA locale not found.", chinaDefinitions.get("test.common"));
+        assertNotNull("test.common.french definition in FRENCH locale not found.",
+            canadaFrendDefinitions.get("test.common.french"));
+        assertNotNull("test.common.french definition in CANADA_FRENCH locale not found.",
+            canadaFrendDefinitions.get("test.common.french"));
+        assertNotNull("test.def.toextend definition not found.", defaultDefinitions.get("test.def.toextend"));
+        assertNotNull("test.def.overridden definition not found.", defaultDefinitions.get("test.def.overridden"));
+        assertNotNull("test.def.overridden definition in FRENCH locale not found.",
+            frenchDefinitions.get("test.def.overridden"));
+
+        assertEquals("Incorrect default country value", "default",
+            defaultDefinitions.get("test.def1").getAttribute("country").getValue());
+        assertEquals("Incorrect US country value", "US", usDefinitions.get("test.def1").getAttribute("country")
+            .getValue());
+        assertEquals("Incorrect France country value", "France",
+            frenchDefinitions.get("test.def1").getAttribute("country").getValue());
+        assertEquals("Incorrect Chinese country value (should be default)", "default", chinaDefinitions
+            .get("test.def1").getAttribute("country").getValue());
+        assertEquals("Incorrect default country value", "default", defaultDefinitions.get("test.def.overridden")
+            .getAttribute("country").getValue());
+        assertEquals("Incorrect default title value", "Definition to be overridden",
+            defaultDefinitions.get("test.def.overridden").getAttribute("title").getValue());
+        assertEquals("Incorrect France country value", "France", frenchDefinitions.get("test.def.overridden")
+            .getAttribute("country").getValue());
+        assertEquals("Incorrect France title value", "Definition to be extended",
+            frenchDefinitions.get("test.def.overridden").getAttribute("title").getValue());
+    }
+
+    @Test
+    public void testSetSourceURLs() {
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        assertEquals("The source URLs are not set correctly", sourceURLs, definitionDao.sources);
+    }
+
+    @Test
+    public void testSetReader() {
+        DefinitionsReader reader = createMock(DefinitionsReader.class);
+        definitionDao.setReader(reader);
+        assertEquals("There reader has not been set correctly", reader, definitionDao.reader);
+    }
+
+    /**
+     * Tests {@link ResolvingLocaleUrlDefinitionDAO#resolveInheritance(Definition, Map, Locale, Set)}.
+     */
+    @Test(expected = NoSuchDefinitionException.class)
+    public void testResolveInheritanceNoParent() {
+        Definition definition = new Definition("mydef", null, null);
+        definition.setExtends("otherDef");
+        definitionDao.resolveInheritance(definition, new HashMap<>(), Locale.ITALY,
+            new HashSet<>());
+    }
+
+    /**
+     * Tests execution.
+     */
+    @Test
+    public void testInit() {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Set<ApplicationResource> urlSet = new HashSet<>();
+        urlSet.add(url1);
+        expect(applicationContext.getResources("/WEB-INF/tiles.xml")).andReturn(urlSet);
+        replay(applicationContext);
+        DefinitionsReader reader = new DigesterDefinitionsReader();
+        definitionDao.setReader(reader);
+        List<ApplicationResource> sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        definitionDao.setSources(sourceURLs);
+        assertEquals("The reader is not of the correct class", DigesterDefinitionsReader.class,
+            definitionDao.reader.getClass());
+        assertEquals("The source URLs are not correct", sourceURLs, definitionDao.sources);
+        reset(applicationContext);
+
+        applicationContext = createMock(ApplicationContext.class);
+        replay(applicationContext);
+        definitionDao.setReader(new MockDefinitionsReader());
+        assertEquals("The reader is not of the correct class", MockDefinitionsReader.class,
+            definitionDao.reader.getClass());
+        sourceURLs = new ArrayList<>();
+        sourceURLs.add(url1);
+        sourceURLs.add(url2);
+        sourceURLs.add(url3);
+        definitionDao.setSources(sourceURLs);
+        assertEquals("The source URLs are not correct", sourceURLs, definitionDao.sources);
+        verify(applicationContext);
+    }
+
+    /**
+     * Tests wildcard mappings.
+     */
+    @Test
+    public void testWildcardMapping() {
+        List<ApplicationResource> urls = new ArrayList<>();
+        urls.add(urlWildcard);
+        definitionDao.setSources(urls);
+        definitionDao.setReader(new DigesterDefinitionsReader());
+
+        Definition definition = definitionDao.getDefinition("test.defName.subLayered", Locale.ITALY);
+        assertEquals("The template is not correct", "/testName.jsp", definition.getTemplateAttribute().getValue());
+        assertEquals("The header attribute is not correct", "/common/headerLayered.jsp",
+            definition.getAttribute("header").getValue());
+        definition = definitionDao.getDefinition("test.defName.subLayered", Locale.ITALIAN);
+        assertEquals("The template is not correct", "/testName.jsp", definition.getTemplateAttribute().getValue());
+        assertEquals("The header attribute is not correct", "/common/headerLayered.jsp",
+            definition.getAttribute("header").getValue());
+        definition = definitionDao.getDefinition("test.defName.subLayered", null);
+        assertEquals("The template is not correct", "/testName.jsp", definition.getTemplateAttribute().getValue());
+        assertEquals("The header attribute is not correct", "/common/headerLayered.jsp",
+            definition.getAttribute("header").getValue());
+        definition = definitionDao.getDefinition("test.defName.noAttribute", null);
+        assertEquals("/testName.jsp", definition.getTemplateAttribute().getValue());
+        assertNull(definition.getLocalAttributeNames());
+        definition = definitionDao.getDefinition("test.def3", null);
+        assertNotNull("The simple definition is null", definition);
+
+        definition = definitionDao.getDefinition("test.extended.defName.subLayered", null);
+        assertEquals("test.defName.subLayered", definition.getExtends());
+        assertEquals(ATTRIBUTE_NAMES_COUNT, definition.getLocalAttributeNames().size());
+        assertEquals("The template is not correct", "/testName.jsp", definition.getTemplateAttribute().getValue());
+        assertEquals("Overridden Title", definition.getAttribute("title").getValue());
+        assertEquals("The header attribute is not correct", "/common/headerLayered.jsp",
+            definition.getAttribute("header").getValue());
+    }
+
+    /**
+     * Tests
+     * {@link ResolvingLocaleUrlDefinitionDAO#getDefinition(String, Locale)}
+     * when loading multiple files for a locale.
+     */
+    @Test
+    public void testListAttributeLocaleInheritance() {
+        List<ApplicationResource> urls = new ArrayList<>();
+        urls.add(url21);
+        definitionDao.setSources(urls);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        definitionDao.setReader(new DigesterDefinitionsReader());
+        replay(applicationContext);
+
+        Definition definition = definitionDao.getDefinition("test.inherit.list", Locale.ITALIAN);
+        ListAttribute listAttribute = (ListAttribute) definition.getAttribute("list");
+        List<Attribute> attributes = listAttribute.getValue();
+        assertEquals(2, attributes.size());
+        verify(applicationContext);
+    }
+
+    @Test
+    public void testTiles512() {
+        List<ApplicationResource> urls = new ArrayList<>();
+        urls.add(url21);
+        definitionDao.setSources(urls);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        definitionDao.setReader(new DigesterDefinitionsReader());
+        replay(applicationContext);
+
+        Definition definition = definitionDao.getDefinition("test.inherit.othertype", Locale.ITALIAN);
+        assertEquals("/layout.ftl", definition.getTemplateAttribute().getValue());
+        assertEquals("freemarker", definition.getTemplateAttribute().getRenderer());
+    }
+
+    @Test
+    public void testTiles513() {
+        List<ApplicationResource> urls = new ArrayList<>();
+        urls.add(url513);
+        definitionDao.setSources(urls);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        definitionDao.setReader(new DigesterDefinitionsReader());
+        replay(applicationContext);
+
+        Definition definition = definitionDao.getDefinition("test.anonymous", null);
+        definitionDao.getDefinition("test.anonymous", new Locale("es", "CO"));
+        definitionDao.getDefinition("test.anonymous", new Locale("en", "CA"));
+        Attribute attribute = definition.getAttribute("header");
+        Definition child = definitionDao.getDefinition((String) attribute.getValue(), null);
+        assertNotNull(child);
+        attribute = definition.getAttribute("menu");
+        child = definitionDao.getDefinition((String) attribute.getValue(), null);
+        assertNotNull(child);
+        attribute = definition.getAttribute("footer");
+        child = definitionDao.getDefinition((String) attribute.getValue(), null);
+        assertNotNull(child);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderExceptionTest.java
similarity index 69%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderExceptionTest.java
index 777ecd57c..55403cbbb 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -18,8 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-package org.apache.tiles.api;
+package org.apache.tiles.core.definition.digester;
 
 import org.junit.Test;
 
@@ -27,13 +24,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link NoSuchContainerException}.
+ * Tests {@link DigesterDefinitionsReaderException}.
  */
-public class NoSuchContainerExceptionTest {
+public class DigesterDefinitionsReaderExceptionTest {
 
+    /**
+     * Test method for {@link DigesterDefinitionsReaderException#DigesterDefinitionsReaderException(String)}.
+     */
     @Test
-    public void testNoSuchContainerExceptionString() {
-        NoSuchContainerException exception = new NoSuchContainerException("my message");
+    public void testDigesterDefinitionsReaderExceptionString() {
+        DigesterDefinitionsReaderException exception = new DigesterDefinitionsReaderException("my message");
         assertEquals("my message", exception.getMessage());
         assertNull(exception.getCause());
     }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/digester/TestDigesterDefinitionsReader.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/digester/TestDigesterDefinitionsReader.java
new file mode 100644
index 000000000..f8a5ee0a3
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/digester/TestDigesterDefinitionsReader.java
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.digester;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.core.definition.DefinitionsFactoryException;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests the <code>org.apache.tiles.definition.digester.DigesterDefinitionsReader</code> class.
+ */
+public class TestDigesterDefinitionsReader {
+
+    private DigesterDefinitionsReader reader;
+
+    @Before
+    public void setUp() {
+        reader = new DigesterDefinitionsReader();
+    }
+
+    /**
+     * Tests the read method under normal conditions.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testRead() throws IOException {
+        URL configFile = this.getClass().getClassLoader().getResource("org/apache/tiles/core/config/tiles-defs.xml");
+        assertNotNull("Config file not found", configFile);
+
+        InputStream source = configFile.openStream();
+        Map<String, Definition> definitions = reader.read(source);
+
+        assertNotNull("Definitions not returned.", definitions);
+        assertNotNull("Couldn't find doc.mainLayout tile.", definitions.get("doc.mainLayout"));
+        assertNotNull("Couldn't Find title attribute.", definitions.get("doc.mainLayout").getAttribute("title").getValue());
+        assertEquals("Incorrect Find title attribute.", "Tiles Library Documentation", definitions.get("doc.mainLayout").getAttribute("title").getValue());
+
+        Definition def = definitions.get("doc.role.test");
+        assertNotNull("Couldn't find doc.role.test tile.", def);
+        Attribute attribute = def.getAttribute("title");
+        assertNotNull("Couldn't Find title attribute.", attribute.getValue());
+        assertEquals("Role 'myrole' expected", attribute.getRole(), "myrole");
+
+        def = definitions.get("doc.listattribute.test");
+        assertNotNull("Couldn't find doc.listattribute.test tile.", def);
+        attribute = def.getAttribute("items");
+        assertNotNull("Couldn't Find items attribute.", attribute);
+        assertTrue("The class of the attribute is not right", attribute instanceof ListAttribute);
+        assertTrue("The class of value of the attribute is not right", attribute.getValue() instanceof List);
+    }
+
+
+    /**
+     * Tests the read method under normal conditions for the new features in 2.1
+     * version of the DTD.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testRead21Version() throws IOException {
+        URL configFile = this.getClass().getClassLoader().getResource("org/apache/tiles/core/config/tiles-defs-2.1.xml");
+        assertNotNull("Config file not found", configFile);
+
+        InputStream source = configFile.openStream();
+        Map<String, Definition> definitions = reader.read(source);
+
+        assertNotNull("Definitions not returned.", definitions);
+        Definition def = definitions.get("doc.cascaded.test");
+
+        assertNotNull("Couldn't find doc.role.test tile.", def);
+        Attribute attribute = def.getLocalAttribute("title");
+        assertNotNull("Couldn't Find title local attribute.", attribute);
+        attribute = def.getCascadedAttribute("title2");
+        assertNotNull("Couldn't Find title2 cascaded attribute.", attribute);
+        attribute = def.getLocalAttribute("items1");
+        assertNotNull("Couldn't Find items1 local attribute.", attribute);
+        attribute = def.getCascadedAttribute("items2");
+        assertNotNull("Couldn't Find items2 cascaded attribute.", attribute);
+
+        def = definitions.get("test.nesting.definitions");
+        assertNotNull("Couldn't find test.nesting.definitions tile.", def);
+        assertEquals("/layout.jsp", def.getTemplateAttribute().getValue());
+        assertEquals("template", def.getTemplateAttribute().getRenderer());
+        attribute = def.getAttribute("body");
+        assertNotNull("Couldn't Find body attribute.", attribute);
+        assertEquals("Attribute not of 'definition' type", "definition", attribute.getRenderer());
+        assertNotNull("Attribute value null", attribute.getValue());
+        String defName = attribute.getValue().toString();
+        def = definitions.get(defName);
+        assertNotNull("Couldn't find " + defName + " tile.", def);
+
+        def = definitions.get("test.nesting.list.definitions");
+        assertNotNull("Couldn't find test.nesting.list.definitions tile.", def);
+        attribute = def.getAttribute("list");
+        assertNotNull("Couldn't Find list attribute.", attribute);
+        assertTrue("Attribute not of valid type", attribute instanceof ListAttribute);
+        ListAttribute listAttribute = (ListAttribute) attribute;
+        List<Attribute> list = listAttribute.getValue();
+        assertEquals("The list is not of correct size", 1, list.size());
+        attribute = list.get(0);
+        assertNotNull("Couldn't Find element attribute.", attribute);
+        assertEquals("Attribute not of 'definition' type", "definition", attribute.getRenderer());
+        assertNotNull("Attribute value null", attribute.getValue());
+        defName = attribute.getValue().toString();
+        def = definitions.get(defName);
+        assertNotNull("Couldn't find " + defName + " tile.", def);
+
+        defName = "test.inherit.list.base";
+        def = definitions.get(defName);
+        assertNotNull("Couldn't find " + defName + " tile.", def);
+        defName = "test.inherit.list";
+        def = definitions.get(defName);
+        assertNotNull("Couldn't find " + defName + " tile.", def);
+        listAttribute = (ListAttribute) def.getAttribute("list");
+        assertTrue("This definition does not inherit its list attribute", listAttribute.isInherit());
+        defName = "test.noinherit.list";
+        def = definitions.get(defName);
+        listAttribute = (ListAttribute) def.getAttribute("list");
+        assertFalse("This definition inherits its list attribute", listAttribute.isInherit());
+
+        defName = "test.new.attributes";
+        def = definitions.get(defName);
+        assertNotNull("Couldn't find " + defName + " tile.", def);
+        Attribute templateAttribute = def.getTemplateAttribute();
+        assertEquals(templateAttribute.getExpressionObject().getExpression(), "${my.expression}");
+        assertEquals("mytype", templateAttribute.getRenderer());
+        attribute = def.getAttribute("body");
+        assertNotNull("Couldn't Find body attribute.", attribute);
+        assertEquals("${my.attribute.expression}", attribute.getExpressionObject().getExpression());
+    }
+
+    /**
+     * Tests read with bad input source.
+     */
+    @Test
+    public void testBadSource() {
+        try {
+            reader.read("Bad Input");
+            fail("Should've thrown an exception.");
+        } catch (DefinitionsFactoryException e) {
+            assertTrue(true);
+        } catch (Exception e) {
+            fail("Exception reading configuration." + e);
+        }
+    }
+
+    /**
+     * Tests read with bad XML source.
+     */
+    @Test
+    public void testBadXml() {
+        try {
+            URL configFile = this.getClass().getClassLoader().getResource(
+                "org/apache/tiles/config/malformed-defs.xml");
+            assertNotNull("Config file not found", configFile);
+
+            InputStream source = configFile.openStream();
+            reader.read(source);
+            fail("Should've thrown an exception.");
+        } catch (DefinitionsFactoryException e) {
+            assertTrue(true);
+        } catch (Exception e) {
+            fail("Exception reading configuration." + e);
+        }
+    }
+
+    /**
+     * Tests the validating input parameter.
+     * <p>
+     * This test case enables Digester's validating property then passes in a
+     * configuration file with invalid XML.
+     */
+    @Test
+    public void testValidatingParameter() {
+        // Testing with default (validation ON).
+        try {
+            URL configFile = this.getClass().getClassLoader().getResource(
+                "org/apache/tiles/config/invalid-defs.xml");
+            assertNotNull("Config file not found", configFile);
+
+            InputStream source = configFile.openStream();
+            reader.setValidating(true);
+            reader.read(source);
+            fail("Should've thrown an exception.");
+        } catch (DefinitionsFactoryException e) {
+            assertTrue(true);
+        } catch (Exception e) {
+            fail("Exception reading configuration." + e);
+        }
+
+        // Testing with validation OFF.
+        try {
+            setUp();
+            URL configFile = this.getClass().getClassLoader().getResource(
+                "org/apache/tiles/config/invalid-defs.xml");
+            assertNotNull("Config file not found", configFile);
+
+            InputStream source = configFile.openStream();
+            reader.read(source);
+        } catch (DefinitionsFactoryException e) {
+            fail("Should not have thrown an exception." + e);
+        } catch (Exception e) {
+            fail("Exception reading configuration." + e);
+        }
+    }
+
+    /**
+     * Regression test for bug TILES-352.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testRegressionTiles352() throws IOException {
+        URL configFile = this.getClass().getClassLoader().getResource(
+            "org/apache/tiles/config/defs_regression_TILES-352.xml");
+        assertNotNull("Config file not found", configFile);
+
+        InputStream source = configFile.openStream();
+        Map<String, Definition> name2defs = reader.read(source);
+        source.close();
+        Definition root = name2defs.get("root");
+        Attribute attribute = root.getAttribute("body");
+        Definition child = name2defs.get(attribute.getValue());
+        ListAttribute listAttribute = (ListAttribute) child.getAttribute("list");
+        List<Attribute> list = listAttribute.getValue();
+        assertEquals((list.get(0)).getValue(), "This is a value");
+    }
+
+    /**
+     * Tests {@link DigesterDefinitionsReader#read(Object)}.
+     */
+    @Test
+    public void testReadNoSource() {
+        assertNull(reader.read(null));
+    }
+
+    /**
+     * Tests {@link DigesterDefinitionsReader#addDefinition(Definition)}.
+     */
+    @Test(expected = DigesterDefinitionsReaderException.class)
+    public void testAddDefinitionNoName() {
+        Definition def = new Definition();
+        reader.addDefinition(def);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolverTest.java
new file mode 100644
index 000000000..db9c00f6e
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolverTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Definition;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link AbstractPatternDefinitionResolver}.
+ */
+public class AbstractPatternDefinitionResolverTest {
+
+    private DefinitionPatternMatcher firstMatcher;
+    private DefinitionPatternMatcher thirdMatcher;
+
+    private final PatternDefinitionResolver<Integer> resolver = new AbstractPatternDefinitionResolver<Integer>() {
+        @Override
+        protected Map<String, Definition> addDefinitionsAsPatternMatchers(List<DefinitionPatternMatcher> matchers, Map<String, Definition> defsMap) {
+            if (defsMap.containsKey("first")) {
+                matchers.add(firstMatcher);
+            }
+            if (defsMap.containsKey("third")) {
+                matchers.add(thirdMatcher);
+            }
+            Map<String, Definition> retValue = new HashMap<>(defsMap);
+            retValue.remove("first");
+            retValue.remove("third");
+            return retValue;
+        }
+    };
+
+    /**
+     * Test method for
+     * {@link BasicPatternDefinitionResolver#resolveDefinition(String, Object)}.
+     */
+    @Test
+    public void testResolveDefinition() {
+        testResolveDefinitionImpl();
+    }
+
+    /**
+     * Test method for
+     * {@link BasicPatternDefinitionResolver#clearPatternPaths(Object)}.
+     */
+    @Test
+    public void testClearPatternPaths() {
+        testResolveDefinitionImpl();
+        resolver.clearPatternPaths(1);
+        resolver.clearPatternPaths(2);
+        testResolveDefinitionImpl();
+    }
+
+    private void testResolveDefinitionImpl() {
+
+        firstMatcher = createMock(DefinitionPatternMatcher.class);
+        thirdMatcher = createMock(DefinitionPatternMatcher.class);
+
+        Definition firstDefinition = new Definition("first", null, null);
+        Definition secondDefinition = new Definition("second", null, null);
+        Definition thirdDefinition = new Definition("third", null, null);
+
+        Definition firstTransformedDefinition = new Definition("firstTransformed", null, null);
+        Definition thirdTransformedDefinition = new Definition("thirdTransformed", null, null);
+
+        expect(firstMatcher.createDefinition("firstTransformed")).andReturn(firstTransformedDefinition);
+        expect(firstMatcher.createDefinition("secondTransformed")).andReturn(null);
+        expect(firstMatcher.createDefinition("thirdTransformed")).andReturn(null);
+        expect(thirdMatcher.createDefinition("thirdTransformed")).andReturn(thirdTransformedDefinition).times(2);
+        expect(thirdMatcher.createDefinition("firstTransformed")).andReturn(null);
+        expect(thirdMatcher.createDefinition("secondTransformed")).andReturn(null).times(2);
+
+        replay(firstMatcher, thirdMatcher);
+
+        Map<String, Definition> localeDefsMap = new LinkedHashMap<>();
+        localeDefsMap.put("first", firstDefinition);
+        localeDefsMap.put("second", secondDefinition);
+        localeDefsMap.put("third", thirdDefinition);
+        resolver.storeDefinitionPatterns(localeDefsMap, 1);
+        localeDefsMap = new LinkedHashMap<>();
+        localeDefsMap.put("third", thirdDefinition);
+        resolver.storeDefinitionPatterns(localeDefsMap, 2);
+        assertEquals(firstTransformedDefinition, resolver.resolveDefinition("firstTransformed", 1));
+        assertNull(resolver.resolveDefinition("secondTransformed", 1));
+        assertEquals(thirdTransformedDefinition, resolver.resolveDefinition("thirdTransformed", 1));
+        assertNull(resolver.resolveDefinition("firstTransformed", 2));
+        assertNull(resolver.resolveDefinition("secondTransformed", 2));
+        assertEquals(thirdTransformedDefinition, resolver.resolveDefinition("thirdTransformed", 2));
+        verify(firstMatcher, thirdMatcher);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolverTest.java
new file mode 100644
index 000000000..7cd651b98
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolverTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Definition;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link BasicPatternDefinitionResolver}.
+ */
+public class BasicPatternDefinitionResolverTest {
+
+    /**
+     * Test method for
+     * {@link BasicPatternDefinitionResolver#addDefinitionsAsPatternMatchers(List, Map)}.
+     */
+    @Test
+    public void testAddDefinitionsAsPatternMatchers() {
+        DefinitionPatternMatcherFactory factory = createMock(DefinitionPatternMatcherFactory.class);
+        PatternRecognizer recognizer = createMock(PatternRecognizer.class);
+        DefinitionPatternMatcher firstMatcher = createMock(DefinitionPatternMatcher.class);
+        DefinitionPatternMatcher thirdMatcher = createMock(DefinitionPatternMatcher.class);
+
+        expect(recognizer.isPatternRecognized("first")).andReturn(true);
+        expect(recognizer.isPatternRecognized("second")).andReturn(false);
+        expect(recognizer.isPatternRecognized("third")).andReturn(true);
+
+        Definition firstDefinition = new Definition("first", null, null);
+        Definition secondDefinition = new Definition("second", null, null);
+        Definition thirdDefinition = new Definition("third", null, null);
+
+        expect(factory.createDefinitionPatternMatcher("first", firstDefinition))
+            .andReturn(firstMatcher);
+        expect(factory.createDefinitionPatternMatcher("third", thirdDefinition))
+            .andReturn(thirdMatcher);
+
+        replay(factory, recognizer, firstMatcher, thirdMatcher);
+        BasicPatternDefinitionResolver<Integer> resolver = new BasicPatternDefinitionResolver<>(factory, recognizer);
+        Map<String, Definition> localeDefsMap = new LinkedHashMap<>();
+        localeDefsMap.put("first", firstDefinition);
+        localeDefsMap.put("second", secondDefinition);
+        localeDefsMap.put("third", thirdDefinition);
+        List<DefinitionPatternMatcher> matchers = new ArrayList<>();
+        resolver.addDefinitionsAsPatternMatchers(matchers, localeDefsMap);
+        assertEquals(2, matchers.size());
+        assertEquals(firstMatcher, matchers.get(0));
+        assertEquals(thirdMatcher, matchers.get(1));
+        verify(factory, recognizer, firstMatcher, thirdMatcher);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/PatternUtilTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/PatternUtilTest.java
new file mode 100644
index 000000000..8dea7b4af
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/PatternUtilTest.java
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.api.ListAttribute;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class PatternUtilTest {
+
+    /**
+     * The size of the list in the main list attribute.
+     */
+    private static final int LIST_ATTRIBUTE_SIZE = 3;
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholders() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        attributes.put("attrib1", new Attribute("value{2}"));
+        attributes.put("attrib2", new Attribute("value{2}{3}"));
+        attributes.put("attrib3", new Attribute(null, Expression
+                .createExpression("expr{1}", "EL"), null, null));
+        Definition definition = new Definition("definitionName", new Attribute(
+                "template{1}"), attributes);
+        definition.setExtends("{2}ext");
+        definition.setPreparer("{3}prep");
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef",
+                "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+        assertEquals("value2ext", nudef.getExtends());
+        assertEquals("value3prep", nudef.getPreparer());
+        Attribute attribute = nudef.getTemplateAttribute();
+        assertEquals("templatevalue1", attribute.getValue());
+        attribute = nudef.getAttribute("attrib1");
+        assertEquals("valuevalue2", attribute.getValue());
+        attribute = nudef.getAttribute("attrib2");
+        assertEquals("valuevalue2value3", attribute.getValue());
+        attribute = nudef.getAttribute("attrib3");
+        assertEquals("exprvalue1", attribute.getExpressionObject().getExpression());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholdersNullTemplate() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        attributes.put("attrib1", new Attribute("value{2}"));
+        attributes.put("attrib2", new Attribute("value{2}{3}"));
+        Definition definition = new Definition("definitionName", null, attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef",
+                "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+        assertNull(nudef.getTemplateAttribute());
+        Attribute attribute = nudef.getAttribute("attrib1");
+        assertEquals("valuevalue2", attribute.getValue());
+        attribute = nudef.getAttribute("attrib2");
+        assertEquals("valuevalue2value3", attribute.getValue());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholdersCascadedAttributes() {
+        Definition definition = new Definition("definitionName", new Attribute(
+                "template{1}"), null);
+        definition.putAttribute("attrib1", new Attribute("value{2}"), true);
+        definition.putAttribute("attrib2", new Attribute("value{2}{3}"), true);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef",
+                "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+        Attribute attribute = nudef.getTemplateAttribute();
+        assertEquals("templatevalue1", attribute.getValue());
+        attribute = nudef.getAttribute("attrib1");
+        assertEquals("valuevalue2", attribute.getValue());
+        attribute = nudef.getAttribute("attrib2");
+        assertEquals("valuevalue2value3", attribute.getValue());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholdersListAttribute() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        ListAttribute listAttribute = new ListAttribute();
+        ListAttribute internalListAttribute = new ListAttribute();
+        listAttribute.setInherit(true);
+        attributes.put("myList", listAttribute);
+        listAttribute.add(new Attribute("value{2}"));
+        listAttribute.add(new Attribute("value{2}{3}"));
+        listAttribute.add(internalListAttribute);
+        internalListAttribute.add(new Attribute("secondvalue{2}"));
+        internalListAttribute.add(new Attribute("secondvalue{2}{3}"));
+        Definition definition = new Definition("definitionName", new Attribute(
+                "template{1}"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef",
+                "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+        Attribute attribute = nudef.getTemplateAttribute();
+        assertEquals("templatevalue1", attribute.getValue());
+        ListAttribute nuListAttribute = (ListAttribute) nudef.getAttribute("myList");
+        assertTrue(nuListAttribute.isInherit());
+        List<Attribute> list = nuListAttribute.getValue();
+        assertEquals(LIST_ATTRIBUTE_SIZE, list.size());
+        attribute = list.get(0);
+        assertEquals("valuevalue2", attribute.getValue());
+        attribute = list.get(1);
+        assertEquals("valuevalue2value3", attribute.getValue());
+        ListAttribute evaluatedListAttribute = (ListAttribute) list.get(2);
+        assertFalse(evaluatedListAttribute.isInherit());
+        list = evaluatedListAttribute.getValue();
+        assertEquals(2, list.size());
+        attribute = list.get(0);
+        assertEquals("secondvaluevalue2", attribute.getValue());
+        attribute = list.get(1);
+        assertEquals("secondvaluevalue2value3", attribute.getValue());
+    }
+
+
+    /**
+     * Tests {@link PatternUtil#createExtractedMap(Map, Set)}.
+     */
+    @Test
+    public void testCreateExtractedMap() {
+        Map<Integer, String> map = new HashMap<>();
+        map.put(0, "value0");
+        map.put(1, "value1");
+        map.put(2, "value2");
+        Set<Integer> set = new HashSet<>();
+        set.add(1);
+        set.add(2);
+        Map<Integer, String> extractedMap = PatternUtil.createExtractedMap(map, set);
+        assertEquals(2, extractedMap.size());
+        assertEquals("value1", extractedMap.get(1));
+        assertEquals("value2", extractedMap.get(2));
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     * See TILES-502
+     */
+    @Test
+    public void testReplacePlaceholdersEL_0() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        Attribute attribute = new Attribute("some-{1}-${requestScope.someVariable}.jsp");
+        attribute.setExpressionObject(new Expression((String)attribute.getValue()));
+        attributes.put("something", attribute);
+        Definition definition = new Definition("definitionName", new Attribute("template"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef", "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+
+        assertEquals(
+                "some-value1-${requestScope.someVariable}.jsp",
+                nudef.getAttribute("something").getValue());
+
+        assertEquals(
+                "some-value1-${requestScope.someVariable}.jsp",
+                nudef.getAttribute("something").getExpressionObject().getExpression());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     * See TILES-574
+     */
+    @Test
+    public void testReplacePlaceholdersEL_1() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        Attribute attribute = new Attribute("some-{1}-${requestScope.someVariable}-other-{2}.jsp");
+        attribute.setExpressionObject(new Expression((String)attribute.getValue()));
+        attributes.put("something", attribute);
+        Definition definition = new Definition("definitionName", new Attribute("template"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef", "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+
+        assertEquals(
+                "some-value1-${requestScope.someVariable}-other-value2.jsp",
+                nudef.getAttribute("something").getValue());
+
+        assertEquals(
+                "some-value1-${requestScope.someVariable}-other-value2.jsp",
+                nudef.getAttribute("something").getExpressionObject().getExpression());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     * See TILES-574
+     */
+    @Test
+    public void testReplacePlaceholdersEL_2() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        Attribute attribute = new Attribute("some-${requestScope.someVariable}-other-{1}-${requestScope.someOtherVariable}.jsp");
+        attribute.setExpressionObject(new Expression((String)attribute.getValue()));
+        attributes.put("something", attribute);
+        Definition definition = new Definition("definitionName", new Attribute("template"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef", "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+
+        assertEquals(
+                "some-${requestScope.someVariable}-other-value1-${requestScope.someOtherVariable}.jsp",
+                nudef.getAttribute("something").getValue());
+
+        assertEquals(
+                "some-${requestScope.someVariable}-other-value1-${requestScope.someOtherVariable}.jsp",
+                nudef.getAttribute("something").getExpressionObject().getExpression());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholdersEL_conditional() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        Attribute attribute = new Attribute("{1}/some-other-{2}-${requestScope.someBoolean ? 'a' : 'b'}.jsp");
+        attribute.setExpressionObject(new Expression((String)attribute.getValue()));
+        attributes.put("something", attribute);
+        Definition definition = new Definition("definitionName", new Attribute("template"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef", "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+
+        assertEquals(
+                "value1/some-other-value2-${requestScope.someBoolean ? 'a' : 'b'}.jsp",
+                nudef.getAttribute("something").getValue());
+
+        assertEquals(
+                "value1/some-other-value2-${requestScope.someBoolean ? 'a' : 'b'}.jsp",
+                nudef.getAttribute("something").getExpressionObject().getExpression());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholdersEL_twice() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        Attribute attribute = new Attribute("some-${requestScope.firstVariable}-${requestScope.secondVariable}.jsp");
+        attribute.setExpressionObject(new Expression((String)attribute.getValue()));
+        attributes.put("something", attribute);
+        Definition definition = new Definition("definitionName", new Attribute("template"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef", "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+
+        assertEquals(
+                "some-${requestScope.firstVariable}-${requestScope.secondVariable}.jsp",
+                nudef.getAttribute("something").getValue());
+
+        assertEquals(
+                "some-${requestScope.firstVariable}-${requestScope.secondVariable}.jsp",
+                nudef.getAttribute("something").getExpressionObject().getExpression());
+    }
+
+    /**
+     * Test method for
+     * {@link PatternUtil#replacePlaceholders(Definition, String, Object[])}.
+     */
+    @Test
+    public void testReplacePlaceholdersEL_options() {
+        Map<String, Attribute> attributes = new HashMap<>();
+        Attribute attribute = new Attribute("{1}/{options[my_fallback}}/some-other-{2}-${requestScope.someVariable}.jsp");
+        attribute.setExpressionObject(new Expression((String)attribute.getValue()));
+        attributes.put("something", attribute);
+        Definition definition = new Definition("definitionName", new Attribute("template"), attributes);
+        Definition nudef = PatternUtil.replacePlaceholders(definition, "nudef", "value0", "value1", "value2", "value3");
+        assertEquals("nudef", nudef.getName());
+
+        assertEquals(
+                "value1/{options[my_fallback}}/some-other-value2-${requestScope.someVariable}.jsp",
+                nudef.getAttribute("something").getValue());
+
+        assertEquals(
+                "value1/{options[my_fallback}}/some-other-value2-${requestScope.someVariable}.jsp",
+                nudef.getAttribute("something").getExpressionObject().getExpression());
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolverTest.java
new file mode 100644
index 000000000..bdeaca258
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolverTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link PrefixedPatternDefinitionResolver}.
+ */
+public class PrefixedPatternDefinitionResolverTest {
+
+    /**
+     * Test method for {@link PrefixedPatternDefinitionResolver#addDefinitionsAsPatternMatchers(List, Map)}.
+     */
+    @Test
+    public void testAddDefinitionsAsPatternMatchers() {
+        DefinitionPatternMatcherFactory factory1 = createMock(DefinitionPatternMatcherFactory.class);
+        DefinitionPatternMatcherFactory factory2 = createMock(DefinitionPatternMatcherFactory.class);
+        DefinitionPatternMatcher matcher1 = createMock(DefinitionPatternMatcher.class);
+        DefinitionPatternMatcher matcher2 = createMock(DefinitionPatternMatcher.class);
+        Definition definition1 = new Definition("DF1:definition1", null, null);
+        Definition definition2 = new Definition("DF2:definition2", null, null);
+        Definition definition3 = new Definition("noLanguageHere", null, null);
+
+        expect(factory1.createDefinitionPatternMatcher("definition1", definition1)).andReturn(matcher1);
+        expect(factory2.createDefinitionPatternMatcher("definition2", definition2)).andReturn(matcher2);
+
+        replay(factory1, factory2, matcher1, matcher2);
+
+        PrefixedPatternDefinitionResolver<Integer> resolver = new PrefixedPatternDefinitionResolver<>();
+        resolver.registerDefinitionPatternMatcherFactory("DF1", factory1);
+        resolver.registerDefinitionPatternMatcherFactory("DF2", factory2);
+        List<DefinitionPatternMatcher> matchers = new ArrayList<>();
+        Map<String, Definition> definitions = new LinkedHashMap<>();
+        definitions.put("DF1:definition1", definition1);
+        definitions.put("DF2:definition2", definition2);
+        definitions.put("noLanguageHere", definition3);
+
+        resolver.addDefinitionsAsPatternMatchers(matchers, definitions);
+
+        assertEquals(2, matchers.size());
+        assertEquals(matcher1, matchers.get(0));
+        assertEquals(matcher2, matchers.get(1));
+
+        verify(factory1, factory2, matcher1, matcher2);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactoryTest.java
similarity index 59%
copy from plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactoryTest.java
index 3cbffaf99..35e9826cb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactoryTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -21,18 +19,31 @@
 package org.apache.tiles.core.definition.pattern.regexp;
 
 import org.apache.tiles.api.Definition;
-import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
-import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcherFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
 
 /**
- * Creates instances of {@link RegexpDefinitionPatternMatcher}.
+ * Tests {@link RegexpDefinitionPatternMatcherFactory}.
  */
-public class RegexpDefinitionPatternMatcherFactory implements DefinitionPatternMatcherFactory {
+public class RegexpDefinitionPatternMatcherFactoryTest {
 
     /**
-     * {@inheritDoc}
+     * The object to test.
      */
-    public DefinitionPatternMatcher createDefinitionPatternMatcher(String pattern, Definition definition) {
-        return new RegexpDefinitionPatternMatcher(pattern, definition);
+    private RegexpDefinitionPatternMatcherFactory factory;
+
+    /**
+     * Sets up the object to test.
+     */
+    @Before
+    public void setUp() {
+        factory = new RegexpDefinitionPatternMatcherFactory();
+    }
+
+    @Test
+    public void testCreateDefinitionPatternMatcher() {
+        assertTrue(factory.createDefinitionPatternMatcher("myPattern", new Definition()) instanceof RegexpDefinitionPatternMatcher);
     }
 }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherTest.java
new file mode 100644
index 000000000..291918fc2
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern.regexp;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests {@link RegexpDefinitionPatternMatcher}.
+ */
+public class RegexpDefinitionPatternMatcherTest {
+
+    @Test
+    public void testResolveDefinition() {
+        Definition def = new Definition();
+        def.setName("testDef(.*)\\.message(.*)");
+        def.setTemplateAttribute(Attribute.createTemplateAttribute("/test{1}.jsp"));
+        def.putAttribute("body", new Attribute("message{2}"));
+        DefinitionPatternMatcher patternMatcher = new RegexpDefinitionPatternMatcher("testDef(.*)\\.message(.*)", def);
+        Definition result = patternMatcher.createDefinition("testDefOne.messageTwo");
+        assertNotNull(result);
+        assertEquals("testDefOne.messageTwo", result.getName());
+        assertEquals("/testOne.jsp", result.getTemplateAttribute().getValue());
+        assertEquals("messageTwo", result.getAttribute("body").getValue());
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactoryTest.java
new file mode 100644
index 000000000..dc98f2033
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactoryTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern.wildcard;
+
+import org.apache.tiles.api.Definition;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link WildcardDefinitionPatternMatcherFactory}.
+ */
+public class WildcardDefinitionPatternMatcherFactoryTest {
+
+    /**
+     * The object to test.
+     */
+    private WildcardDefinitionPatternMatcherFactory factory;
+
+    /**
+     * Sets up the object to test.
+     */
+    @Before
+    public void setUp() {
+        factory = new WildcardDefinitionPatternMatcherFactory();
+    }
+
+    @Test
+    public void testCreateDefinitionPatternMatcher() {
+        assertTrue(factory.createDefinitionPatternMatcher("myPattern", new Definition()) instanceof WildcardDefinitionPatternMatcher);
+    }
+
+    /**
+     * Test method for {@link WildcardDefinitionPatternMatcherFactory#isPatternRecognized(String)}.
+     */
+    @Test
+    public void testIsPatternRecognized() {
+        assertTrue(factory.isPatternRecognized("my*pattern"));
+        assertFalse(factory.isPatternRecognized("mypattern"));
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherTest.java
new file mode 100644
index 000000000..90eea7eb6
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern.wildcard;
+
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
+import org.apache.tiles.core.util.WildcardHelper;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests {@link WildcardDefinitionPatternMatcher}.
+ */
+public class WildcardDefinitionPatternMatcherTest {
+
+    /**
+     * Test method for {@link WildcardDefinitionPatternMatcher#createDefinition(String)}.
+     */
+    @Test
+    public void testResolveDefinition() {
+        Definition def = new Definition();
+        def.setName("testDef*.message*");
+        def.setTemplateAttribute(Attribute.createTemplateAttribute("/test{1}.jsp"));
+        def.putAttribute("body", new Attribute("message{2}"));
+        DefinitionPatternMatcher patternMatcher = new WildcardDefinitionPatternMatcher("testDef*.message*", def, new WildcardHelper());
+        Definition result = patternMatcher.createDefinition("testDefOne.messageTwo");
+        assertNotNull(result);
+        assertEquals("testDefOne.messageTwo", result.getName());
+        assertEquals("/testOne.jsp", result.getTemplateAttribute().getValue());
+        assertEquals("messageTwo", result.getAttribute("body").getValue());
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactoryTest.java
new file mode 100644
index 000000000..ccba2299b
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactoryTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.evaluator;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Expression;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests {@link BasicAttributeEvaluatorFactory}.
+ */
+public class BasicAttributeEvaluatorFactoryTest {
+
+    /**
+     * Test method for {@link BasicAttributeEvaluatorFactory#getAttributeEvaluator(String)}.
+     */
+    @Test
+    public void testGetAttributeEvaluatorString() {
+        AttributeEvaluator defaultEvaluator = createMock(AttributeEvaluator.class);
+        AttributeEvaluator evaluator1 = createMock(AttributeEvaluator.class);
+        AttributeEvaluator evaluator2 = createMock(AttributeEvaluator.class);
+        replay(defaultEvaluator, evaluator1, evaluator2);
+        BasicAttributeEvaluatorFactory factory = new BasicAttributeEvaluatorFactory(defaultEvaluator);
+        factory.registerAttributeEvaluator("LANG1", evaluator1);
+        factory.registerAttributeEvaluator("LANG2", evaluator2);
+        assertSame(evaluator1, factory.getAttributeEvaluator("LANG1"));
+        assertSame(evaluator2, factory.getAttributeEvaluator("LANG2"));
+        assertSame(defaultEvaluator, factory.getAttributeEvaluator("LANG3"));
+        verify(defaultEvaluator, evaluator1, evaluator2);
+    }
+
+    /**
+     * Test method for {@link BasicAttributeEvaluatorFactory#getAttributeEvaluator(Attribute)}.
+     */
+    @Test
+    public void testGetAttributeEvaluatorAttribute() {
+        AttributeEvaluator defaultEvaluator = createMock(AttributeEvaluator.class);
+        AttributeEvaluator evaluator1 = createMock(AttributeEvaluator.class);
+        AttributeEvaluator evaluator2 = createMock(AttributeEvaluator.class);
+        replay(defaultEvaluator, evaluator1, evaluator2);
+        BasicAttributeEvaluatorFactory factory = new BasicAttributeEvaluatorFactory(defaultEvaluator);
+        factory.registerAttributeEvaluator("LANG1", evaluator1);
+        factory.registerAttributeEvaluator("LANG2", evaluator2);
+        assertSame(evaluator1, factory
+            .getAttributeEvaluator(createExpressionAttribute("LANG1")));
+        assertSame(evaluator2, factory
+            .getAttributeEvaluator(createExpressionAttribute("LANG2")));
+        assertSame(defaultEvaluator, factory
+            .getAttributeEvaluator(createExpressionAttribute("LANG3")));
+        verify(defaultEvaluator, evaluator1, evaluator2);
+    }
+
+    /**
+     * Creates a sample attribute with an expression.
+     *
+     * @param language The expression language.
+     * @return The attribute.
+     */
+    private Attribute createExpressionAttribute(String language) {
+        return new Attribute(null, Expression.createExpression("myExpression", language), null, "string");
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/EvaluatorExceptionTest.java
similarity index 60%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/EvaluatorExceptionTest.java
index fc26afeb0..d3fc07215 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/EvaluatorExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,44 +17,35 @@
  * under the License.
  */
 
-package org.apache.tiles.api;
+package org.apache.tiles.core.evaluator;
 
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link TilesException}.
+ * Tests {@link EvaluationException}.
  */
-public class TilesExceptionTest {
-
-    @Test
-    public void testTilesException() {
-        TilesException exception = new TilesException();
-        assertNull(exception.getMessage());
-        assertNull(exception.getCause());
-    }
-
-    @Test
-    public void testTilesExceptionString() {
-        TilesException exception = new TilesException("my message");
-        assertEquals("my message", exception.getMessage());
-        assertNull(exception.getCause());
-    }
+public class EvaluatorExceptionTest {
 
+    /**
+     * Test method for {@link EvaluationException#EvaluationException(Throwable)}.
+     */
     @Test
-    public void testTilesExceptionThrowable() {
+    public void testEvaluationExceptionThrowable() {
         Throwable cause = new Throwable();
-        TilesException exception = new TilesException(cause);
+        EvaluationException exception = new EvaluationException(cause);
         assertEquals(cause.toString(), exception.getMessage());
         assertEquals(cause, exception.getCause());
     }
 
+    /**
+     * Test method for {@link EvaluationException#EvaluationException(String, Throwable)}.
+     */
     @Test
-    public void testTilesExceptionStringThrowable() {
+    public void testEvaluationExceptionStringThrowable() {
         Throwable cause = new Throwable();
-        TilesException exception = new TilesException("my message", cause);
+        EvaluationException exception = new EvaluationException("my message", cause);
         assertEquals("my message", exception.getMessage());
         assertEquals(cause, exception.getCause());
     }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluatorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluatorTest.java
new file mode 100644
index 000000000..1af84a7d0
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluatorTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.evaluator.impl;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Expression;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link DirectAttributeEvaluator}.
+ */
+public class DirectAttributeEvaluatorTest {
+
+    /**
+     * The evaluator to test.
+     */
+    private DirectAttributeEvaluator evaluator;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        evaluator = new DirectAttributeEvaluator();
+    }
+
+    /**
+     * Tests
+     * {@link DirectAttributeEvaluator#evaluate(Attribute, org.apache.tiles.request.Request)}.
+     */
+    @Test
+    public void testEvaluate() {
+        String expression = "This is an expression";
+        Attribute attribute = new Attribute(null, Expression.createExpression(expression, null), null, null);
+        Object result = evaluator.evaluate(attribute, null);
+        assertEquals("The expression has not been evaluated correctly", result, expression);
+        expression = "${attributeName}";
+        attribute.setExpressionObject(new Expression(expression));
+        result = evaluator.evaluate(attribute, null);
+        assertEquals("The expression has not been evaluated correctly", result, expression);
+    }
+
+    /**
+     * Tests
+     * {@link DirectAttributeEvaluator#evaluate(Attribute, org.apache.tiles.request.Request)}.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testEvaluateNullAttribute() {
+        evaluator.evaluate((Attribute) null, null);
+    }
+
+    /**
+     * Tests
+     * {@link DirectAttributeEvaluator#evaluate(String, org.apache.tiles.request.Request)}.
+     */
+    @Test
+    public void testEvaluateString() {
+        String expression = "This is an expression";
+        Object result = evaluator.evaluate(expression, null);
+        assertEquals("The expression has not been evaluated correctly", result, expression);
+        expression = "${attributeName}";
+        result = evaluator.evaluate(expression, null);
+        assertEquals("The expression has not been evaluated correctly", result, expression);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/factory/BasicPreparerFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/BasicPreparerFactoryTest.java
new file mode 100644
index 000000000..0e5ffed61
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/BasicPreparerFactoryTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.factory;
+
+import junit.framework.TestCase;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.preparer.ViewPreparer;
+import org.apache.tiles.core.prepare.factory.BasicPreparerFactory;
+import org.apache.tiles.request.Request;
+
+/**
+ * Tests the basic preparer factory.
+ */
+public class BasicPreparerFactoryTest extends TestCase {
+
+    /**
+     * The preparer factory.
+     */
+    private BasicPreparerFactory factory;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUp() {
+        factory = new BasicPreparerFactory();
+    }
+
+    /**
+     * Tests getting a preparer.
+     */
+    public void testGetPreparer() {
+        String name = MockViewPreparer.class.getName();
+        ViewPreparer p = factory.getPreparer(name, null);
+        assertNotNull(p);
+        assertTrue(p instanceof MockViewPreparer);
+
+        name = "org.doesnotexist.Class";
+        p = factory.getPreparer(name, null);
+        assertNull(p);
+    }
+
+    /**
+     * Mock view preparer.
+     *
+     * @version $Rev$ $Date$
+     */
+    public static class MockViewPreparer implements ViewPreparer {
+
+        /**
+         * {@inheritDoc}
+         */
+        public void execute(Request tilesContext, AttributeContext attributeContext) {
+        }
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/factory/BasicTilesContainerFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/BasicTilesContainerFactoryTest.java
new file mode 100644
index 000000000..788584650
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/BasicTilesContainerFactoryTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.factory;
+
+import junit.framework.TestCase;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.core.definition.DefinitionsFactory;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.apache.tiles.core.definition.UnresolvingLocaleDefinitionsFactory;
+import org.apache.tiles.core.definition.digester.DigesterDefinitionsReader;
+import org.apache.tiles.core.evaluator.AttributeEvaluatorFactory;
+import org.apache.tiles.core.evaluator.impl.DirectAttributeEvaluator;
+import org.apache.tiles.core.impl.BasicTilesContainer;
+import org.apache.tiles.core.locale.LocaleResolver;
+import org.apache.tiles.core.locale.impl.DefaultLocaleResolver;
+import org.apache.tiles.core.prepare.factory.BasicPreparerFactory;
+import org.apache.tiles.core.prepare.factory.PreparerFactory;
+import org.apache.tiles.core.renderer.DefinitionRenderer;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.locale.URLApplicationResource;
+import org.apache.tiles.request.render.BasicRendererFactory;
+import org.apache.tiles.request.render.ChainedDelegateRenderer;
+import org.apache.tiles.request.render.DispatchRenderer;
+import org.apache.tiles.request.render.Renderer;
+import org.apache.tiles.request.render.RendererFactory;
+import org.apache.tiles.request.render.StringRenderer;
+
+import java.util.List;
+import java.util.Objects;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests {@link BasicTilesContainerFactory}.
+ */
+public class BasicTilesContainerFactoryTest extends TestCase {
+
+    /**
+     * The factory to test.
+     */
+    private BasicTilesContainerFactory factory;
+
+    /**
+     * The context object.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * The resource to load.
+     */
+    private ApplicationResource resource;
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setUp() throws Exception {
+        applicationContext = createMock(ApplicationContext.class);
+        resource = new URLApplicationResource(
+            "/org/apache/tiles/core/config/tiles-defs.xml",
+            Objects.requireNonNull(getClass().getResource("/org/apache/tiles/core/config/tiles-defs.xml"))
+        );
+        expect(applicationContext.getResource("/WEB-INF/tiles.xml")).andReturn(resource);
+        replay(applicationContext);
+        factory = new BasicTilesContainerFactory();
+    }
+
+    /**
+     * Tests {@link BasicTilesContainerFactory#createContainer(ApplicationContext)}.
+     */
+    public void testCreateContainer() {
+        TilesContainer container = factory.createContainer(applicationContext);
+        assertTrue("The class of the container is not correct", container instanceof BasicTilesContainer);
+    }
+
+    /**
+     * Tests {@link BasicTilesContainerFactory#createDefinitionsFactory(
+     * ApplicationContext, LocaleResolver)}.
+     */
+    public void testCreateDefinitionsFactory() {
+        LocaleResolver resolver = factory.createLocaleResolver(applicationContext);
+        DefinitionsFactory defsFactory = factory.createDefinitionsFactory(applicationContext, resolver);
+        assertTrue("The class of the definitions factory is not correct",
+                defsFactory instanceof UnresolvingLocaleDefinitionsFactory);
+    }
+
+    /**
+     * Tests {@link BasicTilesContainerFactory#createLocaleResolver(
+     * ApplicationContext)}.
+     */
+    public void testCreateLocaleResolver() {
+        LocaleResolver localeResolver = factory.createLocaleResolver(applicationContext);
+        assertTrue("The class of the locale resolver is not correct", localeResolver instanceof DefaultLocaleResolver);
+    }
+
+    /**
+     * Tests {@link BasicTilesContainerFactory#createDefinitionsReader(
+     * ApplicationContext)}.
+     */
+    public void testCreateDefinitionsReader() {
+        DefinitionsReader reader = factory.createDefinitionsReader(applicationContext);
+        assertTrue("The class of the reader is not correct", reader instanceof DigesterDefinitionsReader);
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#getSources(ApplicationContext)}.
+     */
+    public void testGetSources() {
+        List<ApplicationResource> resources = factory.getSources(applicationContext);
+        assertEquals("The urls list is not one-sized", 1, resources.size());
+        assertEquals("The URL is not correct", resource, resources.get(0));
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#createAttributeEvaluatorFactory(
+     * ApplicationContext, LocaleResolver)}.
+     */
+    public void testCreateAttributeEvaluatorFactory() {
+        LocaleResolver resolver = factory.createLocaleResolver(applicationContext);
+        AttributeEvaluatorFactory attributeEvaluatorFactory = factory.createAttributeEvaluatorFactory(
+                applicationContext, resolver);
+        assertTrue("The class of the evaluator is not correct",
+                attributeEvaluatorFactory.getAttributeEvaluator((String) null) instanceof DirectAttributeEvaluator);
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#createPreparerFactory(ApplicationContext)}.
+     */
+    public void testCreatePreparerFactory() {
+        PreparerFactory preparerFactory = factory.createPreparerFactory(applicationContext);
+        assertTrue("The class of the preparer factory is not correct", preparerFactory instanceof BasicPreparerFactory);
+    }
+
+    /**
+     * Tests {@link BasicTilesContainerFactory#createRendererFactory(
+     * ApplicationContext, TilesContainer, AttributeEvaluatorFactory)}.
+     */
+    public void testCreateRendererFactory() {
+        TilesContainer container = factory.createContainer(applicationContext);
+        LocaleResolver resolver = factory.createLocaleResolver(applicationContext);
+        AttributeEvaluatorFactory attributeEvaluatorFactory = factory.createAttributeEvaluatorFactory(
+                applicationContext, resolver);
+        RendererFactory rendererFactory = factory.createRendererFactory(applicationContext, container,
+                attributeEvaluatorFactory);
+        assertTrue("The class of the renderer factory is not correct", rendererFactory instanceof BasicRendererFactory);
+        Renderer renderer = rendererFactory.getRenderer("string");
+        assertNotNull("The string renderer is null", renderer);
+        assertTrue("The string renderer class is not correct", renderer instanceof StringRenderer);
+        renderer = rendererFactory.getRenderer("template");
+        assertNotNull("The template renderer is null", renderer);
+        assertTrue("The template renderer class is not correct", renderer instanceof DispatchRenderer);
+        renderer = rendererFactory.getRenderer("definition");
+        assertNotNull("The definition renderer is null", renderer);
+        assertTrue("The definition renderer class is not correct", renderer instanceof DefinitionRenderer);
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#createDefaultAttributeRenderer(BasicRendererFactory,
+     * ApplicationContext, TilesContainer, AttributeEvaluatorFactory)}.
+     */
+    public void testCreateDefaultAttributeRenderer() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeEvaluatorFactory attributeEvaluatorFactory = createMock(AttributeEvaluatorFactory.class);
+        BasicRendererFactory rendererFactory = createMock(BasicRendererFactory.class);
+        Renderer stringRenderer = createMock(Renderer.class);
+        Renderer templateRenderer = createMock(Renderer.class);
+        Renderer definitionRenderer = createMock(Renderer.class);
+
+        expect(rendererFactory.getRenderer("string")).andReturn(stringRenderer);
+        expect(rendererFactory.getRenderer("template")).andReturn(templateRenderer);
+        expect(rendererFactory.getRenderer("definition")).andReturn(definitionRenderer);
+
+        replay(container, attributeEvaluatorFactory, rendererFactory);
+        Renderer renderer = factory.createDefaultAttributeRenderer(rendererFactory, applicationContext, container,
+                attributeEvaluatorFactory);
+        assertTrue("The default renderer class is not correct", renderer instanceof ChainedDelegateRenderer);
+        verify(container, attributeEvaluatorFactory, rendererFactory);
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#createStringAttributeRenderer(BasicRendererFactory,
+     * ApplicationContext, TilesContainer, AttributeEvaluatorFactory)}.
+     */
+    public void testCreateStringAttributeRenderer() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeEvaluatorFactory attributeEvaluatorFactory = createMock(AttributeEvaluatorFactory.class);
+        BasicRendererFactory rendererFactory = createMock(BasicRendererFactory.class);
+
+        replay(container, attributeEvaluatorFactory, rendererFactory);
+        Renderer renderer = factory.createStringAttributeRenderer(rendererFactory, applicationContext, container,
+                attributeEvaluatorFactory);
+        assertTrue("The renderer class is not correct", renderer instanceof StringRenderer);
+        verify(container, attributeEvaluatorFactory, rendererFactory);
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#createTemplateAttributeRenderer(BasicRendererFactory,
+     * ApplicationContext, TilesContainer, AttributeEvaluatorFactory)}.
+     */
+    public void testCreateTemplateAttributeRenderer() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeEvaluatorFactory attributeEvaluatorFactory = createMock(AttributeEvaluatorFactory.class);
+        BasicRendererFactory rendererFactory = createMock(BasicRendererFactory.class);
+
+        replay(container, attributeEvaluatorFactory, rendererFactory);
+        Renderer renderer = factory.createTemplateAttributeRenderer(rendererFactory, applicationContext, container,
+                attributeEvaluatorFactory);
+        assertTrue("The renderer class is not correct", renderer instanceof DispatchRenderer);
+        verify(container, attributeEvaluatorFactory, rendererFactory);
+    }
+
+    /**
+     * Tests
+     * {@link BasicTilesContainerFactory#createDefinitionAttributeRenderer(BasicRendererFactory,
+     * ApplicationContext, TilesContainer, AttributeEvaluatorFactory)}.
+     */
+    public void testCreateDefinitionAttributeRenderer() {
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeEvaluatorFactory attributeEvaluatorFactory = createMock(AttributeEvaluatorFactory.class);
+        BasicRendererFactory rendererFactory = createMock(BasicRendererFactory.class);
+
+        replay(container, attributeEvaluatorFactory, rendererFactory);
+        Renderer renderer = factory.createDefinitionAttributeRenderer(rendererFactory, applicationContext, container,
+                attributeEvaluatorFactory);
+        assertTrue("The renderer class is not correct", renderer instanceof DefinitionRenderer);
+        verify(container, attributeEvaluatorFactory, rendererFactory);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/NoSuchPreparerExceptionTest.java
similarity index 70%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/factory/NoSuchPreparerExceptionTest.java
index 777ecd57c..2255f1667 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/NoSuchPreparerExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,21 +17,25 @@
  * under the License.
  */
 
-package org.apache.tiles.api;
+package org.apache.tiles.core.factory;
 
+import org.apache.tiles.core.prepare.factory.NoSuchPreparerException;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link NoSuchContainerException}.
+ * Tests {@link NoSuchPreparerException}.
  */
-public class NoSuchContainerExceptionTest {
+public class NoSuchPreparerExceptionTest {
 
+    /**
+     * Test method for {@link NoSuchPreparerException#NoSuchPreparerException(String)}.
+     */
     @Test
-    public void testNoSuchContainerExceptionString() {
-        NoSuchContainerException exception = new NoSuchContainerException("my message");
+    public void testNoSuchPreparerExceptionString() {
+        NoSuchPreparerException exception = new NoSuchPreparerException("my message");
         assertEquals("my message", exception.getMessage());
         assertNull(exception.getCause());
     }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/TilesContainerFactoryExceptionTest.java
similarity index 64%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/factory/TilesContainerFactoryExceptionTest.java
index 777ecd57c..bc1aaec3d 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/NoSuchContainerExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/factory/TilesContainerFactoryExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,23 +17,26 @@
  * under the License.
  */
 
-package org.apache.tiles.api;
+package org.apache.tiles.core.factory;
 
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link NoSuchContainerException}.
+ * Tests {@link TilesContainerFactoryException}.
  */
-public class NoSuchContainerExceptionTest {
+public class TilesContainerFactoryExceptionTest {
 
+    /**
+     * Test method for {@link TilesContainerFactoryException#TilesContainerFactoryException(String, Throwable)}.
+     */
     @Test
-    public void testNoSuchContainerExceptionString() {
-        NoSuchContainerException exception = new NoSuchContainerException("my message");
+    public void testTilesContainerFactoryExceptionStringThrowable() {
+        Throwable cause = new Throwable();
+        TilesContainerFactoryException exception = new TilesContainerFactoryException("my message", cause);
         assertEquals("my message", exception.getMessage());
-        assertNull(exception.getCause());
+        assertEquals(cause, exception.getCause());
     }
 
 }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/impl/BasicTilesContainerTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/BasicTilesContainerTest.java
new file mode 100644
index 000000000..2e7328481
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/BasicTilesContainerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.impl;
+
+import junit.framework.TestCase;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.core.factory.AbstractTilesContainerFactory;
+import org.apache.tiles.core.factory.BasicTilesContainerFactory;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.locale.URLApplicationResource;
+import org.apache.tiles.request.render.CannotRenderException;
+import org.easymock.EasyMock;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Objects;
+
+public class BasicTilesContainerTest extends TestCase {
+
+    /**
+     * A sample integer value to check object rendering.
+     */
+    private static final int SAMPLE_INT = 15;
+
+    /**
+     * The container.
+     */
+    private BasicTilesContainer container;
+
+    @Override
+    public void setUp() {
+        ApplicationContext context = EasyMock.createMock(ApplicationContext.class);
+        URLApplicationResource resource = new URLApplicationResource(
+            "/WEB-INF/tiles.xml",
+            Objects.requireNonNull(getClass().getResource("/org/apache/tiles/core/factory/test-defs.xml"))
+        );
+
+        EasyMock.expect(context.getResource("/WEB-INF/tiles.xml")).andReturn(resource);
+        EasyMock.replay(context);
+        AbstractTilesContainerFactory factory = new BasicTilesContainerFactory();
+        container = (BasicTilesContainer) factory.createContainer(context);
+    }
+
+    /**
+     * Tests basic Tiles container initialization.
+     */
+    public void testInitialization() {
+        assertNotNull(container);
+    }
+
+    /**
+     * Tests that attributes of type "object" won't be rendered.
+     *
+     * @throws IOException If something goes wrong, but it's not a Tiles
+     *                     exception.
+     */
+    public void testObjectAttribute() throws IOException {
+        Attribute attribute = new Attribute();
+        Request request = EasyMock.createMock(Request.class);
+        EasyMock.replay(request);
+        boolean exceptionFound = false;
+
+        attribute.setValue(SAMPLE_INT);
+        try {
+            container.render(attribute, request);
+        } catch (CannotRenderException e) {
+            exceptionFound = true;
+        }
+
+        assertTrue("An attribute of 'object' type cannot be rendered", exceptionFound);
+    }
+
+    /**
+     * Tests is attributes are rendered correctly according to users roles.
+     *
+     * @throws IOException If a problem arises during rendering or writing in the writer.
+     */
+    public void testAttributeCredentials() throws IOException {
+        Request request = EasyMock.createMock(Request.class);
+        EasyMock.expect(request.isUserInRole("myrole")).andReturn(Boolean.TRUE);
+        StringWriter writer = new StringWriter();
+        EasyMock.expect(request.getWriter()).andReturn(writer);
+        EasyMock.replay(request);
+        Attribute attribute = new Attribute("This is the value", "myrole");
+        attribute.setRenderer("string");
+        container.render(attribute, request);
+        writer.close();
+        assertEquals("The attribute should have been rendered", "This is the value", writer.toString());
+        EasyMock.reset(request);
+        request = EasyMock.createMock(Request.class);
+        EasyMock.expect(request.isUserInRole("myrole")).andReturn(Boolean.FALSE);
+        EasyMock.replay(request);
+        writer = new StringWriter();
+        container.render(attribute, request);
+        writer.close();
+        assertNotSame("The attribute should have not been rendered", "This is the value", writer.toString());
+    }
+
+    /**
+     * Tests {@link BasicTilesContainer#evaluate(Attribute, Request)}.
+     */
+    public void testEvaluate() {
+        Request request = EasyMock.createMock(Request.class);
+        EasyMock.replay(request);
+        Attribute attribute = new Attribute("This is the value");
+        Object value = container.evaluate(attribute, request);
+        assertEquals("The attribute has not been evaluated correctly", "This is the value", value);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/impl/BasicTilesContainerUnitTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/BasicTilesContainerUnitTest.java
new file mode 100644
index 000000000..7f4c9d0c4
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/BasicTilesContainerUnitTest.java
@@ -0,0 +1,836 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.impl;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.BasicAttributeContext;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.preparer.ViewPreparer;
+import org.apache.tiles.core.definition.DefinitionsFactory;
+import org.apache.tiles.core.definition.NoSuchDefinitionException;
+import org.apache.tiles.core.evaluator.AttributeEvaluator;
+import org.apache.tiles.core.evaluator.AttributeEvaluatorFactory;
+import org.apache.tiles.core.prepare.factory.NoSuchPreparerException;
+import org.apache.tiles.core.prepare.factory.PreparerFactory;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.render.CannotRenderException;
+import org.apache.tiles.request.render.NoSuchRendererException;
+import org.apache.tiles.request.render.Renderer;
+import org.apache.tiles.request.render.RendererFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link BasicTilesContainer}.
+ */
+public class BasicTilesContainerUnitTest {
+
+    /**
+     * Name used to store attribute context stack.
+     */
+    private static final String ATTRIBUTE_CONTEXT_STACK =
+        "org.apache.tiles.AttributeContext.STACK";
+
+    /**
+     * The application context.
+     */
+    private ApplicationContext applicationContext;
+
+    /**
+     * The definitions factory.
+     */
+    private DefinitionsFactory definitionsFactory;
+
+    /**
+     * The preparer factory.
+     */
+    private PreparerFactory preparerFactory;
+
+    /**
+     * The renderer factory.
+     */
+    private RendererFactory rendererFactory;
+
+    /**
+     * The evaluator factory.
+     */
+    private AttributeEvaluatorFactory attributeEvaluatorFactory;
+
+    /**
+     * The container to test.
+     */
+    private BasicTilesContainer container;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        applicationContext = createMock(ApplicationContext.class);
+        definitionsFactory = createMock(DefinitionsFactory.class);
+        preparerFactory = createMock(PreparerFactory.class);
+        rendererFactory = createMock(RendererFactory.class);
+        attributeEvaluatorFactory = createMock(AttributeEvaluatorFactory.class);
+        container = new BasicTilesContainer();
+        container.setApplicationContext(applicationContext);
+        container.setAttributeEvaluatorFactory(attributeEvaluatorFactory);
+        container.setDefinitionsFactory(definitionsFactory);
+        container.setPreparerFactory(preparerFactory);
+        container.setRendererFactory(rendererFactory);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#startContext(Request)}.
+     */
+    @Test
+    public void testStartContext() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+        expect(attributeContext.getCascadedAttributeNames()).andReturn(null);
+        deque.push(isA(BasicAttributeContext.class));
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        assertTrue(container.startContext(request) instanceof BasicAttributeContext);
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#endContext(Request)}.
+     */
+    @Test
+    public void testEndContext() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.pop()).andReturn(attributeContext);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        container.endContext(request);
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#renderContext(Request)}.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void testRenderContext() throws IOException {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ViewPreparer preparer = createMock(ViewPreparer.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        Renderer renderer = createMock(Renderer.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+        expect(attributeContext.getPreparer()).andReturn(null);
+        expect(attributeContext.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(rendererFactory.getRenderer("renderer")).andReturn(renderer);
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/mytemplate.jsp");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        renderer.render("/mytemplate.jsp", request);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, templateAttribute, renderer);
+        container.renderContext(request);
+        verify(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, templateAttribute, renderer);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getApplicationContext()}.
+     */
+    @Test
+    public void testGetApplicationContext() {
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory);
+        assertEquals(applicationContext, container.getApplicationContext());
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getAttributeContext(Request)}.
+     */
+    @Test
+    public void testGetAttributeContext() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        assertEquals(attributeContext, container.getAttributeContext(request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getAttributeContext(Request)}.
+     */
+    @Test
+    public void testGetAttributeContextNew() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope).times(2);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque).times(2);
+        expect(deque.isEmpty()).andReturn(true);
+        deque.push(isA(BasicAttributeContext.class));
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        assertTrue(container.getAttributeContext(request) instanceof BasicAttributeContext);
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#prepare(String, Request)}.
+     */
+    @Test
+    public void testPrepare() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ViewPreparer preparer = createMock(ViewPreparer.class);
+
+        expect(preparerFactory.getPreparer("preparer", request)).andReturn(preparer);
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+        preparer.execute(request, attributeContext);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer);
+        container.prepare("preparer", request);
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#prepare(String, Request)}.
+     */
+    @Test(expected = NoSuchPreparerException.class)
+    public void testPrepareException() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(preparerFactory.getPreparer("preparer", request)).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        try {
+            container.prepare("preparer", request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request, requestScope, deque, attributeContext);
+        }
+    }
+
+    @Test
+    public void testRenderStringRequest() throws IOException {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ViewPreparer preparer = createMock(ViewPreparer.class);
+        Renderer renderer = createMock(Renderer.class);
+        Definition definition = createMock(Definition.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+
+        expect(definitionsFactory.getDefinition("definition", request)).andReturn(definition);
+        expect(request.getContext("request")).andReturn(requestScope).times(3);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque).times(3);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+        expect(attributeContext.getPreparer()).andReturn(null);
+        expect(attributeContext.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(attributeContext.getLocalAttributeNames()).andReturn(null);
+        expect(attributeContext.getCascadedAttributeNames()).andReturn(null);
+        expect(definition.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(rendererFactory.getRenderer("template")).andReturn(renderer);
+        deque.push(isA(BasicAttributeContext.class));
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/my/template.jsp");
+        renderer.render("/my/template.jsp", request);
+        expect(deque.pop()).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, renderer, definition);
+        container.render("definition", request);
+        verify(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, renderer, definition);
+    }
+
+    @Test(expected = NoSuchDefinitionException.class)
+    public void testRenderStringRequestException() {
+        Request request = createMock(Request.class);
+
+        expect(definitionsFactory.getDefinition("definition", request)).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request);
+        try {
+            container.render("definition", request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory,
+                definitionsFactory, preparerFactory, rendererFactory);
+        }
+    }
+
+    @Test
+    public void testRenderAttributeRequest() throws IOException {
+        Request request = createMock(Request.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        Renderer renderer = createMock(Renderer.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(rendererFactory.getRenderer("renderer")).andReturn(renderer);
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/mytemplate.jsp");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        renderer.render("/mytemplate.jsp", request);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute, renderer);
+        container.render(templateAttribute, request);
+        verify(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute, renderer);
+    }
+
+    @Test(expected = CannotRenderException.class)
+    public void testRenderAttributeRequestException1() throws IOException {
+        Request request = createMock(Request.class);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request);
+        try {
+            container.render((Attribute) null, request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request);
+        }
+    }
+
+    @Test(expected = NoSuchRendererException.class)
+    public void testRenderAttributeRequestException2() throws IOException {
+        Request request = createMock(Request.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        expect(rendererFactory.getRenderer("renderer")).andThrow(new NoSuchRendererException("Boom!"));
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute);
+        try {
+            container.render(templateAttribute, request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory, evaluator,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request, templateAttribute);
+        }
+    }
+
+    @Test(expected = CannotRenderException.class)
+    public void testRenderAttributeRequestException3() throws IOException {
+        Request request = createMock(Request.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+        Renderer renderer = createMock(Renderer.class);
+
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        expect(rendererFactory.getRenderer("renderer")).andReturn(renderer);
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn(1);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute);
+        try {
+            container.render(templateAttribute, request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory, evaluator,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request, templateAttribute);
+        }
+    }
+
+    @Test(expected = NoSuchRendererException.class)
+    public void testRenderAttributeRequestException() throws IOException {
+        Request request = createMock(Request.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        expect(rendererFactory.getRenderer("renderer")).andThrow(new NoSuchRendererException("Boom!"));
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute);
+        try {
+            container.render(templateAttribute, request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory, evaluator,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request, templateAttribute);
+        }
+    }
+
+    @Test
+    public void testEvaluate() {
+        Request request = createMock(Request.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn(1);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute, evaluator);
+        assertEquals(1, container.evaluate(templateAttribute, request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            templateAttribute, evaluator);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#isValidDefinition(String, Request)}.
+     */
+    @Test
+    public void testIsValidDefinition() {
+        Request request = createMock(Request.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(definitionsFactory.getDefinition("definition", request)).andReturn(definition);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request, definition);
+        assertTrue(container.isValidDefinition("definition", request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request, definition);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#isValidDefinition(String, Request)}.
+     */
+    @Test
+    public void testIsValidDefinitionNull() {
+        Request request = createMock(Request.class);
+
+        expect(definitionsFactory.getDefinition("definition", request)).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request);
+        assertFalse(container.isValidDefinition("definition", request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#isValidDefinition(String, Request)}.
+     */
+    @Test
+    public void testIsValidDefinitionException() {
+        Request request = createMock(Request.class);
+
+        expect(definitionsFactory.getDefinition("definition", request))
+            .andThrow(new NoSuchDefinitionException("Boom!"));
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request);
+        assertFalse(container.isValidDefinition("definition", request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getDefinition(String, Request)}.
+     */
+    @Test
+    public void testGetDefinition() {
+        Request request = createMock(Request.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(definitionsFactory.getDefinition("definition", request)).andReturn(definition);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request, definition);
+        assertEquals(definition, container.getDefinition("definition", request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request, definition);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getContextStack(Request)}.
+     */
+    @Test
+    public void testGetContextStack() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque);
+        assertEquals(deque, container.getContextStack(request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getContextStack(Request)}.
+     */
+    @Test
+    public void testGetContextStackNew() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(null);
+        expect(requestScope.put(eq(ATTRIBUTE_CONTEXT_STACK), isA(LinkedList.class))).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope);
+        assertTrue(container.getContextStack(request) instanceof LinkedList);
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope);
+    }
+
+    @Test
+    public void testPushContext() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        deque.push(attributeContext);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        container.pushContext(attributeContext, request);
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#popContext(Request)}.
+     */
+    @Test
+    public void testPopContext() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.pop()).andReturn(attributeContext);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        assertEquals(attributeContext, container.popContext(request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getContext(Request)}.
+     */
+    @Test
+    public void testGetContext() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+        assertEquals(attributeContext, container.getContext(request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext);
+    }
+
+    /**
+     * Test method for {@link BasicTilesContainer#getContext(Request)}.
+     */
+    @Test
+    public void testGetContextNull() {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque);
+        expect(deque.isEmpty()).andReturn(true);
+
+        replay(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque);
+        assertNull(container.getContext(request));
+        verify(applicationContext, attributeEvaluatorFactory,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque);
+    }
+
+    @Test
+    public void testRenderRequestDefinition() throws IOException {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ViewPreparer preparer = createMock(ViewPreparer.class);
+        Renderer renderer = createMock(Renderer.class);
+        Definition definition = createMock(Definition.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+
+        expect(request.getContext("request")).andReturn(requestScope).times(3);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque).times(3);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+        expect(attributeContext.getPreparer()).andReturn(null);
+        expect(attributeContext.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(attributeContext.getLocalAttributeNames()).andReturn(null);
+        expect(attributeContext.getCascadedAttributeNames()).andReturn(null);
+        expect(definition.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(rendererFactory.getRenderer("template")).andReturn(renderer);
+        deque.push(isA(BasicAttributeContext.class));
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/my/template.jsp");
+        renderer.render("/my/template.jsp", request);
+        expect(deque.pop()).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, renderer, definition);
+        container.render(definition, request);
+        verify(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, renderer, definition);
+    }
+
+    @Test(expected = CannotRenderException.class)
+    public void testRenderRequestDefinitionException() throws IOException {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ViewPreparer preparer = createMock(ViewPreparer.class);
+        Renderer renderer = createMock(Renderer.class);
+        Definition definition = createMock(Definition.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        Attribute templateAttribute = Attribute.createTemplateAttribute("/my/template.jsp");
+
+        expect(request.getContext("request")).andReturn(requestScope).times(3);
+        expect(requestScope.get(ATTRIBUTE_CONTEXT_STACK)).andReturn(deque).times(3);
+        expect(deque.isEmpty()).andReturn(false);
+        expect(deque.peek()).andReturn(attributeContext);
+        expect(attributeContext.getPreparer()).andReturn(null);
+        expect(attributeContext.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(attributeContext.getLocalAttributeNames()).andReturn(null);
+        expect(attributeContext.getCascadedAttributeNames()).andReturn(null);
+        expect(definition.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(rendererFactory.getRenderer("template")).andReturn(renderer);
+        deque.push(isA(BasicAttributeContext.class));
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/mytemplate.jsp");
+        renderer.render("/mytemplate.jsp", request);
+        expectLastCall().andThrow(new IOException());
+        expect(deque.pop()).andReturn(null);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, renderer, definition);
+        try {
+            container.render(definition, request);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory, evaluator,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request, requestScope, deque, attributeContext, preparer,
+                renderer, definition);
+        }
+    }
+
+    @Test
+    public void testRenderRequestAttributeContext() throws IOException {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        ViewPreparer preparer = createMock(ViewPreparer.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        Renderer renderer = createMock(Renderer.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        expect(attributeContext.getPreparer()).andReturn(null);
+        expect(attributeContext.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(rendererFactory.getRenderer("renderer")).andReturn(renderer);
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/mytemplate.jsp");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        renderer.render("/mytemplate.jsp", request);
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, templateAttribute, renderer);
+        container.render(request, attributeContext);
+        verify(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, preparer, templateAttribute, renderer);
+    }
+
+    @Test(expected = CannotRenderException.class)
+    public void testRenderRequestAttributeContextException() throws IOException {
+        Request request = createMock(Request.class);
+        Map<String, Object> requestScope = createMock(Map.class);
+        Deque<AttributeContext> deque = createMock(Deque.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute templateAttribute = createMock(Attribute.class);
+        Renderer renderer = createMock(Renderer.class);
+        AttributeEvaluator evaluator = createMock(AttributeEvaluator.class);
+
+        expect(attributeContext.getPreparer()).andReturn("preparer").times(2);
+        expect(preparerFactory.getPreparer("preparer", request)).andReturn(null);
+        expect(attributeContext.getTemplateAttribute()).andReturn(templateAttribute);
+        expect(templateAttribute.getRenderer()).andReturn("renderer");
+        expect(rendererFactory.getRenderer("renderer")).andReturn(renderer);
+        expect(attributeEvaluatorFactory.getAttributeEvaluator(templateAttribute)).andReturn(evaluator);
+        expect(evaluator.evaluate(templateAttribute, request)).andReturn("/mytemplate.jsp");
+        expect(templateAttribute.isPermitted(request)).andReturn(true);
+        renderer.render("/mytemplate.jsp", request);
+        expectLastCall().andThrow(new IOException());
+
+        replay(applicationContext, attributeEvaluatorFactory, evaluator,
+            definitionsFactory, preparerFactory, rendererFactory, request,
+            requestScope, deque, attributeContext, templateAttribute, renderer);
+        try {
+            container.render(request, attributeContext);
+        } finally {
+            verify(applicationContext, attributeEvaluatorFactory, evaluator,
+                definitionsFactory, preparerFactory, rendererFactory,
+                request, requestScope, deque, attributeContext,
+                templateAttribute, renderer);
+        }
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/CannotRenderExceptionTest.java
similarity index 59%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/impl/CannotRenderExceptionTest.java
index fc26afeb0..77fb1202b 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/CannotRenderExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,44 +17,36 @@
  * under the License.
  */
 
-package org.apache.tiles.api;
+package org.apache.tiles.core.impl;
 
+import org.apache.tiles.request.render.CannotRenderException;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link TilesException}.
+ * Tests {@link CannotRenderException}.
  */
-public class TilesExceptionTest {
-
-    @Test
-    public void testTilesException() {
-        TilesException exception = new TilesException();
-        assertNull(exception.getMessage());
-        assertNull(exception.getCause());
-    }
+public class CannotRenderExceptionTest {
 
+    /**
+     * Test method for {@link CannotRenderException#CannotRenderException(String)}.
+     */
     @Test
-    public void testTilesExceptionString() {
-        TilesException exception = new TilesException("my message");
+    public void testCannotRenderExceptionString() {
+        CannotRenderException exception = new CannotRenderException("my message");
         assertEquals("my message", exception.getMessage());
         assertNull(exception.getCause());
     }
 
+    /**
+     * Test method for {@link CannotRenderException#CannotRenderException(String, Throwable)}.
+     */
     @Test
-    public void testTilesExceptionThrowable() {
-        Throwable cause = new Throwable();
-        TilesException exception = new TilesException(cause);
-        assertEquals(cause.toString(), exception.getMessage());
-        assertEquals(cause, exception.getCause());
-    }
-
-    @Test
-    public void testTilesExceptionStringThrowable() {
+    public void testCannotRenderExceptionStringThrowable() {
         Throwable cause = new Throwable();
-        TilesException exception = new TilesException("my message", cause);
+        CannotRenderException exception = new CannotRenderException("my message", cause);
         assertEquals("my message", exception.getMessage());
         assertEquals(cause, exception.getCause());
     }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/impl/DefaultLocaleResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/DefaultLocaleResolverTest.java
new file mode 100644
index 000000000..8b678ddb1
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/DefaultLocaleResolverTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.impl;
+
+import org.apache.tiles.core.locale.impl.DefaultLocaleResolver;
+import org.apache.tiles.request.Request;
+import org.junit.Test;
+
+import java.util.Locale;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests {@link DefaultLocaleResolver}.
+ */
+public class DefaultLocaleResolverTest {
+
+    /**
+     * Test method for {@link DefaultLocaleResolver#resolveLocale(Request)}.
+     */
+    @Test
+    public void testResolveLocale() {
+        Request request = createMock(Request.class);
+        Map<String, Object> sessionScope = createMock(Map.class);
+        Locale locale = Locale.ITALY;
+
+        expect(request.getContext("session")).andReturn(sessionScope);
+        expect(sessionScope.get(DefaultLocaleResolver.LOCALE_KEY)).andReturn(null);
+        expect(request.getRequestLocale()).andReturn(locale);
+
+        replay(request, sessionScope);
+        DefaultLocaleResolver resolver = new DefaultLocaleResolver();
+        assertSame(locale, resolver.resolveLocale(request));
+        verify(request, sessionScope);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/InvalidTemplateExceptionTest.java
similarity index 59%
copy from plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
copy to plugins/tiles/src/test/java/org/apache/tiles/core/impl/InvalidTemplateExceptionTest.java
index fc26afeb0..60e0e0bb4 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/TilesExceptionTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/InvalidTemplateExceptionTest.java
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * 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
@@ -19,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.tiles.api;
+package org.apache.tiles.core.impl;
 
 import org.junit.Test;
 
@@ -27,38 +25,29 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 /**
- * Tests {@link TilesException}.
+ * Tests {@link InvalidTemplateException}.
  */
-public class TilesExceptionTest {
-
-    @Test
-    public void testTilesException() {
-        TilesException exception = new TilesException();
-        assertNull(exception.getMessage());
-        assertNull(exception.getCause());
-    }
+public class InvalidTemplateExceptionTest {
 
+    /**
+     * Test method for {@link InvalidTemplateException#InvalidTemplateException(String)}.
+     */
     @Test
-    public void testTilesExceptionString() {
-        TilesException exception = new TilesException("my message");
+    public void testInvalidTemplateExceptionString() {
+        InvalidTemplateException exception = new InvalidTemplateException("my message");
         assertEquals("my message", exception.getMessage());
         assertNull(exception.getCause());
     }
 
+    /**
+     * Test method for {@link InvalidTemplateException#InvalidTemplateException(Throwable)}.
+     */
     @Test
-    public void testTilesExceptionThrowable() {
+    public void testInvalidTemplateExceptionThrowable() {
         Throwable cause = new Throwable();
-        TilesException exception = new TilesException(cause);
+        InvalidTemplateException exception = new InvalidTemplateException(cause);
         assertEquals(cause.toString(), exception.getMessage());
         assertEquals(cause, exception.getCause());
     }
 
-    @Test
-    public void testTilesExceptionStringThrowable() {
-        Throwable cause = new Throwable();
-        TilesException exception = new TilesException("my message", cause);
-        assertEquals("my message", exception.getMessage());
-        assertEquals(cause, exception.getCause());
-    }
-
 }
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainerTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainerTest.java
new file mode 100644
index 000000000..d32fcfa2d
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainerTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.impl.mgmt;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.core.definition.NoSuchDefinitionException;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link CachingTilesContainer}.
+ *
+ * @version $Rev$ $Date$
+ */
+public class CachingTilesContainerTest {
+
+    /**
+     * The default name of the attribute in which storing custom definitions.
+     */
+    private static final String DEFAULT_DEFINITIONS_ATTRIBUTE_NAME =
+        "org.apache.tiles.impl.mgmt.DefinitionManager.DEFINITIONS";
+
+    /**
+     * The wrapped Tiles container.
+     */
+    private TilesContainer wrapped;
+
+    /**
+     * The Tiles container to test.
+     */
+    private CachingTilesContainer container;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        wrapped = createMock(TilesContainer.class);
+        container = new CachingTilesContainer(wrapped);
+    }
+
+    @Test
+    public void testCachingTilesContainer() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+        TilesContainer wrapped = createMock(TilesContainer.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(definitions);
+        expect(definitions.get("definition")).andReturn(definition);
+
+        replay(wrapped, request, definitions, scope, definition);
+        CachingTilesContainer container = new CachingTilesContainer(wrapped);
+        assertSame(definition, container.getDefinition("definition", request));
+        verify(wrapped, request, definitions, scope, definition);
+    }
+
+    @Test
+    public void testGetDefinition() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(
+            definitions);
+        expect(definitions.get("definition")).andReturn(definition);
+
+        replay(wrapped, request, definitions, scope, definition);
+        assertSame(definition, container.getDefinition("definition", request));
+        verify(wrapped, request, definitions, scope, definition);
+    }
+
+    @Test
+    public void testGetDefinitionContainer() {
+        Request request = createMock(Request.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(
+            null);
+        expect(wrapped.getDefinition("definition", request)).andReturn(
+            definition);
+
+        replay(wrapped, request, scope, definition);
+        assertSame(definition, container.getDefinition("definition", request));
+        verify(wrapped, request, scope, definition);
+    }
+
+    @Test
+    public void testIsValidDefinition() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(definitions);
+        expect(definitions.get("definition")).andReturn(definition);
+
+        replay(wrapped, request, definitions, scope, definition);
+        assertTrue(container.isValidDefinition("definition", request));
+        verify(wrapped, request, definitions, scope, definition);
+    }
+
+    @Test
+    public void testIsValidDefinitionContainer() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(definitions);
+        expect(definitions.get("definition")).andReturn(null);
+        expect(wrapped.isValidDefinition("definition", request)).andReturn(true);
+
+        replay(wrapped, request, definitions, scope);
+        assertTrue(container.isValidDefinition("definition", request));
+        verify(wrapped, request, definitions, scope);
+    }
+
+    @Test
+    public void testRegister() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(definitions);
+        expect(definition.getName()).andReturn(null);
+        expect(definitions.containsKey("$anonymousMutableDefinition1")).andReturn(false);
+        definition.setName("$anonymousMutableDefinition1");
+        expect(definition.isExtending()).andReturn(true);
+        // trick to test resolve definition separately.
+        expect(definition.isExtending()).andReturn(false);
+        expect(definition.getName()).andReturn("$anonymousMutableDefinition1");
+        expect(definitions.put("$anonymousMutableDefinition1", definition)).andReturn(null);
+
+        replay(wrapped, request, definitions, scope, definition);
+        container.register(definition, request);
+        verify(wrapped, request, definitions, scope, definition);
+    }
+
+    @Test
+    public void testRegisterInheritance() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+        Definition parent = createMock(Definition.class);
+        Definition grandparent = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope).anyTimes();
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(
+            definitions).anyTimes();
+        expect(definition.getName()).andReturn(null);
+        expect(definitions.containsKey("$anonymousMutableDefinition1"))
+            .andReturn(false);
+        definition.setName("$anonymousMutableDefinition1");
+        expect(definition.isExtending()).andReturn(true);
+        // trick to test resolve definition separately.
+        expect(definition.isExtending()).andReturn(true);
+        expect(definition.getExtends()).andReturn("parent");
+        expect(definitions.get("parent")).andReturn(parent);
+        expect(parent.isExtending()).andReturn(true);
+        expect(parent.getExtends()).andReturn("grandparent");
+        expect(definition.getName()).andReturn("$anonymousMutableDefinition1");
+        expect(definitions.get("grandparent")).andReturn(null);
+        expect(wrapped.getDefinition("grandparent", request)).andReturn(
+            grandparent);
+        parent.inherit(grandparent);
+        definition.inherit(parent);
+        expect(definitions.put("$anonymousMutableDefinition1", definition))
+            .andReturn(null);
+
+        replay(wrapped, request, definitions, scope, definition, parent,
+            grandparent);
+        container.register(definition, request);
+        verify(wrapped, request, definitions, scope, definition, parent,
+            grandparent);
+    }
+
+    @Test(expected = NoSuchDefinitionException.class)
+    public void testRegisterInheritanceFail() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope).anyTimes();
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(
+            definitions).anyTimes();
+        expect(definition.getName()).andReturn(null);
+        expect(definitions.containsKey("$anonymousMutableDefinition1"))
+            .andReturn(false);
+        definition.setName("$anonymousMutableDefinition1");
+        expect(definition.isExtending()).andReturn(true);
+        // trick to test resolve definition separately.
+        expect(definition.isExtending()).andReturn(true);
+        expect(definition.getExtends()).andReturn("parent");
+        expect(definitions.get("parent")).andReturn(null);
+        expect(wrapped.getDefinition("parent", request)).andReturn(null);
+        expect(definition.getName()).andReturn("$anonymousMutableDefinition1");
+
+        replay(wrapped, request, definitions, scope, definition);
+        try {
+            container.register(definition, request);
+        } finally {
+            verify(wrapped, request, definitions, scope, definition);
+        }
+    }
+
+    @Test
+    public void testRegisterCreateDefinitions() {
+        Request request = createMock(Request.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope).anyTimes();
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(
+            null);
+        expect(scope.put(eq(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME), isA(HashMap.class))).andReturn(null);
+        expect(definition.getName()).andReturn(null);
+        definition.setName("$anonymousMutableDefinition1");
+        expect(definition.isExtending()).andReturn(true);
+        // trick to test resolve definition separately.
+        expect(definition.isExtending()).andReturn(false);
+        expect(definition.getName()).andReturn("$anonymousMutableDefinition1");
+
+        replay(wrapped, request, scope, definition);
+        container.register(definition, request);
+        verify(wrapped, request, scope, definition);
+    }
+
+    @Test
+    public void testRender() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+        Definition definition = createMock(Definition.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(definitions);
+        expect(definitions.get("definition")).andReturn(definition);
+        container.render(definition, request);
+
+        replay(wrapped, request, definitions, scope, definition);
+        container.render("definition", request);
+        verify(wrapped, request, definitions, scope, definition);
+    }
+
+    @Test(expected = NoSuchDefinitionException.class)
+    public void testRenderFail() {
+        Request request = createMock(Request.class);
+        Map<String, Definition> definitions = createMock(Map.class);
+        Map<String, Object> scope = createMock(Map.class);
+
+        expect(request.getContext("request")).andReturn(scope);
+        expect(scope.get(DEFAULT_DEFINITIONS_ATTRIBUTE_NAME)).andReturn(definitions);
+        expect(definitions.get("definition")).andReturn(null);
+        expect(wrapped.getDefinition("definition", request)).andReturn(null);
+
+        replay(wrapped, request, definitions, scope);
+        try {
+            container.render("definition", request);
+        } finally {
+            verify(wrapped, request, definitions, scope);
+        }
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/renderer/DefinitionRendererTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/renderer/DefinitionRendererTest.java
new file mode 100644
index 000000000..70e6fba58
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/renderer/DefinitionRendererTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.renderer;
+
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.render.CannotRenderException;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link DefinitionRenderer}.
+ */
+public class DefinitionRendererTest {
+
+    /**
+     * The renderer.
+     */
+    private DefinitionRenderer renderer;
+
+    /**
+     * The container.
+     */
+    private TilesContainer container;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Before
+    public void setUp() {
+        container = createMock(TilesContainer.class);
+        renderer = new DefinitionRenderer(container);
+    }
+
+    /**
+     * Tests
+     * {@link DefinitionRenderer#render(String, Request)}.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test
+    public void testWrite() throws IOException {
+        Request requestContext = createMock(Request.class);
+        container.render("my.definition", requestContext);
+        replay(requestContext, container);
+        renderer.render("my.definition", requestContext);
+        verify(requestContext, container);
+    }
+
+    /**
+     * Tests
+     * {@link DefinitionRenderer#render(String, Request)}.
+     *
+     * @throws IOException If something goes wrong during rendition.
+     */
+    @Test(expected = CannotRenderException.class)
+    public void testRenderException() throws IOException {
+        Request requestContext = createMock(Request.class);
+        replay(requestContext, container);
+        try {
+            renderer.render(null, requestContext);
+        } finally {
+            verify(requestContext, container);
+        }
+    }
+
+    /**
+     * Tests
+     * {@link DefinitionRenderer#isRenderable(String, Request)}
+     * .
+     */
+    @Test
+    public void testIsRenderable() {
+        Request requestContext = createMock(Request.class);
+        expect(container.isValidDefinition("my.definition", requestContext)).andReturn(Boolean.TRUE);
+        replay(requestContext, container);
+        assertTrue(renderer.isRenderable("my.definition", requestContext));
+        assertFalse(renderer.isRenderable(null, requestContext));
+        verify(requestContext, container);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/startup/AbstractTilesInitializerTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/startup/AbstractTilesInitializerTest.java
new file mode 100644
index 000000000..fa7789132
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/startup/AbstractTilesInitializerTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+package org.apache.tiles.core.startup;
+
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.core.factory.AbstractTilesContainerFactory;
+import org.apache.tiles.request.ApplicationAccess;
+import org.apache.tiles.request.ApplicationContext;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link AbstractTilesInitializer}.
+ *
+ * @version $Rev$ $Date$
+ */
+public class AbstractTilesInitializerTest {
+
+    /**
+     * A mock Tiles container factory.
+     */
+    private AbstractTilesContainerFactory containerFactory;
+
+    /**
+     * The object to test.
+     */
+    private AbstractTilesInitializer initializer;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        containerFactory = createMock(AbstractTilesContainerFactory.class);
+        initializer = new AbstractTilesInitializer() {
+
+            @Override
+            protected AbstractTilesContainerFactory createContainerFactory(
+                ApplicationContext context) {
+                return containerFactory;
+            }
+        };
+    }
+
+    /**
+     * Test method for {@link AbstractTilesInitializer#initialize(ApplicationContext)}.
+     */
+    @Test
+    public void testInitialize() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        Map<String, Object> scope = createMock(Map.class);
+
+        expect(containerFactory.createContainer(context)).andReturn(container);
+        expect(context.getApplicationScope()).andReturn(scope).anyTimes();
+        expect(scope.put(ApplicationAccess.APPLICATION_CONTEXT_ATTRIBUTE,
+            context)).andReturn(null);
+        expect(scope.put(TilesAccess.CONTAINER_ATTRIBUTE, container)).andReturn(null);
+        expect(scope.remove(TilesAccess.CONTAINER_ATTRIBUTE)).andReturn(container);
+
+        replay(containerFactory, context, container, scope);
+        initializer.initialize(context);
+        initializer.destroy();
+        verify(containerFactory, context, container, scope);
+    }
+
+    /**
+     * Test method for {@link AbstractTilesInitializer#createTilesApplicationContext(ApplicationContext)}.
+     */
+    @Test
+    public void testCreateTilesApplicationContext() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        replay(containerFactory, context);
+        assertEquals(context, initializer.createTilesApplicationContext(context));
+        verify(containerFactory, context);
+    }
+
+    /**
+     * Test method for {@link AbstractTilesInitializer#getContainerKey(ApplicationContext)}.
+     */
+    @Test
+    public void testGetContainerKey() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        replay(containerFactory, context);
+        assertNull(initializer.getContainerKey(context));
+        verify(containerFactory, context);
+    }
+
+    /**
+     * Test method for {@link AbstractTilesInitializer#createContainer(ApplicationContext)}.
+     */
+    @Test
+    public void testCreateContainer() {
+        ApplicationContext context = createMock(ApplicationContext.class);
+        TilesContainer container = createMock(TilesContainer.class);
+
+        expect(containerFactory.createContainer(context)).andReturn(container);
+
+        replay(containerFactory, context, container);
+        assertEquals(container, initializer.createContainer(context));
+        verify(containerFactory, context, container);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/core/util/CombinedBeanInfoTest.java b/plugins/tiles/src/test/java/org/apache/tiles/core/util/CombinedBeanInfoTest.java
new file mode 100644
index 000000000..b1108d3bd
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/core/util/CombinedBeanInfoTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.core.util;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.reflect.ClassUtil;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.beans.FeatureDescriptor;
+import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link CombinedBeanInfo}.
+ */
+public class CombinedBeanInfoTest {
+
+    /**
+     * The bean info to test.
+     */
+    private CombinedBeanInfo beanInfo;
+
+    /**
+     * The property descriptors.
+     */
+    private List<FeatureDescriptor> descriptors;
+
+    /**
+     * The map of property descriptors for request.
+     */
+    private Map<String, PropertyDescriptor> requestMap;
+
+    /**
+     * The map of property descriptors for application.
+     */
+    private Map<String, PropertyDescriptor> applicationMap;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        beanInfo = new CombinedBeanInfo(Request.class, ApplicationContext.class);
+        requestMap = new LinkedHashMap<>();
+        ClassUtil.collectBeanInfo(Request.class, requestMap);
+        applicationMap = new LinkedHashMap<>();
+        ClassUtil.collectBeanInfo(ApplicationContext.class, applicationMap);
+        descriptors = new ArrayList<>();
+        descriptors.addAll(requestMap.values());
+        descriptors.addAll(applicationMap.values());
+    }
+
+    @Test
+    public void testGetDescriptors() {
+        assertEquals(descriptors, beanInfo.getDescriptors());
+    }
+
+    @Test
+    public void testGetMappedDescriptors() {
+        assertEquals(requestMap, beanInfo.getMappedDescriptors(Request.class));
+        assertEquals(applicationMap, beanInfo.getMappedDescriptors(ApplicationContext.class));
+    }
+
+    @Test
+    public void testGetProperties() {
+        assertEquals(requestMap.keySet(), beanInfo.getProperties(Request.class));
+        assertEquals(applicationMap.keySet(), beanInfo.getProperties(ApplicationContext.class));
+    }
+
+}
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs-tiles-513.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs-tiles-513.xml
new file mode 100644
index 000000000..3b6c6a377
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs-tiles-513.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+ -->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
+       "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
+
+<!-- Definitions for Tiles documentation -->
+
+<tiles-definitions>
+  <!-- Authentication Layout -->
+  <definition name="test.anonymous.base" template="/layout.jsp">
+    <put-attribute name="header">
+      <definition template="/header.jsp" />
+    </put-attribute>
+    <put-attribute name="menu">
+      <definition template="/localnav.jsp" />
+    </put-attribute>
+    <put-attribute name="footer">
+      <definition template="/footer.jsp" />
+    </put-attribute>
+  </definition>
+
+  <!-- index page -->
+  <definition name="test.anonymous" extends="test.anonymous.base">
+    <put-attribute name="title" value="page.title.security.login" />
+    <put-attribute name="body" value="/body.jsp" />
+  </definition>
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs-wildcard.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs-wildcard.xml
new file mode 100644
index 000000000..9312f9d60
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs-wildcard.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+  <definition name="test.def3" template="/test.jsp">
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+  <definition name="test.def*.sub*" template="/test{1}.jsp">
+      <put-attribute name="country" value="default"/>
+      <put-attribute name="title"  value="Tiles Library Documentation" />
+      <put-attribute name="header" value="/common/header{2}.jsp" />
+      <put-attribute name="menu"   value="doc.menu.main" />
+      <put-attribute name="footer" value="/common/footer.jsp" />
+      <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <definition name="test.def*.noAttribute" template="/test{1}.jsp" />
+
+  <!-- Never used on purpose, if there is the TILES-416 the test will fail -->
+  <definition name="test.def*" template="/test{1}.jsp">
+      <put-attribute name="country" value="default"/>
+      <put-attribute name="title"  value="Tiles Library Documentation" />
+      <put-attribute name="header" value="/common/header-sub.jsp" />
+      <put-attribute name="menu"   value="doc.menu.main" />
+      <put-attribute name="footer" value="/common/footer.jsp" />
+      <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <definition name="test.extended.def*.sub*" extends="test.def{1}.sub{2}">
+      <put-attribute name="title"  value="Overridden Title" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1.xml
new file mode 100644
index 000000000..621d7cef9
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- This definition will remain the same for all locales -->
+  <definition name="test.common" template="/test.jsp">
+      <put-attribute name="country" value="none"/>
+    <put-attribute name="title"  value="Common Definition" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <!-- Doc index page description  -->
+  <definition name="test.def1" template="/test.jsp">
+          <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <!-- This definition will be extended -->
+  <definition name="test.def.toextend" template="/test.jsp">
+    <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Definition to be extended" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <!-- This definition will be overridden -->
+  <definition name="test.def.overridden" template="/test.jsp">
+    <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Definition to be overridden" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_en_US.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_en_US.xml
new file mode 100644
index 000000000..1a89b229c
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_en_US.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="test.def1" template="/test.jsp">
+          <put-attribute name="country" value="US"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_fr.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_fr.xml
new file mode 100644
index 000000000..62ed68170
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_fr.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="test.def1" template="/test.jsp">
+          <put-attribute name="country" value="France"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <definition name="test.common.french" template="/test.jsp">
+          <put-attribute name="country" value="France"/>
+    <put-attribute name="title"  value="Common Definition for French" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+  <definition name="test.def.overridden" extends="test.def.toextend">
+    <put-attribute name="country" value="France"/>
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_fr_CA.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_fr_CA.xml
new file mode 100644
index 000000000..b35d0d83e
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs1_fr_CA.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="test.def1" template="/test.jsp">
+          <put-attribute name="country" value="Canada"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs2.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs2.xml
new file mode 100644
index 000000000..f24f1c5d7
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs2.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="test.def2" template="/test.jsp">
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs3.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs3.xml
new file mode 100644
index 000000000..77d7bed2d
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs3.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="test.def3" template="/test.jsp">
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs_regression_TILES-352.xml
similarity index 57%
copy from plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs_regression_TILES-352.xml
index cd9c1c6c5..a28ec49ca 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/defs_regression_TILES-352.xml
@@ -1,6 +1,6 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <!--
 /*
- * $Id$
- *
  * 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
@@ -18,27 +18,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.core.definition.digester;
+ -->
 
-import org.apache.tiles.api.TilesException;
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
 
-/**
- * Indicates that something went wrong during the use of
- * {@link DigesterDefinitionsReader}.
- *
- * @version $Rev$ $Date$
- * @since 2.1.0
- */
-public class DigesterDefinitionsReaderException extends TilesException {
+ <!-- Definitions to check regression from TILES-252    -->
 
-    /**
-     * Constructor.
-     *
-     * @param message The detail message.
-     * @since 2.1.0
-     */
-    public DigesterDefinitionsReaderException(String message) {
-        super(message);
-    }
+<tiles-definitions>
+ <definition name="root">
+  <put-attribute name="body">
+   <definition template="/my/template.jsp">
+    <put-list-attribute name="list">
+     <add-attribute value="This is a value" type="string" />
+    </put-list-attribute>
+   </definition>
+  </put-attribute>
+ </definition>
 
-}
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/invalid-defs.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/invalid-defs.xml
new file mode 100644
index 000000000..3973a749a
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/invalid-defs.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Dorked up XML tag.  -->
+  <definitionasdfad name="doc.mainLayout" template="/layout/classicLayout.jsp">
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definitionasdfad>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/malformed-defs.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/malformed-defs.xml
new file mode 100644
index 000000000..b82f95de7
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/malformed-defs.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="doc.mainLayout" template="/layout/classicLayout.jsp">
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/temp-defs.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/temp-defs.xml
new file mode 100644
index 000000000..d5334eab4
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/temp-defs.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="test.def1" template="/test.jsp">
+          <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs-2.1.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs-2.1.xml
new file mode 100644
index 000000000..f8b651ce2
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs-2.1.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+  <definition name="doc.cascaded.test" template="/layout/classicLayout.jsp">
+    <put-attribute name="title" value="Test title" cascade="false" />
+    <put-attribute name="title2" value="Test title two" cascade="true" />
+    <put-list-attribute name="items1" cascade="false">
+        <add-attribute value="value1" type="string" />
+    </put-list-attribute>
+    <put-list-attribute name="items2" cascade="true">
+        <add-attribute value="value2" type="string" />
+    </put-list-attribute>
+  </definition>
+
+  <definition name="test.nesting.definitions" template="/layout.jsp">
+      <put-attribute name="body">
+          <definition template="/layout.jsp">
+              <put-attribute name="title"  value="This is a nested definition."/>
+          </definition>
+      </put-attribute>
+  </definition>
+
+  <definition name="test.nesting.list.definitions" template="/layout.jsp">
+      <put-list-attribute name="list">
+          <add-attribute>
+              <definition template="/layout.jsp">
+                  <put-attribute name="title"  value="This is a nested definition."/>
+              </definition>
+          </add-attribute>
+      </put-list-attribute>
+  </definition>
+
+  <definition name="test.inherit.list.base" template="/layout.jsp">
+      <put-list-attribute name="list">
+          <add-attribute value="first" />
+      </put-list-attribute>
+  </definition>
+
+  <definition name="test.inherit.list" extends="test.inherit.list.base">
+      <put-list-attribute name="list" inherit="true">
+          <add-attribute value="second" />
+      </put-list-attribute>
+  </definition>
+
+  <definition name="test.noinherit.list" extends="test.inherit.list.base">
+      <put-list-attribute name="list">
+          <add-attribute value="second" />
+      </put-list-attribute>
+  </definition>
+
+  <definition name="test.new.attributes" templateExpression="${my.expression}"
+          templateType="mytype" >
+      <put-attribute name="body" expression="${my.attribute.expression}" />
+  </definition>
+
+  <definition name="test.inherit.othertype.base" template="/layout.ftl" templateType="freemarker">
+      <put-attribute name="body" value="/jsp/body.jsp" />
+  </definition>
+
+  <definition name="test.inherit.othertype" extends="test.inherit.othertype.base">
+  </definition>
+</tiles-definitions>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs-2.1_it.xml
similarity index 64%
copy from plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs-2.1_it.xml
index aaab7652c..4c7c0834f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/NoSuchAttributeException.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs-2.1_it.xml
@@ -1,6 +1,6 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
 /*
- * $Id$
- *
  * 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
@@ -18,25 +18,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.template;
-
-import org.apache.tiles.api.TilesException;
+-->
 
-/**
- * Indicates that a named attribute has not been found.
- *
- * @since 2.2.0
- */
-public class NoSuchAttributeException extends TilesException {
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
 
-    /**
-     * Constructor.
-     *
-     * @param message The detail message.
-     * @since 2.2.0
-     */
-    public NoSuchAttributeException(String message) {
-        super(message);
-    }
+<!-- Definitions for Tiles documentation   -->
 
-}
+<tiles-definitions>
+  <definition name="test.dummy" template="/dummy_layout.jsp">
+      <put-attribute name="body" expression="/dummy_body.jsp" />
+  </definition>
+</tiles-definitions>
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs.xml b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs.xml
new file mode 100644
index 000000000..590e0c7cf
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/config/tiles-defs.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+/*
+ * 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.
+ */
+-->
+
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
+
+<!-- Definitions for Tiles documentation   -->
+
+<tiles-definitions>
+
+  <!-- =======================================================  -->
+  <!-- Master definition  									-->
+  <!-- =======================================================  -->
+
+  <!-- Doc index page description  -->
+  <definition name="doc.mainLayout" template="/layout/classicLayout.jsp">
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+      <put-attribute name="bean"   value="This is an object" type="object" />
+  </definition>
+
+  <!-- =======================================================  -->
+  <!-- Main page body definitions  									-->
+  <!-- =======================================================  -->
+
+  <definition name="doc.portal.body" template="/layout/columnsLayout.jsp">
+    <put-attribute name="numCols" value="2" />
+    <put-list-attribute name="list0" >
+      <add-attribute value="/doc/portal/welcome.jsp" />
+      <add-attribute value="/doc/portal/features.jsp" />
+      <!--<add-attribute value="/doc/portal/todo.jsp" /> -->
+      <add-attribute value="/doc/portal/documentation.jsp" />
+    </put-list-attribute>
+    <put-list-attribute name="list1" >
+      <add-attribute value="/doc/portal/news.jsp" />
+      <add-attribute value="/doc/portal/download.jsp" />
+      <add-attribute value="/doc/portal/tilesCompsTemplates.jsp" />
+      <add-attribute value="/doc/portal/strutsIntegration.jsp" />
+      <add-attribute value="/doc/portal/comments.jsp" />
+      <add-attribute value="/doc/portal/revisions.jsp" />
+    </put-list-attribute>
+  </definition>
+
+  <!-- =======================================================  -->
+  <!-- Menus definitions  									-->
+  <!-- =======================================================  -->
+
+  <!-- Menu bar definition -->
+<definition name="doc.menu.main" template="/layout/vboxLayout.jsp" >
+  <put-list-attribute name="componentsList" >
+    <add-attribute value="doc.menu.links" />
+    <add-attribute value="doc.menu.taglib.references" />
+    <add-attribute value="doc.menu.printer.friendly" />
+    <add-attribute value="doc.menu.old.documents" />
+  </put-list-attribute>
+</definition>
+
+  <!-- Documentation menu definition v1.1-->
+<definition name="doc.menu.links" template="/layouts/menu.jsp" >
+  <put-attribute name="title" value="Documentation" />
+    <put-list-attribute name="items" >
+      <item value="Home"           link="/index.jsp"  />
+      <item value="Live Examples (new)" link="/examples/index.jsp"  />
+      <!--
+    <item> <value>Commented Examples</value>
+        <link>/examples/index.jsp</link>
+      <classtype>org.apache.tiles.beans.SimpleMenuItem</classtype>
+    </item>
+    -->
+      <item value="Quick overview" link="/doc/quickOverview.jsp"  />
+      <!--
+      <item value="Tutorial"       link="/doc/tutorial.jsp"  />
+      -->
+      <item value="Tutorial Live Examples" link="/tutorial/index.jsp" />
+      <item value="Download"       link="/doc/download.jsp" />
+      <item value="Installation"   link="/doc/installation.jsp" />
+      <item value="User Guide"	   link="/doc/userGuide.jsp" />
+      <item value="Javadoc"        link="/api/index.html" />
+      <item value="Struts Home"    link="http://www.apache.org"   icon="/images/struts-power.gif"
+      classtype="org.apache.tiles.beans.SimpleMenuItem" />
+    </put-list-attribute>
+</definition>
+
+  <!-- Printer friendly menu definition -->
+<definition name="doc.menu.printer.friendly" template="/layouts/menu.jsp" >
+  <put-attribute name="title" value="Printer Versions" />
+  <put-list-attribute name="items" >
+    <item value="Quick Overview"     link="/test/testAll.jsp" />
+    <item value="Tutorial"           link="/doc/tutorialBody.html" />
+    <item value="User Guide"         link="/doc/userGuideBody.html" />
+    <item value="Overview (old)"  	 link="/doc/overviewBody.html" />
+  </put-list-attribute>
+</definition>
+
+  <!-- Taglib menu definition -->
+<definition name="doc.menu.taglib.references" template="/layouts/menu.jsp" >
+  <put-attribute name="title" value="Tag Library Reference" />
+    <put-list-attribute name="items" >
+      <item value="Tiles Tags"     link="/doc/tilesTags.jsp" />
+      <!-- <item value="Extension Tags (old)"   link="/doc/extensionsTags.jsp" /> -->
+    </put-list-attribute>
+</definition>
+
+  <!-- Oldies menu definition -->
+<definition name="doc.menu.old.documents" template="/layouts/menu.jsp" >
+  <put-attribute name="title" value="Old Documents" />
+  <put-list-attribute name="items" >
+    <item value="Overview (old)"     link="/doc/overview.jsp" />
+  </put-list-attribute>
+</definition>
+
+<definition name="doc.role.test" template="/layout/classicLayout.jsp">
+  <put-attribute name="title" value="Test title" role="myrole" />
+</definition>
+
+<definition name="doc.listattribute.test" template="/layout/classicLayout.jsp">
+  <put-list-attribute name="items" />
+</definition>
+
+</tiles-definitions>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java b/plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs-key-one.xml
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs-key-one.xml
index 858db324d..180fb0a8c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs-key-one.xml
@@ -1,6 +1,6 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
 /*
- * $Id$
- *
  * 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
@@ -18,23 +18,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.api;
+-->
 
-/**
- * Indicates that a keyed container has not been found.
- *
- * @since 2.1.0
- */
-public class NoSuchContainerException extends TilesException {
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
 
-    /**
-     * Constructor.
-     *
-     * @param message The detail message.
-     * @since 2.1.0
-     */
-    public NoSuchContainerException(String message) {
-        super(message);
-    }
+<tiles-definitions>
+  <definition name="test.def.one" template="/test.jsp">
+          <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
 
-}
+</tiles-definitions>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java b/plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs-key-two.xml
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs-key-two.xml
index 858db324d..d0639d696 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs-key-two.xml
@@ -1,6 +1,6 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
 /*
- * $Id$
- *
  * 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
@@ -18,23 +18,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.api;
+-->
 
-/**
- * Indicates that a keyed container has not been found.
- *
- * @since 2.1.0
- */
-public class NoSuchContainerException extends TilesException {
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
 
-    /**
-     * Constructor.
-     *
-     * @param message The detail message.
-     * @since 2.1.0
-     */
-    public NoSuchContainerException(String message) {
-        super(message);
-    }
+<tiles-definitions>
+  <definition name="test.def.two" template="/test.jsp">
+          <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
 
-}
+</tiles-definitions>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java b/plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs.xml
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs.xml
index 858db324d..2d124a2be 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/core/factory/test-defs.xml
@@ -1,6 +1,6 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
 /*
- * $Id$
- *
  * 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
@@ -18,23 +18,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.api;
+-->
 
-/**
- * Indicates that a keyed container has not been found.
- *
- * @since 2.1.0
- */
-public class NoSuchContainerException extends TilesException {
+ <!DOCTYPE tiles-definitions PUBLIC
+       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
+       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
 
-    /**
-     * Constructor.
-     *
-     * @param message The detail message.
-     * @since 2.1.0
-     */
-    public NoSuchContainerException(String message) {
-        super(message);
-    }
+<tiles-definitions>
+  <definition name="test.def1" template="/test.jsp">
+          <put-attribute name="country" value="default"/>
+    <put-attribute name="title"  value="Tiles Library Documentation" />
+    <put-attribute name="header" value="/common/header.jsp" />
+    <put-attribute name="menu"   value="doc.menu.main" />
+    <put-attribute name="footer" value="/common/footer.jsp" />
+    <put-attribute name="body"   value="doc.portal.body" />
+  </definition>
 
-}
+</tiles-definitions>
diff --git a/pom.xml b/pom.xml
index d915a38ef..14a01e163 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1028,6 +1028,12 @@
                 <version>${log4j2.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>org.apache.logging.log4j</groupId>
+                <artifactId>log4j-jcl</artifactId>
+                <version>${log4j2.version}</version>
+            </dependency>
+
             <dependency>
                 <groupId>org.testng</groupId>
                 <artifactId>testng</artifactId>


[struts] 19/23: Add generating of Autotags and tests.

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 6715a5243e9f36ec96a5397c53802adb3e01e3ee
Author: Greg Huber <gh...@apache.org>
AuthorDate: Tue Oct 11 10:19:37 2022 +0100

    Add generating of Autotags and tests.
---
 plugins/tiles/pom.xml                              |   52 +-
 .../org/apache/struts2/tiles/BuildJspAutotags.java |  114 ++
 .../org/apache/tiles/api/AttributeContext.java     |    1 -
 .../autotag/core/AutotagRuntimeException.java      |   60 +
 .../generate/AbstractTemplateClassGenerator.java   |  143 +++
 .../generate/AbstractTemplateSuiteGenerator.java   |  128 +++
 .../autotag/generate/BasicTemplateGenerator.java   |  187 +++
 .../autotag/generate/TemplateClassGenerator.java   |   45 +
 .../tiles/autotag/generate/TemplateGenerator.java  |   56 +
 .../autotag/generate/TemplateGeneratorBuilder.java |  180 +++
 .../autotag/generate/TemplateGeneratorFactory.java |   32 +
 .../autotag/generate/TemplateSuiteGenerator.java   |   40 +
 .../tiles/autotag/generate/package-info.java       |   22 +
 .../autotag/jsp/JspTemplateGeneratorFactory.java   |   79 ++
 .../org/apache/tiles/autotag/jsp/TLDGenerator.java |   60 +
 .../tiles/autotag/jsp/TagClassGenerator.java       |   63 ++
 .../org/apache/tiles/autotag/jsp/package-info.java |   22 +
 .../org/apache/tiles/autotag/tool/StringTool.java  |  138 +++
 .../apache/tiles/autotag/tool/package-info.java    |   22 +
 .../tiles/core/definition/dao/DefinitionDAO.java   |    1 -
 .../pattern/PatternDefinitionResolver.java         |    1 -
 .../pattern/PrefixedPatternDefinitionResolver.java |    1 -
 .../tiles/web/jsp/taglib/AddAttributeTag.java      |   97 +-
 .../tiles/web/jsp/taglib/AddListAttributeTag.java  |   34 +-
 .../apache/tiles/web/jsp/taglib/DefinitionTag.java |  107 +-
 .../tiles/web/jsp/taglib/GetAsStringTag.java       |  161 +--
 .../tiles/web/jsp/taglib/ImportAttributeTag.java   |   92 +-
 .../tiles/web/jsp/taglib/InsertAttributeTag.java   |  170 +--
 .../tiles/web/jsp/taglib/InsertDefinitionTag.java  |  149 +--
 .../tiles/web/jsp/taglib/InsertTemplateTag.java    |  132 ++-
 .../tiles/web/jsp/taglib/PutAttributeTag.java      |  118 +-
 .../tiles/web/jsp/taglib/PutListAttributeTag.java  |   76 +-
 .../web/jsp/taglib/SetCurrentContainerTag.java     |   36 +-
 .../src/main/resources/META-INF/template-suite.xml | 1188 ++++++++++++++++++++
 .../src/main/resources/META-INF/tld/tiles-jsp.tld  |  228 ++--
 .../org/apache/tiles/autotag/jsp/bodyTag.vm}       |   72 +-
 .../resources/org/apache/tiles/autotag/jsp/tld.vm  |   66 ++
 .../org/apache/tiles/autotag/velocity.properties   |  114 ++
 .../jsp/JspTemplateGeneratorFactoryTest.java       |   61 +
 .../apache/tiles/autotag/jsp/TLDGeneratorTest.java |  129 +++
 .../tiles/autotag/jsp/TagClassGeneratorTest.java   |  139 +++
 .../tiles/web/jsp/taglib/UseAttributeTagTest.java  |  220 ++++
 .../tiles/autotag/jsp/test/DoStuffNoBodyTag.java   |  134 +++
 .../apache/tiles/autotag/jsp/test/DoStuffTag.java  |  136 +++
 plugins/tiles/src/test/resources/tldtest-jsp.tld   |  121 ++
 45 files changed, 4594 insertions(+), 633 deletions(-)

diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index c92bd571c..236af9172 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -30,6 +30,48 @@
     <artifactId>struts2-tiles-plugin</artifactId>
     <packaging>jar</packaging>
     <name>Struts 2 Tiles Plugin</name>
+    
+    <!-- mvn -P build-jsp-autotags exec:java -->
+    <profiles>
+        <profile>
+            <id>build-jsp-autotags</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <version>3.1.0</version>
+                        <executions>
+                          <execution>
+                            <phase>compile</phase>
+                            <goals>
+                              <goal>java</goal>
+                            </goals>
+                          </execution>
+                        </executions>
+                        <configuration>
+                            <mainClass>org.apache.struts2.tiles.BuildJspAutotags</mainClass>
+                            <arguments>
+                                <!-- taglibURI   -->
+                                <argument>http://tiles.apache.org/tags-tiles</argument>
+                                <!-- packageName -->
+                                <argument>org.apache.tiles.web.jsp.taglib</argument>
+                                <!-- requestClass -->
+                                <argument>org.apache.tiles.request.Request</argument>
+                                <!-- jspRuntime -->
+                                <argument>org.apache.tiles.request.jsp.autotag.JspAutotagRuntime</argument>
+                                <!-- Output folder -->
+                                <argument>${project.build.directory}</argument>
+                            </arguments>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 
     <dependencies>
         <dependency>
@@ -56,8 +98,16 @@
             <artifactId>log4j-jcl</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+        </dependency>
     </dependencies>
     <properties>
-    	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 </project>
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildJspAutotags.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildJspAutotags.java
new file mode 100644
index 000000000..64aa03254
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildJspAutotags.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+package org.apache.struts2.tiles;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.tiles.autotag.jsp.JspTemplateGeneratorFactory;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
+/**
+ * Helper class for building the JSP tag classes and .tld file.
+ */
+public class BuildJspAutotags {
+
+    public BuildJspAutotags() {
+    }
+
+    /**
+     * The main method.
+     *
+     * @param args the arguments
+     */
+    public static void main(String[] args) {
+
+        BuildJspAutotags me = new BuildJspAutotags();
+
+        me.build(args[0], args[1], args[2], args[3], args[4]);
+
+    }
+
+    /**
+     * Build
+     *
+     * @param taglibURI    the taglib URI
+     * @param packageName  the package name
+     * @param requestClass the request class
+     * @param jspRuntime   the jsp runtime
+     * @param outputDir    the output dir
+     */
+    public void build(String taglibURI, String packageName, String requestClass, String jspRuntime, String outputDir) {
+
+        // Default values
+        // taglibURI = "org.apache.tiles.autotag.jsp.runtime.Runtime";
+        // packageName = "org.apache.tiles.web.jsp.taglib";
+        // requestClass = "org.apache.tiles.request.Request";
+        // jspRuntime = "org.apache.tiles.autotag.jsp.runtime.Runtime";
+        // outputDir = "/target"
+
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("taglibURI", taglibURI);
+
+        try {
+
+            TemplateSuite suite;
+
+            InputStream stream = getClass().getResourceAsStream("/META-INF/template-suite.xml");
+
+            try {
+                XStream xstream = new XStream(new DomDriver());
+                xstream.allowTypes(new Class[] { org.apache.tiles.autotag.model.TemplateClass.class,
+                        org.apache.tiles.autotag.model.TemplateSuite.class,
+                        org.apache.tiles.autotag.model.TemplateParameter.class });
+                suite = (TemplateSuite) xstream.fromXML(stream);
+            } finally {
+                stream.close();
+            }
+
+            Properties props = new Properties();
+            InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+            props.load(propsStream);
+            propsStream.close();
+
+            File classesOutputDirectory = new File(outputDir + "/generated-sources/autotag/classes");
+            File resourcesOutputDirectory = new File(outputDir + "/generated-sources/autotag");
+
+            TemplateGenerator generator = new JspTemplateGeneratorFactory(classesOutputDirectory,
+                    resourcesOutputDirectory, new VelocityEngine(props), TemplateGeneratorBuilder.createNewInstance())
+                    .createTemplateGenerator();
+
+            generator.generate(packageName, suite, parameters, jspRuntime, requestClass);
+
+        } catch (Exception e) {
+            // ignored
+        }
+
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
index 24c4fa5fa..554bd9ec0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
@@ -25,7 +25,6 @@ import java.util.Set;
  * Encapsulation of the current state of execution.
  *
  * @since Tiles 2.0
- * @version $Rev$ $Date$
  */
 public interface AttributeContext {
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/AutotagRuntimeException.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/AutotagRuntimeException.java
new file mode 100644
index 000000000..188dae269
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/AutotagRuntimeException.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.core;
+
+/**
+ * Generic exception for Autotag.
+  */
+public class AutotagRuntimeException extends RuntimeException {
+
+    /**
+     * Constructor.
+     */
+    public AutotagRuntimeException() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The message of the exception.
+     */
+    public AutotagRuntimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param cause The cause.
+     */
+    public AutotagRuntimeException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The message of the exception.
+     * @param cause The cause.
+     */
+    public AutotagRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/AbstractTemplateClassGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/AbstractTemplateClassGenerator.java
new file mode 100644
index 000000000..009d6d1a5
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/AbstractTemplateClassGenerator.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.AutotagRuntimeException;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.tiles.autotag.tool.StringTool;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+
+/**
+ * A base template class generator.
+ */
+public abstract class AbstractTemplateClassGenerator implements
+        TemplateClassGenerator {
+
+    /**
+     * The Velocity engine to use.
+     */
+    private VelocityEngine velocityEngine;
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public AbstractTemplateClassGenerator(VelocityEngine velocityEngine) {
+        this.velocityEngine = velocityEngine;
+    }
+
+    @Override
+    public void generate(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        File dir = new File(directory, getDirectoryName(directory, packageName,
+                suite, clazz, parameters, runtimeClass, requestClass));
+        dir.mkdirs();
+        File file = new File(dir, getFilename(dir, packageName, suite, clazz, parameters, runtimeClass, requestClass));
+        VelocityContext context = new VelocityContext();
+        context.put("packageName", packageName);
+        context.put("suite", suite);
+        context.put("clazz", clazz);
+        context.put("stringTool", new StringTool());
+        context.put("parameters", parameters);
+        context.put("runtimeClass", runtimeClass);
+        context.put("requestClass", requestClass);
+        try {
+            file.createNewFile();
+            Template template = velocityEngine.getTemplate(getTemplatePath(dir,
+                    packageName, suite, clazz, parameters, runtimeClass, requestClass));
+            Writer writer = new FileWriter(file);
+            try {
+                template.merge(context, writer);
+            } finally {
+                writer.close();
+            }
+        } catch (ResourceNotFoundException e) {
+            throw new AutotagRuntimeException("Cannot find template resource",
+                    e);
+        } catch (ParseErrorException e) {
+            throw new AutotagRuntimeException(
+                    "The template resource is not parseable", e);
+        } catch (IOException e) {
+            throw new AutotagRuntimeException(
+                    "I/O Exception when generating file", e);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new AutotagRuntimeException(
+                    "Another generic exception while parsing the template resource",
+                    e);
+        }
+    }
+
+    /**
+     * Calculates and returns the template path.
+     *
+     * @param directory The directory where the file will be written.
+     * @param packageName The name of the package.
+     * @param suite The template suite.
+     * @param clazz The template class.
+     * @param parameters The map of parameters.
+     * @return The template path.
+     */
+    protected abstract String getTemplatePath(File directory,
+            String packageName, TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass);
+
+    /**
+     * Calculates and returns the filename of the generated file.
+     *
+     * @param directory The directory where the file will be written.
+     * @param packageName The name of the package.
+     * @param suite The template suite.
+     * @param clazz The template class.
+     * @param parameters The map of parameters.
+     * @return The template path.
+     */
+    protected abstract String getFilename(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters, String runtimeClass,
+            String requestClass);
+
+    /**
+     * Calculates and returns the directory where the file will be written..
+     *
+     * @param directory The directory where the file will be written.
+     * @param packageName The name of the package.
+     * @param suite The template suite.
+     * @param clazz The template class.
+     * @param parameters The map of parameters.
+     * @return The template path.
+     */
+    protected abstract String getDirectoryName(File directory,
+            String packageName, TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters, 
+            String runtimeClass, String requestClass);
+    
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/AbstractTemplateSuiteGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/AbstractTemplateSuiteGenerator.java
new file mode 100644
index 000000000..16e3234b6
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/AbstractTemplateSuiteGenerator.java
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.AutotagRuntimeException;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.tiles.autotag.tool.StringTool;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+
+/**
+ * A base template suite generator.
+ */
+public abstract class AbstractTemplateSuiteGenerator implements TemplateSuiteGenerator {
+
+    /**
+     * The velocity engine.
+     */
+    private VelocityEngine velocityEngine;
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public AbstractTemplateSuiteGenerator(VelocityEngine velocityEngine) {
+        this.velocityEngine = velocityEngine;
+    }
+
+    @Override
+    public void generate(File directory, String packageName, TemplateSuite suite, Map<String, String> parameters) {
+        File dir = new File(directory, getDirectoryName(directory, packageName, suite, parameters));
+        dir.mkdirs();
+        File file = new File(dir, getFilename(dir, packageName, suite, parameters));
+        VelocityContext context = new VelocityContext();
+        context.put("packageName", packageName);
+        context.put("suite", suite);
+        context.put("stringTool", new StringTool());
+        context.put("parameters", parameters);
+        try {
+            file.createNewFile();
+            Template template = velocityEngine.getTemplate(getTemplatePath(dir,
+                    packageName, suite, parameters));
+            Writer writer = new FileWriter(file);
+            try {
+                template.merge(context, writer);
+            } finally {
+                writer.close();
+            }
+        } catch (ResourceNotFoundException e) {
+            throw new AutotagRuntimeException("Cannot find template resource", e);
+        } catch (ParseErrorException e) {
+            throw new AutotagRuntimeException("The template resource is not parseable", e);
+        } catch (IOException e) {
+            throw new AutotagRuntimeException(
+                    "I/O Exception when generating file", e);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new AutotagRuntimeException(
+                    "Another generic exception while parsing the template resource",
+                    e);
+        }
+    }
+
+    /**
+     * Calculates and returns the template path.
+     *
+     * @param directory The directory where the file will be written.
+     * @param packageName The name of the package.
+     * @param suite The template suite.
+     * @param parameters The map of parameters.
+     * @return The template path.
+     */
+    protected abstract String getTemplatePath(File directory,
+            String packageName, TemplateSuite suite,
+            Map<String, String> parameters);
+
+    /**
+     * Calculates and returns the filename of the generated file.
+     *
+     * @param directory The directory where the file will be written.
+     * @param packageName The name of the package.
+     * @param suite The template suite.
+     * @param parameters The map of parameters.
+     * @return The template path.
+     */
+    protected abstract String getFilename(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters);
+
+    /**
+     * Calculates and returns the directory where the file will be written..
+     *
+     * @param directory The directory where the file will be written.
+     * @param packageName The name of the package.
+     * @param suite The template suite.
+     * @param parameters The map of parameters.
+     * @return The template path.
+     */
+    protected abstract String getDirectoryName(File directory,
+            String packageName, TemplateSuite suite,
+            Map<String, String> parameters);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/BasicTemplateGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/BasicTemplateGenerator.java
new file mode 100644
index 000000000..e9b27b060
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/BasicTemplateGenerator.java
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateSuite;
+
+/**
+ * The basic template generator. Use {@link TemplateGeneratorBuilder} to
+ * create instances of this class.
+ */
+class BasicTemplateGenerator implements TemplateGenerator {
+
+    /**
+     * The template suite generators.
+     */
+    private List<TSGeneratorDirectoryPair> templateSuiteGenerators;
+
+    /**
+     * The template class generators.
+     */
+    private List<TCGeneratorDirectoryPair> templateClassGenerators;
+
+    /**
+     * Indicates that this generator generates resources.
+     */
+    private boolean generatingResources = false;
+
+    /**
+     * Indicates that this generator generates classes.
+     */
+    private boolean generatingClasses = false;
+
+    /**
+     * Constructor.
+     *
+     * @param templateSuiteGenerators The template suite generators.
+     * @param templateClassGenerators The template class generators.
+     * @param generatingClasses Indicates that this generator generates classes.
+     * @param generatingResources Indicates that this generator generates resources.
+     */
+    BasicTemplateGenerator(
+            List<TSGeneratorDirectoryPair> templateSuiteGenerators,
+            List<TCGeneratorDirectoryPair> templateClassGenerators,
+            boolean generatingClasses, boolean generatingResources) {
+        this.templateSuiteGenerators = templateSuiteGenerators;
+        this.templateClassGenerators = templateClassGenerators;
+        this.generatingClasses = generatingClasses;
+        this.generatingResources = generatingResources;
+    }
+
+
+
+    @Override
+    public void generate(String packageName, TemplateSuite suite, Map<String, String> parameters, 
+        String runtimeClass, String requestClass) {
+        for (TSGeneratorDirectoryPair pair : templateSuiteGenerators) {
+            pair.getGenerator().generate(pair.getDirectory(), packageName, suite, parameters);
+        }
+        for (TemplateClass templateClass : suite.getTemplateClasses()) {
+            for (TCGeneratorDirectoryPair pair : templateClassGenerators) {
+                pair.getGenerator().generate(pair.getDirectory(), packageName,
+                        suite, templateClass, parameters, runtimeClass, requestClass);
+            }
+        }
+    }
+
+    /**
+     * A pair of a template suite generator and a directory.
+     */
+    static class TSGeneratorDirectoryPair {
+        /**
+         * The directory where files are generated.
+         */
+        private File directory;
+
+        /**
+         * The generator.
+         */
+        private TemplateSuiteGenerator generator;
+
+        /**
+         * Constructor.
+         *
+         * @param directory The directory where files are generated.
+         * @param generator The generator.
+         */
+        public TSGeneratorDirectoryPair(File directory,
+                TemplateSuiteGenerator generator) {
+            this.directory = directory;
+            this.generator = generator;
+        }
+
+        /**
+         * Returns the directory where files are generated.
+         *
+         * @return The directory where files are generated.
+         */
+        public File getDirectory() {
+            return directory;
+        }
+
+        /**
+         * Returns the generator.
+         *
+         * @return The generator.
+         */
+        public TemplateSuiteGenerator getGenerator() {
+            return generator;
+        }
+    }
+
+    /**
+     * A pair of a template class generator and a directory.
+     */
+    static class TCGeneratorDirectoryPair {
+        /**
+         * The directory where files are generated.
+         */
+        private File directory;
+
+        /**
+         * The generator.
+         */
+        private TemplateClassGenerator generator;
+
+        /**
+         * Constructor.
+         *
+         * @param directory The directory where files are generated.
+         * @param generator The generator.
+         */
+        public TCGeneratorDirectoryPair(File directory,
+                TemplateClassGenerator generator) {
+            this.directory = directory;
+            this.generator = generator;
+        }
+
+        /**
+         * Returns the directory where files are generated.
+         *
+         * @return The directory where files are generated.
+         */
+        public File getDirectory() {
+            return directory;
+        }
+
+        /**
+         * Returns the generator.
+         *
+         * @return The generator.
+         */
+        public TemplateClassGenerator getGenerator() {
+            return generator;
+        }
+    }
+
+    @Override
+    public boolean isGeneratingResources() {
+        return generatingResources;
+    }
+
+    @Override
+    public boolean isGeneratingClasses() {
+        return generatingClasses;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateClassGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateClassGenerator.java
new file mode 100644
index 000000000..3d958beef
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateClassGenerator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateSuite;
+
+/**
+ * Generates code from a parsed class.
+ */
+public interface TemplateClassGenerator {
+
+    /**
+     * Generates the code.
+     *
+     * @param directory The base directory where the code will be put.
+     * @param packageName The package name.
+     * @param suite The template suite.
+     * @param clazz The template class.
+     * @param parameters Configuration parameters.
+     * @param runtimeClass The RequestBuilder implementation.
+     */
+    void generate(File directory, String packageName, TemplateSuite suite,
+            TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGenerator.java
new file mode 100644
index 000000000..9e462ff2d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGenerator.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+
+import java.util.Map;
+
+import org.apache.tiles.autotag.model.TemplateSuite;
+
+/**
+ * Generates all the code for a template suite.
+ */
+public interface TemplateGenerator {
+
+    /**
+     * Generates the code.
+     *
+     * @param packageName The package name.
+     * @param suite The template suite.
+     * @param parameters Configuration parameters.
+     * @param runtimeClass The RequestBuilder implementation.
+     * @param requestClass The request class to use.
+     */
+    void generate(String packageName, TemplateSuite suite, Map<String, String> parameters, 
+        String runtimeClass, String requestClass);
+
+    /**
+     * Indicates that this generator generates resources.
+     *
+     * @return <code>true</code> if the generator generates resources.
+     */
+    boolean isGeneratingResources();
+
+    /**
+     * Indicates that this generator generates classes.
+     *
+     * @return <code>true</code> if the generator generates classes.
+     */
+    boolean isGeneratingClasses();
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorBuilder.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorBuilder.java
new file mode 100644
index 000000000..943175da6
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorBuilder.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tiles.autotag.generate.BasicTemplateGenerator.TCGeneratorDirectoryPair;
+import org.apache.tiles.autotag.generate.BasicTemplateGenerator.TSGeneratorDirectoryPair;
+
+/**
+ * Builds a TemplateGenerator.
+ */
+public class TemplateGeneratorBuilder {
+
+    /**
+     * The template suite generators.
+     */
+    private List<TSGeneratorDirectoryPair> templateSuiteGenerators;
+
+    /**
+     * The template class generators.
+     */
+    private List<TCGeneratorDirectoryPair> templateClassGenerators;
+
+    /**
+     * Indicates that this generator generates resources.
+     */
+    private boolean generatingResources = false;
+
+    /**
+     * Indicates that this generator generates classes.
+     */
+    private boolean generatingClasses = false;
+
+    /**
+     * The classes output directory.
+     */
+    private File classesOutputDirectory;
+
+    /**
+     * The resources output directory.
+     */
+    private File resourcesOutputDirectory;
+
+    /**
+     * Constructor.
+     */
+    private TemplateGeneratorBuilder() {
+        templateSuiteGenerators = new ArrayList<BasicTemplateGenerator.TSGeneratorDirectoryPair>();
+        templateClassGenerators = new ArrayList<BasicTemplateGenerator.TCGeneratorDirectoryPair>();
+    }
+
+    /**
+     * Creates a new instance of the builder.
+     *
+     * @return A new instance of the builder.
+     */
+    public static TemplateGeneratorBuilder createNewInstance() {
+        return new TemplateGeneratorBuilder();
+    }
+
+    /**
+     * Sets the classes output directory.
+     *
+     * @param classesOutputDirectory The classes output directory.
+     * @return This instance.
+     */
+    public TemplateGeneratorBuilder setClassesOutputDirectory(File classesOutputDirectory) {
+        this.classesOutputDirectory = classesOutputDirectory;
+        return this;
+    }
+
+    /**
+     * Sets the resources output directory.
+     *
+     * @param resourcesOutputDirectory The resources output directory.
+     * @return This instance.
+     */
+    public TemplateGeneratorBuilder setResourcesOutputDirectory(File resourcesOutputDirectory) {
+        this.resourcesOutputDirectory = resourcesOutputDirectory;
+        return this;
+    }
+
+    /**
+     * Adds a new template suite generator to generate classes.
+     *
+     * @param generator The generator to add.
+     * @return This instance.
+     */
+    public TemplateGeneratorBuilder addClassesTemplateSuiteGenerator(TemplateSuiteGenerator generator) {
+        if (classesOutputDirectory == null) {
+            throw new NullPointerException(
+                    "Classes output directory not specified, call 'setClassesOutputDirectory' first");
+        }
+        templateSuiteGenerators.add(new TSGeneratorDirectoryPair(
+                classesOutputDirectory, generator));
+        generatingClasses = true;
+        return this;
+    }
+
+    /**
+     * Adds a new template class generator to generate classes.
+     *
+     * @param generator The generator to add.
+     * @return This instance.
+     */
+    public TemplateGeneratorBuilder addClassesTemplateClassGenerator(TemplateClassGenerator generator) {
+        if (classesOutputDirectory == null) {
+            throw new NullPointerException(
+                    "Classes output directory not specified, call 'setClassesOutputDirectory' first");
+        }
+        templateClassGenerators.add(new TCGeneratorDirectoryPair(
+                classesOutputDirectory, generator));
+        generatingClasses = true;
+        return this;
+    }
+
+    /**
+     * Adds a new template suite generator to generate resources.
+     *
+     * @param generator The generator to add.
+     * @return This instance.
+     */
+    public TemplateGeneratorBuilder addResourcesTemplateSuiteGenerator(TemplateSuiteGenerator generator) {
+        if (resourcesOutputDirectory == null) {
+            throw new NullPointerException(
+                    "Resources output directory not specified, call 'setClassesOutputDirectory' first");
+        }
+        templateSuiteGenerators.add(new TSGeneratorDirectoryPair(
+                resourcesOutputDirectory, generator));
+        generatingResources = true;
+        return this;
+    }
+
+    /**
+     * Adds a new template class generator to generate resources.
+     *
+     * @param generator The generator to add.
+     * @return This instance.
+     */
+    public TemplateGeneratorBuilder addResourcesTemplateClassGenerator(TemplateClassGenerator generator) {
+        if (resourcesOutputDirectory == null) {
+            throw new NullPointerException(
+                    "Resources output directory not specified, call 'setClassesOutputDirectory' first");
+        }
+        templateClassGenerators.add(new TCGeneratorDirectoryPair(
+                resourcesOutputDirectory, generator));
+        generatingResources = true;
+        return this;
+    }
+
+    /**
+     * Builds and returns a new template generator.
+     *
+     * @return The new template generator.
+     */
+    public TemplateGenerator build() {
+        return new BasicTemplateGenerator(templateSuiteGenerators,
+                templateClassGenerators, generatingClasses, generatingResources);
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorFactory.java
new file mode 100644
index 000000000..11fbf693f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+/**
+ * Creates a new template generator.
+ */
+public interface TemplateGeneratorFactory {
+
+    /**
+     * Creates a template generator.
+     *
+     * @return The newly created template generator.
+     */
+    TemplateGenerator createTemplateGenerator();
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateSuiteGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateSuiteGenerator.java
new file mode 100644
index 000000000..f8986779d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateSuiteGenerator.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.generate;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.model.TemplateSuite;
+
+/**
+ * Generates code from a template suite.
+ */
+public interface TemplateSuiteGenerator {
+
+    /**
+     * Generates the code.
+     *
+     * @param directory The base directory where the code will be put.
+     * @param packageName The package name.
+     * @param suite The template suite.
+     * @param parameters Configuration parameters.
+     */
+    void generate(File directory, String packageName, TemplateSuite suite, Map<String, String> parameters);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/package-info.java
new file mode 100644
index 000000000..2fbdf2ae0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * The Autotag generation classes.
+ */
+package org.apache.tiles.autotag.generate;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/JspTemplateGeneratorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/JspTemplateGeneratorFactory.java
new file mode 100644
index 000000000..90c7ce32e
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/JspTemplateGeneratorFactory.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.jsp;
+
+import java.io.File;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.tiles.autotag.generate.TemplateGeneratorFactory;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Creates a template generator to build JSP code around template models.
+ */
+public class JspTemplateGeneratorFactory implements TemplateGeneratorFactory {
+
+    /**
+     * Location of the file.
+     */
+    private File classesOutputDirectory;
+
+    /**
+     * Location of the file.
+     */
+    private File resourcesOutputDirectory;
+
+    /**
+     * The Velocity engine.
+     */
+    private VelocityEngine velocityEngine;
+
+    /**
+     * The template generator builder.
+     */
+    private TemplateGeneratorBuilder templateGeneratorBuilder;
+
+    /**
+     * Constructor.
+     *
+     * @param classesOutputDirectory   The directory where classes will be
+     *                                 generated.
+     * @param resourcesOutputDirectory The directory where the TLD file will be
+     *                                 generated.
+     * @param velocityEngine           The Velocity engine.
+     * @param templateGeneratorBuilder The template generator builder.
+     */
+    public JspTemplateGeneratorFactory(File classesOutputDirectory, File resourcesOutputDirectory,
+            VelocityEngine velocityEngine, TemplateGeneratorBuilder templateGeneratorBuilder) {
+        this.classesOutputDirectory = classesOutputDirectory;
+        this.resourcesOutputDirectory = resourcesOutputDirectory;
+        this.velocityEngine = velocityEngine;
+        this.templateGeneratorBuilder = templateGeneratorBuilder;
+    }
+
+    @Override
+    public TemplateGenerator createTemplateGenerator() {
+        return templateGeneratorBuilder.setClassesOutputDirectory(classesOutputDirectory)
+                .setResourcesOutputDirectory(resourcesOutputDirectory)
+                .addResourcesTemplateSuiteGenerator(new TLDGenerator(velocityEngine))
+                .addClassesTemplateClassGenerator(new TagClassGenerator(velocityEngine)).build();
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/TLDGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/TLDGenerator.java
new file mode 100644
index 000000000..28d947d6e
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/TLDGenerator.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.jsp;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.generate.AbstractTemplateSuiteGenerator;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Generates the TLD file, using a template suite.
+ */
+public class TLDGenerator extends AbstractTemplateSuiteGenerator {
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public TLDGenerator(VelocityEngine velocityEngine) {
+        super(velocityEngine);
+    }
+
+    @Override
+    protected String getTemplatePath(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return "/org/apache/tiles/autotag/jsp/tld.vm";
+    }
+
+    @Override
+    protected String getFilename(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return suite.getName() + "-jsp.tld";
+    }
+
+    @Override
+    protected String getDirectoryName(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return "META-INF/tld/";
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/TagClassGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/TagClassGenerator.java
new file mode 100644
index 000000000..c0ee919de
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/TagClassGenerator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.jsp;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.generate.AbstractTemplateClassGenerator;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Generates a tag class using a template class.
+ */
+public class TagClassGenerator extends AbstractTemplateClassGenerator {
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public TagClassGenerator(VelocityEngine velocityEngine) {
+        super(velocityEngine);
+    }
+
+    @Override
+    protected String getDirectoryName(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return packageName.replaceAll("\\.", "/");
+    }
+
+    @Override
+    protected String getFilename(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return clazz.getTagClassPrefix() + "Tag.java";
+    }
+
+    @Override
+    protected String getTemplatePath(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return "/org/apache/tiles/autotag/jsp/bodyTag.vm";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/package-info.java
new file mode 100644
index 000000000..f142dabfa
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Autotag support for JavaServer Pages.
+ */
+package org.apache.tiles.autotag.jsp;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/StringTool.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/StringTool.java
new file mode 100644
index 000000000..247529835
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/StringTool.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.tool;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.AutotagRuntimeException;
+
+/**
+ * A Velocity tools to manipulate strings.
+ */
+public class StringTool {
+
+    /**
+     * Maps a primitive type to its default value as a string.
+     */
+    private Map<String, String> type2default;
+
+    /**
+     * Maps a primitive type to its boxed version.
+     */
+    private Map<String, String> primitive2wrapped;
+
+    /**
+     * Constructor.
+     */
+    public StringTool() {
+        type2default = new HashMap<String, String>();
+        type2default.put("byte", "0");
+        type2default.put("short", "0");
+        type2default.put("int", "0");
+        type2default.put("long", "0L");
+        type2default.put("float", "0.0f");
+        type2default.put("double", "0.0d");
+        type2default.put("char", "'\\u0000'");
+        type2default.put("boolean", "false");
+
+        primitive2wrapped = new HashMap<String, String>();
+        primitive2wrapped.put("byte", Byte.class.getName());
+        primitive2wrapped.put("short", Short.class.getName());
+        primitive2wrapped.put("int", Integer.class.getName());
+        primitive2wrapped.put("long", Long.class.getName());
+        primitive2wrapped.put("float", Float.class.getName());
+        primitive2wrapped.put("double", Double.class.getName());
+        primitive2wrapped.put("char", Character.class.getName());
+        primitive2wrapped.put("boolean", Boolean.class.getName());
+    }
+
+    /**
+     * Creates a list of strings, separating a string when a newline is encountered.
+     *
+     * @param toSplit The string to split.
+     * @return The list of splitted strings.
+     */
+    public List<String> splitOnNewlines(String toSplit) {
+        List<String> retValue = new ArrayList<String>();
+        if (toSplit == null) {
+            return retValue;
+        }
+        Reader reader = new StringReader(toSplit);
+        BufferedReader bufReader = new BufferedReader(reader);
+        try {
+            String line;
+            while ((line = bufReader.readLine()) != null) {
+                retValue.add(line);
+            }
+        } catch (IOException e) {
+            throw new AutotagRuntimeException("Cannot read the string completely", e);
+        }
+        return retValue;
+    }
+
+    /**
+     * Creates a string in which the first character is capitalized.
+     *
+     * @param string The string to use.
+     * @return The same string with the first character capitalized.
+     */
+    public String capitalizeFirstLetter(String string) {
+        return string.substring(0, 1).toUpperCase() + string.substring(1);
+    }
+
+    /**
+     * Returns the default value for a type.
+     *
+     * @param type                   The type.
+     * @param overriddenDefaultValue The default value, as specified by developers.
+     * @return The default value to use.
+     */
+    public String getDefaultValue(String type, String overriddenDefaultValue) {
+        if (overriddenDefaultValue != null) {
+            return overriddenDefaultValue;
+        }
+
+        String retValue = type2default.get(type);
+        if (retValue == null) {
+            retValue = "null";
+        }
+        return retValue;
+    }
+
+    /**
+     * Returns the class to be used to cast an Object.
+     *
+     * @param type The type to use, even a primitive type.
+     * @return The class to be used in casts.
+     */
+    public String getClassToCast(String type) {
+        String retValue = primitive2wrapped.get(type);
+        if (retValue == null) {
+            retValue = type;
+        }
+        return retValue;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/package-info.java
new file mode 100644
index 000000000..b58748ab0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * Velocity tools to be used in Velocity templates.
+ */
+package org.apache.tiles.autotag.tool;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
index 45358a25a..ce0b1ef4a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
@@ -27,7 +27,6 @@ import java.util.Map;
  * customization key.
  *
  * @param <K> The customization key class.
- * @version $Rev$ $Date$
  * @since 2.1.0
  */
 public interface DefinitionDAO<K> {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
index 0e3d397a3..959f082b9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
@@ -26,7 +26,6 @@ import java.util.Map;
  * Resolves a definition starting from patterns stored in definition maps.
  *
  * @param <T> The type of the customization key.
- * @version $Rev$ $Date$
  * @since 2.2.0
  */
 public interface PatternDefinitionResolver<T> {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
index 42095e43f..a2148f1d8 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
@@ -37,7 +37,6 @@ import java.util.Set;
  * method before using this resolver.
  *
  * @param <T> The type of the customization key.
- * @version $Rev$ $Date$
  * @since 2.2.0
  */
 public class PrefixedPatternDefinitionResolver<T> extends AbstractPatternDefinitionResolver<T> {
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
index a5bd36b04..affe32dcc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,15 +27,12 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.AddAttributeModel;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Add an element to the surrounding list. Equivalent to 'putAttribute', but for
- * list element.
+ * Add an element to the surrounding list. Equivalent to 'putAttribute',
+ * but for list element.
  * </p>
  * 
  * <p>
@@ -46,112 +46,120 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private AddAttributeModel model = new AddAttributeModel();
+    private org.apache.tiles.template.AddAttributeModel model = new org.apache.tiles.template.AddAttributeModel();
 
     /**
-     * The value of the attribute. Use this parameter, or expression, or body.
+     * The value of the attribute. Use this parameter, or
+     * expression, or body.
      */
-    private Object value;
+    private java.lang.Object value;
 
     /**
-     * The expression to calculate the value from. Use this parameter, or value, or
-     * body.
+     * The expression to calculate the value from. Use this
+     * parameter, or value, or body.
      */
-    private String expression;
+    private java.lang.String expression;
 
     /**
-     * A comma-separated list of roles. If present, the attribute will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
      * The type (renderer) of the attribute.
      */
-    private String type;
+    private java.lang.String type;
 
     /**
      * Getter for value property.
      *
-     * @return The value of the attribute. Use this parameter, or expression, or
-     *         body.
+     * @return
+     * The value of the attribute. Use this parameter, or
+     * expression, or body.
      */
-    public Object getValue() {
+    public java.lang.Object getValue() {
         return value;
     }
 
     /**
      * Setter for value property.
      *
-     * @param value The value of the attribute. Use this parameter, or expression,
-     *              or body.
+     * @param value
+     * The value of the attribute. Use this parameter, or
+     * expression, or body.
      */
-    public void setValue(Object value) {
+    public void setValue(java.lang.Object value) {
         this.value = value;
     }
 
     /**
      * Getter for expression property.
      *
-     * @return The expression to calculate the value from. Use this parameter, or
-     *         value, or body.
+     * @return
+     * The expression to calculate the value from. Use this
+     * parameter, or value, or body.
      */
-    public String getExpression() {
+    public java.lang.String getExpression() {
         return expression;
     }
 
     /**
      * Setter for expression property.
      *
-     * @param expression The expression to calculate the value from. Use this
-     *                   parameter, or value, or body.
+     * @param expression
+     * The expression to calculate the value from. Use this
+     * parameter, or value, or body.
      */
-    public void setExpression(String expression) {
+    public void setExpression(java.lang.String expression) {
         this.expression = expression;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the attribute will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the attribute will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for type property.
      *
-     * @return The type (renderer) of the attribute.
+     * @return
+     * The type (renderer) of the attribute.
      */
-    public String getType() {
+    public java.lang.String getType() {
         return type;
     }
 
     /**
      * Setter for type property.
      *
-     * @param type The type (renderer) of the attribute.
+     * @param type
+     * The type (renderer) of the attribute.
      */
-    public void setType(String type) {
+    public void setType(java.lang.String type) {
         this.type = type;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -159,8 +167,15 @@ public class AddAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(value, expression, role, type, request, modelBody);
+        model.execute(
+            value,
+            expression,
+            role,
+            type,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
index 5f17d8145..fd39f386f 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,14 +27,11 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.AddListAttributeModel;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Declare a list that will be pass as an attribute.
+ * Declare a list that will be pass as an attribute. 
  * </p>
  * <p>
  * Declare a list that will be pass as an attribute . List elements are added
@@ -44,36 +44,36 @@ public class AddListAttributeTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private AddListAttributeModel model = new AddListAttributeModel();
+    private org.apache.tiles.template.AddListAttributeModel model = new org.apache.tiles.template.AddListAttributeModel();
 
     /**
      * The comma-separated list of roles that can use the list attribute.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
      * Getter for role property.
      *
-     * @return The comma-separated list of roles that can use the list attribute.
+     * @return
+     * The comma-separated list of roles that can use the list attribute.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role The comma-separated list of roles that can use the list
-     *             attribute.
+     * @param role
+     * The comma-separated list of roles that can use the list attribute.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -81,8 +81,12 @@ public class AddListAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(role, request, modelBody);
+        model.execute(
+            role,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
index 340917369..e755d18dc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,14 +27,11 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.DefinitionModel;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Create a definition at runtime.
+ * Create a definition at runtime. 
  * </p>
  * <p>
  * Create a new definition at runtime. Newly created definition will be
@@ -43,134 +43,145 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private DefinitionModel model = new DefinitionModel();
+    private org.apache.tiles.template.DefinitionModel model = new org.apache.tiles.template.DefinitionModel();
 
     /**
-     * The name of the definition to create. If not specified, an anonymous
-     * definition will be created.
+     * The name of the definition to create. If not specified, an
+     * anonymous definition will be created.
      */
-    private String name;
+    private java.lang.String name;
 
     /**
      * The template of this definition.
      */
-    private String template;
+    private java.lang.String template;
 
     /**
-     * A comma-separated list of roles. If present, the definition will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the definition
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
      * The definition name that this definition extends.
      */
-    private String extendsParam;
+    private java.lang.String extendsParam;
 
     /**
-     * The preparer to use to invoke before the definition is rendered.
+     * The preparer to use to invoke before the definition is
+     * rendered.
      */
-    private String preparer;
+    private java.lang.String preparer;
 
     /**
      * Getter for name property.
      *
-     * @return The name of the definition to create. If not specified, an anonymous
-     *         definition will be created.
+     * @return
+     * The name of the definition to create. If not specified, an
+     * anonymous definition will be created.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return name;
     }
 
     /**
      * Setter for name property.
      *
-     * @param name The name of the definition to create. If not specified, an
-     *             anonymous definition will be created.
+     * @param name
+     * The name of the definition to create. If not specified, an
+     * anonymous definition will be created.
      */
-    public void setName(String name) {
+    public void setName(java.lang.String name) {
         this.name = name;
     }
 
     /**
      * Getter for template property.
      *
-     * @return The template of this definition.
+     * @return
+     * The template of this definition.
      */
-    public String getTemplate() {
+    public java.lang.String getTemplate() {
         return template;
     }
 
     /**
      * Setter for template property.
      *
-     * @param template The template of this definition.
+     * @param template
+     * The template of this definition.
      */
-    public void setTemplate(String template) {
+    public void setTemplate(java.lang.String template) {
         this.template = template;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the definition will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the definition
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the definition will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the definition
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for extends property.
      *
-     * @return The definition name that this definition extends.
+     * @return
+     * The definition name that this definition extends.
      */
-    public String getExtends() {
+    public java.lang.String getExtends() {
         return extendsParam;
     }
 
     /**
      * Setter for extends property.
      *
-     * @param extendsParam The definition name that this definition extends.
+     * @param extendsParam
+     * The definition name that this definition extends.
      */
-    public void setExtends(String extendsParam) {
+    public void setExtends(java.lang.String extendsParam) {
         this.extendsParam = extendsParam;
     }
 
     /**
      * Getter for preparer property.
      *
-     * @return The preparer to use to invoke before the definition is rendered.
+     * @return
+     * The preparer to use to invoke before the definition is
+     * rendered.
      */
-    public String getPreparer() {
+    public java.lang.String getPreparer() {
         return preparer;
     }
 
     /**
      * Setter for preparer property.
      *
-     * @param preparer The preparer to use to invoke before the definition is
-     *                 rendered.
+     * @param preparer
+     * The preparer to use to invoke before the definition is
+     * rendered.
      */
-    public void setPreparer(String preparer) {
+    public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -178,8 +189,16 @@ public class DefinitionTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(name, template, role, extendsParam, preparer, request, modelBody);
+        model.execute(
+            name,
+            template,
+            role,
+            extendsParam,
+            preparer,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
index 5cd777819..1eb28583d 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,15 +27,12 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.GetAsStringModel;
-import org.apache.tiles.api.Attribute;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Render the value of the specified template attribute to the current Writer
+ *  Render the value of the specified template attribute to the current
+ * Writer
  * </p>
  * 
  * <p>
@@ -46,58 +46,59 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private GetAsStringModel model = new GetAsStringModel();
+    private org.apache.tiles.template.GetAsStringModel model = new org.apache.tiles.template.GetAsStringModel();
 
     /**
-     * If true, if an exception happens during rendering, of if the attribute is
-     * null, the problem will be ignored.
+     * If true, if an exception happens during
+     * rendering, of if the attribute is null, the problem will be ignored.
      */
     private boolean ignore;
 
     /**
      * The preparer to invoke before rendering the attribute.
      */
-    private String preparer;
+    private java.lang.String preparer;
 
     /**
-     * A comma-separated list of roles. If present, the attribute will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
-     * The default value of the attribute. To use only if the attribute was not
-     * computed.
+     * The default value of the attribute. To use only if
+     * the attribute was not computed.
      */
-    private Object defaultValue;
+    private java.lang.Object defaultValue;
 
     /**
-     * The default comma-separated list of roles. To use only if the attribute was
-     * not computed.
+     * The default comma-separated list of roles. To use
+     * only if the attribute was not computed.
      */
-    private String defaultValueRole;
+    private java.lang.String defaultValueRole;
 
     /**
-     * The default type of the attribute. To use only if the attribute was not
-     * computed.
+     * The default type of the attribute. To use only if
+     * the attribute was not computed.
      */
-    private String defaultValueType;
+    private java.lang.String defaultValueType;
 
     /**
      * The name of the attribute.
      */
-    private String name;
+    private java.lang.String name;
 
     /**
      * The attribute to use immediately, if not null.
      */
-    private Attribute value;
+    private org.apache.tiles.api.Attribute value;
 
     /**
      * Getter for ignore property.
      *
-     * @return If true, if an exception happens during rendering, of if the
-     *         attribute is null, the problem will be ignored.
+     * @return
+     * If true, if an exception happens during
+     * rendering, of if the attribute is null, the problem will be ignored.
      */
     public boolean isIgnore() {
         return ignore;
@@ -106,8 +107,9 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for ignore property.
      *
-     * @param ignore If true, if an exception happens during rendering, of if the
-     *               attribute is null, the problem will be ignored.
+     * @param ignore
+     * If true, if an exception happens during
+     * rendering, of if the attribute is null, the problem will be ignored.
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
@@ -116,141 +118,154 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return The preparer to invoke before rendering the attribute.
+     * @return
+     * The preparer to invoke before rendering the attribute.
      */
-    public String getPreparer() {
+    public java.lang.String getPreparer() {
         return preparer;
     }
 
     /**
      * Setter for preparer property.
      *
-     * @param preparer The preparer to invoke before rendering the attribute.
+     * @param preparer
+     * The preparer to invoke before rendering the attribute.
      */
-    public void setPreparer(String preparer) {
+    public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the attribute will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the attribute will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for defaultValue property.
      *
-     * @return The default value of the attribute. To use only if the attribute was
-     *         not computed.
+     * @return
+     * The default value of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public Object getDefaultValue() {
+    public java.lang.Object getDefaultValue() {
         return defaultValue;
     }
 
     /**
      * Setter for defaultValue property.
      *
-     * @param defaultValue The default value of the attribute. To use only if the
-     *                     attribute was not computed.
+     * @param defaultValue
+     * The default value of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public void setDefaultValue(Object defaultValue) {
+    public void setDefaultValue(java.lang.Object defaultValue) {
         this.defaultValue = defaultValue;
     }
 
     /**
      * Getter for defaultValueRole property.
      *
-     * @return The default comma-separated list of roles. To use only if the
-     *         attribute was not computed.
+     * @return
+     * The default comma-separated list of roles. To use
+     * only if the attribute was not computed.
      */
-    public String getDefaultValueRole() {
+    public java.lang.String getDefaultValueRole() {
         return defaultValueRole;
     }
 
     /**
      * Setter for defaultValueRole property.
      *
-     * @param defaultValueRole The default comma-separated list of roles. To use
-     *                         only if the attribute was not computed.
+     * @param defaultValueRole
+     * The default comma-separated list of roles. To use
+     * only if the attribute was not computed.
      */
-    public void setDefaultValueRole(String defaultValueRole) {
+    public void setDefaultValueRole(java.lang.String defaultValueRole) {
         this.defaultValueRole = defaultValueRole;
     }
 
     /**
      * Getter for defaultValueType property.
      *
-     * @return The default type of the attribute. To use only if the attribute was
-     *         not computed.
+     * @return
+     * The default type of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public String getDefaultValueType() {
+    public java.lang.String getDefaultValueType() {
         return defaultValueType;
     }
 
     /**
      * Setter for defaultValueType property.
      *
-     * @param defaultValueType The default type of the attribute. To use only if the
-     *                         attribute was not computed.
+     * @param defaultValueType
+     * The default type of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public void setDefaultValueType(String defaultValueType) {
+    public void setDefaultValueType(java.lang.String defaultValueType) {
         this.defaultValueType = defaultValueType;
     }
 
     /**
      * Getter for name property.
      *
-     * @return The name of the attribute.
+     * @return
+     * The name of the attribute.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return name;
     }
 
     /**
      * Setter for name property.
      *
-     * @param name The name of the attribute.
+     * @param name
+     * The name of the attribute.
      */
-    public void setName(String name) {
+    public void setName(java.lang.String name) {
         this.name = name;
     }
 
     /**
      * Getter for value property.
      *
-     * @return The attribute to use immediately, if not null.
+     * @return
+     * The attribute to use immediately, if not null.
      */
-    public Attribute getValue() {
+    public org.apache.tiles.api.Attribute getValue() {
         return value;
     }
 
     /**
      * Setter for value property.
      *
-     * @param value The attribute to use immediately, if not null.
+     * @param value
+     * The attribute to use immediately, if not null.
      */
-    public void setValue(Attribute value) {
+    public void setValue(org.apache.tiles.api.Attribute value) {
         this.value = value;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -258,9 +273,19 @@ public class GetAsStringTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(ignore, preparer, role, defaultValue, defaultValueRole, defaultValueType, name, value, request,
-                modelBody);
+        model.execute(
+            ignore,
+            preparer,
+            role,
+            defaultValue,
+            defaultValueRole,
+            defaultValueType,
+            name,
+            value,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
index 3468f3865..13d8630cc 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,9 +27,6 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.ImportAttributeModel;
 
 /**
  * <p>
@@ -43,25 +43,25 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private ImportAttributeModel model = new ImportAttributeModel();
+    private org.apache.tiles.template.ImportAttributeModel model = new org.apache.tiles.template.ImportAttributeModel();
 
     /**
-     * The name of the attribute to import. If it is null, all the attributes will
-     * be imported.
+     * The name of the attribute to import. If it is null, all the attributes will be imported.
      */
-    private String name;
+    private java.lang.String name;
 
     /**
-     * The scope into which the attribute(s) will be imported. If null, the import
-     * will go in page scope.
+     * The scope into which the attribute(s) will be imported. If
+     * null, the import will go in page scope.
      */
-    private String scope;
+    private java.lang.String scope;
 
     /**
-     * The name of the attribute into which the attribute will be imported. To be
-     * used in conjunction to name. If null, the value of name will be used.
+     * The name of the attribute into which the attribute will be
+     * imported. To be used in conjunction to name. If
+     * null, the value of name will be used.
      */
-    private String toName;
+    private java.lang.String toName;
 
     /**
      * If true, if the attribute is not present, the problem will be ignored.
@@ -71,70 +71,74 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return The name of the attribute to import. If it is null, all the
-     *         attributes will be imported.
+     * @return
+     * The name of the attribute to import. If it is null, all the attributes will be imported.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return name;
     }
 
     /**
      * Setter for name property.
      *
-     * @param name The name of the attribute to import. If it is null, all the
-     *             attributes will be imported.
+     * @param name
+     * The name of the attribute to import. If it is null, all the attributes will be imported.
      */
-    public void setName(String name) {
+    public void setName(java.lang.String name) {
         this.name = name;
     }
 
     /**
      * Getter for scope property.
      *
-     * @return The scope into which the attribute(s) will be imported. If null, the
-     *         import will go in page scope.
+     * @return
+     * The scope into which the attribute(s) will be imported. If
+     * null, the import will go in page scope.
      */
-    public String getScope() {
+    public java.lang.String getScope() {
         return scope;
     }
 
     /**
      * Setter for scope property.
      *
-     * @param scope The scope into which the attribute(s) will be imported. If null,
-     *              the import will go in page scope.
+     * @param scope
+     * The scope into which the attribute(s) will be imported. If
+     * null, the import will go in page scope.
      */
-    public void setScope(String scope) {
+    public void setScope(java.lang.String scope) {
         this.scope = scope;
     }
 
     /**
      * Getter for toName property.
      *
-     * @return The name of the attribute into which the attribute will be imported.
-     *         To be used in conjunction to name. If null, the value of name will be
-     *         used.
+     * @return
+     * The name of the attribute into which the attribute will be
+     * imported. To be used in conjunction to name. If
+     * null, the value of name will be used.
      */
-    public String getToName() {
+    public java.lang.String getToName() {
         return toName;
     }
 
     /**
      * Setter for toName property.
      *
-     * @param toName The name of the attribute into which the attribute will be
-     *               imported. To be used in conjunction to name. If null, the value
-     *               of name will be used.
+     * @param toName
+     * The name of the attribute into which the attribute will be
+     * imported. To be used in conjunction to name. If
+     * null, the value of name will be used.
      */
-    public void setToName(String toName) {
+    public void setToName(java.lang.String toName) {
         this.toName = toName;
     }
 
     /**
      * Getter for ignore property.
      *
-     * @return If true, if the attribute is not present, the problem will be
-     *         ignored.
+     * @return
+     * If true, if the attribute is not present, the problem will be ignored.
      */
     public boolean isIgnore() {
         return ignore;
@@ -143,17 +147,16 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Setter for ignore property.
      *
-     * @param ignore If true, if the attribute is not present, the problem will be
-     *               ignored.
+     * @param ignore
+     * If true, if the attribute is not present, the problem will be ignored.
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -161,7 +164,14 @@ public class ImportAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
-        model.execute(name, scope, toName, ignore, request);
+        org.apache.tiles.request.Request request = runtime.createRequest();        
+        model.execute(
+            name,
+            scope,
+            toName,
+            ignore,
+            request
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
index 58909fc6c..f20d83ba0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,10 +27,6 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.InsertAttributeModel;
-import org.apache.tiles.api.Attribute;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
@@ -46,66 +45,65 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * </p>
  * 
  * <p>
- * Example :
+ * Example : 
  * </p>
  * 
  * <pre>
- *   &lt;code&gt;
  *     &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
- *   &lt;/code&gt;
  * </pre>
+ *     
  */
 public class InsertAttributeTag extends SimpleTagSupport {
 
     /**
      * The template model.
      */
-    private InsertAttributeModel model = new InsertAttributeModel();
+    private org.apache.tiles.template.InsertAttributeModel model = new org.apache.tiles.template.InsertAttributeModel();
 
     /**
-     * If true, if an exception happens during rendering, of if the attribute is
-     * null, the problem will be ignored.
+     * If true, if an exception happens during
+     * rendering, of if the attribute is null, the problem will be ignored.
      */
     private boolean ignore;
 
     /**
      * The preparer to invoke before rendering the attribute.
      */
-    private String preparer;
+    private java.lang.String preparer;
 
     /**
-     * A comma-separated list of roles. If present, the attribute will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
-     * The default value of the attribute. To use only if the attribute was not
-     * computed.
+     * The default value of the attribute. To use only if
+     * the attribute was not computed.
      */
-    private Object defaultValue;
+    private java.lang.Object defaultValue;
 
     /**
-     * The default comma-separated list of roles. To use only if the attribute was
-     * not computed.
+     * The default comma-separated list of roles. To use
+     * only if the attribute was not computed.
      */
-    private String defaultValueRole;
+    private java.lang.String defaultValueRole;
 
     /**
-     * The default type of the attribute. To use only if the attribute was not
-     * computed.
+     * The default type of the attribute. To use only if
+     * the attribute was not computed.
      */
-    private String defaultValueType;
+    private java.lang.String defaultValueType;
 
     /**
      * The name of the attribute.
      */
-    private String name;
+    private java.lang.String name;
 
     /**
      * The attribute to use immediately, if not null.
      */
-    private Attribute value;
+    private org.apache.tiles.api.Attribute value;
 
     /**
      * If true, the response will be flushed after the insert.
@@ -115,8 +113,9 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for ignore property.
      *
-     * @return If true, if an exception happens during rendering, of if the
-     *         attribute is null, the problem will be ignored.
+     * @return
+     * If true, if an exception happens during
+     * rendering, of if the attribute is null, the problem will be ignored.
      */
     public boolean isIgnore() {
         return ignore;
@@ -125,8 +124,9 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for ignore property.
      *
-     * @param ignore If true, if an exception happens during rendering, of if the
-     *               attribute is null, the problem will be ignored.
+     * @param ignore
+     * If true, if an exception happens during
+     * rendering, of if the attribute is null, the problem will be ignored.
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
@@ -135,141 +135,156 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return The preparer to invoke before rendering the attribute.
+     * @return
+     * The preparer to invoke before rendering the attribute.
      */
-    public String getPreparer() {
+    public java.lang.String getPreparer() {
         return preparer;
     }
 
     /**
      * Setter for preparer property.
      *
-     * @param preparer The preparer to invoke before rendering the attribute.
+     * @param preparer
+     * The preparer to invoke before rendering the attribute.
      */
-    public void setPreparer(String preparer) {
+    public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the attribute will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the attribute will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for defaultValue property.
      *
-     * @return The default value of the attribute. To use only if the attribute was
-     *         not computed.
+     * @return
+     * The default value of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public Object getDefaultValue() {
+    public java.lang.Object getDefaultValue() {
         return defaultValue;
     }
 
     /**
      * Setter for defaultValue property.
      *
-     * @param defaultValue The default value of the attribute. To use only if the
-     *                     attribute was not computed.
+     * @param defaultValue
+     * The default value of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public void setDefaultValue(Object defaultValue) {
+    public void setDefaultValue(java.lang.Object defaultValue) {
         this.defaultValue = defaultValue;
     }
 
     /**
      * Getter for defaultValueRole property.
      *
-     * @return The default comma-separated list of roles. To use only if the
-     *         attribute was not computed.
+     * @return
+     * The default comma-separated list of roles. To use
+     * only if the attribute was not computed.
      */
-    public String getDefaultValueRole() {
+    public java.lang.String getDefaultValueRole() {
         return defaultValueRole;
     }
 
     /**
      * Setter for defaultValueRole property.
      *
-     * @param defaultValueRole The default comma-separated list of roles. To use
-     *                         only if the attribute was not computed.
+     * @param defaultValueRole
+     * The default comma-separated list of roles. To use
+     * only if the attribute was not computed.
      */
-    public void setDefaultValueRole(String defaultValueRole) {
+    public void setDefaultValueRole(java.lang.String defaultValueRole) {
         this.defaultValueRole = defaultValueRole;
     }
 
     /**
      * Getter for defaultValueType property.
      *
-     * @return The default type of the attribute. To use only if the attribute was
-     *         not computed.
+     * @return
+     * The default type of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public String getDefaultValueType() {
+    public java.lang.String getDefaultValueType() {
         return defaultValueType;
     }
 
     /**
      * Setter for defaultValueType property.
      *
-     * @param defaultValueType The default type of the attribute. To use only if the
-     *                         attribute was not computed.
+     * @param defaultValueType
+     * The default type of the attribute. To use only if
+     * the attribute was not computed.
      */
-    public void setDefaultValueType(String defaultValueType) {
+    public void setDefaultValueType(java.lang.String defaultValueType) {
         this.defaultValueType = defaultValueType;
     }
 
     /**
      * Getter for name property.
      *
-     * @return The name of the attribute.
+     * @return
+     * The name of the attribute.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return name;
     }
 
     /**
      * Setter for name property.
      *
-     * @param name The name of the attribute.
+     * @param name
+     * The name of the attribute.
      */
-    public void setName(String name) {
+    public void setName(java.lang.String name) {
         this.name = name;
     }
 
     /**
      * Getter for value property.
      *
-     * @return The attribute to use immediately, if not null.
+     * @return
+     * The attribute to use immediately, if not null.
      */
-    public Attribute getValue() {
+    public org.apache.tiles.api.Attribute getValue() {
         return value;
     }
 
     /**
      * Setter for value property.
      *
-     * @param value The attribute to use immediately, if not null.
+     * @param value
+     * The attribute to use immediately, if not null.
      */
-    public void setValue(Attribute value) {
+    public void setValue(org.apache.tiles.api.Attribute value) {
         this.value = value;
     }
 
     /**
      * Getter for flush property.
      *
-     * @return If true, the response will be flushed after the insert.
+     * @return
+     * If true, the response will be flushed after the insert.
      */
     public boolean isFlush() {
         return flush;
@@ -278,16 +293,16 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for flush property.
      *
-     * @param flush If true, the response will be flushed after the insert.
+     * @param flush
+     * If true, the response will be flushed after the insert.
      */
     public void setFlush(boolean flush) {
         this.flush = flush;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -295,9 +310,20 @@ public class InsertAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(ignore, preparer, role, defaultValue, defaultValueRole, defaultValueType, name, value, flush,
-                request, modelBody);
+        model.execute(
+            ignore,
+            preparer,
+            role,
+            defaultValue,
+            defaultValueRole,
+            defaultValueType,
+            name,
+            value,
+            flush,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
index bd42a4b78..d513601b9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,9 +27,6 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.InsertDefinitionModel;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
@@ -37,20 +37,19 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * Insert a definition with the possibility to override and specify parameters
  * (called attributes). A definition can be seen as a (partially or totally)
  * filled template that can override or complete attribute values.
- * &lt;tiles:insertDefinition&gt; allows to define these attributes and pass
- * them to the inserted jsp page, called template. Attributes are defined using
- * nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+ * &lt;tiles:insertDefinition&gt; allows to define these attributes
+ * and pass them to the inserted jsp page, called template. Attributes are
+ * defined using nested tag &lt;tiles:putAttribute&gt; or
+ * &lt;tiles:putListAttribute&gt;.
  * </p>
  * <p>
- * You must specify name tag attribute, for inserting a definition from
- * definitions factory.
+ * You must specify name tag attribute, for inserting a definition from definitions factory.
  * </p>
  * <p>
- * Example :
+ * Example : 
  * </p>
  * 
  * <pre>
- *   &lt;code&gt;
  *     &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
  *     &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
  *     &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
@@ -58,48 +57,49 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  *     &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
  *     &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
  *     &lt;/tiles:insertDefinition&gt;
- *   &lt;/code&gt;
  * </pre>
+ *     
  */
 public class InsertDefinitionTag extends SimpleTagSupport {
 
     /**
      * The template model.
      */
-    private InsertDefinitionModel model = new InsertDefinitionModel();
+    private org.apache.tiles.template.InsertDefinitionModel model = new org.apache.tiles.template.InsertDefinitionModel();
 
     /**
      * The name of the definition to render.
      */
-    private String definitionName;
+    private java.lang.String definitionName;
 
     /**
-     * If specified, this template will be used instead of the one used by the
-     * definition.
+     * If specified, this template will be used instead of the
+     * one used by the definition.
      */
-    private String template;
+    private java.lang.String template;
 
     /**
      * The type of the template attribute.
      */
-    private String templateType;
+    private java.lang.String templateType;
 
     /**
      * The expression to evaluate to get the value of the template.
      */
-    private String templateExpression;
+    private java.lang.String templateExpression;
 
     /**
-     * A comma-separated list of roles. If present, the definition will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the definition
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
-     * The preparer to use to invoke before the definition is rendered. If
-     * specified, it overrides the preparer specified in the definition itself.
+     * The preparer to use to invoke before the definition is
+     * rendered. If specified, it overrides the preparer specified in the
+     * definition itself.
      */
-    private String preparer;
+    private java.lang.String preparer;
 
     /**
      * If true, the response will be flushed after the insert.
@@ -109,124 +109,136 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return The name of the definition to render.
+     * @return
+     * The name of the definition to render.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return definitionName;
     }
 
     /**
      * Setter for name property.
      *
-     * @param definitionName The name of the definition to render.
+     * @param definitionName
+     * The name of the definition to render.
      */
-    public void setName(String definitionName) {
+    public void setName(java.lang.String definitionName) {
         this.definitionName = definitionName;
     }
 
     /**
      * Getter for template property.
      *
-     * @return If specified, this template will be used instead of the one used by
-     *         the definition.
+     * @return
+     * If specified, this template will be used instead of the
+     * one used by the definition.
      */
-    public String getTemplate() {
+    public java.lang.String getTemplate() {
         return template;
     }
 
     /**
      * Setter for template property.
      *
-     * @param template If specified, this template will be used instead of the one
-     *                 used by the definition.
+     * @param template
+     * If specified, this template will be used instead of the
+     * one used by the definition.
      */
-    public void setTemplate(String template) {
+    public void setTemplate(java.lang.String template) {
         this.template = template;
     }
 
     /**
      * Getter for templateType property.
      *
-     * @return The type of the template attribute.
+     * @return
+     * The type of the template attribute.
      */
-    public String getTemplateType() {
+    public java.lang.String getTemplateType() {
         return templateType;
     }
 
     /**
      * Setter for templateType property.
      *
-     * @param templateType The type of the template attribute.
+     * @param templateType
+     * The type of the template attribute.
      */
-    public void setTemplateType(String templateType) {
+    public void setTemplateType(java.lang.String templateType) {
         this.templateType = templateType;
     }
 
     /**
      * Getter for templateExpression property.
      *
-     * @return The expression to evaluate to get the value of the template.
+     * @return
+     * The expression to evaluate to get the value of the template.
      */
-    public String getTemplateExpression() {
+    public java.lang.String getTemplateExpression() {
         return templateExpression;
     }
 
     /**
      * Setter for templateExpression property.
      *
-     * @param templateExpression The expression to evaluate to get the value of the
-     *                           template.
+     * @param templateExpression
+     * The expression to evaluate to get the value of the template.
      */
-    public void setTemplateExpression(String templateExpression) {
+    public void setTemplateExpression(java.lang.String templateExpression) {
         this.templateExpression = templateExpression;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the definition will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the definition
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the definition will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the definition
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for preparer property.
      *
-     * @return The preparer to use to invoke before the definition is rendered. If
-     *         specified, it overrides the preparer specified in the definition
-     *         itself.
+     * @return
+     * The preparer to use to invoke before the definition is
+     * rendered. If specified, it overrides the preparer specified in the
+     * definition itself.
      */
-    public String getPreparer() {
+    public java.lang.String getPreparer() {
         return preparer;
     }
 
     /**
      * Setter for preparer property.
      *
-     * @param preparer The preparer to use to invoke before the definition is
-     *                 rendered. If specified, it overrides the preparer specified
-     *                 in the definition itself.
+     * @param preparer
+     * The preparer to use to invoke before the definition is
+     * rendered. If specified, it overrides the preparer specified in the
+     * definition itself.
      */
-    public void setPreparer(String preparer) {
+    public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
     }
 
     /**
      * Getter for flush property.
      *
-     * @return If true, the response will be flushed after the insert.
+     * @return
+     * If true, the response will be flushed after the insert.
      */
     public boolean isFlush() {
         return flush;
@@ -235,16 +247,16 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for flush property.
      *
-     * @param flush If true, the response will be flushed after the insert.
+     * @param flush
+     * If true, the response will be flushed after the insert.
      */
     public void setFlush(boolean flush) {
         this.flush = flush;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -252,9 +264,18 @@ public class InsertDefinitionTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(definitionName, template, templateType, templateExpression, role, preparer, flush, request,
-                modelBody);
+        model.execute(
+            definitionName,
+            template,
+            templateType,
+            templateExpression,
+            role,
+            preparer,
+            flush,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
index aaa187068..90cd2d8cf 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,9 +27,6 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.InsertTemplateModel;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
@@ -36,9 +36,10 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * <p>
  * Insert a template with the possibility to pass parameters (called
  * attributes). A template can be seen as a procedure that can take parameters
- * or attributes. &lt;tiles:insertTemplate&gt; allows to define these attributes
- * and pass them to the inserted jsp page, called template. Attributes are
- * defined using nested tag &lt;tiles:putAttribute&gt; or
+ * or attributes. &lt;tiles:insertTemplate&gt; allows to define
+ * these attributes and pass them to the inserted jsp page, called template.
+ * Attributes are defined using nested tag
+ * &lt;tiles:putAttribute&gt; or
  * &lt;tiles:putListAttribute&gt;.
  * </p>
  * <p>
@@ -50,50 +51,50 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * </p>
  * 
  * <pre>
- *   &lt;code&gt;
  *     &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
- *       &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
- *       &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
- *       &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
- *       &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
- *       &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
  *     &lt;/tiles:insertTemplate&gt;
- *   &lt;/code&gt;
  * </pre>
+ *     
  */
 public class InsertTemplateTag extends SimpleTagSupport {
 
     /**
      * The template model.
      */
-    private InsertTemplateModel model = new InsertTemplateModel();
+    private org.apache.tiles.template.InsertTemplateModel model = new org.apache.tiles.template.InsertTemplateModel();
 
     /**
      * The template to render.
      */
-    private String template;
+    private java.lang.String template;
 
     /**
      * The type of the template attribute.
      */
-    private String templateType;
+    private java.lang.String templateType;
 
     /**
      * The expression to evaluate to get the value of the template.
      */
-    private String templateExpression;
+    private java.lang.String templateExpression;
 
     /**
-     * A comma-separated list of roles. If present, the template will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the template
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
-     * The preparer to use to invoke before the definition is rendered. If
-     * specified, it overrides the preparer specified in the definition itself.
+     * The preparer to use to invoke before the definition is
+     * rendered. If specified, it overrides the preparer specified in the
+     * definition itself.
      */
-    private String preparer;
+    private java.lang.String preparer;
 
     /**
      * If true, the response will be flushed after the insert.
@@ -103,104 +104,114 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for template property.
      *
-     * @return The template to render.
+     * @return
+     * The template to render.
      */
-    public String getTemplate() {
+    public java.lang.String getTemplate() {
         return template;
     }
 
     /**
      * Setter for template property.
      *
-     * @param template The template to render.
+     * @param template
+     * The template to render.
      */
-    public void setTemplate(String template) {
+    public void setTemplate(java.lang.String template) {
         this.template = template;
     }
 
     /**
      * Getter for templateType property.
      *
-     * @return The type of the template attribute.
+     * @return
+     * The type of the template attribute.
      */
-    public String getTemplateType() {
+    public java.lang.String getTemplateType() {
         return templateType;
     }
 
     /**
      * Setter for templateType property.
      *
-     * @param templateType The type of the template attribute.
+     * @param templateType
+     * The type of the template attribute.
      */
-    public void setTemplateType(String templateType) {
+    public void setTemplateType(java.lang.String templateType) {
         this.templateType = templateType;
     }
 
     /**
      * Getter for templateExpression property.
      *
-     * @return The expression to evaluate to get the value of the template.
+     * @return
+     * The expression to evaluate to get the value of the template.
      */
-    public String getTemplateExpression() {
+    public java.lang.String getTemplateExpression() {
         return templateExpression;
     }
 
     /**
      * Setter for templateExpression property.
      *
-     * @param templateExpression The expression to evaluate to get the value of the
-     *                           template.
+     * @param templateExpression
+     * The expression to evaluate to get the value of the template.
      */
-    public void setTemplateExpression(String templateExpression) {
+    public void setTemplateExpression(java.lang.String templateExpression) {
         this.templateExpression = templateExpression;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the template will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the template
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the template will be
-     *             rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the template
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for preparer property.
      *
-     * @return The preparer to use to invoke before the definition is rendered. If
-     *         specified, it overrides the preparer specified in the definition
-     *         itself.
+     * @return
+     * The preparer to use to invoke before the definition is
+     * rendered. If specified, it overrides the preparer specified in the
+     * definition itself.
      */
-    public String getPreparer() {
+    public java.lang.String getPreparer() {
         return preparer;
     }
 
     /**
      * Setter for preparer property.
      *
-     * @param preparer The preparer to use to invoke before the definition is
-     *                 rendered. If specified, it overrides the preparer specified
-     *                 in the definition itself.
+     * @param preparer
+     * The preparer to use to invoke before the definition is
+     * rendered. If specified, it overrides the preparer specified in the
+     * definition itself.
      */
-    public void setPreparer(String preparer) {
+    public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
     }
 
     /**
      * Getter for flush property.
      *
-     * @return If true, the response will be flushed after the insert.
+     * @return
+     * If true, the response will be flushed after the insert.
      */
     public boolean isFlush() {
         return flush;
@@ -209,16 +220,16 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for flush property.
      *
-     * @param flush If true, the response will be flushed after the insert.
+     * @param flush
+     * If true, the response will be flushed after the insert.
      */
     public void setFlush(boolean flush) {
         this.flush = flush;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -226,8 +237,17 @@ public class InsertTemplateTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(template, templateType, templateExpression, role, preparer, flush, request, modelBody);
+        model.execute(
+            template,
+            templateType,
+            templateExpression,
+            role,
+            preparer,
+            flush,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
index f687d7e49..2d04fff3e 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,9 +27,6 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.PutAttributeModel;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
@@ -42,8 +42,8 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * <li>&lt;insertDefinition&gt;</li>
  * <li>&lt;putListAttribute&gt;</li>
  * </ul>
- * (or any other tag which implements the PutAttributeTagParent interface.
- * Exception is thrown if no appropriate tag can be found.
+ * (or any other tag which implements the PutAttributeTagParent
+ * interface. Exception is thrown if no appropriate tag can be found.
  * </p>
  * <p>
  * Put tag can have following atributes :
@@ -67,34 +67,35 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private PutAttributeModel model = new org.apache.tiles.template.PutAttributeModel();
+    private org.apache.tiles.template.PutAttributeModel model = new org.apache.tiles.template.PutAttributeModel();
 
     /**
      * The name of the attribute to put.
      */
-    private String name;
+    private java.lang.String name;
 
     /**
-     * The value of the attribute. Use this parameter, or expression, or body.
+     * The value of the attribute. Use this parameter, or
+     * expression, or body.
      */
-    private Object value;
+    private java.lang.Object value;
 
     /**
-     * The expression to calculate the value from. Use this parameter, or value, or
-     * body.
+     * The expression to calculate the value from. Use this
+     * parameter, or value, or body.
      */
-    private String expression;
+    private java.lang.String expression;
 
     /**
-     * A comma-separated list of roles. If present, the attribute will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
      * The type (renderer) of the attribute.
      */
-    private String type;
+    private java.lang.String type;
 
     /**
      * If true the attribute will be cascaded to all nested attributes.
@@ -104,103 +105,114 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return The name of the attribute to put.
+     * @return
+     * The name of the attribute to put.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return name;
     }
 
     /**
      * Setter for name property.
      *
-     * @param name The name of the attribute to put.
+     * @param name
+     * The name of the attribute to put.
      */
-    public void setName(String name) {
+    public void setName(java.lang.String name) {
         this.name = name;
     }
 
     /**
      * Getter for value property.
      *
-     * @return The value of the attribute. Use this parameter, or expression, or
-     *         body.
+     * @return
+     * The value of the attribute. Use this parameter, or
+     * expression, or body.
      */
-    public Object getValue() {
+    public java.lang.Object getValue() {
         return value;
     }
 
     /**
      * Setter for value property.
      *
-     * @param value The value of the attribute. Use this parameter, or expression,
-     *              or body.
+     * @param value
+     * The value of the attribute. Use this parameter, or
+     * expression, or body.
      */
-    public void setValue(Object value) {
+    public void setValue(java.lang.Object value) {
         this.value = value;
     }
 
     /**
      * Getter for expression property.
      *
-     * @return The expression to calculate the value from. Use this parameter, or
-     *         value, or body.
+     * @return
+     * The expression to calculate the value from. Use this
+     * parameter, or value, or body.
      */
-    public String getExpression() {
+    public java.lang.String getExpression() {
         return expression;
     }
 
     /**
      * Setter for expression property.
      *
-     * @param expression The expression to calculate the value from. Use this
-     *                   parameter, or value, or body.
+     * @param expression
+     * The expression to calculate the value from. Use this
+     * parameter, or value, or body.
      */
-    public void setExpression(String expression) {
+    public void setExpression(java.lang.String expression) {
         this.expression = expression;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the attribute will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the attribute will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for type property.
      *
-     * @return The type (renderer) of the attribute.
+     * @return
+     * The type (renderer) of the attribute.
      */
-    public String getType() {
+    public java.lang.String getType() {
         return type;
     }
 
     /**
      * Setter for type property.
      *
-     * @param type The type (renderer) of the attribute.
+     * @param type
+     * The type (renderer) of the attribute.
      */
-    public void setType(String type) {
+    public void setType(java.lang.String type) {
         this.type = type;
     }
 
     /**
      * Getter for cascade property.
      *
-     * @return If true the attribute will be cascaded to all nested attributes.
+     * @return
+     * If true the attribute will be cascaded to all nested attributes.
      */
     public boolean isCascade() {
         return cascade;
@@ -209,17 +221,16 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for cascade property.
      *
-     * @param cascade If true the attribute will be cascaded to all nested
-     *                attributes.
+     * @param cascade
+     * If true the attribute will be cascaded to all nested attributes.
      */
     public void setCascade(boolean cascade) {
         this.cascade = cascade;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -227,8 +238,17 @@ public class PutAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(name, value, expression, role, type, cascade, request, modelBody);
+        model.execute(
+            name,
+            value,
+            expression,
+            role,
+            type,
+            cascade,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
index b60628f25..7befc81d1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,13 +27,11 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Declare a list that will be pass as attribute to tile.
+ * Declare a list that will be pass as attribute to tile. 
  * </p>
  * <p>
  * Declare a list that will be pass as attribute to tile. List elements are
@@ -48,17 +49,17 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * The name of the attribute to put.
      */
-    private String name;
+    private java.lang.String name;
 
     /**
-     * A comma-separated list of roles. If present, the attribute will be rendered
-     * only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    private String role;
+    private java.lang.String role;
 
     /**
-     * If true, the list attribute will use, as first elements, the list contained
-     * in the list attribute, put with the same name, of the containing definition.
+     * If true, the list attribute will use, as first elements, the
+     * list contained in the list attribute, put with the same name, of the containing definition.
      */
     private boolean inherit;
 
@@ -70,47 +71,51 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return The name of the attribute to put.
+     * @return
+     * The name of the attribute to put.
      */
-    public String getName() {
+    public java.lang.String getName() {
         return name;
     }
 
     /**
      * Setter for name property.
      *
-     * @param name The name of the attribute to put.
+     * @param name
+     * The name of the attribute to put.
      */
-    public void setName(String name) {
+    public void setName(java.lang.String name) {
         this.name = name;
     }
 
     /**
      * Getter for role property.
      *
-     * @return A comma-separated list of roles. If present, the attribute will be
-     *         rendered only if the current user belongs to one of the roles.
+     * @return
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public String getRole() {
+    public java.lang.String getRole() {
         return role;
     }
 
     /**
      * Setter for role property.
      *
-     * @param role A comma-separated list of roles. If present, the attribute will
-     *             be rendered only if the current user belongs to one of the roles.
+     * @param role
+     * A comma-separated list of roles. If present, the attribute
+     * will be rendered only if the current user belongs to one of the roles.
      */
-    public void setRole(String role) {
+    public void setRole(java.lang.String role) {
         this.role = role;
     }
 
     /**
      * Getter for inherit property.
      *
-     * @return If true, the list attribute will use, as first elements, the list
-     *         contained in the list attribute, put with the same name, of the
-     *         containing definition.
+     * @return
+     * If true, the list attribute will use, as first elements, the
+     * list contained in the list attribute, put with the same name, of the containing definition.
      */
     public boolean isInherit() {
         return inherit;
@@ -119,9 +124,9 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for inherit property.
      *
-     * @param inherit If true, the list attribute will use, as first elements, the
-     *                list contained in the list attribute, put with the same name,
-     *                of the containing definition.
+     * @param inherit
+     * If true, the list attribute will use, as first elements, the
+     * list contained in the list attribute, put with the same name, of the containing definition.
      */
     public void setInherit(boolean inherit) {
         this.inherit = inherit;
@@ -130,7 +135,8 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for cascade property.
      *
-     * @return If true the attribute will be cascaded to all nested attributes.
+     * @return
+     * If true the attribute will be cascaded to all nested attributes.
      */
     public boolean isCascade() {
         return cascade;
@@ -139,17 +145,16 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for cascade property.
      *
-     * @param cascade If true the attribute will be cascaded to all nested
-     *                attributes.
+     * @param cascade
+     * If true the attribute will be cascaded to all nested attributes.
      */
     public void setCascade(boolean cascade) {
         this.cascade = cascade;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -157,8 +162,15 @@ public class PutListAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        org.apache.tiles.request.Request request = runtime.createRequest();        
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(name, role, inherit, cascade, request, modelBody);
+        model.execute(
+            name,
+            role,
+            inherit,
+            cascade,
+            request, modelBody
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
index ee4877c38..802dfb411 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+ /*
+ * This file was automatically generated by Apache Tiles Autotag.
+ */
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -24,9 +27,6 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.SetCurrentContainerModel;
 
 /**
  * Selects a container to be used as the "current" container.
@@ -36,38 +36,36 @@ public class SetCurrentContainerTag extends SimpleTagSupport {
     /**
      * The template model.
      */
-    private SetCurrentContainerModel model = new SetCurrentContainerModel();
+    private org.apache.tiles.template.SetCurrentContainerModel model = new org.apache.tiles.template.SetCurrentContainerModel();
 
     /**
-     * The key of the container to be used as "current". If null, the default one
-     * will be used.
+     * The key of the container to be used as "current". If null, the default one will be used.
      */
-    private String containerKey;
+    private java.lang.String containerKey;
 
     /**
      * Getter for containerKey property.
      *
-     * @return The key of the container to be used as "current". If null, the
-     *         default one will be used.
+     * @return
+     * The key of the container to be used as "current". If null, the default one will be used.
      */
-    public String getContainerKey() {
+    public java.lang.String getContainerKey() {
         return containerKey;
     }
 
     /**
      * Setter for containerKey property.
      *
-     * @param containerKey The key of the container to be used as "current". If
-     *                     null, the default one will be used.
+     * @param containerKey
+     * The key of the container to be used as "current". If null, the default one will be used.
      */
-    public void setContainerKey(String containerKey) {
+    public void setContainerKey(java.lang.String containerKey) {
         this.containerKey = containerKey;
     }
 
-    /** {@inheritDoc} */
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.jsp.autotag.JspAutotagRuntime();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -75,7 +73,11 @@ public class SetCurrentContainerTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
-        model.execute(containerKey, request);
+        org.apache.tiles.request.Request request = runtime.createRequest();        
+        model.execute(
+            containerKey,
+            request
+
+        );
     }
 }
diff --git a/plugins/tiles/src/main/resources/META-INF/template-suite.xml b/plugins/tiles/src/main/resources/META-INF/template-suite.xml
new file mode 100644
index 000000000..3d0a48ec5
--- /dev/null
+++ b/plugins/tiles/src/main/resources/META-INF/template-suite.xml
@@ -0,0 +1,1188 @@
+<!--
+/*
+ * 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.
+ */
+-->
+<org.apache.tiles.autotag.model.TemplateSuite>
+  <name>tiles</name>
+  <documentation>This tag library provides Tiles tags.</documentation>
+  <templateClasses class="linked-hash-map">
+    <entry>
+      <string>org.apache.tiles.template.InsertDefinitionModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.InsertDefinitionModel</name>
+        <tagName>insertDefinition</tagName>
+        <tagClassPrefix>InsertDefinition</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Insert a definition.
+&lt;/p&gt;
+&lt;p&gt;
+Insert a definition with the possibility to override and specify parameters
+(called attributes). A definition can be seen as a (partially or totally)
+filled template that can override or complete attribute values.
+&amp;lt;tiles:insertDefinition&amp;gt; allows to define these attributes
+and pass them to the inserted jsp page, called template. Attributes are
+defined using nested tag &amp;lt;tiles:putAttribute&amp;gt; or
+&amp;lt;tiles:putListAttribute&amp;gt;.
+&lt;/p&gt;
+&lt;p&gt;
+You must specify name tag attribute, for inserting a definition from definitions factory.
+&lt;/p&gt;
+&lt;p&gt;
+Example : 
+&lt;/p&gt;
+
+&lt;pre&gt;
+    &amp;lt;tiles:insertDefinition name=&amp;quot;.my.tiles.defininition flush=&amp;quot;true&amp;quot;&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;title&amp;quot; value=&amp;quot;My first page&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;header&amp;quot; value=&amp;quot;/common/header.jsp&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;footer&amp;quot; value=&amp;quot;/common/footer.jsp&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;menu&amp;quot; value=&amp;quot;/basic/menu.jsp&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;body&amp;quot; value=&amp;quot;/basic/helloBody.jsp&amp;quot; /&amp;gt;
+    &amp;lt;/tiles:insertDefinition&amp;gt;
+&lt;/pre&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>definitionName</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>definitionName</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the definition to render.</documentation>
+                <type>java.lang.String</type>
+                <required>true</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>template</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>template</name>
+                <exportedName>template</exportedName>
+                <documentation>If specified, this template will be used instead of the one used by the definition.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>templateType</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>templateType</name>
+                <exportedName>templateType</exportedName>
+                <documentation>The type of the template attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>templateExpression</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>templateExpression</name>
+                <exportedName>templateExpression</exportedName>
+                <documentation>The expression to evaluate to get the value of the template.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the definition
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>preparer</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>preparer</name>
+                <exportedName>preparer</exportedName>
+                <documentation>The preparer to use to invoke before the definition is
+rendered. If specified, it overrides the preparer specified in the definition itself.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>flush</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>flush</name>
+                <exportedName>flush</exportedName>
+                <documentation>If true, the response will be flushed after the insert.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.ImportAttributeModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.ImportAttributeModel</name>
+        <tagName>importAttribute</tagName>
+        <tagClassPrefix>ImportAttribute</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Import attribute(s) in specified context.
+&lt;/p&gt;
+&lt;p&gt;
+Import attribute(s) to requested scope. Attribute name and scope are
+optional. If not specified, all attributes are imported in page scope. Once
+imported, an attribute can be used as any other beans from jsp contexts.
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the model.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>name</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>name</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the attribute to import. If it is null, all the attributes will be imported.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>scope</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>scope</name>
+                <exportedName>scope</exportedName>
+                <documentation>The scope into which the attribute(s) will be imported. If
+null, the import will go in page scope.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>toName</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>toName</name>
+                <exportedName>toName</exportedName>
+                <documentation>The name of the attribute into which the attribute will be
+imported. To be used in conjunction to name. If null, the value of name will be used.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>ignore</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>ignore</name>
+                <exportedName>ignore</exportedName>
+                <documentation>If true, if the attribute is not present, the problem will be ignored.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.SetCurrentContainerModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.SetCurrentContainerModel</name>
+        <tagName>setCurrentContainer</tagName>
+        <tagClassPrefix>SetCurrentContainer</tagClassPrefix>
+        <documentation>Selects a container to be used as the &quot;current&quot; container.</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the model.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>containerKey</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>containerKey</name>
+                <exportedName>containerKey</exportedName>
+                <documentation>The key of the container to be used as &quot;current&quot;. If null, the default one will be used.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.AddListAttributeModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.AddListAttributeModel</name>
+        <tagName>addListAttribute</tagName>
+        <tagClassPrefix>AddListAttribute</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Declare a list that will be pass as an attribute. 
+&lt;/p&gt;
+&lt;p&gt;
+Declare a list that will be pass as an attribute . List elements are added
+using the tag &apos;addAttribute&apos; or &apos;addListAttribute&apos;. This tag can only be used
+inside &apos;insertTemplate&apos;, &apos;insertDefinition&apos; or &apos;definition&apos; tag.
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the model.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>The comma-separated list of roles that can use the list attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.GetAsStringModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.GetAsStringModel</name>
+        <tagName>getAsString</tagName>
+        <tagClassPrefix>GetAsString</tagClassPrefix>
+        <documentation>&lt;p&gt;
+ Render the value of the specified template attribute to the current Writer
+&lt;/p&gt;
+
+&lt;p&gt;
+Retrieve the value of the specified template attribute property, and render
+it to the current Writer as a String. The usual toString() conversions is applied on found value.
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>ignore</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>ignore</name>
+                <exportedName>ignore</exportedName>
+                <documentation>If true, if an exception happens during
+rendering, of if the attribute is null, the problem will be ignored.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>preparer</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>preparer</name>
+                <exportedName>preparer</exportedName>
+                <documentation>The preparer to invoke before rendering the attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the attribute
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>defaultValue</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>defaultValue</name>
+                <exportedName>defaultValue</exportedName>
+                <documentation>The default value of the attribute. To use only if
+the attribute was not computed.</documentation>
+                <type>java.lang.Object</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>defaultValueRole</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>defaultValueRole</name>
+                <exportedName>defaultValueRole</exportedName>
+                <documentation>The default comma-separated list of roles. To use
+only if the attribute was not computed.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>defaultValueType</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>defaultValueType</name>
+                <exportedName>defaultValueType</exportedName>
+                <documentation>The default type of the attribute. To use only if
+the attribute was not computed.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>name</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>name</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>true</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>value</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>value</name>
+                <exportedName>value</exportedName>
+                <documentation>The attribute to use immediately, if not null.</documentation>
+                <type>org.apache.tiles.api.Attribute</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.InsertAttributeModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.InsertAttributeModel</name>
+        <tagName>insertAttribute</tagName>
+        <tagClassPrefix>InsertAttribute</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Inserts the value of an attribute into the page.
+&lt;/p&gt;
+&lt;p&gt;
+This tag can be flexibly used to insert the value of an attribute into a
+page. As in other usages in Tiles, every attribute can be determined to have
+a &quot;type&quot;, either set explicitly when it was defined, or &quot;computed&quot;. If the
+type is not explicit, then if the attribute value is a valid definition, it
+will be inserted as such. Otherwise, if it begins with a &quot;/&quot; character, it
+will be treated as a &quot;template&quot;. Finally, if it has not otherwise been
+assigned a type, it will be treated as a String and included without any special handling.
+&lt;/p&gt;
+
+&lt;p&gt;
+Example : 
+&lt;/p&gt;
+
+&lt;pre&gt;
+    &amp;lt;tiles:insertAttribute name=&amp;quot;body&amp;quot; /&amp;gt;
+&lt;/pre&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>ignore</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>ignore</name>
+                <exportedName>ignore</exportedName>
+                <documentation>If true, if an exception happens during
+rendering, of if the attribute is null, the problem will be ignored.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>preparer</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>preparer</name>
+                <exportedName>preparer</exportedName>
+                <documentation>The preparer to invoke before rendering the attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the attribute
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>defaultValue</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>defaultValue</name>
+                <exportedName>defaultValue</exportedName>
+                <documentation>The default value of the attribute. To use only if
+the attribute was not computed.</documentation>
+                <type>java.lang.Object</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>defaultValueRole</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>defaultValueRole</name>
+                <exportedName>defaultValueRole</exportedName>
+                <documentation>The default comma-separated list of roles. To use
+only if the attribute was not computed.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>defaultValueType</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>defaultValueType</name>
+                <exportedName>defaultValueType</exportedName>
+                <documentation>The default type of the attribute. To use only if
+the attribute was not computed.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>name</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>name</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>value</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>value</name>
+                <exportedName>value</exportedName>
+                <documentation>The attribute to use immediately, if not null.</documentation>
+                <type>org.apache.tiles.api.Attribute</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>flush</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>flush</name>
+                <exportedName>flush</exportedName>
+                <documentation>If true, the response will be flushed after the insert.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.PutAttributeModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.PutAttributeModel</name>
+        <tagName>putAttribute</tagName>
+        <tagClassPrefix>PutAttribute</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Put an attribute in enclosing attribute container tag.
+&lt;/p&gt;
+&lt;p&gt;
+Enclosing attribute container tag can be :
+&lt;ul&gt;
+&lt;li&gt;&amp;lt;initContainer&amp;gt;&lt;/li&gt;
+&lt;li&gt;&amp;lt;definition&amp;gt;&lt;/li&gt;
+&lt;li&gt;&amp;lt;insertAttribute&amp;gt;&lt;/li&gt;
+&lt;li&gt;&amp;lt;insertDefinition&amp;gt;&lt;/li&gt;
+&lt;li&gt;&amp;lt;putListAttribute&amp;gt;&lt;/li&gt;
+&lt;/ul&gt;
+(or any other tag which implements the PutAttributeTagParent
+interface. Exception is thrown if no appropriate tag can be found.
+&lt;/p&gt;
+&lt;p&gt;
+Put tag can have following atributes :
+&lt;ul&gt;
+&lt;li&gt;name : Name of the attribute&lt;/li&gt;
+&lt;li&gt;value : value to put as attribute&lt;/li&gt;
+&lt;li&gt;type : value type. Possible type are : string (value is used as direct
+string), template (value is used as a page url to insert), definition (value
+is used as a definition name to insert), object (value is used as it is)&lt;/li&gt;
+&lt;li&gt;role : Role to check when &apos;insertAttribute&apos; will be called.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/p&gt;
+&lt;p&gt;
+Value can also come from tag body. Tag body is taken into account only if
+value is not set by one of the tag attributes. In this case Attribute type is
+&quot;string&quot;, unless tag body define another type.
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>name</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>name</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the attribute to put.</documentation>
+                <type>java.lang.String</type>
+                <required>true</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>value</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>value</name>
+                <exportedName>value</exportedName>
+                <documentation>The value of the attribute. Use this parameter, or expression, or body.</documentation>
+                <type>java.lang.Object</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>expression</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>expression</name>
+                <exportedName>expression</exportedName>
+                <documentation>The expression to calculate the value from. Use this
+parameter, or value, or body.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the attribute
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>type</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>type</name>
+                <exportedName>type</exportedName>
+                <documentation>The type (renderer) of the attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>cascade</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>cascade</name>
+                <exportedName>cascade</exportedName>
+                <documentation>If true the attribute will be cascaded to all nested attributes.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.DefinitionModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.DefinitionModel</name>
+        <tagName>definition</tagName>
+        <tagClassPrefix>Definition</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Create a definition at runtime. 
+&lt;/p&gt;
+&lt;p&gt;
+Create a new definition at runtime. Newly created definition will be
+available across the entire request.
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>name</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>name</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the definition to create. If not specified, an
+anonymous definition will be created.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>template</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>template</name>
+                <exportedName>template</exportedName>
+                <documentation>The template of this definition.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the definition
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>extendsParam</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>extendsParam</name>
+                <exportedName>extends</exportedName>
+                <documentation>The definition name that this definition extends.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>preparer</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>preparer</name>
+                <exportedName>preparer</exportedName>
+                <documentation>The preparer to use to invoke before the definition is rendered.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.AddAttributeModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.AddAttributeModel</name>
+        <tagName>addAttribute</tagName>
+        <tagClassPrefix>AddAttribute</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Add an element to the surrounding list. Equivalent to &apos;putAttribute&apos;,
+but for list element.
+&lt;/p&gt;
+
+&lt;p&gt;
+Add an element to the surrounding list. This tag can only be used inside
+&apos;putListAttribute&apos; or &apos;addListAttribute&apos; tags. Value can come from a direct
+assignment (value=&quot;aValue&quot;)
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>value</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>value</name>
+                <exportedName>value</exportedName>
+                <documentation>The value of the attribute. Use this parameter, or expression, or body.</documentation>
+                <type>java.lang.Object</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>expression</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>expression</name>
+                <exportedName>expression</exportedName>
+                <documentation>The expression to calculate the value from. Use this
+parameter, or value, or body.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the attribute
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>type</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>type</name>
+                <exportedName>type</exportedName>
+                <documentation>The type (renderer) of the attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.PutListAttributeModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.PutListAttributeModel</name>
+        <tagName>putListAttribute</tagName>
+        <tagClassPrefix>PutListAttribute</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Declare a list that will be pass as attribute to tile. 
+&lt;/p&gt;
+&lt;p&gt;
+Declare a list that will be pass as attribute to tile. List elements are
+added using the tags &apos;addAttribute&apos; or &apos;addListAttribute&apos;. This tag can only
+be used inside &apos;insertTemplate&apos;, &apos;insertDefinition&apos;, &apos;definition&apos; tags.
+&lt;/p&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the model.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>name</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>name</name>
+                <exportedName>name</exportedName>
+                <documentation>The name of the attribute to put.</documentation>
+                <type>java.lang.String</type>
+                <required>true</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the attribute
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>inherit</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>inherit</name>
+                <exportedName>inherit</exportedName>
+                <documentation>If true, the list attribute will use, as first elements, the
+list contained in the list attribute, put with the same name, of the containing definition.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>cascade</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>cascade</name>
+                <exportedName>cascade</exportedName>
+                <documentation>If true the attribute will be cascaded to all nested attributes.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+    <entry>
+      <string>org.apache.tiles.template.InsertTemplateModel</string>
+      <org.apache.tiles.autotag.model.TemplateClass>
+        <name>org.apache.tiles.template.InsertTemplateModel</name>
+        <tagName>insertTemplate</tagName>
+        <tagClassPrefix>InsertTemplate</tagClassPrefix>
+        <documentation>&lt;p&gt;
+Insert a template.
+&lt;/p&gt;
+&lt;p&gt;
+Insert a template with the possibility to pass parameters (called
+attributes). A template can be seen as a procedure that can take parameters
+or attributes. &amp;lt;tiles:insertTemplate&amp;gt; allows to define
+these attributes and pass them to the inserted jsp page, called template.
+Attributes are defined using nested tag
+&amp;lt;tiles:putAttribute&amp;gt; or
+&amp;lt;tiles:putListAttribute&amp;gt;.
+&lt;/p&gt;
+&lt;p&gt;
+You must specify template attribute, for inserting a template
+&lt;/p&gt;
+
+&lt;p&gt;
+Example :
+&lt;/p&gt;
+
+&lt;pre&gt;
+    &amp;lt;tiles:insertTemplate template=&amp;quot;/basic/myLayout.jsp&amp;quot; flush=&amp;quot;true&amp;quot;&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;title&amp;quot; value=&amp;quot;My first page&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;header&amp;quot; value=&amp;quot;/common/header.jsp&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;footer&amp;quot; value=&amp;quot;/common/footer.jsp&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;menu&amp;quot; value=&amp;quot;/basic/menu.jsp&amp;quot; /&amp;gt;
+        &amp;lt;tiles:putAttribute name=&amp;quot;body&amp;quot; value=&amp;quot;/basic/helloBody.jsp&amp;quot; /&amp;gt;
+    &amp;lt;/tiles:insertTemplate&amp;gt;
+&lt;/pre&gt;</documentation>
+        <executeMethod>
+          <name>execute</name>
+          <documentation>Executes the operation.</documentation>
+          <parameters class="linked-hash-map">
+            <entry>
+              <string>template</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>template</name>
+                <exportedName>template</exportedName>
+                <documentation>The template to render.</documentation>
+                <type>java.lang.String</type>
+                <required>true</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>templateType</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>templateType</name>
+                <exportedName>templateType</exportedName>
+                <documentation>The type of the template attribute.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>templateExpression</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>templateExpression</name>
+                <exportedName>templateExpression</exportedName>
+                <documentation>The expression to evaluate to get the value of the template.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>role</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>role</name>
+                <exportedName>role</exportedName>
+                <documentation>A comma-separated list of roles. If present, the template
+will be rendered only if the current user belongs to one of the roles.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>preparer</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>preparer</name>
+                <exportedName>preparer</exportedName>
+                <documentation>The preparer to use to invoke before the definition is
+rendered. If specified, it overrides the preparer specified in the
+definition itself.</documentation>
+                <type>java.lang.String</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>flush</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>flush</name>
+                <exportedName>flush</exportedName>
+                <documentation>If true, the response will be flushed after the insert.</documentation>
+                <type>boolean</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>request</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>request</name>
+                <exportedName>request</exportedName>
+                <documentation>The request.</documentation>
+                <type>org.apache.tiles.request.Request</type>
+                <required>false</required>
+                <request>true</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+            <entry>
+              <string>modelBody</string>
+              <org.apache.tiles.autotag.model.TemplateParameter>
+                <name>modelBody</name>
+                <exportedName>modelBody</exportedName>
+                <documentation>The body.</documentation>
+                <type>org.apache.tiles.autotag.core.runtime.ModelBody</type>
+                <required>false</required>
+                <request>false</request>
+              </org.apache.tiles.autotag.model.TemplateParameter>
+            </entry>
+          </parameters>
+        </executeMethod>
+      </org.apache.tiles.autotag.model.TemplateClass>
+    </entry>
+  </templateClasses>
+</org.apache.tiles.autotag.model.TemplateSuite>
\ No newline at end of file
diff --git a/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld b/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
index 6a85017ac..10d63e325 100644
--- a/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
+++ b/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
@@ -19,13 +19,14 @@
  * under the License.
  */
 -->
+<!-- This file was automatically generated.  Please do not edit it manually -->
 <taglib
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
   xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   version="2.1">
    <description>
    <![CDATA[
-   <p>This tag library provides Tiles tags.</p>
+   This tag library provides Tiles tags.
    ]]>
    </description>
    <tlib-version>1.2</tlib-version>
@@ -34,13 +35,17 @@
    <tag>
       <description>
       <![CDATA[
-      <p>Insert a definition.</p>
       <p>
-      Insert a definition with the possibility to override and specify parameters (called attributes).
-      A definition can be seen as a (partially or totally) filled template that can override or
-      complete attribute values. &lt;tiles:insertDefinition&gt; allows to define these attributes
-      and pass them to the inserted jsp page, called template. Attributes are defined using nested
-      tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+      Insert a definition.
+      </p>
+      <p>
+      Insert a definition with the possibility to override and specify parameters
+      (called attributes). A definition can be seen as a (partially or totally)
+      filled template that can override or complete attribute values.
+      &lt;tiles:insertDefinition&gt; allows to define these attributes
+      and pass them to the inserted jsp page, called template. Attributes are
+      defined using nested tag &lt;tiles:putAttribute&gt; or
+      &lt;tiles:putListAttribute&gt;.
       </p>
       <p>
       You must specify name tag attribute, for inserting a definition from definitions factory.
@@ -48,14 +53,15 @@
       <p>
       Example : 
       </p>
+      
       <pre>
-        &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
-          &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
-        &lt;/tiles:insertDefinition&gt;
+          &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
+              &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+          &lt;/tiles:insertDefinition&gt;
       </pre>
       ]]>
       </description>
@@ -109,8 +115,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the definition will be rendered only if
-         the current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the definition
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -121,8 +127,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The preparer to use to invoke before the definition is rendered. If specified, it
-         overrides the preparer specified in the definition itself.
+         The preparer to use to invoke before the definition is
+         rendered. If specified, it overrides the preparer specified in the definition itself.
          ]]>
          </description>
          <name>preparer</name>
@@ -149,9 +155,9 @@
       Import attribute(s) in specified context.
       </p>
       <p>
-      Import attribute(s) to requested scope. Attribute name and scope are optional. If not
-      specified, all attributes are imported in page scope. Once imported, an attribute can be
-      used as any other beans from jsp contexts.
+      Import attribute(s) to requested scope. Attribute name and scope are
+      optional. If not specified, all attributes are imported in page scope. Once
+      imported, an attribute can be used as any other beans from jsp contexts.
       </p>
       ]]>
       </description>
@@ -172,8 +178,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The scope into which the attribute(s) will be imported. If null, the import will go in page
-         scope.
+         The scope into which the attribute(s) will be imported. If
+         null, the import will go in page scope.
          ]]>
          </description>
          <name>scope</name>
@@ -184,8 +190,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The name of the attribute into which the attribute will be imported. To be used in conjunction
-         to name. If null, the value of name will be used.
+         The name of the attribute into which the attribute will be
+         imported. To be used in conjunction to name. If null, the value of name will be used.
          ]]>
          </description>
          <name>toName</name>
@@ -217,7 +223,7 @@
       <attribute>
          <description>
          <![CDATA[
-         The key of the container to be used as 'current'. If null, the default one will be used.
+         The key of the container to be used as "current". If null, the default one will be used.
          ]]>
          </description>
          <name>containerKey</name>
@@ -233,9 +239,9 @@
       Declare a list that will be pass as an attribute. 
       </p>
       <p>
-      Declare a list that will be pass as an attribute . List elements are added using the tag
-      'addAttribute' or 'addListAttribute'. This tag can only be used inside 'insertTemplate',
-      'insertDefinition' or 'definition' tag.
+      Declare a list that will be pass as an attribute . List elements are added
+      using the tag 'addAttribute' or 'addListAttribute'. This tag can only be used
+      inside 'insertTemplate', 'insertDefinition' or 'definition' tag.
       </p>
       ]]>
       </description>
@@ -258,11 +264,12 @@
       <description>
       <![CDATA[
       <p>
-      Render the value of the specified template attribute to the current Writer
+       Render the value of the specified template attribute to the current Writer
       </p>
+      
       <p>
-      Retrieve the value of the specified template attribute property, and render it to the current
-      Writer as a String. The usual toString() conversions is applied on found value.
+      Retrieve the value of the specified template attribute property, and render
+      it to the current Writer as a String. The usual toString() conversions is applied on found value.
       </p>
       ]]>
       </description>
@@ -272,8 +279,8 @@
       <attribute>
          <description>
          <![CDATA[
-         If true, if an exception happens during rendering, of if the attribute is null, the problem
-         will be ignored.
+         If true, if an exception happens during
+         rendering, of if the attribute is null, the problem will be ignored.
          ]]>
          </description>
          <name>ignore</name>
@@ -295,8 +302,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the attribute will be rendered only if
-         the current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the attribute
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -307,7 +314,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The default value of the attribute. To use only if the attribute was not computed.
+         The default value of the attribute. To use only if
+         the attribute was not computed.
          ]]>
          </description>
          <name>defaultValue</name>
@@ -318,7 +326,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The default comma-separated list of roles. To use only if the attribute was not computed.
+         The default comma-separated list of roles. To use
+         only if the attribute was not computed.
          ]]>
          </description>
          <name>defaultValueRole</name>
@@ -329,7 +338,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The default type of the attribute. To use only if the attribute was not computed.
+         The default type of the attribute. To use only if
+         the attribute was not computed.
          ]]>
          </description>
          <name>defaultValueType</name>
@@ -357,7 +367,7 @@
          <name>value</name>
          <required>false</required>
          <rtexprvalue>true</rtexprvalue>
-         <type>org.apache.tiles.Attribute</type>
+         <type>org.apache.tiles.api.Attribute</type>
       </attribute>
    </tag>
    <tag>
@@ -367,18 +377,21 @@
       Inserts the value of an attribute into the page.
       </p>
       <p>
-      This tag can be flexibly used to insert the value of an attribute into a page. As in other
-      usages in Tiles, every attribute can be determined to have a 'type', either set explicitly
-      when it was defined, or 'computed'. If the type is not explicit, then if the attribute value
-      is a valid definition, it will be inserted as such. Otherwise, if it begins with a '/' character,
-      it will be treated as a 'template'. Finally, if it has not otherwise been assigned a type,
-      it will be treated as a String and included without any special handling.
+      This tag can be flexibly used to insert the value of an attribute into a
+      page. As in other usages in Tiles, every attribute can be determined to have
+      a "type", either set explicitly when it was defined, or "computed". If the
+      type is not explicit, then if the attribute value is a valid definition, it
+      will be inserted as such. Otherwise, if it begins with a "/" character, it
+      will be treated as a "template". Finally, if it has not otherwise been
+      assigned a type, it will be treated as a String and included without any special handling.
       </p>
+      
       <p>
       Example : 
       </p>
+      
       <pre>
-        &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
+          &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
       </pre>
       ]]>
       </description>
@@ -388,8 +401,8 @@
       <attribute>
          <description>
          <![CDATA[
-         If true, if an exception happens during rendering, of if the attribute is null,
-         the problem will be ignored.
+         If true, if an exception happens during
+         rendering, of if the attribute is null, the problem will be ignored.
          ]]>
          </description>
          <name>ignore</name>
@@ -411,8 +424,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the attribute will be rendered only if
-         the current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the attribute
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -423,7 +436,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The default value of the attribute. To use only if the attribute was not computed.
+         The default value of the attribute. To use only if
+         the attribute was not computed.
          ]]>
          </description>
          <name>defaultValue</name>
@@ -434,7 +448,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The default comma-separated list of roles. To use only if the attribute was not computed.
+         The default comma-separated list of roles. To use
+         only if the attribute was not computed.
          ]]>
          </description>
          <name>defaultValueRole</name>
@@ -445,7 +460,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The default type of the attribute. To use only if the attribute was not computed.
+         The default type of the attribute. To use only if
+         the attribute was not computed.
          ]]>
          </description>
          <name>defaultValueType</name>
@@ -473,7 +489,7 @@
          <name>value</name>
          <required>false</required>
          <rtexprvalue>true</rtexprvalue>
-         <type>org.apache.tiles.Attribute</type>
+         <type>org.apache.tiles.api.Attribute</type>
       </attribute>
       <attribute>
          <description>
@@ -502,24 +518,24 @@
       <li>&lt;insertDefinition&gt;</li>
       <li>&lt;putListAttribute&gt;</li>
       </ul>
-      or any other tag which implements the PutAttributeTagParent interface. Exception is thrown
-      if no appropriate tag can be found.
+      (or any other tag which implements the PutAttributeTagParent
+      interface. Exception is thrown if no appropriate tag can be found.
       </p>
       <p>
       Put tag can have following atributes :
       <ul>
       <li>name : Name of the attribute</li>
       <li>value : value to put as attribute</li>
-      <li>type : value type. Possible type are : string (value is used as direct string),
-      template (value is used as a page url to insert), definition (value is used as a definition
-      name to insert), object (value is used as it is)</li>
+      <li>type : value type. Possible type are : string (value is used as direct
+      string), template (value is used as a page url to insert), definition (value
+      is used as a definition name to insert), object (value is used as it is)</li>
       <li>role : Role to check when 'insertAttribute' will be called.</li>
       </ul>
       </p>
       <p>
-      Value can also come from tag body. Tag body is taken into account only if value is not set
-      by one of the tag attributes. In this case Attribute type is 'string', unless tag body define
-      another type.
+      Value can also come from tag body. Tag body is taken into account only if
+      value is not set by one of the tag attributes. In this case Attribute type is
+      "string", unless tag body define another type.
       </p>
       ]]>
       </description>
@@ -551,7 +567,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The expression to calculate the value from. Use this parameter, or value, or body.
+         The expression to calculate the value from. Use this
+         parameter, or value, or body.
          ]]>
          </description>
          <name>expression</name>
@@ -562,8 +579,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the attribute will be rendered only if
-         the current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the attribute
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -601,8 +618,8 @@
       Create a definition at runtime. 
       </p>
       <p>
-      Create a new definition at runtime. Newly created definition will be available across the
-      entire request.
+      Create a new definition at runtime. Newly created definition will be
+      available across the entire request.
       </p>
       ]]>
       </description>
@@ -612,7 +629,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The name of the definition to create. If not specified, an anonymous definition will be created.
+         The name of the definition to create. If not specified, an
+         anonymous definition will be created.
          ]]>
          </description>
          <name>name</name>
@@ -634,8 +652,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the definition will be rendered only if the
-         current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the definition
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -670,11 +688,14 @@
       <description>
       <![CDATA[
       <p>
-      Add an element to the surrounding list. Equivalent to 'putAttribute', but for list element.
+      Add an element to the surrounding list. Equivalent to 'putAttribute',
+      but for list element.
       </p>
+      
       <p>
-      Add an element to the surrounding list. This tag can only be used inside 'putListAttribute'
-      or 'addListAttribute' tags. Value can come from a direct assignment (value="aValue")
+      Add an element to the surrounding list. This tag can only be used inside
+      'putListAttribute' or 'addListAttribute' tags. Value can come from a direct
+      assignment (value="aValue")
       </p>
       ]]>
       </description>
@@ -695,7 +716,8 @@
       <attribute>
          <description>
          <![CDATA[
-         The expression to calculate the value from. Use this parameter, or value, or body.
+         The expression to calculate the value from. Use this
+         parameter, or value, or body.
          ]]>
          </description>
          <name>expression</name>
@@ -706,8 +728,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the attribute will be rendered only if the
-         current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the attribute
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -734,9 +756,9 @@
       Declare a list that will be pass as attribute to tile. 
       </p>
       <p>
-      Declare a list that will be pass as attribute to tile. List elements are added using the tags
-      'addAttribute' or 'addListAttribute'. This tag can only be used inside 'insertTemplate',
-      'insertDefinition', 'definition' tags.
+      Declare a list that will be pass as attribute to tile. List elements are
+      added using the tags 'addAttribute' or 'addListAttribute'. This tag can only
+      be used inside 'insertTemplate', 'insertDefinition', 'definition' tags.
       </p>
       ]]>
       </description>
@@ -757,8 +779,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the attribute will be rendered only if the
-         current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the attribute
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -769,8 +791,8 @@
       <attribute>
          <description>
          <![CDATA[
-         If true, the list attribute will use, as first elements, the list contained in the list
-         attribute, put with the same name, of the containing definition.
+         If true, the list attribute will use, as first elements, the
+         list contained in the list attribute, put with the same name, of the containing definition.
          ]]>
          </description>
          <name>inherit</name>
@@ -797,25 +819,30 @@
       Insert a template.
       </p>
       <p>
-      Insert a template with the possibility to pass parameters (called attributes). A template can
-      be seen as a procedure that can take parameters or attributes. &lt;tiles:insertTemplate&gt;
-      allows to define these attributes and pass them to the inserted jsp page, called template.
-      Attributes are defined using nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+      Insert a template with the possibility to pass parameters (called
+      attributes). A template can be seen as a procedure that can take parameters
+      or attributes. &lt;tiles:insertTemplate&gt; allows to define
+      these attributes and pass them to the inserted jsp page, called template.
+      Attributes are defined using nested tag
+      &lt;tiles:putAttribute&gt; or
+      &lt;tiles:putListAttribute&gt;.
       </p>
       <p>
       You must specify template attribute, for inserting a template
       </p>
+      
       <p>
-      Example : 
+      Example :
       </p>
+      
       <pre>
-        &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
-          &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
-          &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
-        &lt;/tiles:insertTemplate&gt;
+          &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
+              &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+              &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+          &lt;/tiles:insertTemplate&gt;
       </pre>
       ]]>
       </description>
@@ -858,8 +885,8 @@
       <attribute>
          <description>
          <![CDATA[
-         A comma-separated list of roles. If present, the template will be rendered only if the
-         current user belongs to one of the roles.
+         A comma-separated list of roles. If present, the template
+         will be rendered only if the current user belongs to one of the roles.
          ]]>
          </description>
          <name>role</name>
@@ -870,8 +897,9 @@
       <attribute>
          <description>
          <![CDATA[
-         The preparer to use to invoke before the definition is rendered. If specified, it overrides
-         the preparer specified in the definition itself.
+         The preparer to use to invoke before the definition is
+         rendered. If specified, it overrides the preparer specified in the
+         definition itself.
          ]]>
          </description>
          <name>preparer</name>
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm
similarity index 51%
copy from plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
copy to plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm
index 5f17d8145..f71d55514 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm
@@ -16,64 +16,71 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.web.jsp.taglib;
+ /*
+ * This file was automatically generated.
+ */
+package ${packageName};
 
 import java.io.IOException;
 
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.tagext.SimpleTagSupport;
 
+#if(${clazz.hasBody()})
 import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
-import org.apache.tiles.template.AddListAttributeModel;
+#end
 import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
- * <p>
- * Declare a list that will be pass as an attribute.
- * </p>
- * <p>
- * Declare a list that will be pass as an attribute . List elements are added
- * using the tag 'addAttribute' or 'addListAttribute'. This tag can only be used
- * inside 'insertTemplate', 'insertDefinition' or 'definition' tag.
- * </p>
+#foreach($line in $stringTool.splitOnNewlines(${clazz.documentation}))
+ * ${line}
+#end
  */
-public class AddListAttributeTag extends SimpleTagSupport {
+public class ${clazz.tagClassPrefix}Tag extends SimpleTagSupport {
 
     /**
      * The template model.
      */
-    private AddListAttributeModel model = new AddListAttributeModel();
+    private ${clazz.name} model = new ${clazz.name}();
 
+#foreach($parameter in ${clazz.parameters})
     /**
-     * The comma-separated list of roles that can use the list attribute.
+#foreach($line in $stringTool.splitOnNewlines(${parameter.documentation}))
+     * ${line}
+#end
      */
-    private String role;
+    private ${parameter.type} ${parameter.name};
 
+#end
+#foreach($parameter in ${clazz.parameters})
     /**
-     * Getter for role property.
+     * Getter for ${parameter.exportedName} property.
      *
-     * @return The comma-separated list of roles that can use the list attribute.
+     * @return
+#foreach($line in $stringTool.splitOnNewlines(${parameter.documentation}))
+     * ${line}
+#end
      */
-    public String getRole() {
-        return role;
+    public ${parameter.type} #if(${parameter.type} == 'boolean')is#{else}get#end${parameter.getterSetterSuffix}() {
+        return ${parameter.name};
     }
 
     /**
-     * Setter for role property.
+     * Setter for ${parameter.exportedName} property.
      *
-     * @param role The comma-separated list of roles that can use the list
-     *             attribute.
+     * @param ${parameter.name}
+#foreach($line in $stringTool.splitOnNewlines(${parameter.documentation}))
+     * ${line}
+#end
      */
-    public void setRole(String role) {
-        this.role = role;
+    public void set${parameter.getterSetterSuffix}(${parameter.type} ${parameter.name}) {
+        this.${parameter.name} = ${parameter.name};
     }
 
-    /** {@inheritDoc} */
+#end
     @Override
     public void doTag() throws JspException, IOException {
-        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        AutotagRuntime<${requestClass}> runtime = new ${runtimeClass}();
         if (runtime instanceof SimpleTagSupport) {
             SimpleTagSupport tag = (SimpleTagSupport) runtime;
             tag.setJspContext(getJspContext());
@@ -81,8 +88,15 @@ public class AddListAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        Request request = runtime.createRequest();
+        ${requestClass} request = runtime.createRequest();
+#if(${clazz.hasBody()})
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(role, request, modelBody);
+#end
+        model.execute(
+#foreach($parameter in ${clazz.parameters})
+            ${parameter.name},
+#end
+            request#if(${clazz.hasBody()}), modelBody#end
+        );
     }
 }
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm
new file mode 100644
index 000000000..8717882de
--- /dev/null
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<!-- This file was automatically generated.  Please do not edit it manually -->
+<taglib
+  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
+  xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  version="2.1">
+   <description>
+   <![CDATA[
+#foreach($line in $stringTool.splitOnNewlines(${suite.documentation}))
+   $line
+#end
+   ]]>
+   </description>
+   <tlib-version>1.2</tlib-version>
+   <short-name>${suite.name}</short-name>
+   <uri>${parameters.taglibURI}</uri>
+#foreach($clazz in ${suite.getTemplateClasses()})
+   <tag>
+      <description>
+      <![CDATA[
+#foreach($line in $stringTool.splitOnNewlines(${clazz.documentation}))
+      $line
+#end
+      ]]>
+      </description>
+      <name>${clazz.tagName}</name>
+      <tag-class>${packageName}.${clazz.tagClassPrefix}Tag</tag-class>
+      <body-content>#if(${clazz.hasBody()})scriptless#{else}empty#end</body-content>
+#foreach($parameter in ${clazz.parameters})
+      <attribute>
+         <description>
+         <![CDATA[
+#foreach($line in $stringTool.splitOnNewlines(${parameter.documentation}))
+         $line
+#end
+         ]]>
+         </description>
+         <name>${parameter.exportedName}</name>
+         <required>${parameter.required}</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>${parameter.type}</type>
+      </attribute>
+#end
+   </tag>
+#end
+</taglib>
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties
new file mode 100644
index 000000000..29ae759db
--- /dev/null
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/velocity.properties
@@ -0,0 +1,114 @@
+ # 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.
+# ----------------------------------------------------------------------------
+# These are the default properties for the
+# Velocity Runtime. These values are used when
+# Runtime.init() is called, and when Runtime.init(properties)
+# fails to find the specificed properties file.
+# ----------------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------------
+# R U N T I M E  L O G
+# ----------------------------------------------------------------------------
+# Velocity uses the Servlet APIs logging facilites.
+
+# ----------------------------------------------------------------------------
+# This controls if Runtime.error(), info() and warn() messages include the
+# whole stack trace. The last property controls whether invalid references
+# are logged.
+# ----------------------------------------------------------------------------
+
+runtime.log.invalid.reference = true
+
+
+# ----------------------------------------------------------------------------
+# T E M P L A T E  E N C O D I N G
+# ----------------------------------------------------------------------------
+
+input.encoding=ISO-8859-1
+output.encoding=ISO-8859-1
+
+
+# ----------------------------------------------------------------------------
+# F O R E A C H  P R O P E R T I E S
+# ----------------------------------------------------------------------------
+# These properties control how the counter is accessed in the #foreach
+# directive. By default the reference $velocityCount will be available
+# in the body of the #foreach directive. The default starting value
+# for this reference is 1.
+# ----------------------------------------------------------------------------
+
+directive.foreach.counter.name = velocityCount
+directive.foreach.counter.initial.value = 1
+
+
+# ----------------------------------------------------------------------------
+# I N C L U D E  P R O P E R T I E S
+# ----------------------------------------------------------------------------
+# These are the properties that governed the way #include'd content
+# is governed.
+# ----------------------------------------------------------------------------
+
+directive.include.output.errormsg.start = <!-- include error :
+directive.include.output.errormsg.end   =  see error log -->
+
+
+# ----------------------------------------------------------------------------
+# P A R S E  P R O P E R T I E S
+# ----------------------------------------------------------------------------
+
+directive.parse.max.depth = 10
+
+
+# ----------------------------------------------------------------------------
+# VELOCIMACRO PROPERTIES
+# ----------------------------------------------------------------------------
+# global : name of default global library.  It is expected to be in the regular
+# template path.  You may remove it (either the file or this property) if
+# you wish with no harm.
+# ----------------------------------------------------------------------------
+# dev-changes by Marino
+resource.loader=class, string
+
+class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
+
+velocimacro.library.autoreload = false
+
+velocimacro.permissions.allow.inline = true
+velocimacro.permissions.allow.inline.to.replace.global = false
+velocimacro.permissions.allow.inline.local.scope = false
+
+velocimacro.context.localscope = false
+
+# ----------------------------------------------------------------------------
+# INTERPOLATION
+# ----------------------------------------------------------------------------
+# turn off and on interpolation of references and directives in string
+# literals.  ON by default :)
+# ----------------------------------------------------------------------------
+runtime.interpolate.string.literals = true
+
+
+# ----------------------------------------------------------------------------
+# RESOURCE MANAGEMENT
+# ----------------------------------------------------------------------------
+# Allows alternative ResourceManager and ResourceCache implementations
+# to be plugged in.
+# ----------------------------------------------------------------------------
+resource.manager.class = org.apache.velocity.runtime.resource.ResourceManagerImpl
+resource.manager.cache.class = org.apache.velocity.runtime.resource.ResourceCacheImpl
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/JspTemplateGeneratorFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/JspTemplateGeneratorFactoryTest.java
new file mode 100644
index 000000000..a753756c9
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/JspTemplateGeneratorFactoryTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.jsp;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests JspTemplateGeneratorFactory.
+ */
+public class JspTemplateGeneratorFactoryTest {
+
+    /**
+     * Test method JspTemplateGeneratorFactory#createTemplateGenerator().
+     */
+    @Test
+    public void testCreateTemplateGenerator() {
+        File classesOutputDirectory = createMock(File.class);
+        File resourcesOutputDirectory = createMock(File.class);
+        VelocityEngine velocityEngine = createMock(VelocityEngine.class);
+        TemplateGeneratorBuilder builder = createMock(TemplateGeneratorBuilder.class);
+        TemplateGenerator generator = createMock(TemplateGenerator.class);
+
+        expect(builder.setClassesOutputDirectory(classesOutputDirectory)).andReturn(builder);
+        expect(builder.setResourcesOutputDirectory(resourcesOutputDirectory)).andReturn(builder);
+        expect(builder.addResourcesTemplateSuiteGenerator(isA(TLDGenerator.class))).andReturn(builder);
+        expect(builder.addClassesTemplateClassGenerator(isA(TagClassGenerator.class))).andReturn(builder);
+        expect(builder.build()).andReturn(generator);
+
+        replay(classesOutputDirectory, resourcesOutputDirectory, velocityEngine, builder, generator);
+        JspTemplateGeneratorFactory factory = new JspTemplateGeneratorFactory(
+                classesOutputDirectory, resourcesOutputDirectory,
+                velocityEngine, builder);
+        assertSame(generator, factory.createTemplateGenerator());
+        verify(classesOutputDirectory, resourcesOutputDirectory, velocityEngine, builder, generator);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/TLDGeneratorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/TLDGeneratorTest.java
new file mode 100644
index 000000000..0fbe25c07
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/TLDGeneratorTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.jsp;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateMethod;
+import org.apache.tiles.autotag.model.TemplateParameter;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests TLDGenerator.
+ *
+ * @version $Rev: 1349964 $ $Date: 2012-06-13 13:18:51 -0400 (Wed, 13 Jun 2012) $
+ */
+public class TLDGeneratorTest {
+    
+    public static final String REQUEST_CLASS = "org.apache.tiles.autotag.jsp.test.Request";
+
+    /**
+     * Test method for TLDGenerator#generate(File, String, TemplateSuite, Map).
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void testGenerate() throws Exception {
+        Properties props = new Properties();
+        InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+        props.load(propsStream);
+        propsStream.close();
+        VelocityEngine velocityEngine = new VelocityEngine(props);
+
+        TLDGenerator generator = new TLDGenerator(velocityEngine);
+        File file = File.createTempFile("autotag", null);
+        file.delete();
+        file.mkdir();
+        file.deleteOnExit();
+        TemplateSuite suite = new TemplateSuite("tldtest", "Test for TLD docs.");
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("taglibURI", "http://www.initrode.net/tags/test");
+
+        List<TemplateParameter> params = new ArrayList<TemplateParameter>();
+        TemplateParameter param = new TemplateParameter("one", "one", "java.lang.String", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "int", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "long", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        param = new TemplateParameter("modelBody", "modelBody", ModelBody.class.getName(), null, false, false);
+        param.setDocumentation("The body.");
+        params.add(param);
+        TemplateMethod executeMethod = new TemplateMethod("execute", params);
+
+        TemplateClass clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffTemplate",
+                "doStuff", "DoStuff", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuff class");
+
+        suite.addTemplateClass(clazz);
+        params = new ArrayList<TemplateParameter>();
+        param = new TemplateParameter("one", "one", "java.lang.Double", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "float", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "java.util.Date", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false ,true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        executeMethod = new TemplateMethod("execute", params);
+
+        clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffNoBodyTemplate",
+                "doStuffNoBody", "DoStuffNoBody", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuffNoBody class");
+
+        suite.addTemplateClass(clazz);
+
+        generator.generate(file, "org.apache.tiles.autotag.jsp.test", suite, parameters);
+
+        InputStream expected = getClass().getResourceAsStream("/tldtest-jsp.tld");
+        File effectiveFile = new File(file, "META-INF/tld/tldtest-jsp.tld");
+        assertTrue(effectiveFile.exists());
+        InputStream effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        FileUtils.deleteDirectory(file);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/TagClassGeneratorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/TagClassGeneratorTest.java
new file mode 100644
index 000000000..834ef8ebd
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/jsp/TagClassGeneratorTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.jsp;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateMethod;
+import org.apache.tiles.autotag.model.TemplateParameter;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests TagClassGenerator.
+ */
+public class TagClassGeneratorTest {
+
+    public static final String REQUEST_CLASS = "org.apache.tiles.autotag.jsp.test.Request";
+    
+    /**
+     * Test method for TagClassGenerator#generate(File, String, TemplateSuite, TemplateClass, Map).
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void testGenerate() throws Exception {
+        Properties props = new Properties();
+        InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+        props.load(propsStream);
+        propsStream.close();
+        VelocityEngine velocityEngine = new VelocityEngine(props);
+
+        TagClassGenerator generator = new TagClassGenerator(velocityEngine);
+        File file = File.createTempFile("autotag", null);
+        file.delete();
+        file.mkdir();
+        file.deleteOnExit();
+        TemplateSuite suite = new TemplateSuite("tldtest", "Test for TLD docs.");
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("taglibURI", "http://www.initrode.net/tags/test");
+
+        List<TemplateParameter> params = new ArrayList<TemplateParameter>();
+        TemplateParameter param = new TemplateParameter("one", "one", "java.lang.String", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "int", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "boolean", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        param = new TemplateParameter("modelBody", "modelBody", ModelBody.class.getName(), null, false, false);
+        param.setDocumentation("The body.");
+        params.add(param);
+        TemplateMethod executeMethod = new TemplateMethod("execute", params);
+
+        TemplateClass clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffTemplate",
+                "doStuff", "DoStuff", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuff class.");
+
+        generator.generate(file, "org.apache.tiles.autotag.jsp.test", suite, clazz, parameters,
+                           "org.apache.tiles.autotag.jsp.test.Runtime", REQUEST_CLASS);
+
+        InputStream expected = getClass().getResourceAsStream("/org/apache/tiles/autotag/jsp/test/DoStuffTag.java");
+        File effectiveFile = new File(file, "/org/apache/tiles/autotag/jsp/test/DoStuffTag.java");
+        assertTrue(effectiveFile.exists());
+        InputStream effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        suite.addTemplateClass(clazz);
+        params = new ArrayList<TemplateParameter>();
+        param = new TemplateParameter("one", "one", "java.lang.Double", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "float", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "java.util.Date", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        executeMethod = new TemplateMethod("execute", params);
+
+        clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffNoBodyTemplate",
+                "doStuffNoBody", "DoStuffNoBody", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuffNoBody class.");
+
+        suite.addTemplateClass(clazz);
+
+        generator.generate(file, "org.apache.tiles.autotag.jsp.test", suite, clazz, parameters,
+                           "org.apache.tiles.autotag.jsp.test.Runtime", REQUEST_CLASS);
+
+        expected = getClass().getResourceAsStream("/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java");
+        effectiveFile = new File(file, "/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java");
+        assertTrue(effectiveFile.exists());
+        effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        FileUtils.deleteDirectory(file);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/web/jsp/taglib/UseAttributeTagTest.java b/plugins/tiles/src/test/java/org/apache/tiles/web/jsp/taglib/UseAttributeTagTest.java
new file mode 100644
index 000000000..48486746f
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/web/jsp/taglib/UseAttributeTagTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.JspFragment;
+import javax.servlet.jsp.tagext.JspTag;
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.request.ApplicationAccess;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.jsp.JspRequest;
+import org.apache.tiles.web.jsp.taglib.UseAttributeTag;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests UseAttributeTag.
+ */
+public class UseAttributeTagTest {
+
+    /**
+     * The tag to test.
+     */
+    private UseAttributeTag tag;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        tag = new UseAttributeTag();
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#execute(org.apache.tiles.request.Request)}.
+     * 
+     * @throws IOException
+     * @throws JspException
+     */
+    @Test
+    public void testExecute() throws JspException, IOException {
+        JspFragment jspBody = createMock(JspFragment.class);
+        PageContext pageContext = createMock(PageContext.class);
+        JspTag parent = createMock(JspTag.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
+        HttpServletResponse httpServletResponse = createMock(HttpServletResponse.class);
+        Map<String, Object> applicationScope = createMock(Map.class);
+        TilesContainer container = createMock(TilesContainer.class);
+        AttributeContext attributeContext = createMock(AttributeContext.class);
+        Attribute attribute = createMock(Attribute.class);
+        expect(pageContext.getAttribute(ApplicationAccess.APPLICATION_CONTEXT_ATTRIBUTE, PageContext.APPLICATION_SCOPE))
+                .andReturn(applicationContext);
+        expect(applicationContext.getApplicationScope()).andReturn(applicationScope).anyTimes();
+        expect(pageContext.getRequest()).andReturn(httpServletRequest);
+        expect(pageContext.getResponse()).andReturn(httpServletResponse);
+        expect(pageContext.getAttribute(TilesAccess.CURRENT_CONTAINER_ATTRIBUTE_NAME, PageContext.REQUEST_SCOPE))
+                .andReturn(container);
+        expect(container.getAttributeContext(isA(JspRequest.class))).andReturn(attributeContext);
+        expect(attributeContext.getAttribute("name")).andReturn(attribute);
+        expect(container.evaluate(isA(Attribute.class), isA(JspRequest.class))).andReturn(new Integer(1));
+        pageContext.setAttribute("id", new Integer(1), PageContext.PAGE_SCOPE);
+        replay(jspBody, pageContext, parent, applicationContext, httpServletRequest, httpServletResponse,
+                applicationScope, container, attributeContext, attribute);
+        tag.setName("name");
+        tag.setScope("page");
+        tag.setId("id");
+        tag.setIgnore(false);
+        tag.setJspContext(pageContext);
+        tag.setJspBody(jspBody);
+        tag.setParent(parent);
+        tag.doTag();
+        verify(jspBody, pageContext, parent, applicationContext, httpServletRequest, httpServletResponse, container,
+                attributeContext, attribute);
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#setId(java.lang.String)}.
+     */
+    @Test
+    public void testSetId() {
+        tag.setId("id");
+        assertEquals("id", tag.getId());
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#getScope()}.
+     */
+    @Test
+    public void testGetScope() {
+        tag.setScope("scope");
+        assertEquals("scope", tag.getScope());
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#setName(java.lang.String)}.
+     */
+    @Test
+    public void testSetName() {
+        tag.setName("name");
+        assertEquals("name", tag.getName());
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#setIgnore(boolean)}.
+     */
+    @Test
+    public void testSetIgnore() {
+        tag.setIgnore(true);
+        assertTrue(tag.isIgnore());
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#setClassname(java.lang.String)}.
+     */
+    @Test
+    public void testSetClassname() {
+        tag.setClassname("classname");
+        assertEquals("classname", tag.getClassname());
+    }
+
+    /**
+     * Test method for
+     * {@link org/apache/tiles/web/jsp/taglib.UseAttributeTag#getScriptingVariable()}.
+     */
+    @Test
+    public void testGetScriptingVariable() {
+        tag.setName("name");
+        assertEquals("name", tag.getScriptingVariable());
+        tag.setId("id");
+        assertEquals("id", tag.getScriptingVariable());
+    }
+
+    /**
+     * Tests {@link UseAttributeTag.Tei}.
+     */
+    @Test
+    public void testTei() {
+        TagData tagData = createMock(TagData.class);
+
+        expect(tagData.getAttributeString("classname")).andReturn("my.Clazz");
+        expect(tagData.getAttributeString("id")).andReturn("id");
+
+        replay(tagData);
+        UseAttributeTag.Tei tei = new UseAttributeTag.Tei();
+        VariableInfo[] infos = tei.getVariableInfo(tagData);
+        assertEquals(1, infos.length);
+        VariableInfo info = infos[0];
+        assertEquals("id", info.getVarName());
+        assertEquals("my.Clazz", info.getClassName());
+        assertTrue(info.getDeclare());
+        assertEquals(VariableInfo.AT_END, info.getScope());
+        verify(tagData);
+    }
+
+    /**
+     * Tests {@link UseAttributeTag.Tei}.
+     */
+    @Test
+    public void testTeiDefaults() {
+        TagData tagData = createMock(TagData.class);
+
+        expect(tagData.getAttributeString("classname")).andReturn(null);
+        expect(tagData.getAttributeString("id")).andReturn(null);
+        expect(tagData.getAttributeString("name")).andReturn("name");
+
+        replay(tagData);
+        UseAttributeTag.Tei tei = new UseAttributeTag.Tei();
+        VariableInfo[] infos = tei.getVariableInfo(tagData);
+        assertEquals(1, infos.length);
+        VariableInfo info = infos[0];
+        assertEquals("name", info.getVarName());
+        assertEquals("java.lang.Object", info.getClassName());
+        assertTrue(info.getDeclare());
+        assertEquals(VariableInfo.AT_END, info.getScope());
+        verify(tagData);
+    }
+}
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java
new file mode 100644
index 000000000..4dac7e17f
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+ /*
+ * This file was automatically generated.
+ */
+package org.apache.tiles.autotag.jsp.test;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * Documentation of the DoStuffNoBody class.
+ */
+public class DoStuffNoBodyTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.autotag.template.DoStuffNoBodyTemplate model = new org.apache.tiles.autotag.template.DoStuffNoBodyTemplate();
+
+    /**
+     * Parameter one.
+     */
+    private java.lang.Double one;
+
+    /**
+     * Parameter two.
+     */
+    private float two;
+
+    /**
+     * Parameter three.
+     */
+    private java.util.Date three;
+
+    /**
+     * Getter for one property.
+     *
+     * @return
+     * Parameter one.
+     */
+    public java.lang.Double getOne() {
+        return one;
+    }
+
+    /**
+     * Setter for one property.
+     *
+     * @param one
+     * Parameter one.
+     */
+    public void setOne(java.lang.Double one) {
+        this.one = one;
+    }
+
+    /**
+     * Getter for two property.
+     *
+     * @return
+     * Parameter two.
+     */
+    public float getTwo() {
+        return two;
+    }
+
+    /**
+     * Setter for two property.
+     *
+     * @param two
+     * Parameter two.
+     */
+    public void setTwo(float two) {
+        this.two = two;
+    }
+
+    /**
+     * Getter for three property.
+     *
+     * @return
+     * Parameter three.
+     */
+    public java.util.Date getThree() {
+        return three;
+    }
+
+    /**
+     * Setter for three property.
+     *
+     * @param three
+     * Parameter three.
+     */
+    public void setThree(java.util.Date three) {
+        this.three = three;
+    }
+
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<org.apache.tiles.autotag.jsp.test.Request> runtime = new org.apache.tiles.autotag.jsp.test.Runtime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        org.apache.tiles.autotag.jsp.test.Request request = runtime.createRequest();
+        model.execute(
+            one,
+            two,
+            three,
+            request
+        );
+    }
+}
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java
new file mode 100644
index 000000000..3116c37eb
--- /dev/null
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+ /*
+ * This file was automatically generated.
+ */
+package org.apache.tiles.autotag.jsp.test;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * Documentation of the DoStuff class.
+ */
+public class DoStuffTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.autotag.template.DoStuffTemplate model = new org.apache.tiles.autotag.template.DoStuffTemplate();
+
+    /**
+     * Parameter one.
+     */
+    private java.lang.String one;
+
+    /**
+     * Parameter two.
+     */
+    private int two;
+
+    /**
+     * Parameter three.
+     */
+    private boolean three;
+
+    /**
+     * Getter for one property.
+     *
+     * @return
+     * Parameter one.
+     */
+    public java.lang.String getOne() {
+        return one;
+    }
+
+    /**
+     * Setter for one property.
+     *
+     * @param one
+     * Parameter one.
+     */
+    public void setOne(java.lang.String one) {
+        this.one = one;
+    }
+
+    /**
+     * Getter for two property.
+     *
+     * @return
+     * Parameter two.
+     */
+    public int getTwo() {
+        return two;
+    }
+
+    /**
+     * Setter for two property.
+     *
+     * @param two
+     * Parameter two.
+     */
+    public void setTwo(int two) {
+        this.two = two;
+    }
+
+    /**
+     * Getter for three property.
+     *
+     * @return
+     * Parameter three.
+     */
+    public boolean isThree() {
+        return three;
+    }
+
+    /**
+     * Setter for three property.
+     *
+     * @param three
+     * Parameter three.
+     */
+    public void setThree(boolean three) {
+        this.three = three;
+    }
+
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<org.apache.tiles.autotag.jsp.test.Request> runtime = new org.apache.tiles.autotag.jsp.test.Runtime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        org.apache.tiles.autotag.jsp.test.Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(
+            one,
+            two,
+            three,
+            request, modelBody
+        );
+    }
+}
diff --git a/plugins/tiles/src/test/resources/tldtest-jsp.tld b/plugins/tiles/src/test/resources/tldtest-jsp.tld
new file mode 100644
index 000000000..6777e39b7
--- /dev/null
+++ b/plugins/tiles/src/test/resources/tldtest-jsp.tld
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<!-- This file was automatically generated.  Please do not edit it manually -->
+<taglib
+  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
+  xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  version="2.1">
+   <description>
+   <![CDATA[
+   Test for TLD docs.
+   ]]>
+   </description>
+   <tlib-version>1.2</tlib-version>
+   <short-name>tldtest</short-name>
+   <uri>http://www.initrode.net/tags/test</uri>
+   <tag>
+      <description>
+      <![CDATA[
+      Documentation of the DoStuff class
+      ]]>
+      </description>
+      <name>doStuff</name>
+      <tag-class>org.apache.tiles.autotag.jsp.test.DoStuffTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         Parameter one.
+         ]]>
+         </description>
+         <name>one</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         Parameter two.
+         ]]>
+         </description>
+         <name>two</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>int</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         Parameter three.
+         ]]>
+         </description>
+         <name>three</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>long</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      Documentation of the DoStuffNoBody class
+      ]]>
+      </description>
+      <name>doStuffNoBody</name>
+      <tag-class>org.apache.tiles.autotag.jsp.test.DoStuffNoBodyTag</tag-class>
+      <body-content>empty</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         Parameter one.
+         ]]>
+         </description>
+         <name>one</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.Double</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         Parameter two.
+         ]]>
+         </description>
+         <name>two</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>float</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         Parameter three.
+         ]]>
+         </description>
+         <name>three</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.util.Date</type>
+      </attribute>
+   </tag>
+</taglib>


[struts] 13/23: WW-5233 Addresses bugs reported by Sonar

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 69e5efc84009057ad7191fb92f9995227c169ab2
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Oct 3 07:49:27 2022 +0200

    WW-5233 Addresses bugs reported by Sonar
---
 .../main/java/org/apache/tiles/api/Attribute.java  | 13 +--
 .../apache/tiles/api/BasicAttributeContext.java    | 22 +++--
 .../main/java/org/apache/tiles/api/Definition.java |  6 ++
 .../main/java/org/apache/tiles/api/Expression.java |  6 ++
 .../java/org/apache/tiles/api/ListAttribute.java   |  6 ++
 .../autotag/core/runtime/AbstractModelBody.java    | 11 +--
 .../definition/dao/BaseLocaleUrlDefinitionDAO.java | 13 +--
 .../tiles/request/collection/HeaderValuesMap.java  | 94 +++++++++++++++-------
 .../apache/tiles/request/collection/KeySet.java    | 13 ++-
 .../request/collection/ReadOnlyEnumerationMap.java | 93 ++++++++++++++-------
 .../java/org/apache/tiles/api/AttributeTest.java   |  4 +-
 .../autotag/runtime/AbstractModelBodyTest.java     |  7 --
 12 files changed, 190 insertions(+), 98 deletions(-)

diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
index e84039c73..69209e5d4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -23,8 +23,6 @@ import com.opensymphony.xwork2.util.TextParseUtil;
 import org.apache.tiles.request.Request;
 
 import java.io.Serializable;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
@@ -267,10 +265,7 @@ public class Attribute implements Serializable, Cloneable {
      */
     @Override
     public String toString() {
-        if (value != null) {
-            return value.toString();
-        }
-        return null;
+        return Objects.toString(value);
     }
 
     /**
@@ -323,6 +318,12 @@ public class Attribute implements Serializable, Cloneable {
      */
     @Override
     public boolean equals(Object obj) {
+        if (obj == null && value == null) {
+            return true;
+        }
+        if (!(obj instanceof Attribute)) {
+            return false;
+        }
         Attribute attribute = (Attribute) obj;
         return Objects.equals(value, attribute.value)
             && Objects.equals(renderer, attribute.renderer)
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
index 8fdc5b8aa..9de064d6b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
@@ -149,7 +149,9 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
      */
     public void inheritCascadedAttributes(AttributeContext context) {
         if (context instanceof BasicAttributeContext) {
-            copyCascadedAttributes((BasicAttributeContext) context);
+            if (((BasicAttributeContext) context).cascadedAttributes != null && !((BasicAttributeContext) context).cascadedAttributes.isEmpty()) {
+                cascadedAttributes = deepCopyAttributeMap(((BasicAttributeContext) context).cascadedAttributes);
+            }
         } else {
             this.cascadedAttributes = new HashMap<>();
             Set<String> parentAttributeNames = context.getCascadedAttributeNames();
@@ -353,6 +355,12 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
      */
     @Override
     public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof BasicAttributeContext)) {
+            return false;
+        }
         BasicAttributeContext bac = (BasicAttributeContext) obj;
         return Objects.equals(templateAttribute, bac.templateAttribute)
             && Objects.equals(preparer, bac.preparer)
@@ -400,17 +408,7 @@ public class BasicAttributeContext implements AttributeContext, Serializable {
         if (context.attributes != null && !context.attributes.isEmpty()) {
             attributes = deepCopyAttributeMap(context.attributes);
         }
-        copyCascadedAttributes(context);
-    }
-
-    /**
-     * Copies the cascaded attributes to the current context.
-     *
-     * @param context The context to copy from.
-     */
-    private void copyCascadedAttributes(BasicAttributeContext context) {
-        if (context.cascadedAttributes != null
-            && !context.cascadedAttributes.isEmpty()) {
+        if (context.cascadedAttributes != null && !context.cascadedAttributes.isEmpty()) {
             cascadedAttributes = deepCopyAttributeMap(context.cascadedAttributes);
         }
     }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
index 3cd217b1c..54ac5e035 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
@@ -116,6 +116,12 @@ public class Definition extends BasicAttributeContext {
      */
     @Override
     public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Definition)) {
+            return false;
+        }
         Definition def = (Definition) obj;
         return Objects.equals(name, def.name) && Objects.equals(inherit, def.inherit) && super.equals(def);
     }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
index 6efe6ce1b..38d152ccb 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
@@ -137,6 +137,12 @@ public class Expression {
      */
     @Override
     public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof Expression)) {
+            return false;
+        }
         Expression exp = (Expression) obj;
         return Objects.equals(expression, exp.expression) && Objects.equals(language, exp.language);
     }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
index 3daeff4f5..227380af0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
@@ -146,6 +146,12 @@ public class ListAttribute extends Attribute {
     /** {@inheritDoc} */
     @Override
     public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ListAttribute)) {
+            return false;
+        }
         ListAttribute attribute = (ListAttribute) obj;
         return super.equals(attribute) && this.inherit == attribute.inherit;
     }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
index 72b3a9938..b1a937e73 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
@@ -31,12 +31,12 @@ import java.util.regex.Pattern;
 public abstract class AbstractModelBody implements ModelBody {
 
     // precompiled the pattern to avoid compiling on every method call
-    private static final Pattern PATTERN = Pattern.compile("^\\s*|\\s*$");
+    private static final Pattern PATTERN = Pattern.compile("^\\s*$");
 
     /**
      * The default writer to use.
      */
-    private Writer defaultWriter;
+    private final Writer defaultWriter;
 
     /**
      * Constructor.
@@ -63,7 +63,7 @@ public abstract class AbstractModelBody implements ModelBody {
         String body = writer.toString();
         if (body != null) {
             body = PATTERN.matcher(body).replaceAll("");
-            if (body.length() <= 0) {
+            if (body.length() == 0) {
                 body = null;
             }
         }
@@ -72,11 +72,8 @@ public abstract class AbstractModelBody implements ModelBody {
 
     @Override
     public void evaluateWithoutWriting() throws IOException {
-        NullWriter writer = new NullWriter();
-        try {
+        try (NullWriter writer = new NullWriter()) {
             evaluate(writer);
-        } finally {
-            writer.close();
         }
     }
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
index 45aa73840..cb01af434 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
@@ -89,8 +89,8 @@ public abstract class BaseLocaleUrlDefinitionDAO implements DefinitionDAO<Locale
     public void setSources(List<ApplicationResource> sources) {
         // filter out any sources that are already localized
         ArrayList<ApplicationResource> defaultSources = new ArrayList<>();
-        for(ApplicationResource source: sources) {
-            if(Locale.ROOT.equals(source.getLocale())) {
+        for (ApplicationResource source : sources) {
+            if (Locale.ROOT.equals(source.getLocale())) {
                 defaultSources.add(source);
             }
         }
@@ -101,7 +101,9 @@ public abstract class BaseLocaleUrlDefinitionDAO implements DefinitionDAO<Locale
         this.reader = reader;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public boolean refreshRequired() {
         boolean status = false;
 
@@ -136,7 +138,7 @@ public abstract class BaseLocaleUrlDefinitionDAO implements DefinitionDAO<Locale
         InputStream stream = null;
         try {
             lastModifiedDates.put(resource.getLocalePath(), resource
-                    .getLastModified());
+                .getLastModified());
 
             // Definition must be collected, starting from the base
             // source up to the last localized file.
@@ -152,8 +154,7 @@ public abstract class BaseLocaleUrlDefinitionDAO implements DefinitionDAO<Locale
                 if (stream != null) {
                     stream.close();
                 }
-            } catch (IOException e) {
-                throw new DefinitionsFactoryException("I/O error closing " + resource, e);
+            } catch (IOException ignore) {
             }
         }
 
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java
index 6c91895ad..fa50dbab9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/HeaderValuesMap.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tiles.request.collection;
 
-import static org.apache.tiles.request.collection.CollectionUtil.*;
+import org.apache.tiles.request.attribute.EnumeratedValuesExtractor;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -28,9 +28,11 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
-import org.apache.tiles.request.attribute.EnumeratedValuesExtractor;
+import static org.apache.tiles.request.collection.CollectionUtil.enumerationSize;
+import static org.apache.tiles.request.collection.CollectionUtil.key;
 
 /**
  * Exposes an {@link EnumeratedValuesExtractor} object as a read-only map.
@@ -52,19 +54,25 @@ public class HeaderValuesMap implements Map<String, String[]> {
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void clear() {
         throw new UnsupportedOperationException();
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public boolean containsKey(Object key) {
         return (request.getValue(key(key)) != null);
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public boolean containsValue(Object value) {
         if (!(value instanceof String[])) {
             return (false);
@@ -81,18 +89,28 @@ public class HeaderValuesMap implements Map<String, String[]> {
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Set<Entry<String, String[]>> entrySet() {
         return new HeadersEntrySet();
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public boolean equals(Object o) {
-        EnumeratedValuesExtractor otherRequest = ((HeaderValuesMap) o).request;
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof HeaderValuesMap)) {
+            return false;
+        }
+        EnumeratedValuesExtractor otherRequest = ((HeaderValuesMap) obj).request;
         boolean retValue = true;
-        for (Enumeration<String> attribs = request.getKeys(); attribs.hasMoreElements() && retValue;) {
+        for (Enumeration<String> attribs = request.getKeys(); attribs.hasMoreElements() && retValue; ) {
             String parameterName = attribs.nextElement();
             Set<String> valueSet = enumeration2set(otherRequest.getValues(parameterName));
             retValue = compareHeaders(parameterName, valueSet);
@@ -102,17 +120,21 @@ public class HeaderValuesMap implements Map<String, String[]> {
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public String[] get(Object key) {
         return getHeaderValues(key(key));
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
         int retValue = 0;
         for (Enumeration<String> attribs = request.getKeys(); attribs
-                .hasMoreElements();) {
+            .hasMoreElements(); ) {
             String parameterName = attribs.nextElement();
             Enumeration<String> values = request.getValues(parameterName);
             int valueHash = 0;
@@ -125,44 +147,57 @@ public class HeaderValuesMap implements Map<String, String[]> {
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public boolean isEmpty() {
         return !request.getKeys().hasMoreElements();
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Set<String> keySet() {
         return new KeySet(request);
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public String[] put(String key, String[] value) {
         throw new UnsupportedOperationException();
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void putAll(Map<? extends String, ? extends String[]> map) {
         throw new UnsupportedOperationException();
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public String[] remove(Object key) {
         throw new UnsupportedOperationException();
     }
 
 
-
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public int size() {
         return enumerationSize(request.getKeys());
     }
 
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Collection<String[]> values() {
         return new HeaderValuesCollection();
     }
@@ -212,7 +247,7 @@ public class HeaderValuesMap implements Map<String, String[]> {
      * Checks if values of a header attribute are the same as the one passed in
      * the set.
      *
-     * @param name The name of the header.
+     * @param name    The name of the header.
      * @param testSet The set of values it must contain.
      * @return <code>true</code> if all the values, and only them, are present
      * in the header values.
@@ -240,7 +275,7 @@ public class HeaderValuesMap implements Map<String, String[]> {
 
         @Override
         public boolean addAll(
-                Collection<? extends Entry<String, String[]>> c) {
+            Collection<? extends Entry<String, String[]>> c) {
             throw new UnsupportedOperationException();
         }
 
@@ -346,8 +381,7 @@ public class HeaderValuesMap implements Map<String, String[]> {
          * @param names The enumeration to get the next name from..
          * @return The next map entry.
          */
-        private MapEntry<String, String[]> extractNextEntry(
-                Enumeration<String> names) {
+        private MapEntry<String, String[]> extractNextEntry(Enumeration<String> names) {
             String name = names.nextElement();
             return new MapEntryArrayValues<>(name, getHeaderValues(name), false);
         }
@@ -369,7 +403,10 @@ public class HeaderValuesMap implements Map<String, String[]> {
 
             @Override
             public Entry<String, String[]> next() {
-                return extractNextEntry(namesEnumeration);
+                if (namesEnumeration.hasMoreElements()) {
+                    return extractNextEntry(namesEnumeration);
+                }
+                throw new NoSuchElementException();
             }
 
             @Override
@@ -504,7 +541,10 @@ public class HeaderValuesMap implements Map<String, String[]> {
 
             @Override
             public String[] next() {
-                return enumeration2array(request.getValues(namesEnumeration.nextElement()));
+                if (namesEnumeration.hasMoreElements()) {
+                    return enumeration2array(request.getValues(namesEnumeration.nextElement()));
+                }
+                throw new NoSuchElementException();
             }
 
             @Override
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java
index e89d60bdc..f34688088 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/KeySet.java
@@ -18,16 +18,18 @@
  */
 package org.apache.tiles.request.collection;
 
-import static org.apache.tiles.request.collection.CollectionUtil.*;
+import org.apache.tiles.request.attribute.HasKeys;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
-import org.apache.tiles.request.attribute.HasKeys;
+import static org.apache.tiles.request.collection.CollectionUtil.enumerationSize;
+import static org.apache.tiles.request.collection.CollectionUtil.key;
 
 /**
  * Exposes keys of a {@link HasKeys} object as a set.
@@ -142,7 +144,7 @@ public class KeySet implements Set<String> {
         /**
          * The key names enumeration.
          */
-        private Enumeration<String> namesEnumeration = request.getKeys();
+        private final Enumeration<String> namesEnumeration = request.getKeys();
 
         @Override
         public boolean hasNext() {
@@ -151,7 +153,10 @@ public class KeySet implements Set<String> {
 
         @Override
         public String next() {
-            return namesEnumeration.nextElement();
+            if (namesEnumeration.hasMoreElements()) {
+                return namesEnumeration.nextElement();
+            }
+            throw new NoSuchElementException();
         }
 
         @Override
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
index 85c17b656..2db0e83ae 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/request/collection/ReadOnlyEnumerationMap.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tiles.request.collection;
 
-import static org.apache.tiles.request.collection.CollectionUtil.*;
+import org.apache.tiles.request.attribute.HasKeys;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -27,9 +27,11 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
-import org.apache.tiles.request.attribute.HasKeys;
+import static org.apache.tiles.request.collection.CollectionUtil.enumerationSize;
+import static org.apache.tiles.request.collection.CollectionUtil.key;
 
 /**
  * Wraps an {@link HasKeys} object into a read-only map.
@@ -52,21 +54,27 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
         this.request = request;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void clear() {
         throw new UnsupportedOperationException();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public boolean containsKey(Object key) {
         return (request.getValue(key(key)) != null);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @SuppressWarnings("unchecked")
     public boolean containsValue(Object value) {
         V realValue = (V) value;
-        for (Enumeration<String> keysIt = request.getKeys(); keysIt.hasMoreElements();) {
+        for (Enumeration<String> keysIt = request.getKeys(); keysIt.hasMoreElements(); ) {
             if (realValue.equals(request.getValue(keysIt.nextElement()))) {
                 return true;
             }
@@ -74,63 +82,89 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
         return false;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Set<Entry<String, V>> entrySet() {
         return new ReadOnlyEnumerationMapEntrySet();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public V get(Object key) {
         return (request.getValue(key(key)));
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public boolean isEmpty() {
         return !request.getKeys().hasMoreElements();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Set<String> keySet() {
         return new KeySet(request);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public V put(String key, V value) {
         throw new UnsupportedOperationException();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public void putAll(Map<? extends String, ? extends V> map) {
         throw new UnsupportedOperationException();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public V remove(Object key) {
         throw new UnsupportedOperationException();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public int size() {
         return enumerationSize(request.getKeys());
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     public Collection<V> values() {
         return new ReadOnlyEnumerationMapValuesCollection();
     }
 
-    /** {@inheritDoc} */
-    @SuppressWarnings("unchecked")
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public boolean equals(Object o) {
-        HasKeys<V> otherRequest = ((ReadOnlyEnumerationMap<V>) o).request;
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ReadOnlyEnumerationMap)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        HasKeys<V> otherRequest = ((ReadOnlyEnumerationMap<V>) obj).request;
         boolean retValue = true;
         Set<String> otherKeys;
         otherKeys = new HashSet<>();
-        for (Enumeration<String> attribs = otherRequest.getKeys(); attribs.hasMoreElements();) {
+        for (Enumeration<String> attribs = otherRequest.getKeys(); attribs.hasMoreElements(); ) {
             otherKeys.add(attribs.nextElement());
         }
-        for (Enumeration<String> attribs = request.getKeys(); attribs.hasMoreElements() && retValue;) {
+        for (Enumeration<String> attribs = request.getKeys(); attribs.hasMoreElements() && retValue; ) {
             String parameterName = attribs.nextElement();
             retValue = request.getValue(parameterName).equals(otherRequest.getValue(parameterName));
             otherKeys.remove(parameterName);
@@ -139,12 +173,14 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
         return retValue && otherKeys.isEmpty();
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
         int retValue = 0;
         for (Enumeration<String> attribs = request.getKeys(); attribs
-                .hasMoreElements();) {
+            .hasMoreElements(); ) {
             String parameterName = attribs.nextElement();
             V value = request.getValue(parameterName);
             retValue += parameterName.hashCode() ^ (value == null ? 0 : value.hashCode());
@@ -164,7 +200,7 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
 
         @Override
         public boolean addAll(
-                Collection<? extends Entry<String, V>> c) {
+            Collection<? extends Entry<String, V>> c) {
             throw new UnsupportedOperationException();
         }
 
@@ -264,7 +300,7 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
          * @return The next entry.
          */
         private MapEntry<String, V> extractNextEntry(
-                Enumeration<String> names) {
+            Enumeration<String> names) {
             String name = names.nextElement();
             return new MapEntry<>(name, request.getValue(name), false);
         }
@@ -327,7 +363,7 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
         public boolean containsAll(Collection<?> c) {
             Collection<String> realCollection = (Collection<String>) c;
             List<String> valueList = new ArrayList<>(realCollection);
-            for (Enumeration<String> keysEnum = request.getKeys(); keysEnum.hasMoreElements();) {
+            for (Enumeration<String> keysEnum = request.getKeys(); keysEnum.hasMoreElements(); ) {
                 valueList.remove(request.getValue(keysEnum.nextElement()));
                 if (valueList.isEmpty()) {
                     return true;
@@ -407,7 +443,10 @@ public class ReadOnlyEnumerationMap<V> implements Map<String, V> {
 
             @Override
             public V next() {
-                return request.getValue(namesEnumeration.nextElement());
+                if (namesEnumeration.hasMoreElements()) {
+                    return request.getValue(namesEnumeration.nextElement());
+                }
+                throw new NoSuchElementException();
             }
 
             @Override
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
index 875431c6f..5c46b42e0 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/api/AttributeTest.java
@@ -33,6 +33,7 @@ import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -41,7 +42,6 @@ import static org.junit.Assert.assertTrue;
  */
 public class AttributeTest {
 
-
     /**
      * Tests {@link Attribute#createTemplateAttribute(String)}.
      */
@@ -193,7 +193,7 @@ public class AttributeTest {
         Attribute attribute = new Attribute("my.value", expression, "role1,role2", "myrenderer");
         assertEquals("my.value", attribute.toString());
         attribute.setValue(null);
-        assertNull(attribute.toString());
+        assertNotNull(attribute.toString());
     }
 
     @Test
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java
index 08e4d9011..3bfe89ff5 100644
--- a/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/runtime/AbstractModelBodyTest.java
@@ -37,8 +37,6 @@ import static org.junit.Assert.assertNull;
 
 /**
  * Tests {@link AbstractModelBody}.
- *
- * @version $Rev$ $Date$
  */
 public class AbstractModelBodyTest {
 
@@ -132,11 +130,6 @@ public class AbstractModelBodyTest {
         }
     }
 
-    /**
-     * A mock model body.
-     *
-     * @version $Rev$ $Date$
-     */
     public static class MockModelBody extends AbstractModelBody {
 
         /**


[struts] 20/23: Make plugin standalone with all generated resources.

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit bae3e3954865d29df6ec69822f2a09413756e13a
Author: Greg Huber <gh...@apache.org>
AuthorDate: Fri Oct 14 11:07:45 2022 +0100

    Make plugin standalone with all generated resources.
---
 plugins/tiles/pom.xml                              |  14 +-
 .../{BuildJspAutotags.java => BuildAutotags.java}  |  91 ++++++++++---
 .../StrutsWildcardServletApplicationContext.java   |   1 -
 .../tiles/autotag/freemarker/FMModelGenerator.java |  63 +++++++++
 .../freemarker/FMModelRepositoryGenerator.java     |  61 +++++++++
 .../freemarker/FMTemplateGeneratorFactory.java     |  69 ++++++++++
 .../tiles/autotag/freemarker/package-info.java     |  24 ++++
 .../freemarker/template/AddAttributeFMModel.java   |  58 ++++-----
 .../template/AddListAttributeFMModel.java          |  48 +++----
 .../freemarker/template/DefinitionFMModel.java     |  56 ++++----
 .../freemarker/template/GetAsStringFMModel.java    |  66 ++++------
 .../template/ImportAttributeFMModel.java           |  51 ++++----
 .../template/InsertAttributeFMModel.java           |  75 +++++------
 .../template/InsertDefinitionFMModel.java          |  91 ++++++-------
 .../freemarker/template/InsertTemplateFMModel.java |  91 ++++++-------
 .../freemarker/template/PutAttributeFMModel.java   |  64 ++++-----
 .../template/PutListAttributeFMModel.java          |  54 ++++----
 .../template/SetCurrentContainerFMModel.java       |  43 +++---
 .../template/TilesFMModelRepository.java           | 144 ++++++++++++++++++++-
 .../tiles/web/jsp/taglib/AddAttributeTag.java      |  68 ++++------
 .../tiles/web/jsp/taglib/AddListAttributeTag.java  |  23 ++--
 .../apache/tiles/web/jsp/taglib/DefinitionTag.java |  72 ++++-------
 .../tiles/web/jsp/taglib/GetAsStringTag.java       | 113 ++++++----------
 .../tiles/web/jsp/taglib/ImportAttributeTag.java   |  69 +++++-----
 .../tiles/web/jsp/taglib/InsertAttributeTag.java   | 120 +++++++----------
 .../tiles/web/jsp/taglib/InsertDefinitionTag.java  | 116 +++++++----------
 .../tiles/web/jsp/taglib/InsertTemplateTag.java    |  95 ++++++--------
 .../tiles/web/jsp/taglib/PutAttributeTag.java      |  83 +++++-------
 .../tiles/web/jsp/taglib/PutListAttributeTag.java  |  62 ++++-----
 .../web/jsp/taglib/SetCurrentContainerTag.java     |  25 ++--
 .../src/main/resources/META-INF/tld/tiles-jsp.tld  |   2 +-
 .../apache/tiles/autotag/freemarker/fmModel.vm}    |  69 +++++-----
 .../apache/tiles/autotag/freemarker/repository.vm} |  48 ++++---
 .../org/apache/tiles/autotag/jsp/bodyTag.vm        |   2 +-
 .../resources/org/apache/tiles/autotag/jsp/tld.vm  |   2 +-
 .../autotag/freemarker/FMModelGeneratorTest.java   | 139 ++++++++++++++++++++
 .../freemarker/FMModelRepositoryGeneratorTest.java | 126 ++++++++++++++++++
 .../freemarker/FMTemplateGeneratorFactoryTest.java |  58 +++++++++
 .../autotag/freemarker/test/DoStuffFMModel.javat}  |  63 ++++-----
 .../freemarker/test/DoStuffNoBodyFMModel.javat}    |  53 ++++----
 .../test/TldtestFMModelRepository.javat}           |  39 +++---
 .../tiles/autotag/jsp/test/DoStuffNoBodyTag.java   |   2 +-
 .../apache/tiles/autotag/jsp/test/DoStuffTag.java  |   2 +-
 plugins/tiles/src/test/resources/tldtest-jsp.tld   |   2 +-
 44 files changed, 1523 insertions(+), 1094 deletions(-)

diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 236af9172..627f3c317 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -31,10 +31,10 @@
     <packaging>jar</packaging>
     <name>Struts 2 Tiles Plugin</name>
     
-    <!-- mvn -P build-jsp-autotags exec:java -->
+    <!-- mvn -P build-autotags exec:java -->
     <profiles>
         <profile>
-            <id>build-jsp-autotags</id>
+            <id>build-autotags</id>
             <activation>
                 <activeByDefault>true</activeByDefault>
             </activation>
@@ -53,16 +53,8 @@
                           </execution>
                         </executions>
                         <configuration>
-                            <mainClass>org.apache.struts2.tiles.BuildJspAutotags</mainClass>
+                            <mainClass>org.apache.struts2.tiles.BuildAutotags</mainClass>
                             <arguments>
-                                <!-- taglibURI   -->
-                                <argument>http://tiles.apache.org/tags-tiles</argument>
-                                <!-- packageName -->
-                                <argument>org.apache.tiles.web.jsp.taglib</argument>
-                                <!-- requestClass -->
-                                <argument>org.apache.tiles.request.Request</argument>
-                                <!-- jspRuntime -->
-                                <argument>org.apache.tiles.request.jsp.autotag.JspAutotagRuntime</argument>
                                 <!-- Output folder -->
                                 <argument>${project.build.directory}</argument>
                             </arguments>
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildJspAutotags.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
similarity index 50%
rename from plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildJspAutotags.java
rename to plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
index 64aa03254..de2eaee1e 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildJspAutotags.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.tiles.autotag.freemarker.FMTemplateGeneratorFactory;
 import org.apache.tiles.autotag.generate.TemplateGenerator;
 import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
 import org.apache.tiles.autotag.jsp.JspTemplateGeneratorFactory;
@@ -34,11 +35,12 @@ import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.io.xml.DomDriver;
 
 /**
- * Helper class for building the JSP tag classes and .tld file.
+ * Helper class for building/generating the classes and resources used in the
+ * plugin.
  */
-public class BuildJspAutotags {
+public class BuildAutotags {
 
-    public BuildJspAutotags() {
+    public BuildAutotags() {
     }
 
     /**
@@ -48,28 +50,32 @@ public class BuildJspAutotags {
      */
     public static void main(String[] args) {
 
-        BuildJspAutotags me = new BuildJspAutotags();
+        BuildAutotags me = new BuildAutotags();
 
-        me.build(args[0], args[1], args[2], args[3], args[4]);
+        // Jsp classes
+        me.buildJsp(args[0]);
+
+        // Freemarker classes
+        me.buildFreemarker(args[0]);
 
     }
 
     /**
-     * Build
+     * Build JSP tag classes and .tld file.
+     * 
+     * To build, change template-suite.xml as required and then run this program.
+     * Copy the classes and .tld from the target autotag folder into the packageName
+     * location, .tld to src/main/resources/META-INF/tld/tiles-jsp.tld
      *
-     * @param taglibURI    the taglib URI
-     * @param packageName  the package name
-     * @param requestClass the request class
-     * @param jspRuntime   the jsp runtime
-     * @param outputDir    the output dir
+     * @param outputDir the output dir
      */
-    public void build(String taglibURI, String packageName, String requestClass, String jspRuntime, String outputDir) {
+    public void buildJsp(String outputDir) {
 
         // Default values
-        // taglibURI = "org.apache.tiles.autotag.jsp.runtime.Runtime";
-        // packageName = "org.apache.tiles.web.jsp.taglib";
-        // requestClass = "org.apache.tiles.request.Request";
-        // jspRuntime = "org.apache.tiles.autotag.jsp.runtime.Runtime";
+        String taglibURI = "http://tiles.apache.org/tags-tiles";
+        String packageName = "org.apache.tiles.web.jsp.taglib";
+        String requestClass = "org.apache.tiles.request.Request";
+        String runtime = "org.apache.tiles.request.jsp.autotag.JspAutotagRuntime";
         // outputDir = "/target"
 
         Map<String, String> parameters = new HashMap<String, String>();
@@ -103,7 +109,58 @@ public class BuildJspAutotags {
                     resourcesOutputDirectory, new VelocityEngine(props), TemplateGeneratorBuilder.createNewInstance())
                     .createTemplateGenerator();
 
-            generator.generate(packageName, suite, parameters, jspRuntime, requestClass);
+            generator.generate(packageName, suite, parameters, runtime, requestClass);
+
+        } catch (Exception e) {
+            // ignored
+        }
+
+    }
+
+    /**
+     * Builds the freemarker.
+     * 
+     * To build, change template-suite.xml as required and then run this program.
+     * Copy the classes from the target autotag folder into the packageName
+     * location.
+     *
+     * @param outputDir the output dir
+     */
+    public void buildFreemarker(String outputDir) {
+
+        // Default values
+        String packageName = "org.apache.tiles.freemarker.template";
+        String requestClass = "org.apache.tiles.request.Request";
+        String runtime = "org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime";
+        // outputDir = "/target"
+
+        try {
+
+            TemplateSuite suite;
+
+            InputStream stream = getClass().getResourceAsStream("/META-INF/template-suite.xml");
+
+            try {
+                XStream xstream = new XStream(new DomDriver());
+                xstream.allowTypes(new Class[] { org.apache.tiles.autotag.model.TemplateClass.class,
+                        org.apache.tiles.autotag.model.TemplateSuite.class,
+                        org.apache.tiles.autotag.model.TemplateParameter.class });
+                suite = (TemplateSuite) xstream.fromXML(stream);
+            } finally {
+                stream.close();
+            }
+
+            Properties props = new Properties();
+            InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+            props.load(propsStream);
+            propsStream.close();
+
+            File classesOutputDirectory = new File(outputDir + "/generated-sources/autotag/classes");
+
+            TemplateGenerator generator = new FMTemplateGeneratorFactory(classesOutputDirectory,
+                    new VelocityEngine(props), TemplateGeneratorBuilder.createNewInstance()).createTemplateGenerator();
+
+            generator.generate(packageName, suite, null, runtime, requestClass);
 
         } catch (Exception e) {
             // ignored
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsWildcardServletApplicationContext.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsWildcardServletApplicationContext.java
index 6a890d4a9..7af6069bb 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsWildcardServletApplicationContext.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsWildcardServletApplicationContext.java
@@ -24,7 +24,6 @@ import com.opensymphony.xwork2.util.finder.ResourceFinder;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.tiles.request.ApplicationResource;
-import org.apache.tiles.request.locale.URLApplicationResource;
 import org.apache.tiles.request.servlet.ServletApplicationContext;
 
 import javax.servlet.ServletContext;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMModelGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMModelGenerator.java
new file mode 100644
index 000000000..8c3520e91
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMModelGenerator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.freemarker;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.generate.AbstractTemplateClassGenerator;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Generates a single Freemarker directive model, given a template class.
+ */
+public class FMModelGenerator extends AbstractTemplateClassGenerator {
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public FMModelGenerator(VelocityEngine velocityEngine) {
+        super(velocityEngine);
+    }
+
+    @Override
+    protected String getDirectoryName(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return packageName.replaceAll("\\.", "/");
+    }
+
+    @Override
+    protected String getFilename(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return clazz.getTagClassPrefix() + "FMModel.java";
+    }
+
+    @Override
+    protected String getTemplatePath(File directory, String packageName,
+            TemplateSuite suite, TemplateClass clazz, Map<String, String> parameters,
+            String runtimeClass, String requestClass) {
+        return "/org/apache/tiles/autotag/freemarker/fmModel.vm";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMModelRepositoryGenerator.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMModelRepositoryGenerator.java
new file mode 100644
index 000000000..6c045a535
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMModelRepositoryGenerator.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.freemarker;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.generate.AbstractTemplateSuiteGenerator;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Generates the model repository, given the template suite.
+ */
+public class FMModelRepositoryGenerator extends AbstractTemplateSuiteGenerator {
+
+    /**
+     * Constructor.
+     *
+     * @param velocityEngine The Velocity engine.
+     */
+    public FMModelRepositoryGenerator(VelocityEngine velocityEngine) {
+        super(velocityEngine);
+    }
+
+    @Override
+    protected String getTemplatePath(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return "/org/apache/tiles/autotag/freemarker/repository.vm";
+    }
+
+    @Override
+    protected String getFilename(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        String name = suite.getName();
+        return name.substring(0, 1).toUpperCase() + name.substring(1) + "FMModelRepository.java";
+    }
+
+    @Override
+    protected String getDirectoryName(File directory, String packageName,
+            TemplateSuite suite, Map<String, String> parameters) {
+        return packageName.replaceAll("\\.", "/");
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMTemplateGeneratorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMTemplateGeneratorFactory.java
new file mode 100644
index 000000000..b13b7a37c
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/FMTemplateGeneratorFactory.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.freemarker;
+
+import java.io.File;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.tiles.autotag.generate.TemplateGeneratorFactory;
+import org.apache.velocity.app.VelocityEngine;
+
+/**
+ * Creates a template generator that generates code for Freemarker.
+ */
+public class FMTemplateGeneratorFactory implements TemplateGeneratorFactory {
+
+    /**
+     * Location of the file.
+     */
+    private File classesOutputDirectory;
+
+    /**
+     * The Velocity engine.
+     */
+    private VelocityEngine velocityEngine;
+
+    /**
+     * The template generator builder.
+     */
+    private TemplateGeneratorBuilder templateGeneratorBuilder;
+
+    /**
+     * Constructor.
+     *
+     * @param classesOutputDirectory   Directory where code will be placed.
+     * @param velocityEngine           The Velocity engine.
+     * @param templateGeneratorBuilder The template generator builder.
+     */
+    public FMTemplateGeneratorFactory(File classesOutputDirectory, VelocityEngine velocityEngine,
+            TemplateGeneratorBuilder templateGeneratorBuilder) {
+        this.classesOutputDirectory = classesOutputDirectory;
+        this.velocityEngine = velocityEngine;
+        this.templateGeneratorBuilder = templateGeneratorBuilder;
+    }
+
+    @Override
+    public TemplateGenerator createTemplateGenerator() {
+        return templateGeneratorBuilder.setClassesOutputDirectory(classesOutputDirectory)
+                .addClassesTemplateSuiteGenerator(new FMModelRepositoryGenerator(velocityEngine))
+                .addClassesTemplateClassGenerator(new FMModelGenerator(velocityEngine)).build();
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/package-info.java
new file mode 100644
index 000000000..f891ee347
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * $Id: package-info.java 1044819 2010-12-12 13:29:34Z apetrelli $
+ *
+ * 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.
+ */
+/**
+ * Autotag support for Freemarker.
+ */
+package org.apache.tiles.autotag.freemarker;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddAttributeFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddAttributeFMModel.java
index c6efb87f0..5c656fe87 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddAttributeFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddAttributeFMModel.java
@@ -16,28 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.AddAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Add an element to the surrounding list. Equivalent to 'putAttribute',
- * but for list element.</strong>
+ * Add an element to the surrounding list. Equivalent to 'putAttribute', but for
+ * list element.
  * </p>
- *
+ * 
  * <p>
  * Add an element to the surrounding list. This tag can only be used inside
  * 'putListAttribute' or 'addListAttribute' tags. Value can come from a direct
@@ -49,38 +50,29 @@ public class AddAttributeFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final AddAttributeModel model;
+    private org.apache.tiles.template.AddAttributeModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public AddAttributeFMModel(AddAttributeModel model) {
+    public AddAttributeFMModel(org.apache.tiles.template.AddAttributeModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("value", Object.class, null),
-            runtime.getParameter("expression", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("type", String.class, null),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("value", java.lang.Object.class, null),
+                runtime.getParameter("expression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("type", java.lang.String.class, null), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
index 764846ac7..ef81f9a44 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
@@ -16,25 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.AddListAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Declare a list that will be pass as an attribute. </strong>
+ * Declare a list that will be pass as an attribute.
  * </p>
  * <p>
  * Declare a list that will be pass as an attribute . List elements are added
@@ -47,35 +48,26 @@ public class AddListAttributeFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final AddListAttributeModel model;
+    private org.apache.tiles.template.AddListAttributeModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public AddListAttributeFMModel(AddListAttributeModel model) {
+    public AddListAttributeFMModel(org.apache.tiles.template.AddListAttributeModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("role", String.class, null),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("role", java.lang.String.class, null), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/DefinitionFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/DefinitionFMModel.java
index e7342c631..433f44fbf 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/DefinitionFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/DefinitionFMModel.java
@@ -16,25 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.DefinitionModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Create a definition at runtime. </strong>
+ * Create a definition at runtime.
  * </p>
  * <p>
  * Create a new definition at runtime. Newly created definition will be
@@ -46,39 +47,30 @@ public class DefinitionFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final DefinitionModel model;
+    private org.apache.tiles.template.DefinitionModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public DefinitionFMModel(DefinitionModel model) {
+    public DefinitionFMModel(org.apache.tiles.template.DefinitionModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("template", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("extends", String.class, null),
-            runtime.getParameter("preparer", String.class, null),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("template", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("extends", java.lang.String.class, null),
+                runtime.getParameter("preparer", java.lang.String.class, null), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/GetAsStringFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/GetAsStringFMModel.java
index 41cc6a9b1..555a708e1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/GetAsStringFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/GetAsStringFMModel.java
@@ -16,29 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.api.Attribute;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.GetAsStringModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong> Render the value of the specified template attribute to the current
- * Writer</strong>
+ * Render the value of the specified template attribute to the current Writer
  * </p>
- *
+ * 
  * <p>
  * Retrieve the value of the specified template attribute property, and render
  * it to the current Writer as a String. The usual toString() conversions is
@@ -50,42 +49,33 @@ public class GetAsStringFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final GetAsStringModel model;
+    private org.apache.tiles.template.GetAsStringModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public GetAsStringFMModel(GetAsStringModel model) {
+    public GetAsStringFMModel(org.apache.tiles.template.GetAsStringModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("ignore", Boolean.class, false),
-            runtime.getParameter("preparer", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("defaultValue", Object.class, null),
-            runtime.getParameter("defaultValueRole", String.class, null),
-            runtime.getParameter("defaultValueType", String.class, null),
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("value", Attribute.class, null),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("ignore", java.lang.Boolean.class, false),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("defaultValue", java.lang.Object.class, null),
+                runtime.getParameter("defaultValueRole", java.lang.String.class, null),
+                runtime.getParameter("defaultValueType", java.lang.String.class, null),
+                runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("value", org.apache.tiles.api.Attribute.class, null), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/ImportAttributeFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/ImportAttributeFMModel.java
index 40a00f806..ebee22db9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/ImportAttributeFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/ImportAttributeFMModel.java
@@ -16,24 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.ImportAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Import attribute(s) in specified context.</strong>
+ * Import attribute(s) in specified context.
  * </p>
  * <p>
  * Import attribute(s) to requested scope. Attribute name and scope are
@@ -46,36 +47,28 @@ public class ImportAttributeFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final ImportAttributeModel model;
+    private org.apache.tiles.template.ImportAttributeModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public ImportAttributeFMModel(ImportAttributeModel model) {
+    public ImportAttributeFMModel(org.apache.tiles.template.ImportAttributeModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
-        model.execute(
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("scope", String.class, null),
-            runtime.getParameter("toName", String.class, null),
-            runtime.getParameter("ignore", Boolean.class, false),
-            request
-        );
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("scope", java.lang.String.class, null),
+                runtime.getParameter("toName", java.lang.String.class, null),
+                runtime.getParameter("ignore", java.lang.Boolean.class, false), request);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertAttributeFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertAttributeFMModel.java
index 4e679acf1..67b36eec4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertAttributeFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertAttributeFMModel.java
@@ -16,26 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.api.Attribute;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.InsertAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Inserts the value of an attribute into the page.</strong>
+ * Inserts the value of an attribute into the page.
  * </p>
  * <p>
  * This tag can be flexibly used to insert the value of an attribute into a
@@ -47,15 +47,13 @@ import java.util.Map;
  * assigned a type, it will be treated as a String and included without any
  * special handling.
  * </p>
- *
+ * 
  * <p>
- * <strong>Example : </strong>
+ * Example :
  * </p>
- *
+ * 
  * <pre>
- * &lt;code&gt;
- *           &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
- *         &lt;/code&gt;
+ *     &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
  * </pre>
  */
 public class InsertAttributeFMModel implements TemplateDirectiveModel {
@@ -63,43 +61,34 @@ public class InsertAttributeFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final InsertAttributeModel model;
+    private org.apache.tiles.template.InsertAttributeModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public InsertAttributeFMModel(InsertAttributeModel model) {
+    public InsertAttributeFMModel(org.apache.tiles.template.InsertAttributeModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("ignore", Boolean.class, false),
-            runtime.getParameter("preparer", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("defaultValue", Object.class, null),
-            runtime.getParameter("defaultValueRole", String.class, null),
-            runtime.getParameter("defaultValueType", String.class, null),
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("value", Attribute.class, null),
-            runtime.getParameter("flush", Boolean.class, false),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("ignore", java.lang.Boolean.class, false),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("defaultValue", java.lang.Object.class, null),
+                runtime.getParameter("defaultValueRole", java.lang.String.class, null),
+                runtime.getParameter("defaultValueType", java.lang.String.class, null),
+                runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("value", org.apache.tiles.api.Attribute.class, null),
+                runtime.getParameter("flush", java.lang.Boolean.class, false), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertDefinitionFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertDefinitionFMModel.java
index 4ae8fdff8..0f1cdd838 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertDefinitionFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertDefinitionFMModel.java
@@ -16,53 +16,51 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.InsertDefinitionModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Insert a definition.</strong>
+ * Insert a definition.
  * </p>
  * <p>
  * Insert a definition with the possibility to override and specify parameters
  * (called attributes). A definition can be seen as a (partially or totally)
  * filled template that can override or complete attribute values.
- * <code>&lt;tiles:insertDefinition&gt;</code> allows to define these attributes
- * and pass them to the inserted jsp page, called template. Attributes are
- * defined using nested tag <code>&lt;tiles:putAttribute&gt;</code> or
- * <code>&lt;tiles:putListAttribute&gt;</code>.
+ * &lt;tiles:insertDefinition&gt; allows to define these attributes and pass
+ * them to the inserted jsp page, called template. Attributes are defined using
+ * nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
  * </p>
  * <p>
- * You must specify <code>name</code> tag attribute, for inserting a definition
- * from definitions factory.
+ * You must specify name tag attribute, for inserting a definition from
+ * definitions factory.
  * </p>
  * <p>
- * <strong>Example : </strong>
+ * Example :
  * </p>
- *
+ * 
  * <pre>
- * &lt;code&gt;
- *           &lt;tiles:insertDefinition name=&quot;.my.tiles.definition flush=&quot;true&quot;&gt;
- *              &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
- *           &lt;/tiles:insertDefinition&gt;
- *         &lt;/code&gt;
+ *     &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
+ *         &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;/tiles:insertDefinition&gt;
  * </pre>
  */
 public class InsertDefinitionFMModel implements TemplateDirectiveModel {
@@ -70,41 +68,32 @@ public class InsertDefinitionFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final InsertDefinitionModel model;
+    private org.apache.tiles.template.InsertDefinitionModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public InsertDefinitionFMModel(InsertDefinitionModel model) {
+    public InsertDefinitionFMModel(org.apache.tiles.template.InsertDefinitionModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("template", String.class, null),
-            runtime.getParameter("templateType", String.class, null),
-            runtime.getParameter("templateExpression", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("preparer", String.class, null),
-            runtime.getParameter("flush", Boolean.class, false),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("template", java.lang.String.class, null),
+                runtime.getParameter("templateType", java.lang.String.class, null),
+                runtime.getParameter("templateExpression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("flush", java.lang.Boolean.class, false), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertTemplateFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertTemplateFMModel.java
index d769b6073..64c04acc9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertTemplateFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/InsertTemplateFMModel.java
@@ -16,53 +16,51 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.InsertTemplateModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Insert a template.</strong>
+ * Insert a template.
  * </p>
  * <p>
  * Insert a template with the possibility to pass parameters (called
  * attributes). A template can be seen as a procedure that can take parameters
- * or attributes. <code>&lt;tiles:insertTemplate&gt;</code> allows to define
- * these attributes and pass them to the inserted jsp page, called template.
- * Attributes are defined using nested tag
- * <code>&lt;tiles:putAttribute&gt;</code> or
- * <code>&lt;tiles:putListAttribute&gt;</code>.
+ * or attributes. &lt;tiles:insertTemplate&gt; allows to define these attributes
+ * and pass them to the inserted jsp page, called template. Attributes are
+ * defined using nested tag &lt;tiles:putAttribute&gt; or
+ * &lt;tiles:putListAttribute&gt;.
  * </p>
  * <p>
- * You must specify <code>template</code> attribute, for inserting a template
+ * You must specify template attribute, for inserting a template
  * </p>
- *
+ * 
  * <p>
- * <strong>Example : </strong>
+ * Example :
  * </p>
- *
+ * 
  * <pre>
- * &lt;code&gt;
- *           &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
- *              &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
- *              &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
- *           &lt;/tiles:insertTemplate&gt;
- *         &lt;/code&gt;
+ *     &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
+ *         &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;/tiles:insertTemplate&gt;
  * </pre>
  */
 public class InsertTemplateFMModel implements TemplateDirectiveModel {
@@ -70,40 +68,31 @@ public class InsertTemplateFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final InsertTemplateModel model;
+    private org.apache.tiles.template.InsertTemplateModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public InsertTemplateFMModel(InsertTemplateModel model) {
+    public InsertTemplateFMModel(org.apache.tiles.template.InsertTemplateModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("template", String.class, null),
-            runtime.getParameter("templateType", String.class, null),
-            runtime.getParameter("templateExpression", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("preparer", String.class, null),
-            runtime.getParameter("flush", Boolean.class, false),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("template", java.lang.String.class, null),
+                runtime.getParameter("templateType", java.lang.String.class, null),
+                runtime.getParameter("templateExpression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("preparer", java.lang.String.class, null),
+                runtime.getParameter("flush", java.lang.Boolean.class, false), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutAttributeFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutAttributeFMModel.java
index 42ac040c4..3d71b32a3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutAttributeFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutAttributeFMModel.java
@@ -16,25 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.PutAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Put an attribute in enclosing attribute container tag.</strong>
+ * Put an attribute in enclosing attribute container tag.
  * </p>
  * <p>
  * Enclosing attribute container tag can be :
@@ -45,11 +46,11 @@ import java.util.Map;
  * <li>&lt;insertDefinition&gt;</li>
  * <li>&lt;putListAttribute&gt;</li>
  * </ul>
- * (or any other tag which implements the <code>PutAttributeTagParent</code>
- * interface. Exception is thrown if no appropriate tag can be found.
+ * (or any other tag which implements the PutAttributeTagParent interface.
+ * Exception is thrown if no appropriate tag can be found.
  * </p>
  * <p>
- * Put tag can have following attributes :
+ * Put tag can have following atributes :
  * <ul>
  * <li>name : Name of the attribute</li>
  * <li>value : value to put as attribute</li>
@@ -70,40 +71,31 @@ public class PutAttributeFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final PutAttributeModel model;
+    private org.apache.tiles.template.PutAttributeModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public PutAttributeFMModel(PutAttributeModel model) {
+    public PutAttributeFMModel(org.apache.tiles.template.PutAttributeModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("value", Object.class, null),
-            runtime.getParameter("expression", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("type", String.class, null),
-            runtime.getParameter("cascade", Boolean.class, false),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("value", java.lang.Object.class, null),
+                runtime.getParameter("expression", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("type", java.lang.String.class, null),
+                runtime.getParameter("cascade", java.lang.Boolean.class, false), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutListAttributeFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutListAttributeFMModel.java
index 9b48faf22..3eb5cb2c7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutListAttributeFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/PutListAttributeFMModel.java
@@ -16,25 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.PutListAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * <p>
- * <strong>Declare a list that will be pass as attribute to tile. </strong>
+ * Declare a list that will be pass as attribute to tile.
  * </p>
  * <p>
  * Declare a list that will be pass as attribute to tile. List elements are
@@ -47,38 +48,29 @@ public class PutListAttributeFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final PutListAttributeModel model;
+    private org.apache.tiles.template.PutListAttributeModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public PutListAttributeFMModel(PutListAttributeModel model) {
+    public PutListAttributeFMModel(org.apache.tiles.template.PutListAttributeModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            runtime.getParameter("name", String.class, null),
-            runtime.getParameter("role", String.class, null),
-            runtime.getParameter("inherit", Boolean.class, false),
-            runtime.getParameter("cascade", Boolean.class, false),
-            request,
-            modelBody
-        );
+        model.execute(runtime.getParameter("name", java.lang.String.class, null),
+                runtime.getParameter("role", java.lang.String.class, null),
+                runtime.getParameter("inherit", java.lang.Boolean.class, false),
+                runtime.getParameter("cascade", java.lang.Boolean.class, false), request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java
index 7703a80aa..66d56ce34 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java
@@ -16,20 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.SetCurrentContainerModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
  * Selects a container to be used as the "current" container.
@@ -39,33 +40,25 @@ public class SetCurrentContainerFMModel implements TemplateDirectiveModel {
     /**
      * The template model.
      */
-    private final SetCurrentContainerModel model;
+    private org.apache.tiles.template.SetCurrentContainerModel model;
 
     /**
      * Constructor.
      *
      * @param model The template model.
      */
-    public SetCurrentContainerFMModel(SetCurrentContainerModel model) {
+    public SetCurrentContainerFMModel(org.apache.tiles.template.SetCurrentContainerModel model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
-        model.execute(
-            runtime.getParameter("containerKey", String.class, null),
-            request
-        );
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.request.Request> runtime = new org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        model.execute(runtime.getParameter("containerKey", java.lang.String.class, null), request);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
index f7f3d9607..d91766a2b 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
@@ -16,26 +16,140 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
 package org.apache.tiles.freemarker.template;
 
+/**
+ * This tag library provides Tiles tags.
+ */
 public class TilesFMModelRepository {
 
+    /**
+     * The "insertDefinition" directive.
+     */
+    private InsertDefinitionFMModel insertDefinition;
+
+    /**
+     * The "importAttribute" directive.
+     */
+    private ImportAttributeFMModel importAttribute;
+
+    /**
+     * The "setCurrentContainer" directive.
+     */
+    private SetCurrentContainerFMModel setCurrentContainer;
+
+    /**
+     * The "addListAttribute" directive.
+     */
+    private AddListAttributeFMModel addListAttribute;
+
+    /**
+     * The "getAsString" directive.
+     */
+    private GetAsStringFMModel getAsString;
+
+    /**
+     * The "insertAttribute" directive.
+     */
+    private InsertAttributeFMModel insertAttribute;
+
     /**
      * The "putAttribute" directive.
      */
-    private final PutAttributeFMModel putAttribute;
+    private PutAttributeFMModel putAttribute;
 
     /**
      * The "definition" directive.
      */
-    private final DefinitionFMModel definition;
+    private DefinitionFMModel definition;
+
+    /**
+     * The "addAttribute" directive.
+     */
+    private AddAttributeFMModel addAttribute;
+
+    /**
+     * The "putListAttribute" directive.
+     */
+    private PutListAttributeFMModel putListAttribute;
+
+    /**
+     * The "insertTemplate" directive.
+     */
+    private InsertTemplateFMModel insertTemplate;
 
     /**
      * Constructor.
      */
     public TilesFMModelRepository() {
+        insertDefinition = new InsertDefinitionFMModel(new org.apache.tiles.template.InsertDefinitionModel());
+        importAttribute = new ImportAttributeFMModel(new org.apache.tiles.template.ImportAttributeModel());
+        setCurrentContainer = new SetCurrentContainerFMModel(new org.apache.tiles.template.SetCurrentContainerModel());
+        addListAttribute = new AddListAttributeFMModel(new org.apache.tiles.template.AddListAttributeModel());
+        getAsString = new GetAsStringFMModel(new org.apache.tiles.template.GetAsStringModel());
+        insertAttribute = new InsertAttributeFMModel(new org.apache.tiles.template.InsertAttributeModel());
         putAttribute = new PutAttributeFMModel(new org.apache.tiles.template.PutAttributeModel());
         definition = new DefinitionFMModel(new org.apache.tiles.template.DefinitionModel());
+        addAttribute = new AddAttributeFMModel(new org.apache.tiles.template.AddAttributeModel());
+        putListAttribute = new PutListAttributeFMModel(new org.apache.tiles.template.PutListAttributeModel());
+        insertTemplate = new InsertTemplateFMModel(new org.apache.tiles.template.InsertTemplateModel());
+    }
+
+    /**
+     * Returns the "insertDefinition" directive.
+     *
+     * @return The "insertDefinition" directive.
+     */
+    public InsertDefinitionFMModel getInsertDefinition() {
+        return insertDefinition;
+    }
+
+    /**
+     * Returns the "importAttribute" directive.
+     *
+     * @return The "importAttribute" directive.
+     */
+    public ImportAttributeFMModel getImportAttribute() {
+        return importAttribute;
+    }
+
+    /**
+     * Returns the "setCurrentContainer" directive.
+     *
+     * @return The "setCurrentContainer" directive.
+     */
+    public SetCurrentContainerFMModel getSetCurrentContainer() {
+        return setCurrentContainer;
+    }
+
+    /**
+     * Returns the "addListAttribute" directive.
+     *
+     * @return The "addListAttribute" directive.
+     */
+    public AddListAttributeFMModel getAddListAttribute() {
+        return addListAttribute;
+    }
+
+    /**
+     * Returns the "getAsString" directive.
+     *
+     * @return The "getAsString" directive.
+     */
+    public GetAsStringFMModel getGetAsString() {
+        return getAsString;
+    }
+
+    /**
+     * Returns the "insertAttribute" directive.
+     *
+     * @return The "insertAttribute" directive.
+     */
+    public InsertAttributeFMModel getInsertAttribute() {
+        return insertAttribute;
     }
 
     /**
@@ -56,4 +170,30 @@ public class TilesFMModelRepository {
         return definition;
     }
 
+    /**
+     * Returns the "addAttribute" directive.
+     *
+     * @return The "addAttribute" directive.
+     */
+    public AddAttributeFMModel getAddAttribute() {
+        return addAttribute;
+    }
+
+    /**
+     * Returns the "putListAttribute" directive.
+     *
+     * @return The "putListAttribute" directive.
+     */
+    public PutListAttributeFMModel getPutListAttribute() {
+        return putListAttribute;
+    }
+
+    /**
+     * Returns the "insertTemplate" directive.
+     *
+     * @return The "insertTemplate" directive.
+     */
+    public InsertTemplateFMModel getInsertTemplate() {
+        return insertTemplate;
+    }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
index affe32dcc..53c42cef2 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -31,8 +31,8 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Add an element to the surrounding list. Equivalent to 'putAttribute',
- * but for list element.
+ * Add an element to the surrounding list. Equivalent to 'putAttribute', but for
+ * list element.
  * </p>
  * 
  * <p>
@@ -49,20 +49,19 @@ public class AddAttributeTag extends SimpleTagSupport {
     private org.apache.tiles.template.AddAttributeModel model = new org.apache.tiles.template.AddAttributeModel();
 
     /**
-     * The value of the attribute. Use this parameter, or
-     * expression, or body.
+     * The value of the attribute. Use this parameter, or expression, or body.
      */
     private java.lang.Object value;
 
     /**
-     * The expression to calculate the value from. Use this
-     * parameter, or value, or body.
+     * The expression to calculate the value from. Use this parameter, or value, or
+     * body.
      */
     private java.lang.String expression;
 
     /**
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
@@ -74,9 +73,8 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Getter for value property.
      *
-     * @return
-     * The value of the attribute. Use this parameter, or
-     * expression, or body.
+     * @return The value of the attribute. Use this parameter, or expression, or
+     *         body.
      */
     public java.lang.Object getValue() {
         return value;
@@ -85,9 +83,8 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Setter for value property.
      *
-     * @param value
-     * The value of the attribute. Use this parameter, or
-     * expression, or body.
+     * @param value The value of the attribute. Use this parameter, or expression,
+     *              or body.
      */
     public void setValue(java.lang.Object value) {
         this.value = value;
@@ -96,9 +93,8 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Getter for expression property.
      *
-     * @return
-     * The expression to calculate the value from. Use this
-     * parameter, or value, or body.
+     * @return The expression to calculate the value from. Use this parameter, or
+     *         value, or body.
      */
     public java.lang.String getExpression() {
         return expression;
@@ -107,9 +103,8 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Setter for expression property.
      *
-     * @param expression
-     * The expression to calculate the value from. Use this
-     * parameter, or value, or body.
+     * @param expression The expression to calculate the value from. Use this
+     *                   parameter, or value, or body.
      */
     public void setExpression(java.lang.String expression) {
         this.expression = expression;
@@ -118,9 +113,8 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -129,9 +123,8 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -140,8 +133,7 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Getter for type property.
      *
-     * @return
-     * The type (renderer) of the attribute.
+     * @return The type (renderer) of the attribute.
      */
     public java.lang.String getType() {
         return type;
@@ -150,8 +142,7 @@ public class AddAttributeTag extends SimpleTagSupport {
     /**
      * Setter for type property.
      *
-     * @param type
-     * The type (renderer) of the attribute.
+     * @param type The type (renderer) of the attribute.
      */
     public void setType(java.lang.String type) {
         this.type = type;
@@ -167,15 +158,8 @@ public class AddAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            value,
-            expression,
-            role,
-            type,
-            request, modelBody
-
-        );
+        model.execute(value, expression, role, type, request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
index fd39f386f..0dc5c9fde 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -31,7 +31,7 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Declare a list that will be pass as an attribute. 
+ * Declare a list that will be pass as an attribute.
  * </p>
  * <p>
  * Declare a list that will be pass as an attribute . List elements are added
@@ -54,8 +54,7 @@ public class AddListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * The comma-separated list of roles that can use the list attribute.
+     * @return The comma-separated list of roles that can use the list attribute.
      */
     public java.lang.String getRole() {
         return role;
@@ -64,8 +63,8 @@ public class AddListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * The comma-separated list of roles that can use the list attribute.
+     * @param role The comma-separated list of roles that can use the list
+     *             attribute.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -81,12 +80,8 @@ public class AddListAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            role,
-            request, modelBody
-
-        );
+        model.execute(role, request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
index e755d18dc..eac32da5a 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -31,7 +31,7 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Create a definition at runtime. 
+ * Create a definition at runtime.
  * </p>
  * <p>
  * Create a new definition at runtime. Newly created definition will be
@@ -46,8 +46,8 @@ public class DefinitionTag extends SimpleTagSupport {
     private org.apache.tiles.template.DefinitionModel model = new org.apache.tiles.template.DefinitionModel();
 
     /**
-     * The name of the definition to create. If not specified, an
-     * anonymous definition will be created.
+     * The name of the definition to create. If not specified, an anonymous
+     * definition will be created.
      */
     private java.lang.String name;
 
@@ -57,8 +57,8 @@ public class DefinitionTag extends SimpleTagSupport {
     private java.lang.String template;
 
     /**
-     * A comma-separated list of roles. If present, the definition
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the definition will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
@@ -68,17 +68,15 @@ public class DefinitionTag extends SimpleTagSupport {
     private java.lang.String extendsParam;
 
     /**
-     * The preparer to use to invoke before the definition is
-     * rendered.
+     * The preparer to use to invoke before the definition is rendered.
      */
     private java.lang.String preparer;
 
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the definition to create. If not specified, an
-     * anonymous definition will be created.
+     * @return The name of the definition to create. If not specified, an anonymous
+     *         definition will be created.
      */
     public java.lang.String getName() {
         return name;
@@ -87,9 +85,8 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param name
-     * The name of the definition to create. If not specified, an
-     * anonymous definition will be created.
+     * @param name The name of the definition to create. If not specified, an
+     *             anonymous definition will be created.
      */
     public void setName(java.lang.String name) {
         this.name = name;
@@ -98,8 +95,7 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Getter for template property.
      *
-     * @return
-     * The template of this definition.
+     * @return The template of this definition.
      */
     public java.lang.String getTemplate() {
         return template;
@@ -108,8 +104,7 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Setter for template property.
      *
-     * @param template
-     * The template of this definition.
+     * @param template The template of this definition.
      */
     public void setTemplate(java.lang.String template) {
         this.template = template;
@@ -118,9 +113,8 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the definition
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the definition will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -129,9 +123,8 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the definition
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the definition will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -140,8 +133,7 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Getter for extends property.
      *
-     * @return
-     * The definition name that this definition extends.
+     * @return The definition name that this definition extends.
      */
     public java.lang.String getExtends() {
         return extendsParam;
@@ -150,8 +142,7 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Setter for extends property.
      *
-     * @param extendsParam
-     * The definition name that this definition extends.
+     * @param extendsParam The definition name that this definition extends.
      */
     public void setExtends(java.lang.String extendsParam) {
         this.extendsParam = extendsParam;
@@ -160,9 +151,7 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return
-     * The preparer to use to invoke before the definition is
-     * rendered.
+     * @return The preparer to use to invoke before the definition is rendered.
      */
     public java.lang.String getPreparer() {
         return preparer;
@@ -171,9 +160,8 @@ public class DefinitionTag extends SimpleTagSupport {
     /**
      * Setter for preparer property.
      *
-     * @param preparer
-     * The preparer to use to invoke before the definition is
-     * rendered.
+     * @param preparer The preparer to use to invoke before the definition is
+     *                 rendered.
      */
     public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
@@ -189,16 +177,8 @@ public class DefinitionTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            name,
-            template,
-            role,
-            extendsParam,
-            preparer,
-            request, modelBody
-
-        );
+        model.execute(name, template, role, extendsParam, preparer, request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
index 1eb28583d..e34a1efc1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -31,8 +31,7 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- *  Render the value of the specified template attribute to the current
- * Writer
+ * Render the value of the specified template attribute to the current Writer
  * </p>
  * 
  * <p>
@@ -49,8 +48,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     private org.apache.tiles.template.GetAsStringModel model = new org.apache.tiles.template.GetAsStringModel();
 
     /**
-     * If true, if an exception happens during
-     * rendering, of if the attribute is null, the problem will be ignored.
+     * If true, if an exception happens during rendering, of if the attribute is
+     * null, the problem will be ignored.
      */
     private boolean ignore;
 
@@ -60,26 +59,26 @@ public class GetAsStringTag extends SimpleTagSupport {
     private java.lang.String preparer;
 
     /**
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
     /**
-     * The default value of the attribute. To use only if
-     * the attribute was not computed.
+     * The default value of the attribute. To use only if the attribute was not
+     * computed.
      */
     private java.lang.Object defaultValue;
 
     /**
-     * The default comma-separated list of roles. To use
-     * only if the attribute was not computed.
+     * The default comma-separated list of roles. To use only if the attribute was
+     * not computed.
      */
     private java.lang.String defaultValueRole;
 
     /**
-     * The default type of the attribute. To use only if
-     * the attribute was not computed.
+     * The default type of the attribute. To use only if the attribute was not
+     * computed.
      */
     private java.lang.String defaultValueType;
 
@@ -96,9 +95,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for ignore property.
      *
-     * @return
-     * If true, if an exception happens during
-     * rendering, of if the attribute is null, the problem will be ignored.
+     * @return If true, if an exception happens during rendering, of if the
+     *         attribute is null, the problem will be ignored.
      */
     public boolean isIgnore() {
         return ignore;
@@ -107,9 +105,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for ignore property.
      *
-     * @param ignore
-     * If true, if an exception happens during
-     * rendering, of if the attribute is null, the problem will be ignored.
+     * @param ignore If true, if an exception happens during rendering, of if the
+     *               attribute is null, the problem will be ignored.
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
@@ -118,8 +115,7 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return
-     * The preparer to invoke before rendering the attribute.
+     * @return The preparer to invoke before rendering the attribute.
      */
     public java.lang.String getPreparer() {
         return preparer;
@@ -128,8 +124,7 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for preparer property.
      *
-     * @param preparer
-     * The preparer to invoke before rendering the attribute.
+     * @param preparer The preparer to invoke before rendering the attribute.
      */
     public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
@@ -138,9 +133,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -149,9 +143,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -160,9 +153,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for defaultValue property.
      *
-     * @return
-     * The default value of the attribute. To use only if
-     * the attribute was not computed.
+     * @return The default value of the attribute. To use only if the attribute was
+     *         not computed.
      */
     public java.lang.Object getDefaultValue() {
         return defaultValue;
@@ -171,9 +163,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for defaultValue property.
      *
-     * @param defaultValue
-     * The default value of the attribute. To use only if
-     * the attribute was not computed.
+     * @param defaultValue The default value of the attribute. To use only if the
+     *                     attribute was not computed.
      */
     public void setDefaultValue(java.lang.Object defaultValue) {
         this.defaultValue = defaultValue;
@@ -182,9 +173,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for defaultValueRole property.
      *
-     * @return
-     * The default comma-separated list of roles. To use
-     * only if the attribute was not computed.
+     * @return The default comma-separated list of roles. To use only if the
+     *         attribute was not computed.
      */
     public java.lang.String getDefaultValueRole() {
         return defaultValueRole;
@@ -193,9 +183,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for defaultValueRole property.
      *
-     * @param defaultValueRole
-     * The default comma-separated list of roles. To use
-     * only if the attribute was not computed.
+     * @param defaultValueRole The default comma-separated list of roles. To use
+     *                         only if the attribute was not computed.
      */
     public void setDefaultValueRole(java.lang.String defaultValueRole) {
         this.defaultValueRole = defaultValueRole;
@@ -204,9 +193,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for defaultValueType property.
      *
-     * @return
-     * The default type of the attribute. To use only if
-     * the attribute was not computed.
+     * @return The default type of the attribute. To use only if the attribute was
+     *         not computed.
      */
     public java.lang.String getDefaultValueType() {
         return defaultValueType;
@@ -215,9 +203,8 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for defaultValueType property.
      *
-     * @param defaultValueType
-     * The default type of the attribute. To use only if
-     * the attribute was not computed.
+     * @param defaultValueType The default type of the attribute. To use only if the
+     *                         attribute was not computed.
      */
     public void setDefaultValueType(java.lang.String defaultValueType) {
         this.defaultValueType = defaultValueType;
@@ -226,8 +213,7 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the attribute.
+     * @return The name of the attribute.
      */
     public java.lang.String getName() {
         return name;
@@ -236,8 +222,7 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param name
-     * The name of the attribute.
+     * @param name The name of the attribute.
      */
     public void setName(java.lang.String name) {
         this.name = name;
@@ -246,8 +231,7 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Getter for value property.
      *
-     * @return
-     * The attribute to use immediately, if not null.
+     * @return The attribute to use immediately, if not null.
      */
     public org.apache.tiles.api.Attribute getValue() {
         return value;
@@ -256,8 +240,7 @@ public class GetAsStringTag extends SimpleTagSupport {
     /**
      * Setter for value property.
      *
-     * @param value
-     * The attribute to use immediately, if not null.
+     * @param value The attribute to use immediately, if not null.
      */
     public void setValue(org.apache.tiles.api.Attribute value) {
         this.value = value;
@@ -273,19 +256,9 @@ public class GetAsStringTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            ignore,
-            preparer,
-            role,
-            defaultValue,
-            defaultValueRole,
-            defaultValueType,
-            name,
-            value,
-            request, modelBody
-
-        );
+        model.execute(ignore, preparer, role, defaultValue, defaultValueRole, defaultValueType, name, value, request,
+                modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
index 13d8630cc..56ca370e4 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -46,20 +46,20 @@ public class ImportAttributeTag extends SimpleTagSupport {
     private org.apache.tiles.template.ImportAttributeModel model = new org.apache.tiles.template.ImportAttributeModel();
 
     /**
-     * The name of the attribute to import. If it is null, all the attributes will be imported.
+     * The name of the attribute to import. If it is null, all the attributes will
+     * be imported.
      */
     private java.lang.String name;
 
     /**
-     * The scope into which the attribute(s) will be imported. If
-     * null, the import will go in page scope.
+     * The scope into which the attribute(s) will be imported. If null, the import
+     * will go in page scope.
      */
     private java.lang.String scope;
 
     /**
-     * The name of the attribute into which the attribute will be
-     * imported. To be used in conjunction to name. If
-     * null, the value of name will be used.
+     * The name of the attribute into which the attribute will be imported. To be
+     * used in conjunction to name. If null, the value of name will be used.
      */
     private java.lang.String toName;
 
@@ -71,8 +71,8 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the attribute to import. If it is null, all the attributes will be imported.
+     * @return The name of the attribute to import. If it is null, all the
+     *         attributes will be imported.
      */
     public java.lang.String getName() {
         return name;
@@ -81,8 +81,8 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param name
-     * The name of the attribute to import. If it is null, all the attributes will be imported.
+     * @param name The name of the attribute to import. If it is null, all the
+     *             attributes will be imported.
      */
     public void setName(java.lang.String name) {
         this.name = name;
@@ -91,9 +91,8 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Getter for scope property.
      *
-     * @return
-     * The scope into which the attribute(s) will be imported. If
-     * null, the import will go in page scope.
+     * @return The scope into which the attribute(s) will be imported. If null, the
+     *         import will go in page scope.
      */
     public java.lang.String getScope() {
         return scope;
@@ -102,9 +101,8 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Setter for scope property.
      *
-     * @param scope
-     * The scope into which the attribute(s) will be imported. If
-     * null, the import will go in page scope.
+     * @param scope The scope into which the attribute(s) will be imported. If null,
+     *              the import will go in page scope.
      */
     public void setScope(java.lang.String scope) {
         this.scope = scope;
@@ -113,10 +111,9 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Getter for toName property.
      *
-     * @return
-     * The name of the attribute into which the attribute will be
-     * imported. To be used in conjunction to name. If
-     * null, the value of name will be used.
+     * @return The name of the attribute into which the attribute will be imported.
+     *         To be used in conjunction to name. If null, the value of name will be
+     *         used.
      */
     public java.lang.String getToName() {
         return toName;
@@ -125,10 +122,9 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Setter for toName property.
      *
-     * @param toName
-     * The name of the attribute into which the attribute will be
-     * imported. To be used in conjunction to name. If
-     * null, the value of name will be used.
+     * @param toName The name of the attribute into which the attribute will be
+     *               imported. To be used in conjunction to name. If null, the value
+     *               of name will be used.
      */
     public void setToName(java.lang.String toName) {
         this.toName = toName;
@@ -137,8 +133,8 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Getter for ignore property.
      *
-     * @return
-     * If true, if the attribute is not present, the problem will be ignored.
+     * @return If true, if the attribute is not present, the problem will be
+     *         ignored.
      */
     public boolean isIgnore() {
         return ignore;
@@ -147,8 +143,8 @@ public class ImportAttributeTag extends SimpleTagSupport {
     /**
      * Setter for ignore property.
      *
-     * @param ignore
-     * If true, if the attribute is not present, the problem will be ignored.
+     * @param ignore If true, if the attribute is not present, the problem will be
+     *               ignored.
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
@@ -164,14 +160,7 @@ public class ImportAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
-        model.execute(
-            name,
-            scope,
-            toName,
-            ignore,
-            request
-
-        );
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        model.execute(name, scope, toName, ignore, request);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
index f20d83ba0..be288e864 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -45,13 +45,12 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * </p>
  * 
  * <p>
- * Example : 
+ * Example :
  * </p>
  * 
  * <pre>
  *     &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
  * </pre>
- *     
  */
 public class InsertAttributeTag extends SimpleTagSupport {
 
@@ -61,8 +60,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     private org.apache.tiles.template.InsertAttributeModel model = new org.apache.tiles.template.InsertAttributeModel();
 
     /**
-     * If true, if an exception happens during
-     * rendering, of if the attribute is null, the problem will be ignored.
+     * If true, if an exception happens during rendering, of if the attribute is
+     * null, the problem will be ignored.
      */
     private boolean ignore;
 
@@ -72,26 +71,26 @@ public class InsertAttributeTag extends SimpleTagSupport {
     private java.lang.String preparer;
 
     /**
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
     /**
-     * The default value of the attribute. To use only if
-     * the attribute was not computed.
+     * The default value of the attribute. To use only if the attribute was not
+     * computed.
      */
     private java.lang.Object defaultValue;
 
     /**
-     * The default comma-separated list of roles. To use
-     * only if the attribute was not computed.
+     * The default comma-separated list of roles. To use only if the attribute was
+     * not computed.
      */
     private java.lang.String defaultValueRole;
 
     /**
-     * The default type of the attribute. To use only if
-     * the attribute was not computed.
+     * The default type of the attribute. To use only if the attribute was not
+     * computed.
      */
     private java.lang.String defaultValueType;
 
@@ -113,9 +112,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for ignore property.
      *
-     * @return
-     * If true, if an exception happens during
-     * rendering, of if the attribute is null, the problem will be ignored.
+     * @return If true, if an exception happens during rendering, of if the
+     *         attribute is null, the problem will be ignored.
      */
     public boolean isIgnore() {
         return ignore;
@@ -124,9 +122,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for ignore property.
      *
-     * @param ignore
-     * If true, if an exception happens during
-     * rendering, of if the attribute is null, the problem will be ignored.
+     * @param ignore If true, if an exception happens during rendering, of if the
+     *               attribute is null, the problem will be ignored.
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
@@ -135,8 +132,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return
-     * The preparer to invoke before rendering the attribute.
+     * @return The preparer to invoke before rendering the attribute.
      */
     public java.lang.String getPreparer() {
         return preparer;
@@ -145,8 +141,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for preparer property.
      *
-     * @param preparer
-     * The preparer to invoke before rendering the attribute.
+     * @param preparer The preparer to invoke before rendering the attribute.
      */
     public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
@@ -155,9 +150,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -166,9 +160,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -177,9 +170,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for defaultValue property.
      *
-     * @return
-     * The default value of the attribute. To use only if
-     * the attribute was not computed.
+     * @return The default value of the attribute. To use only if the attribute was
+     *         not computed.
      */
     public java.lang.Object getDefaultValue() {
         return defaultValue;
@@ -188,9 +180,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for defaultValue property.
      *
-     * @param defaultValue
-     * The default value of the attribute. To use only if
-     * the attribute was not computed.
+     * @param defaultValue The default value of the attribute. To use only if the
+     *                     attribute was not computed.
      */
     public void setDefaultValue(java.lang.Object defaultValue) {
         this.defaultValue = defaultValue;
@@ -199,9 +190,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for defaultValueRole property.
      *
-     * @return
-     * The default comma-separated list of roles. To use
-     * only if the attribute was not computed.
+     * @return The default comma-separated list of roles. To use only if the
+     *         attribute was not computed.
      */
     public java.lang.String getDefaultValueRole() {
         return defaultValueRole;
@@ -210,9 +200,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for defaultValueRole property.
      *
-     * @param defaultValueRole
-     * The default comma-separated list of roles. To use
-     * only if the attribute was not computed.
+     * @param defaultValueRole The default comma-separated list of roles. To use
+     *                         only if the attribute was not computed.
      */
     public void setDefaultValueRole(java.lang.String defaultValueRole) {
         this.defaultValueRole = defaultValueRole;
@@ -221,9 +210,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for defaultValueType property.
      *
-     * @return
-     * The default type of the attribute. To use only if
-     * the attribute was not computed.
+     * @return The default type of the attribute. To use only if the attribute was
+     *         not computed.
      */
     public java.lang.String getDefaultValueType() {
         return defaultValueType;
@@ -232,9 +220,8 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for defaultValueType property.
      *
-     * @param defaultValueType
-     * The default type of the attribute. To use only if
-     * the attribute was not computed.
+     * @param defaultValueType The default type of the attribute. To use only if the
+     *                         attribute was not computed.
      */
     public void setDefaultValueType(java.lang.String defaultValueType) {
         this.defaultValueType = defaultValueType;
@@ -243,8 +230,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the attribute.
+     * @return The name of the attribute.
      */
     public java.lang.String getName() {
         return name;
@@ -253,8 +239,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param name
-     * The name of the attribute.
+     * @param name The name of the attribute.
      */
     public void setName(java.lang.String name) {
         this.name = name;
@@ -263,8 +248,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for value property.
      *
-     * @return
-     * The attribute to use immediately, if not null.
+     * @return The attribute to use immediately, if not null.
      */
     public org.apache.tiles.api.Attribute getValue() {
         return value;
@@ -273,8 +257,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for value property.
      *
-     * @param value
-     * The attribute to use immediately, if not null.
+     * @param value The attribute to use immediately, if not null.
      */
     public void setValue(org.apache.tiles.api.Attribute value) {
         this.value = value;
@@ -283,8 +266,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Getter for flush property.
      *
-     * @return
-     * If true, the response will be flushed after the insert.
+     * @return If true, the response will be flushed after the insert.
      */
     public boolean isFlush() {
         return flush;
@@ -293,8 +275,7 @@ public class InsertAttributeTag extends SimpleTagSupport {
     /**
      * Setter for flush property.
      *
-     * @param flush
-     * If true, the response will be flushed after the insert.
+     * @param flush If true, the response will be flushed after the insert.
      */
     public void setFlush(boolean flush) {
         this.flush = flush;
@@ -310,20 +291,9 @@ public class InsertAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            ignore,
-            preparer,
-            role,
-            defaultValue,
-            defaultValueRole,
-            defaultValueType,
-            name,
-            value,
-            flush,
-            request, modelBody
-
-        );
+        model.execute(ignore, preparer, role, defaultValue, defaultValueRole, defaultValueType, name, value, flush,
+                request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
index d513601b9..0beec1aa1 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -37,28 +37,27 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * Insert a definition with the possibility to override and specify parameters
  * (called attributes). A definition can be seen as a (partially or totally)
  * filled template that can override or complete attribute values.
- * &lt;tiles:insertDefinition&gt; allows to define these attributes
- * and pass them to the inserted jsp page, called template. Attributes are
- * defined using nested tag &lt;tiles:putAttribute&gt; or
- * &lt;tiles:putListAttribute&gt;.
+ * &lt;tiles:insertDefinition&gt; allows to define these attributes and pass
+ * them to the inserted jsp page, called template. Attributes are defined using
+ * nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
  * </p>
  * <p>
- * You must specify name tag attribute, for inserting a definition from definitions factory.
+ * You must specify name tag attribute, for inserting a definition from
+ * definitions factory.
  * </p>
  * <p>
- * Example : 
+ * Example :
  * </p>
  * 
  * <pre>
  *     &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
- *     &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
  *     &lt;/tiles:insertDefinition&gt;
  * </pre>
- *     
  */
 public class InsertDefinitionTag extends SimpleTagSupport {
 
@@ -73,8 +72,8 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     private java.lang.String definitionName;
 
     /**
-     * If specified, this template will be used instead of the
-     * one used by the definition.
+     * If specified, this template will be used instead of the one used by the
+     * definition.
      */
     private java.lang.String template;
 
@@ -89,15 +88,14 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     private java.lang.String templateExpression;
 
     /**
-     * A comma-separated list of roles. If present, the definition
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the definition will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
     /**
-     * The preparer to use to invoke before the definition is
-     * rendered. If specified, it overrides the preparer specified in the
-     * definition itself.
+     * The preparer to use to invoke before the definition is rendered. If
+     * specified, it overrides the preparer specified in the definition itself.
      */
     private java.lang.String preparer;
 
@@ -109,8 +107,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the definition to render.
+     * @return The name of the definition to render.
      */
     public java.lang.String getName() {
         return definitionName;
@@ -119,8 +116,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param definitionName
-     * The name of the definition to render.
+     * @param definitionName The name of the definition to render.
      */
     public void setName(java.lang.String definitionName) {
         this.definitionName = definitionName;
@@ -129,9 +125,8 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for template property.
      *
-     * @return
-     * If specified, this template will be used instead of the
-     * one used by the definition.
+     * @return If specified, this template will be used instead of the one used by
+     *         the definition.
      */
     public java.lang.String getTemplate() {
         return template;
@@ -140,9 +135,8 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for template property.
      *
-     * @param template
-     * If specified, this template will be used instead of the
-     * one used by the definition.
+     * @param template If specified, this template will be used instead of the one
+     *                 used by the definition.
      */
     public void setTemplate(java.lang.String template) {
         this.template = template;
@@ -151,8 +145,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for templateType property.
      *
-     * @return
-     * The type of the template attribute.
+     * @return The type of the template attribute.
      */
     public java.lang.String getTemplateType() {
         return templateType;
@@ -161,8 +154,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for templateType property.
      *
-     * @param templateType
-     * The type of the template attribute.
+     * @param templateType The type of the template attribute.
      */
     public void setTemplateType(java.lang.String templateType) {
         this.templateType = templateType;
@@ -171,8 +163,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for templateExpression property.
      *
-     * @return
-     * The expression to evaluate to get the value of the template.
+     * @return The expression to evaluate to get the value of the template.
      */
     public java.lang.String getTemplateExpression() {
         return templateExpression;
@@ -181,8 +172,8 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for templateExpression property.
      *
-     * @param templateExpression
-     * The expression to evaluate to get the value of the template.
+     * @param templateExpression The expression to evaluate to get the value of the
+     *                           template.
      */
     public void setTemplateExpression(java.lang.String templateExpression) {
         this.templateExpression = templateExpression;
@@ -191,9 +182,8 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the definition
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the definition will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -202,9 +192,8 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the definition
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the definition will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -213,10 +202,9 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return
-     * The preparer to use to invoke before the definition is
-     * rendered. If specified, it overrides the preparer specified in the
-     * definition itself.
+     * @return The preparer to use to invoke before the definition is rendered. If
+     *         specified, it overrides the preparer specified in the definition
+     *         itself.
      */
     public java.lang.String getPreparer() {
         return preparer;
@@ -225,10 +213,9 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for preparer property.
      *
-     * @param preparer
-     * The preparer to use to invoke before the definition is
-     * rendered. If specified, it overrides the preparer specified in the
-     * definition itself.
+     * @param preparer The preparer to use to invoke before the definition is
+     *                 rendered. If specified, it overrides the preparer specified
+     *                 in the definition itself.
      */
     public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
@@ -237,8 +224,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Getter for flush property.
      *
-     * @return
-     * If true, the response will be flushed after the insert.
+     * @return If true, the response will be flushed after the insert.
      */
     public boolean isFlush() {
         return flush;
@@ -247,8 +233,7 @@ public class InsertDefinitionTag extends SimpleTagSupport {
     /**
      * Setter for flush property.
      *
-     * @param flush
-     * If true, the response will be flushed after the insert.
+     * @param flush If true, the response will be flushed after the insert.
      */
     public void setFlush(boolean flush) {
         this.flush = flush;
@@ -264,18 +249,9 @@ public class InsertDefinitionTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            definitionName,
-            template,
-            templateType,
-            templateExpression,
-            role,
-            preparer,
-            flush,
-            request, modelBody
-
-        );
+        model.execute(definitionName, template, templateType, templateExpression, role, preparer, flush, request,
+                modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
index 90cd2d8cf..afe633881 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -36,10 +36,9 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * <p>
  * Insert a template with the possibility to pass parameters (called
  * attributes). A template can be seen as a procedure that can take parameters
- * or attributes. &lt;tiles:insertTemplate&gt; allows to define
- * these attributes and pass them to the inserted jsp page, called template.
- * Attributes are defined using nested tag
- * &lt;tiles:putAttribute&gt; or
+ * or attributes. &lt;tiles:insertTemplate&gt; allows to define these attributes
+ * and pass them to the inserted jsp page, called template. Attributes are
+ * defined using nested tag &lt;tiles:putAttribute&gt; or
  * &lt;tiles:putListAttribute&gt;.
  * </p>
  * <p>
@@ -52,14 +51,13 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * 
  * <pre>
  *     &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
- *     &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
- *     &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *         &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
  *     &lt;/tiles:insertTemplate&gt;
  * </pre>
- *     
  */
 public class InsertTemplateTag extends SimpleTagSupport {
 
@@ -84,15 +82,14 @@ public class InsertTemplateTag extends SimpleTagSupport {
     private java.lang.String templateExpression;
 
     /**
-     * A comma-separated list of roles. If present, the template
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the template will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
     /**
-     * The preparer to use to invoke before the definition is
-     * rendered. If specified, it overrides the preparer specified in the
-     * definition itself.
+     * The preparer to use to invoke before the definition is rendered. If
+     * specified, it overrides the preparer specified in the definition itself.
      */
     private java.lang.String preparer;
 
@@ -104,8 +101,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for template property.
      *
-     * @return
-     * The template to render.
+     * @return The template to render.
      */
     public java.lang.String getTemplate() {
         return template;
@@ -114,8 +110,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for template property.
      *
-     * @param template
-     * The template to render.
+     * @param template The template to render.
      */
     public void setTemplate(java.lang.String template) {
         this.template = template;
@@ -124,8 +119,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for templateType property.
      *
-     * @return
-     * The type of the template attribute.
+     * @return The type of the template attribute.
      */
     public java.lang.String getTemplateType() {
         return templateType;
@@ -134,8 +128,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for templateType property.
      *
-     * @param templateType
-     * The type of the template attribute.
+     * @param templateType The type of the template attribute.
      */
     public void setTemplateType(java.lang.String templateType) {
         this.templateType = templateType;
@@ -144,8 +137,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for templateExpression property.
      *
-     * @return
-     * The expression to evaluate to get the value of the template.
+     * @return The expression to evaluate to get the value of the template.
      */
     public java.lang.String getTemplateExpression() {
         return templateExpression;
@@ -154,8 +146,8 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for templateExpression property.
      *
-     * @param templateExpression
-     * The expression to evaluate to get the value of the template.
+     * @param templateExpression The expression to evaluate to get the value of the
+     *                           template.
      */
     public void setTemplateExpression(java.lang.String templateExpression) {
         this.templateExpression = templateExpression;
@@ -164,9 +156,8 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the template
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the template will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -175,9 +166,8 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the template
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the template will be
+     *             rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -186,10 +176,9 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for preparer property.
      *
-     * @return
-     * The preparer to use to invoke before the definition is
-     * rendered. If specified, it overrides the preparer specified in the
-     * definition itself.
+     * @return The preparer to use to invoke before the definition is rendered. If
+     *         specified, it overrides the preparer specified in the definition
+     *         itself.
      */
     public java.lang.String getPreparer() {
         return preparer;
@@ -198,10 +187,9 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for preparer property.
      *
-     * @param preparer
-     * The preparer to use to invoke before the definition is
-     * rendered. If specified, it overrides the preparer specified in the
-     * definition itself.
+     * @param preparer The preparer to use to invoke before the definition is
+     *                 rendered. If specified, it overrides the preparer specified
+     *                 in the definition itself.
      */
     public void setPreparer(java.lang.String preparer) {
         this.preparer = preparer;
@@ -210,8 +198,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Getter for flush property.
      *
-     * @return
-     * If true, the response will be flushed after the insert.
+     * @return If true, the response will be flushed after the insert.
      */
     public boolean isFlush() {
         return flush;
@@ -220,8 +207,7 @@ public class InsertTemplateTag extends SimpleTagSupport {
     /**
      * Setter for flush property.
      *
-     * @param flush
-     * If true, the response will be flushed after the insert.
+     * @param flush If true, the response will be flushed after the insert.
      */
     public void setFlush(boolean flush) {
         this.flush = flush;
@@ -237,17 +223,8 @@ public class InsertTemplateTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            template,
-            templateType,
-            templateExpression,
-            role,
-            preparer,
-            flush,
-            request, modelBody
-
-        );
+        model.execute(template, templateType, templateExpression, role, preparer, flush, request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
index 2d04fff3e..c4fa7c91c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -42,8 +42,8 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
  * <li>&lt;insertDefinition&gt;</li>
  * <li>&lt;putListAttribute&gt;</li>
  * </ul>
- * (or any other tag which implements the PutAttributeTagParent
- * interface. Exception is thrown if no appropriate tag can be found.
+ * (or any other tag which implements the PutAttributeTagParent interface.
+ * Exception is thrown if no appropriate tag can be found.
  * </p>
  * <p>
  * Put tag can have following atributes :
@@ -75,20 +75,19 @@ public class PutAttributeTag extends SimpleTagSupport {
     private java.lang.String name;
 
     /**
-     * The value of the attribute. Use this parameter, or
-     * expression, or body.
+     * The value of the attribute. Use this parameter, or expression, or body.
      */
     private java.lang.Object value;
 
     /**
-     * The expression to calculate the value from. Use this
-     * parameter, or value, or body.
+     * The expression to calculate the value from. Use this parameter, or value, or
+     * body.
      */
     private java.lang.String expression;
 
     /**
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
@@ -105,8 +104,7 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the attribute to put.
+     * @return The name of the attribute to put.
      */
     public java.lang.String getName() {
         return name;
@@ -115,8 +113,7 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param name
-     * The name of the attribute to put.
+     * @param name The name of the attribute to put.
      */
     public void setName(java.lang.String name) {
         this.name = name;
@@ -125,9 +122,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for value property.
      *
-     * @return
-     * The value of the attribute. Use this parameter, or
-     * expression, or body.
+     * @return The value of the attribute. Use this parameter, or expression, or
+     *         body.
      */
     public java.lang.Object getValue() {
         return value;
@@ -136,9 +132,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for value property.
      *
-     * @param value
-     * The value of the attribute. Use this parameter, or
-     * expression, or body.
+     * @param value The value of the attribute. Use this parameter, or expression,
+     *              or body.
      */
     public void setValue(java.lang.Object value) {
         this.value = value;
@@ -147,9 +142,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for expression property.
      *
-     * @return
-     * The expression to calculate the value from. Use this
-     * parameter, or value, or body.
+     * @return The expression to calculate the value from. Use this parameter, or
+     *         value, or body.
      */
     public java.lang.String getExpression() {
         return expression;
@@ -158,9 +152,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for expression property.
      *
-     * @param expression
-     * The expression to calculate the value from. Use this
-     * parameter, or value, or body.
+     * @param expression The expression to calculate the value from. Use this
+     *                   parameter, or value, or body.
      */
     public void setExpression(java.lang.String expression) {
         this.expression = expression;
@@ -169,9 +162,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -180,9 +172,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -191,8 +182,7 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for type property.
      *
-     * @return
-     * The type (renderer) of the attribute.
+     * @return The type (renderer) of the attribute.
      */
     public java.lang.String getType() {
         return type;
@@ -201,8 +191,7 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for type property.
      *
-     * @param type
-     * The type (renderer) of the attribute.
+     * @param type The type (renderer) of the attribute.
      */
     public void setType(java.lang.String type) {
         this.type = type;
@@ -211,8 +200,7 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Getter for cascade property.
      *
-     * @return
-     * If true the attribute will be cascaded to all nested attributes.
+     * @return If true the attribute will be cascaded to all nested attributes.
      */
     public boolean isCascade() {
         return cascade;
@@ -221,8 +209,8 @@ public class PutAttributeTag extends SimpleTagSupport {
     /**
      * Setter for cascade property.
      *
-     * @param cascade
-     * If true the attribute will be cascaded to all nested attributes.
+     * @param cascade If true the attribute will be cascaded to all nested
+     *                attributes.
      */
     public void setCascade(boolean cascade) {
         this.cascade = cascade;
@@ -238,17 +226,8 @@ public class PutAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            name,
-            value,
-            expression,
-            role,
-            type,
-            cascade,
-            request, modelBody
-
-        );
+        model.execute(name, value, expression, role, type, cascade, request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
index 7befc81d1..1e96972c7 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -31,7 +31,7 @@ import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 /**
  * <p>
- * Declare a list that will be pass as attribute to tile. 
+ * Declare a list that will be pass as attribute to tile.
  * </p>
  * <p>
  * Declare a list that will be pass as attribute to tile. List elements are
@@ -52,14 +52,14 @@ public class PutListAttributeTag extends SimpleTagSupport {
     private java.lang.String name;
 
     /**
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
      */
     private java.lang.String role;
 
     /**
-     * If true, the list attribute will use, as first elements, the
-     * list contained in the list attribute, put with the same name, of the containing definition.
+     * If true, the list attribute will use, as first elements, the list contained
+     * in the list attribute, put with the same name, of the containing definition.
      */
     private boolean inherit;
 
@@ -71,8 +71,7 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for name property.
      *
-     * @return
-     * The name of the attribute to put.
+     * @return The name of the attribute to put.
      */
     public java.lang.String getName() {
         return name;
@@ -81,8 +80,7 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for name property.
      *
-     * @param name
-     * The name of the attribute to put.
+     * @param name The name of the attribute to put.
      */
     public void setName(java.lang.String name) {
         this.name = name;
@@ -91,9 +89,8 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for role property.
      *
-     * @return
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
      */
     public java.lang.String getRole() {
         return role;
@@ -102,9 +99,8 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for role property.
      *
-     * @param role
-     * A comma-separated list of roles. If present, the attribute
-     * will be rendered only if the current user belongs to one of the roles.
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
      */
     public void setRole(java.lang.String role) {
         this.role = role;
@@ -113,9 +109,9 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for inherit property.
      *
-     * @return
-     * If true, the list attribute will use, as first elements, the
-     * list contained in the list attribute, put with the same name, of the containing definition.
+     * @return If true, the list attribute will use, as first elements, the list
+     *         contained in the list attribute, put with the same name, of the
+     *         containing definition.
      */
     public boolean isInherit() {
         return inherit;
@@ -124,9 +120,9 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for inherit property.
      *
-     * @param inherit
-     * If true, the list attribute will use, as first elements, the
-     * list contained in the list attribute, put with the same name, of the containing definition.
+     * @param inherit If true, the list attribute will use, as first elements, the
+     *                list contained in the list attribute, put with the same name,
+     *                of the containing definition.
      */
     public void setInherit(boolean inherit) {
         this.inherit = inherit;
@@ -135,8 +131,7 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Getter for cascade property.
      *
-     * @return
-     * If true the attribute will be cascaded to all nested attributes.
+     * @return If true the attribute will be cascaded to all nested attributes.
      */
     public boolean isCascade() {
         return cascade;
@@ -145,8 +140,8 @@ public class PutListAttributeTag extends SimpleTagSupport {
     /**
      * Setter for cascade property.
      *
-     * @param cascade
-     * If true the attribute will be cascaded to all nested attributes.
+     * @param cascade If true the attribute will be cascaded to all nested
+     *                attributes.
      */
     public void setCascade(boolean cascade) {
         this.cascade = cascade;
@@ -162,15 +157,8 @@ public class PutListAttributeTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
+        org.apache.tiles.request.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
-        model.execute(
-            name,
-            role,
-            inherit,
-            cascade,
-            request, modelBody
-
-        );
+        model.execute(name, role, inherit, cascade, request, modelBody);
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
index 802dfb411..370f3b418 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- /*
- * This file was automatically generated by Apache Tiles Autotag.
- */
+/*
+* This file was automatically generated by Autotag.  Please do not edit it manually.
+*/
 package org.apache.tiles.web.jsp.taglib;
 
 import java.io.IOException;
@@ -39,15 +39,16 @@ public class SetCurrentContainerTag extends SimpleTagSupport {
     private org.apache.tiles.template.SetCurrentContainerModel model = new org.apache.tiles.template.SetCurrentContainerModel();
 
     /**
-     * The key of the container to be used as "current". If null, the default one will be used.
+     * The key of the container to be used as "current". If null, the default one
+     * will be used.
      */
     private java.lang.String containerKey;
 
     /**
      * Getter for containerKey property.
      *
-     * @return
-     * The key of the container to be used as "current". If null, the default one will be used.
+     * @return The key of the container to be used as "current". If null, the
+     *         default one will be used.
      */
     public java.lang.String getContainerKey() {
         return containerKey;
@@ -56,8 +57,8 @@ public class SetCurrentContainerTag extends SimpleTagSupport {
     /**
      * Setter for containerKey property.
      *
-     * @param containerKey
-     * The key of the container to be used as "current". If null, the default one will be used.
+     * @param containerKey The key of the container to be used as "current". If
+     *                     null, the default one will be used.
      */
     public void setContainerKey(java.lang.String containerKey) {
         this.containerKey = containerKey;
@@ -73,11 +74,7 @@ public class SetCurrentContainerTag extends SimpleTagSupport {
             tag.setParent(getParent());
             tag.doTag();
         }
-        org.apache.tiles.request.Request request = runtime.createRequest();        
-        model.execute(
-            containerKey,
-            request
-
-        );
+        org.apache.tiles.request.Request request = runtime.createRequest();
+        model.execute(containerKey, request);
     }
 }
diff --git a/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld b/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
index 10d63e325..defe3ef55 100644
--- a/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
+++ b/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
@@ -19,7 +19,7 @@
  * under the License.
  */
 -->
-<!-- This file was automatically generated.  Please do not edit it manually -->
+<!-- This file was automatically generated by Autotag.  Please do not edit it manually. -->
 <taglib
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
   xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/freemarker/fmModel.vm
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
copy to plugins/tiles/src/main/resources/org/apache/tiles/autotag/freemarker/fmModel.vm
index 764846ac7..c307110dd 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/freemarker/fmModel.vm
@@ -16,66 +16,63 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.freemarker.template;
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package ${packageName};
+
+import java.io.IOException;
+import java.util.Map;
+
+#if(${clazz.hasBody()})
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+#end
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.AddListAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
- * <p>
- * <strong>Declare a list that will be pass as an attribute. </strong>
- * </p>
- * <p>
- * Declare a list that will be pass as an attribute . List elements are added
- * using the tag 'addAttribute' or 'addListAttribute'. This tag can only be used
- * inside 'insertTemplate', 'insertDefinition' or 'definition' tag.
- * </p>
+#foreach($line in $stringTool.splitOnNewlines(${clazz.documentation}))
+ * ${line}
+#end
  */
-public class AddListAttributeFMModel implements TemplateDirectiveModel {
+public class ${clazz.tagClassPrefix}FMModel implements TemplateDirectiveModel {
 
     /**
      * The template model.
      */
-    private final AddListAttributeModel model;
+    private ${clazz.name} model;
 
     /**
      * Constructor.
      *
-     * @param model The template model.
+     * @param model
+     *            The template model.
      */
-    public AddListAttributeFMModel(AddListAttributeModel model) {
+    public ${clazz.tagClassPrefix}FMModel(${clazz.name} model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<${requestClass}> runtime = new ${runtimeClass}();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        ${requestClass} request = runtime.createRequest();
+#if(${clazz.hasBody()})
         ModelBody modelBody = runtime.createModelBody();
+#end
         model.execute(
-            runtime.getParameter("role", String.class, null),
-            request,
-            modelBody
+#foreach($parameter in ${clazz.parameters})
+            runtime.getParameter("${parameter.exportedName}", ${stringTool.getClassToCast(${parameter.type})}.class, $stringTool.getDefaultValue(${parameter.type}, ${parameter.defaultValue})),
+#end
+                request#if(${clazz.hasBody()}), modelBody#end
         );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/freemarker/repository.vm
similarity index 51%
copy from plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
copy to plugins/tiles/src/main/resources/org/apache/tiles/autotag/freemarker/repository.vm
index f7f3d9607..a854aa4ac 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/freemarker/repository.vm
@@ -16,44 +16,42 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.freemarker.template;
-
-public class TilesFMModelRepository {
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package ${packageName};
 
-    /**
-     * The "putAttribute" directive.
-     */
-    private final PutAttributeFMModel putAttribute;
+/**
+#foreach($line in $stringTool.splitOnNewlines(${suite.documentation}))
+ * $line
+#end
+ */
+public class $stringTool.capitalizeFirstLetter(${suite.name})FMModelRepository {
 
+#foreach($clazz in ${suite.getTemplateClasses()})
     /**
-     * The "definition" directive.
+     * The "${clazz.tagName}" directive.
      */
-    private final DefinitionFMModel definition;
+    private ${clazz.tagClassPrefix}FMModel ${clazz.tagName};
 
+#end
     /**
      * Constructor.
      */
     public TilesFMModelRepository() {
-        putAttribute = new PutAttributeFMModel(new org.apache.tiles.template.PutAttributeModel());
-        definition = new DefinitionFMModel(new org.apache.tiles.template.DefinitionModel());
+#foreach($clazz in ${suite.getTemplateClasses()})
+        ${clazz.tagName} = new ${clazz.tagClassPrefix}FMModel(new ${clazz.name}());
+#end
     }
+#foreach($clazz in ${suite.getTemplateClasses()})
 
     /**
-     * Returns the "putAttribute" directive.
+     * Returns the "${clazz.tagName}" directive.
      *
-     * @return The "putAttribute" directive.
+     * @return The "${clazz.tagName}" directive.
      */
-    public PutAttributeFMModel getPutAttribute() {
-        return putAttribute;
+    public ${clazz.tagClassPrefix}FMModel get$stringTool.capitalizeFirstLetter(${clazz.tagName})() {
+        return ${clazz.tagName};
     }
-
-    /**
-     * Returns the "definition" directive.
-     *
-     * @return The "definition" directive.
-     */
-    public DefinitionFMModel getDefinition() {
-        return definition;
-    }
-
+#end
 }
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm
index f71d55514..e48be526c 100644
--- a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/bodyTag.vm
@@ -17,7 +17,7 @@
  * under the License.
  */
  /*
- * This file was automatically generated.
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
  */
 package ${packageName};
 
diff --git a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm
index 8717882de..2faecf662 100644
--- a/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm
+++ b/plugins/tiles/src/main/resources/org/apache/tiles/autotag/jsp/tld.vm
@@ -19,7 +19,7 @@
  * under the License.
  */
 -->
-<!-- This file was automatically generated.  Please do not edit it manually -->
+<!-- This file was automatically generated by Autotag.  Please do not edit it manually. -->
 <taglib
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
   xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMModelGeneratorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMModelGeneratorTest.java
new file mode 100644
index 000000000..599e7f472
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMModelGeneratorTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.freemarker;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateMethod;
+import org.apache.tiles.autotag.model.TemplateParameter;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests TagClassGenerator.
+ */
+public class FMModelGeneratorTest {
+
+    public static final String REQUEST_CLASS = "org.apache.tiles.autotag.freemarker.test.Request";
+
+    /**
+     * Test method for TagClassGenerator#generate(File, String, TemplateSuite,
+     * TemplateClass, java.util.Map).
+     * 
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void testGenerate() throws Exception {
+        Properties props = new Properties();
+        InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+        props.load(propsStream);
+        propsStream.close();
+        VelocityEngine velocityEngine = new VelocityEngine(props);
+
+        FMModelGenerator generator = new FMModelGenerator(velocityEngine);
+        File file = File.createTempFile("autotag", null);
+        file.delete();
+        file.mkdir();
+        file.deleteOnExit();
+        TemplateSuite suite = new TemplateSuite("tldtest", "Test for TLD docs.");
+
+        List<TemplateParameter> params = new ArrayList<TemplateParameter>();
+        TemplateParameter param = new TemplateParameter("one", "one", "java.lang.String", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "int", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "boolean", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        param = new TemplateParameter("modelBody", "modelBody", ModelBody.class.getName(), null, false, false);
+        param.setDocumentation("The body.");
+        params.add(param);
+        TemplateMethod executeMethod = new TemplateMethod("execute", params);
+
+        TemplateClass clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffTemplate", "doStuff",
+                "DoStuff", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuff class.");
+
+        generator.generate(file, "org.apache.tiles.autotag.freemarker.test", suite, clazz, null,
+                "org.apache.tiles.autotag.freemarker.test.Runtime", REQUEST_CLASS);
+
+        InputStream expected = getClass()
+                .getResourceAsStream("/org/apache/tiles/autotag/freemarker/test/DoStuffFMModel.javat");
+        File effectiveFile = new File(file, "/org/apache/tiles/autotag/freemarker/test/DoStuffFMModel.java");
+        assertTrue(effectiveFile.exists());
+        InputStream effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        suite.addTemplateClass(clazz);
+        params = new ArrayList<TemplateParameter>();
+        param = new TemplateParameter("one", "one", "java.lang.Double", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "float", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "java.util.Date", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        executeMethod = new TemplateMethod("execute", params);
+
+        clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffNoBodyTemplate", "doStuffNoBody",
+                "DoStuffNoBody", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuffNoBody class.");
+
+        suite.addTemplateClass(clazz);
+
+        generator.generate(file, "org.apache.tiles.autotag.freemarker.test", suite, clazz, null,
+                "org.apache.tiles.autotag.freemarker.test.Runtime", REQUEST_CLASS);
+
+        expected = getClass()
+                .getResourceAsStream("/org/apache/tiles/autotag/freemarker/test/DoStuffNoBodyFMModel.javat");
+        effectiveFile = new File(file, "/org/apache/tiles/autotag/freemarker/test/DoStuffNoBodyFMModel.java");
+        assertTrue(effectiveFile.exists());
+        effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        FileUtils.deleteDirectory(file);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMModelRepositoryGeneratorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMModelRepositoryGeneratorTest.java
new file mode 100644
index 000000000..ac3b449c4
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMModelRepositoryGeneratorTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.freemarker;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.model.TemplateClass;
+import org.apache.tiles.autotag.model.TemplateMethod;
+import org.apache.tiles.autotag.model.TemplateParameter;
+import org.apache.tiles.autotag.model.TemplateSuite;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests TLDGenerator.
+ */
+public class FMModelRepositoryGeneratorTest {
+
+    public static final String REQUEST_CLASS = "org.apache.tiles.autotag.freemarker.test.Request";
+
+    /**
+     * Test method for
+     * {@link FMModelRepositoryGenerator#generate(File, String, TemplateSuite, java.util.Map)}.
+     * 
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void testGenerate() throws Exception {
+        Properties props = new Properties();
+        InputStream propsStream = getClass().getResourceAsStream("/org/apache/tiles/autotag/velocity.properties");
+        props.load(propsStream);
+        propsStream.close();
+        VelocityEngine velocityEngine = new VelocityEngine(props);
+
+        FMModelRepositoryGenerator generator = new FMModelRepositoryGenerator(velocityEngine);
+        File file = File.createTempFile("autotag", null);
+        file.delete();
+        file.mkdir();
+        file.deleteOnExit();
+        TemplateSuite suite = new TemplateSuite("tldtest", "Test for TLD docs.");
+
+        List<TemplateParameter> params = new ArrayList<TemplateParameter>();
+        TemplateParameter param = new TemplateParameter("one", "one", "java.lang.String", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "int", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "long", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        param = new TemplateParameter("modelBody", "modelBody", ModelBody.class.getName(), null, false, false);
+        param.setDocumentation("The body.");
+        params.add(param);
+        TemplateMethod executeMethod = new TemplateMethod("execute", params);
+
+        TemplateClass clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffTemplate", "doStuff",
+                "DoStuff", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuff class");
+
+        suite.addTemplateClass(clazz);
+        params = new ArrayList<TemplateParameter>();
+        param = new TemplateParameter("one", "one", "java.lang.Double", null, true, false);
+        param.setDocumentation("Parameter one.");
+        params.add(param);
+        param = new TemplateParameter("two", "two", "float", null, false, false);
+        param.setDocumentation("Parameter two.");
+        params.add(param);
+        param = new TemplateParameter("three", "three", "java.util.Date", null, false, false);
+        param.setDocumentation("Parameter three.");
+        params.add(param);
+        param = new TemplateParameter("request", "request", REQUEST_CLASS, null, false, true);
+        param.setDocumentation("The request.");
+        params.add(param);
+        executeMethod = new TemplateMethod("execute", params);
+
+        clazz = new TemplateClass("org.apache.tiles.autotag.template.DoStuffNoBodyTemplate", "doStuffNoBody",
+                "DoStuffNoBody", executeMethod);
+        clazz.setDocumentation("Documentation of the DoStuffNoBody class");
+
+        suite.addTemplateClass(clazz);
+
+        generator.generate(file, "org.apache.tiles.autotag.freemarker.test", suite, null);
+
+        InputStream expected = getClass()
+                .getResourceAsStream("/org/apache/tiles/autotag/freemarker/test/TldtestFMModelRepository.javat");
+        File effectiveFile = new File(file, "/org/apache/tiles/autotag/freemarker/test/TldtestFMModelRepository.java");
+        assertTrue(effectiveFile.exists());
+        InputStream effective = new FileInputStream(effectiveFile);
+        assertTrue(IOUtils.contentEquals(effective, expected));
+        effective.close();
+        expected.close();
+
+        FileUtils.deleteDirectory(file);
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMTemplateGeneratorFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMTemplateGeneratorFactoryTest.java
new file mode 100644
index 000000000..c8f91af82
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/autotag/freemarker/FMTemplateGeneratorFactoryTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.autotag.freemarker;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+
+import org.apache.tiles.autotag.generate.TemplateGenerator;
+import org.apache.tiles.autotag.generate.TemplateGeneratorBuilder;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.Test;
+
+/**
+ * Tests FMTemplateGeneratorFactory.
+ */
+public class FMTemplateGeneratorFactoryTest {
+
+    /**
+     * Test method forFMTemplateGeneratorFactory#createTemplateGenerator().
+     */
+    @Test
+    public void testCreateTemplateGenerator() {
+        File classesOutputDirectory = createMock(File.class);
+        VelocityEngine velocityEngine = createMock(VelocityEngine.class);
+        TemplateGeneratorBuilder builder = createMock(TemplateGeneratorBuilder.class);
+        TemplateGenerator generator = createMock(TemplateGenerator.class);
+
+        expect(builder.setClassesOutputDirectory(classesOutputDirectory)).andReturn(builder);
+        expect(builder.addClassesTemplateSuiteGenerator(isA(FMModelRepositoryGenerator.class))).andReturn(builder);
+        expect(builder.addClassesTemplateClassGenerator(isA(FMModelGenerator.class))).andReturn(builder);
+        expect(builder.build()).andReturn(generator);
+
+        replay(classesOutputDirectory, velocityEngine, builder, generator);
+        FMTemplateGeneratorFactory factory = new FMTemplateGeneratorFactory(classesOutputDirectory, velocityEngine,
+                builder);
+        assertSame(generator, factory.createTemplateGenerator());
+        verify(classesOutputDirectory, velocityEngine, builder, generator);
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/DoStuffFMModel.javat
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/DoStuffFMModel.javat
index 764846ac7..14e3fafc9 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/AddListAttributeFMModel.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/DoStuffFMModel.javat
@@ -16,66 +16,57 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.freemarker.template;
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.autotag.freemarker.test;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.autotag.core.runtime.ModelBody;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.AddListAttributeModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
- * <p>
- * <strong>Declare a list that will be pass as an attribute. </strong>
- * </p>
- * <p>
- * Declare a list that will be pass as an attribute . List elements are added
- * using the tag 'addAttribute' or 'addListAttribute'. This tag can only be used
- * inside 'insertTemplate', 'insertDefinition' or 'definition' tag.
- * </p>
+ * Documentation of the DoStuff class.
  */
-public class AddListAttributeFMModel implements TemplateDirectiveModel {
+public class DoStuffFMModel implements TemplateDirectiveModel {
 
     /**
      * The template model.
      */
-    private final AddListAttributeModel model;
+    private org.apache.tiles.autotag.template.DoStuffTemplate model;
 
     /**
      * Constructor.
      *
-     * @param model The template model.
+     * @param model
+     *            The template model.
      */
-    public AddListAttributeFMModel(AddListAttributeModel model) {
+    public DoStuffFMModel(org.apache.tiles.autotag.template.DoStuffTemplate model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.autotag.freemarker.test.Request> runtime = new org.apache.tiles.autotag.freemarker.test.Runtime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.autotag.freemarker.test.Request request = runtime.createRequest();
         ModelBody modelBody = runtime.createModelBody();
         model.execute(
-            runtime.getParameter("role", String.class, null),
-            request,
-            modelBody
+            runtime.getParameter("one", java.lang.String.class, null),
+            runtime.getParameter("two", java.lang.Integer.class, 0),
+            runtime.getParameter("three", java.lang.Boolean.class, false),
+                request, modelBody
         );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/DoStuffNoBodyFMModel.javat
similarity index 50%
copy from plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/DoStuffNoBodyFMModel.javat
index 7703a80aa..8841206d5 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/SetCurrentContainerFMModel.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/DoStuffNoBodyFMModel.javat
@@ -16,56 +16,55 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.freemarker.template;
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.autotag.freemarker.test;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
 
 import freemarker.core.Environment;
 import freemarker.template.TemplateDirectiveBody;
 import freemarker.template.TemplateDirectiveModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateModel;
-import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.freemarker.autotag.FreemarkerAutotagRuntime;
-import org.apache.tiles.template.SetCurrentContainerModel;
-
-import java.io.IOException;
-import java.util.Map;
 
 /**
- * Selects a container to be used as the "current" container.
+ * Documentation of the DoStuffNoBody class.
  */
-public class SetCurrentContainerFMModel implements TemplateDirectiveModel {
+public class DoStuffNoBodyFMModel implements TemplateDirectiveModel {
 
     /**
      * The template model.
      */
-    private final SetCurrentContainerModel model;
+    private org.apache.tiles.autotag.template.DoStuffNoBodyTemplate model;
 
     /**
      * Constructor.
      *
-     * @param model The template model.
+     * @param model
+     *            The template model.
      */
-    public SetCurrentContainerFMModel(SetCurrentContainerModel model) {
+    public DoStuffNoBodyFMModel(org.apache.tiles.autotag.template.DoStuffNoBodyTemplate model) {
         this.model = model;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute(
-        Environment env,
-        Map params,
-        TemplateModel[] loopVars,
-        TemplateDirectiveBody body
-    ) throws TemplateException, IOException {
-        AutotagRuntime<Request> runtime = new FreemarkerAutotagRuntime();
-        ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
-        Request request = runtime.createRequest();
+    public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
+            TemplateDirectiveBody body) throws TemplateException, IOException {
+        AutotagRuntime<org.apache.tiles.autotag.freemarker.test.Request> runtime = new org.apache.tiles.autotag.freemarker.test.Runtime();
+        if (runtime instanceof TemplateDirectiveModel) {
+            ((TemplateDirectiveModel) runtime).execute(env, params, loopVars, body);
+        }
+        org.apache.tiles.autotag.freemarker.test.Request request = runtime.createRequest();
         model.execute(
-            runtime.getParameter("containerKey", String.class, null),
-            request
+            runtime.getParameter("one", java.lang.Double.class, null),
+            runtime.getParameter("two", java.lang.Float.class, 0.0f),
+            runtime.getParameter("three", java.util.Date.class, null),
+                request
         );
     }
 }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/TldtestFMModelRepository.javat
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
copy to plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/TldtestFMModelRepository.javat
index f7f3d9607..0aaa347f3 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/freemarker/template/TilesFMModelRepository.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/freemarker/test/TldtestFMModelRepository.javat
@@ -16,44 +16,49 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tiles.freemarker.template;
+/*
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
+ */
+package org.apache.tiles.autotag.freemarker.test;
 
-public class TilesFMModelRepository {
+/**
+ * Test for TLD docs.
+ */
+public class TldtestFMModelRepository {
 
     /**
-     * The "putAttribute" directive.
+     * The "doStuff" directive.
      */
-    private final PutAttributeFMModel putAttribute;
+    private DoStuffFMModel doStuff;
 
     /**
-     * The "definition" directive.
+     * The "doStuffNoBody" directive.
      */
-    private final DefinitionFMModel definition;
+    private DoStuffNoBodyFMModel doStuffNoBody;
 
     /**
      * Constructor.
      */
     public TilesFMModelRepository() {
-        putAttribute = new PutAttributeFMModel(new org.apache.tiles.template.PutAttributeModel());
-        definition = new DefinitionFMModel(new org.apache.tiles.template.DefinitionModel());
+        doStuff = new DoStuffFMModel(new org.apache.tiles.autotag.template.DoStuffTemplate());
+        doStuffNoBody = new DoStuffNoBodyFMModel(new org.apache.tiles.autotag.template.DoStuffNoBodyTemplate());
     }
 
     /**
-     * Returns the "putAttribute" directive.
+     * Returns the "doStuff" directive.
      *
-     * @return The "putAttribute" directive.
+     * @return The "doStuff" directive.
      */
-    public PutAttributeFMModel getPutAttribute() {
-        return putAttribute;
+    public DoStuffFMModel getDoStuff() {
+        return doStuff;
     }
 
     /**
-     * Returns the "definition" directive.
+     * Returns the "doStuffNoBody" directive.
      *
-     * @return The "definition" directive.
+     * @return The "doStuffNoBody" directive.
      */
-    public DefinitionFMModel getDefinition() {
-        return definition;
+    public DoStuffNoBodyFMModel getDoStuffNoBody() {
+        return doStuffNoBody;
     }
-
 }
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java
index 4dac7e17f..85433d581 100644
--- a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffNoBodyTag.java
@@ -17,7 +17,7 @@
  * under the License.
  */
  /*
- * This file was automatically generated.
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
  */
 package org.apache.tiles.autotag.jsp.test;
 
diff --git a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java
index 3116c37eb..6ad8b1e6f 100644
--- a/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java
+++ b/plugins/tiles/src/test/resources/org/apache/tiles/autotag/jsp/test/DoStuffTag.java
@@ -17,7 +17,7 @@
  * under the License.
  */
  /*
- * This file was automatically generated.
+ * This file was automatically generated by Autotag.  Please do not edit it manually.
  */
 package org.apache.tiles.autotag.jsp.test;
 
diff --git a/plugins/tiles/src/test/resources/tldtest-jsp.tld b/plugins/tiles/src/test/resources/tldtest-jsp.tld
index 6777e39b7..b2cbb8eb7 100644
--- a/plugins/tiles/src/test/resources/tldtest-jsp.tld
+++ b/plugins/tiles/src/test/resources/tldtest-jsp.tld
@@ -19,7 +19,7 @@
  * under the License.
  */
 -->
-<!-- This file was automatically generated.  Please do not edit it manually -->
+<!-- This file was automatically generated by Autotag.  Please do not edit it manually. -->
 <taglib
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
   xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"


[struts] 05/23: WW-5233 Copies Tiles EL related tests

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 53e219931bd53f6b158604638e9ff72e391bc08a
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Oct 2 13:16:59 2022 +0200

    WW-5233 Copies Tiles EL related tests
---
 .../apache/tiles/el/ELAttributeEvaluatorTest.java  | 189 +++++++++++++
 .../org/apache/tiles/el/ELContextImplTest.java     | 120 +++++++++
 .../tiles/el/JspExpressionFactoryFactoryTest.java  |  84 ++++++
 .../org/apache/tiles/el/ScopeELResolverTest.java   | 175 ++++++++++++
 .../tiles/el/TilesContextBeanELResolverTest.java   | 299 +++++++++++++++++++++
 .../tiles/el/TilesContextELResolverTest.java       | 189 +++++++++++++
 6 files changed, 1056 insertions(+)

diff --git a/plugins/tiles/src/test/java/org/apache/tiles/el/ELAttributeEvaluatorTest.java b/plugins/tiles/src/test/java/org/apache/tiles/el/ELAttributeEvaluatorTest.java
new file mode 100644
index 000000000..8c1c794ba
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/el/ELAttributeEvaluatorTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.el;
+
+import com.sun.el.ExpressionFactoryImpl;
+import junit.framework.TestCase;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.easymock.EasyMock;
+
+import javax.el.ArrayELResolver;
+import javax.el.BeanELResolver;
+import javax.el.CompositeELResolver;
+import javax.el.ELResolver;
+import javax.el.ListELResolver;
+import javax.el.MapELResolver;
+import javax.el.ResourceBundleELResolver;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Tests {@link ELAttributeEvaluator}.
+ */
+public class ELAttributeEvaluatorTest extends TestCase {
+
+    /**
+     * The evaluator to test.
+     */
+    private ELAttributeEvaluator evaluator;
+
+    /**
+     * The request object to use.
+     */
+    private Request request;
+
+    /** {@inheritDoc} */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        evaluator = new ELAttributeEvaluator();
+        Map<String, Object> requestScope = new HashMap<>();
+        Map<String, Object> sessionScope = new HashMap<>();
+        Map<String, Object> applicationScope = new HashMap<>();
+        requestScope.put("object1", "value");
+        sessionScope.put("object2", 1);
+        applicationScope.put("object3", 2.0F);
+        requestScope.put("paulaBean", new PaulaBean());
+        request = EasyMock.createMock(Request.class);
+        EasyMock.expect(request.getContext("request")).andReturn(requestScope)
+                .anyTimes();
+        EasyMock.expect(request.getContext("session")).andReturn(sessionScope)
+                .anyTimes();
+        EasyMock.expect(request.getContext("application")).andReturn(
+                applicationScope).anyTimes();
+        EasyMock.expect(request.getAvailableScopes()).andReturn(
+                Arrays.asList("request", "session", "application")).anyTimes();
+        ApplicationContext applicationContext = EasyMock
+                .createMock(ApplicationContext.class);
+        EasyMock.expect(request.getApplicationContext()).andReturn(
+                applicationContext).anyTimes();
+        EasyMock.replay(request, applicationContext);
+
+        evaluator.setExpressionFactory(new ExpressionFactoryImpl());
+        ELResolver elResolver = new CompositeELResolver() {
+            {
+                BeanELResolver beanElResolver = new BeanELResolver(false);
+                add(new ScopeELResolver());
+                add(new TilesContextELResolver(beanElResolver));
+                add(new TilesContextBeanELResolver());
+                add(new ArrayELResolver(false));
+                add(new ListELResolver(false));
+                add(new MapELResolver(false));
+                add(new ResourceBundleELResolver());
+                add(beanElResolver);
+            }
+        };
+        evaluator.setResolver(elResolver);
+    }
+
+    /**
+     * Tests
+     * {@link ELAttributeEvaluator#evaluate(Attribute, Request)}.
+     */
+    public void testEvaluate() {
+        Attribute attribute = new Attribute();
+        attribute.setExpressionObject(new Expression("${requestScope.object1}"));
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+                attribute, request));
+        attribute.setExpressionObject(new Expression("${sessionScope.object2}"));
+        assertEquals("The value is not correct", 1, evaluator
+                .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("${applicationScope.object3}"));
+        assertEquals("The value is not correct", 2.0F, evaluator
+                .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("${object1}"));
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+                attribute, request));
+        attribute.setExpressionObject(new Expression("${object2}"));
+        assertEquals("The value is not correct", 1, evaluator
+                .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("${object3}"));
+        assertEquals("The value is not correct", 2.0F, evaluator
+                .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("${paulaBean.paula}"));
+        assertEquals("The value is not correct", "Brillant", evaluator
+                .evaluate(attribute, request));
+        attribute.setExpressionObject(new Expression("String literal"));
+        assertEquals("The value is not correct", "String literal", evaluator
+                .evaluate(attribute, request));
+        attribute.setValue(2);
+        assertEquals("The value is not correct", 2, evaluator
+                .evaluate(attribute, request));
+        attribute.setValue("${object1}");
+        assertEquals("The value has been evaluated", "${object1}", evaluator
+                .evaluate(attribute, request));
+    }
+
+    /**
+     * Tests
+     * {@link ELAttributeEvaluator#evaluate(String, Request)}.
+     */
+    public void testEvaluateString() {
+        String expression = "${requestScope.object1}";
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+                expression, request));
+        expression = "${sessionScope.object2}";
+        assertEquals("The value is not correct", 1, evaluator
+                .evaluate(expression, request));
+        expression = "${applicationScope.object3}";
+        assertEquals("The value is not correct", 2.0F, evaluator
+                .evaluate(expression, request));
+        expression = "${object1}";
+        assertEquals("The value is not correct", "value", evaluator.evaluate(
+                expression, request));
+        expression = "${object2}";
+        assertEquals("The value is not correct", 1, evaluator
+                .evaluate(expression, request));
+        expression = "${object3}";
+        assertEquals("The value is not correct", 2.0F, evaluator
+                .evaluate(expression, request));
+        expression = "${paulaBean.paula}";
+        assertEquals("The value is not correct", "Brillant", evaluator
+                .evaluate(expression, request));
+        expression = "String literal";
+        assertEquals("The value is not correct", expression, evaluator
+                .evaluate(expression, request));
+    }
+
+    /**
+     * This is The Brillant Paula Bean (sic) just like it was posted to:
+     * http://thedailywtf.com/Articles/The_Brillant_Paula_Bean.aspx
+     * I hope that there is no copyright on it.
+     */
+    public static class PaulaBean {
+
+        /**
+         * Paula is brillant, really.
+         */
+        private final String paula = "Brillant";
+
+        /**
+         * Returns brillant.
+         *
+         * @return "Brillant".
+         */
+        public String getPaula() {
+            return paula;
+        }
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/el/ELContextImplTest.java b/plugins/tiles/src/test/java/org/apache/tiles/el/ELContextImplTest.java
new file mode 100644
index 000000000..b9a835318
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/el/ELContextImplTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.el;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.el.ELResolver;
+import javax.el.FunctionMapper;
+import javax.el.ValueExpression;
+import javax.el.VariableMapper;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests {@link ELContextImpl}.
+ */
+public class ELContextImplTest {
+
+    /**
+     * The EL context to test.
+     */
+    private ELContextImpl context;
+
+    /**
+     * The EL resolver.
+     */
+    private ELResolver resolver;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        resolver = createMock(ELResolver.class);
+        context = new ELContextImpl(resolver);
+    }
+
+    /**
+     * Test method for {@link ELContextImpl#getELResolver()}.
+     */
+    @Test
+    public void testGetELResolver() {
+        replay(resolver);
+        assertEquals(resolver, context.getELResolver());
+        verify(resolver);
+    }
+
+    /**
+     * Test method for {@link ELContextImpl#setFunctionMapper(FunctionMapper)}.
+     */
+    @Test
+    public void testSetFunctionMapper() {
+        FunctionMapper functionMapper = createMock(FunctionMapper.class);
+
+        replay(resolver, functionMapper);
+        context.setFunctionMapper(functionMapper);
+        assertEquals(functionMapper, context.getFunctionMapper());
+        verify(resolver, functionMapper);
+    }
+
+    /**
+     * Test method for {@link ELContextImpl#setVariableMapper(VariableMapper)}.
+     */
+    @Test
+    public void testSetVariableMapper() {
+        VariableMapper variableMapper = createMock(VariableMapper.class);
+
+        replay(resolver, variableMapper);
+        context.setVariableMapper(variableMapper);
+        assertEquals(variableMapper, context.getVariableMapper());
+        verify(resolver, variableMapper);
+    }
+
+    /**
+     * Tests {@link ELContextImpl#getFunctionMapper()}.
+     */
+    @Test
+    public void testNullFunctionMapper() {
+        replay(resolver);
+        FunctionMapper functionMapper = context.getFunctionMapper();
+        assertNull(functionMapper.resolveFunction("whatever", "it_IT"));
+        verify(resolver);
+    }
+
+    /**
+     * Tests {@link ELContextImpl#getVariableMapper()}.
+     */
+    @Test
+    public void testVariableMapperImpl() {
+        ValueExpression expression = createMock(ValueExpression.class);
+
+        replay(resolver, expression);
+        VariableMapper variableMapper = context.getVariableMapper();
+        assertNull(variableMapper.resolveVariable("whatever"));
+        variableMapper.setVariable("var", expression);
+        assertEquals(expression, variableMapper.resolveVariable("var"));
+        verify(resolver, expression);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/el/JspExpressionFactoryFactoryTest.java b/plugins/tiles/src/test/java/org/apache/tiles/el/JspExpressionFactoryFactoryTest.java
new file mode 100644
index 000000000..b7092e530
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/el/JspExpressionFactoryFactoryTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.el;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.junit.Test;
+
+import javax.el.ExpressionFactory;
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.JspApplicationContext;
+import javax.servlet.jsp.JspFactory;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link JspExpressionFactoryFactory}.
+ */
+public class JspExpressionFactoryFactoryTest {
+
+    /**
+     * Test method for {@link JspExpressionFactoryFactory#getExpressionFactory()}.
+     */
+    @Test
+    public void testGetExpressionFactory() {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ServletContext servletContext = createMock(ServletContext.class);
+        JspFactory jspFactory = createMock(JspFactory.class);
+        JspApplicationContext jspApplicationContext = createMock(JspApplicationContext.class);
+        ExpressionFactory expressionFactory = createMock(ExpressionFactory.class);
+
+        expect(applicationContext.getContext()).andReturn(servletContext);
+        expect(jspFactory.getJspApplicationContext(servletContext)).andReturn(jspApplicationContext);
+        expect(jspApplicationContext.getExpressionFactory()).andReturn(expressionFactory);
+
+        replay(applicationContext, servletContext, jspFactory,
+            jspApplicationContext, expressionFactory);
+        JspFactory.setDefaultFactory(jspFactory);
+        JspExpressionFactoryFactory factory = new JspExpressionFactoryFactory();
+        factory.setApplicationContext(applicationContext);
+        assertEquals(expressionFactory, factory.getExpressionFactory());
+        verify(applicationContext, servletContext, jspFactory,
+            jspApplicationContext, expressionFactory);
+    }
+
+    /**
+     * Test method for {@link JspExpressionFactoryFactory#getExpressionFactory()}.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetApplicationContextIllegal() {
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        Integer servletContext = 1;
+
+        expect(applicationContext.getContext()).andReturn(servletContext);
+
+        replay(applicationContext);
+        try {
+            JspExpressionFactoryFactory factory = new JspExpressionFactoryFactory();
+            factory.setApplicationContext(applicationContext);
+        } finally {
+            verify(applicationContext);
+        }
+    }
+
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/el/ScopeELResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/el/ScopeELResolverTest.java
new file mode 100644
index 000000000..bdd8d799e
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/el/ScopeELResolverTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.el;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.el.ELContext;
+import java.beans.FeatureDescriptor;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link ScopeELResolver}.
+ */
+public class ScopeELResolverTest {
+
+    /**
+     * The resolver to test.
+     */
+    private ScopeELResolver resolver;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Before
+    public void setUp() {
+        resolver = new ScopeELResolver();
+    }
+
+    /**
+     * Tests {@link ScopeELResolver#getCommonPropertyType(ELContext, Object)}.
+     */
+    @Test
+    public void testGetCommonPropertyType() {
+        ELContext elContext = createMock(ELContext.class);
+
+        replay(elContext);
+        assertNull(resolver.getCommonPropertyType(elContext, 1));
+        assertEquals(Map.class, resolver.getCommonPropertyType(elContext, null));
+        verify(elContext);
+    }
+
+    /**
+     * Tests {@link ScopeELResolver#getFeatureDescriptors(ELContext, Object)}.
+     */
+    @Test
+    public void testGetFeatureDescriptors() {
+        ELContext elContext = createMock(ELContext.class);
+        Request request = createMock(Request.class);
+
+        expect(elContext.getContext(Request.class)).andReturn(request);
+        expect(request.getAvailableScopes()).andReturn(Arrays.asList("one", "two"));
+
+        replay(elContext, request);
+        assertFalse(resolver.getFeatureDescriptors(elContext, 1).hasNext());
+        Iterator<FeatureDescriptor> descriptors = resolver.getFeatureDescriptors(elContext, null);
+        FeatureDescriptor descriptor = descriptors.next();
+        assertEquals("oneScope", descriptor.getName());
+        descriptor = descriptors.next();
+        assertEquals("twoScope", descriptor.getName());
+        assertFalse(descriptors.hasNext());
+        verify(elContext, request);
+    }
+
+    /**
+     * Test method for
+     * {@link ScopeELResolver#getType(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testGetType() {
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        ELContext context = new ELContextImpl(resolver);
+        replay(request, applicationContext);
+        context.putContext(Request.class, request);
+        context.putContext(ApplicationContext.class, applicationContext);
+        assertNull(resolver.getType(context, 1, "whatever"));
+        assertEquals("The requestScope object is not a map.", Map.class,
+            resolver.getType(context, null, "requestScope"));
+        assertEquals("The sessionScope object is not a map.", Map.class,
+            resolver.getType(context, null, "sessionScope"));
+        assertEquals("The applicationScope object is not a map.", Map.class,
+            resolver.getType(context, null, "applicationScope"));
+    }
+
+    /**
+     * Test method for
+     * {@link ScopeELResolver#getValue(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testGetValue() {
+        Map<String, Object> requestScope = new HashMap<>();
+        requestScope.put("objectKey", "objectValue");
+        Map<String, Object> sessionScope = new HashMap<>();
+        sessionScope.put("sessionObjectKey", "sessionObjectValue");
+        Map<String, Object> applicationScope = new HashMap<>();
+        applicationScope.put("applicationObjectKey", "applicationObjectValue");
+        Request request = createMock(Request.class);
+        expect(request.getContext("request")).andReturn(requestScope);
+        expect(request.getContext("session")).andReturn(sessionScope);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(request.getContext("application")).andReturn(applicationScope);
+        ELContext context = new ELContextImpl(resolver);
+        replay(request, applicationContext);
+        context.putContext(Request.class, request);
+        context.putContext(ApplicationContext.class, applicationContext);
+        assertNull(resolver.getValue(context, 1, "whatever"));
+        assertEquals("The requestScope map does not correspond", requestScope,
+            resolver.getValue(context, null, "requestScope"));
+        assertEquals("The sessionScope map does not correspond", sessionScope,
+            resolver.getValue(context, null, "sessionScope"));
+        assertEquals("The applicationScope map does not correspond",
+            applicationScope, resolver.getValue(context, null,
+                "applicationScope"));
+    }
+
+    /**
+     * Tests {@link ScopeELResolver#isReadOnly(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testIsReadOnly() {
+        ELContext elContext = createMock(ELContext.class);
+
+        replay(elContext);
+        assertTrue(resolver.isReadOnly(elContext, null, "whatever"));
+        verify(elContext);
+    }
+
+    /**
+     * Tests {@link ScopeELResolver#isReadOnly(ELContext, Object, Object)}.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testIsReadOnlyNPE() {
+        resolver.isReadOnly(null, null, "whatever");
+    }
+
+    /**
+     * Tests {@link ScopeELResolver#setValue(ELContext, Object, Object, Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        // Just to complete code coverage!
+        resolver.setValue(null, null, null, null);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/el/TilesContextBeanELResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/el/TilesContextBeanELResolverTest.java
new file mode 100644
index 000000000..5a1214ec2
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/el/TilesContextBeanELResolverTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.el;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.el.ELContext;
+import java.beans.FeatureDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link TilesContextBeanELResolver}.
+ */
+public class TilesContextBeanELResolverTest {
+
+    /**
+     * The resolver to test.
+     */
+    private TilesContextBeanELResolver resolver;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        resolver = new TilesContextBeanELResolver();
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#getCommonPropertyType(ELContext, Object)}.
+     */
+    @Test
+    public void testGetCommonPropertyType() {
+        Class<?> clazz = resolver.getCommonPropertyType(null, null);
+        assertEquals("The class is not correct", String.class, clazz);
+        clazz = resolver.getCommonPropertyType(null, "Base object");
+        assertNull("The class for non root objects must be null", clazz);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#getFeatureDescriptors(ELContext, Object)}.
+     */
+    @Test
+    public void testGetFeatureDescriptors() {
+        Map<String, Object> requestScope = new HashMap<>();
+        Map<String, Object> sessionScope = new HashMap<>();
+        Map<String, Object> applicationScope = new HashMap<>();
+        requestScope.put("object1", "value");
+        sessionScope.put("object2", 1);
+        applicationScope.put("object3", 2.0F);
+        Request request = createMock(Request.class);
+        expect(request.getContext("request")).andReturn(requestScope)
+            .anyTimes();
+        expect(request.getContext("session")).andReturn(sessionScope)
+            .anyTimes();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(request.getContext("application")).andReturn(
+            applicationScope).anyTimes();
+        expect(request.getAvailableScopes()).andReturn(
+                Arrays.asList("request", "session", "application"))
+            .anyTimes();
+        replay(request, applicationContext);
+
+        ELContext context = new ELContextImpl(resolver);
+        context.putContext(Request.class, request);
+        context.putContext(ApplicationContext.class, applicationContext);
+
+        List<FeatureDescriptor> expected = new ArrayList<>();
+        resolver.collectBeanInfo(requestScope, expected);
+        resolver.collectBeanInfo(sessionScope, expected);
+        resolver.collectBeanInfo(applicationScope, expected);
+        Iterator<FeatureDescriptor> featureIt = resolver.getFeatureDescriptors(
+            context, null);
+        Iterator<FeatureDescriptor> expectedIt = expected.iterator();
+        while (featureIt.hasNext() && expectedIt.hasNext()) {
+            FeatureDescriptor expectedDescriptor = expectedIt.next();
+            FeatureDescriptor descriptor = featureIt.next();
+            assertEquals("The feature is not the same", expectedDescriptor
+                .getDisplayName(), descriptor.getDisplayName());
+            assertEquals("The feature is not the same", expectedDescriptor
+                .getName(), descriptor.getName());
+            assertEquals("The feature is not the same", expectedDescriptor
+                .getShortDescription(), descriptor.getShortDescription());
+            assertEquals("The feature is not the same", expectedDescriptor
+                .getValue("type"), descriptor.getValue("type"));
+            assertEquals("The feature is not the same", expectedDescriptor
+                .getValue("resolvableAtDesignTime"), descriptor
+                .getValue("resolvableAtDesignTime"));
+            assertEquals("The feature is not the same", expectedDescriptor
+                .isExpert(), descriptor.isExpert());
+            assertEquals("The feature is not the same", expectedDescriptor
+                .isHidden(), descriptor.isHidden());
+            assertEquals("The feature is not the same", expectedDescriptor
+                .isPreferred(), descriptor.isPreferred());
+        }
+        assertTrue("The feature descriptors are not of the same size",
+            !featureIt.hasNext() && !expectedIt.hasNext());
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#getType(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testGetType() {
+        Map<String, Object> requestScope = new HashMap<>();
+        Map<String, Object> sessionScope = new HashMap<>();
+        Map<String, Object> applicationScope = new HashMap<>();
+        requestScope.put("object1", "value");
+        sessionScope.put("object2", 1);
+        applicationScope.put("object3", 2.0F);
+        Request request = createMock(Request.class);
+        expect(request.getContext("request")).andReturn(requestScope)
+            .anyTimes();
+        expect(request.getContext("session")).andReturn(sessionScope)
+            .anyTimes();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(request.getContext("application")).andReturn(
+            applicationScope).anyTimes();
+        expect(request.getAvailableScopes()).andReturn(
+                Arrays.asList("request", "session", "application"))
+            .anyTimes();
+        replay(request, applicationContext);
+
+        ELContext context = new ELContextImpl(resolver);
+        context.putContext(Request.class, request);
+        context.putContext(ApplicationContext.class, applicationContext);
+
+        assertEquals("The type is not correct", String.class, resolver.getType(
+            context, null, "object1"));
+        assertEquals("The type is not correct", Integer.class, resolver.getType(
+            context, null, "object2"));
+        assertEquals("The type is not correct", Float.class, resolver.getType(
+            context, null, "object3"));
+        assertNull(resolver.getType(context, 1, "whatever"));
+        assertNull(resolver.getType(context, null, "object4"));
+        verify(request, applicationContext);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#getValue(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testGetValue() {
+        Map<String, Object> requestScope = new HashMap<>();
+        Map<String, Object> sessionScope = new HashMap<>();
+        Map<String, Object> applicationScope = new HashMap<>();
+        requestScope.put("object1", "value");
+        sessionScope.put("object2", 1);
+        applicationScope.put("object3", 2.0F);
+        Request request = createMock(Request.class);
+        expect(request.getContext("request")).andReturn(requestScope)
+            .anyTimes();
+        expect(request.getContext("session")).andReturn(sessionScope)
+            .anyTimes();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(request.getContext("application")).andReturn(
+            applicationScope).anyTimes();
+        expect(request.getAvailableScopes()).andReturn(
+                Arrays.asList("request", "session", "application"))
+            .anyTimes();
+        replay(request, applicationContext);
+
+        ELContext context = new ELContextImpl(resolver);
+        context.putContext(Request.class, request);
+        context.putContext(ApplicationContext.class, applicationContext);
+
+        assertEquals("The value is not correct", "value", resolver.getValue(
+            context, null, "object1"));
+        assertEquals("The value is not correct", 1, resolver
+            .getValue(context, null, "object2"));
+        assertEquals("The value is not correct", 2.0F, resolver
+            .getValue(context, null, "object3"));
+        assertNull(resolver.getValue(context, 1, "whatever"));
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#isReadOnly(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testIsReadOnlyELContextObjectObject() {
+        ELContext context = new ELContextImpl(resolver);
+        assertTrue("The value is not read only", resolver.isReadOnly(context,
+            null, null));
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#isReadOnly(ELContext, Object, Object)}.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testIsReadOnlyNPE() {
+        resolver.isReadOnly(null, null, null);
+    }
+
+    /**
+     * Tests {@link TilesContextBeanELResolver#setValue(ELContext, Object, Object, Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        // Just to complete code coverage!
+        resolver.setValue(null, null, null, null);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#findObjectByProperty(ELContext, Object)}.
+     */
+    @Test
+    public void testFindObjectByProperty() {
+        Map<String, Object> requestScope = new HashMap<>();
+        Map<String, Object> sessionScope = new HashMap<>();
+        Map<String, Object> applicationScope = new HashMap<>();
+        requestScope.put("object1", "value");
+        sessionScope.put("object2", 1);
+        applicationScope.put("object3", 2.0F);
+        Request request = createMock(Request.class);
+        expect(request.getContext("request")).andReturn(requestScope)
+            .anyTimes();
+        expect(request.getContext("session")).andReturn(sessionScope)
+            .anyTimes();
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        expect(request.getContext("application")).andReturn(
+            applicationScope).anyTimes();
+        expect(request.getAvailableScopes()).andReturn(
+                Arrays.asList("request", "session", "application"))
+            .anyTimes();
+        replay(request, applicationContext);
+
+        ELContext context = new ELContextImpl(resolver);
+        context.putContext(Request.class, request);
+        context.putContext(ApplicationContext.class, applicationContext);
+
+        assertEquals("The value is not correct", "value", resolver
+            .findObjectByProperty(context, "object1"));
+        assertEquals("The value is not correct", 1, resolver
+            .findObjectByProperty(context, "object2"));
+        assertEquals("The value is not correct", 2.0F, resolver
+            .findObjectByProperty(context, "object3"));
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextBeanELResolver#getObject(Map, String)}.
+     */
+    @Test
+    public void testGetObject() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("object1", "value");
+        assertEquals("The value is not correct", "value", resolver.getObject(
+            map, "object1"));
+        assertNull("The value is not null", resolver.getObject(map, "object2"));
+        assertNull("The value is not null", resolver.getObject(null, "object1"));
+    }
+
+    /**
+     * Tests {@link TilesContextBeanELResolver#collectBeanInfo(Map, List)}.
+     */
+    @Test
+    public void testCollectBeanInfoEmpty() {
+        resolver.collectBeanInfo(null, null);
+    }
+}
diff --git a/plugins/tiles/src/test/java/org/apache/tiles/el/TilesContextELResolverTest.java b/plugins/tiles/src/test/java/org/apache/tiles/el/TilesContextELResolverTest.java
new file mode 100644
index 000000000..c3685aaf9
--- /dev/null
+++ b/plugins/tiles/src/test/java/org/apache/tiles/el/TilesContextELResolverTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.el;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.reflect.ClassUtil;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import java.beans.FeatureDescriptor;
+import java.beans.PropertyDescriptor;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link TilesContextELResolver}.
+ */
+public class TilesContextELResolverTest {
+
+    /**
+     * The bean resolver.
+     */
+    private ELResolver beanElResolver;
+
+    /**
+     * The resolver to test.
+     */
+    private TilesContextELResolver resolver;
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        beanElResolver = createMock(ELResolver.class);
+        resolver = new TilesContextELResolver(beanElResolver);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextELResolver#getCommonPropertyType(ELContext, Object)}.
+     */
+    @Test
+    public void testGetCommonPropertyTypeELContextObject() {
+        replay(beanElResolver);
+        Class<?> clazz = resolver.getCommonPropertyType(null, null);
+        assertEquals("The class is not correct", String.class, clazz);
+        clazz = resolver.getCommonPropertyType(null, "Base object");
+        assertNull("The class for non root objects must be null", clazz);
+        verify(beanElResolver);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextELResolver#getFeatureDescriptors(ELContext, Object)}.
+     */
+    @Test
+    public void testGetFeatureDescriptorsELContextObject() {
+        replay(beanElResolver);
+        assertNull(resolver.getFeatureDescriptors(null, 1));
+        Map<String, PropertyDescriptor> expected = new LinkedHashMap<>();
+        ClassUtil.collectBeanInfo(Request.class, expected);
+        ClassUtil.collectBeanInfo(ApplicationContext.class, expected);
+        Iterator<FeatureDescriptor> featureIt = resolver.getFeatureDescriptors(
+            null, null);
+        Iterator<? extends FeatureDescriptor> expectedIt = expected.values().iterator();
+        while (featureIt.hasNext() && expectedIt.hasNext()) {
+            assertEquals("The feature is not the same", expectedIt.next(),
+                featureIt.next());
+        }
+        assertTrue("The feature descriptors are not of the same size",
+            !featureIt.hasNext() && !expectedIt.hasNext());
+        verify(beanElResolver);
+    }
+
+    /**
+     * Tests {@link TilesContextBeanELResolver#getType(ELContext, Object, Object)}.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    @Test
+    public void testGetType() {
+        ELContext elContext = createMock(ELContext.class);
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+
+        expect(elContext.getContext(Request.class)).andReturn(request);
+        expect(elContext.getContext(ApplicationContext.class)).andReturn(applicationContext);
+        expect(beanElResolver.getType(elContext, request, "responseCommitted")).andReturn((Class) Boolean.class);
+        expect(beanElResolver.getType(elContext, applicationContext, "initParams")).andReturn((Class) Map.class);
+        elContext.setPropertyResolved(true);
+        expectLastCall().times(2);
+
+        replay(beanElResolver, elContext, request, applicationContext);
+        assertNull(resolver.getType(elContext, 1, "whatever"));
+        assertEquals(Boolean.class, resolver.getType(elContext, null, "responseCommitted"));
+        assertEquals(Map.class, resolver.getType(elContext, null, "initParams"));
+        verify(beanElResolver, elContext, request, applicationContext);
+    }
+
+    /**
+     * Tests {@link TilesContextBeanELResolver#getValue(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testGetValue() {
+        ELContext elContext = createMock(ELContext.class);
+        Request request = createMock(Request.class);
+        ApplicationContext applicationContext = createMock(ApplicationContext.class);
+        @SuppressWarnings("rawtypes")
+        Map map = createMock(Map.class);
+
+        expect(elContext.getContext(Request.class)).andReturn(request);
+        expect(elContext.getContext(ApplicationContext.class)).andReturn(applicationContext);
+        expect(beanElResolver.getValue(elContext, request, "responseCommitted")).andReturn(true);
+        expect(beanElResolver.getValue(elContext, applicationContext, "initParams")).andReturn(map);
+        elContext.setPropertyResolved(true);
+        expectLastCall().times(2);
+
+        replay(beanElResolver, elContext, request, applicationContext, map);
+        assertNull(resolver.getValue(elContext, 1, "whatever"));
+        assertEquals(true, resolver.getValue(elContext, null, "responseCommitted"));
+        assertEquals(map, resolver.getValue(elContext, null, "initParams"));
+        verify(beanElResolver, elContext, request, applicationContext, map);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextELResolver#isReadOnly(ELContext, Object, Object)}.
+     */
+    @Test
+    public void testIsReadOnly() {
+        replay(beanElResolver);
+        ELContext context = new ELContextImpl(resolver);
+        assertTrue("The value is not read only", resolver.isReadOnly(context,
+            null, null));
+        verify(beanElResolver);
+    }
+
+    /**
+     * Test method for
+     * {@link TilesContextELResolver#isReadOnly(ELContext, Object, Object)}.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testIsReadOnlyNPE() {
+        replay(beanElResolver);
+        try {
+            resolver.isReadOnly(null, null, null);
+        } finally {
+            verify(beanElResolver);
+        }
+    }
+
+    /**
+     * Tests {@link TilesContextELResolver#setValue(ELContext, Object, Object, Object)}.
+     */
+    @Test
+    public void testSetValue() {
+        // Just to complete code coverage!
+        resolver.setValue(null, null, null, null);
+    }
+}


[struts] 01/23: WW-5233 Copies a based set of Tiles classes used by Struts

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 1d58de276a47da4994c65ce13b64616d0b02817d
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sat Oct 1 16:48:18 2022 +0200

    WW-5233 Copies a based set of Tiles classes used by Struts
---
 apps/showcase/pom.xml                              |   6 -
 plugins/portlet-tiles/pom.xml                      |   9 -
 .../struts2/views/tiles/PortletTilesResult.java    |   6 +-
 plugins/tiles/pom.xml                              |  40 +-
 .../struts2/tiles/I18NAttributeEvaluator.java      |   2 +-
 .../struts2/tiles/StrutsAttributeEvaluator.java    |   4 +-
 .../tiles/StrutsFreeMarkerAttributeRenderer.java   |   6 +-
 .../struts2/tiles/StrutsPreparerFactory.java       |   4 +-
 .../tiles/StrutsTilesAnnotationProcessor.java      |  10 +-
 .../struts2/tiles/StrutsTilesContainerFactory.java |  44 +-
 .../struts2/tiles/StrutsTilesInitializer.java      |   6 +-
 .../apache/struts2/tiles/StrutsTilesListener.java  |   4 +-
 .../struts2/tiles/StrutsTilesLocaleResolver.java   |   4 +-
 .../apache/struts2/views/tiles/TilesResult.java    |  46 +-
 .../main/java/org/apache/tiles/api/Attribute.java  | 366 ++++++++++++++
 .../org/apache/tiles/api/AttributeContext.java     | 164 +++++++
 .../apache/tiles/api/BasicAttributeContext.java    | 434 ++++++++++++++++
 .../java/org/apache/tiles/api/CompareUtil.java     |  67 +++
 .../main/java/org/apache/tiles/api/Definition.java | 162 ++++++
 .../main/java/org/apache/tiles/api/Expression.java | 157 ++++++
 .../java/org/apache/tiles/api/ListAttribute.java   | 166 +++++++
 .../api/NoSuchContainerException.java}             |  34 +-
 .../java/org/apache/tiles/api/TilesContainer.java  | 139 ++++++
 .../apache/tiles/api/TilesContainerWrapper.java    | 109 +++++
 .../java/org/apache/tiles/api/TilesException.java  |  68 +++
 .../org/apache/tiles/api/access/TilesAccess.java   | 160 ++++++
 .../api/access/package-info.java}                  |  23 +-
 .../api/mgmt/MutableTilesContainer.java}           |  35 +-
 .../api/mgmt/package-info.java}                    |  24 +-
 .../java/org/apache/tiles/api/package-info.java    | 385 +++++++++++++++
 .../tiles/api/preparer/PreparerException.java      |  67 +++
 .../apache/tiles/api/preparer/ViewPreparer.java    |  58 +++
 .../api/preparer/package-info.java}                |  26 +-
 .../autotag/core/runtime/AbstractModelBody.java    |  87 ++++
 .../tiles/autotag/core/runtime/AutotagRuntime.java |  51 ++
 .../tiles/autotag/core/runtime/ModelBody.java      |  62 +++
 .../autotag/core/runtime/annotation/Parameter.java |  56 +++
 .../core/runtime/annotation/package-info.java}     |  26 +-
 .../autotag/core/runtime/package-info.java}        |  26 +-
 .../autotag/core/runtime/util/NullWriter.java}     |  38 +-
 .../autotag/core/runtime/util/package-info.java}   |  26 +-
 .../apache/tiles/autotag/model/TemplateClass.java  | 195 ++++++++
 .../apache/tiles/autotag/model/TemplateMethod.java | 131 +++++
 .../tiles/autotag/model/TemplateParameter.java     | 186 +++++++
 .../apache/tiles/autotag/model/TemplateSuite.java  | 129 +++++
 .../autotag/model/package-info.java}               |  26 +-
 .../tiles/core/definition/DefinitionsFactory.java  |  79 +++
 .../definition/DefinitionsFactoryException.java    |  74 +++
 .../tiles/core/definition/DefinitionsReader.java   |  54 ++
 .../definition/NoSuchDefinitionException.java}     |  33 +-
 .../core/definition/RefreshMonitor.java}           |  34 +-
 .../UnresolvingLocaleDefinitionsFactory.java       |  90 ++++
 .../definition/dao/BaseLocaleUrlDefinitionDAO.java | 164 +++++++
 .../dao/CachingLocaleUrlDefinitionDAO.java         | 275 +++++++++++
 .../tiles/core/definition/dao/DefinitionDAO.java   |  57 +++
 .../dao/ResolvingLocaleUrlDefinitionDAO.java       | 174 +++++++
 .../core/definition/dao/package-info.java}         |  27 +-
 .../digester/DigesterDefinitionsReader.java        | 468 ++++++++++++++++++
 .../DigesterDefinitionsReaderException.java}       |  36 +-
 .../core/definition/digester/package-info.java}    |  26 +-
 .../core/definition/package-info.java}             |  27 +-
 .../pattern/AbstractPatternDefinitionResolver.java | 108 ++++
 .../pattern/BasicPatternDefinitionResolver.java    |  77 +++
 .../pattern/DefinitionPatternMatcher.java}         |  38 +-
 .../pattern/DefinitionPatternMatcherFactory.java   |  45 ++
 .../pattern/PatternDefinitionResolver.java         |  66 +++
 .../pattern/PatternDefinitionResolverAware.java}   |  34 +-
 .../definition/pattern/PatternRecognizer.java}     |  33 +-
 .../tiles/core/definition/pattern/PatternUtil.java | 242 +++++++++
 .../pattern/PrefixedPatternDefinitionResolver.java | 106 ++++
 .../core/definition/pattern/package-info.java}     |  26 +-
 .../regexp/RegexpDefinitionPatternMatcher.java     |  74 +++
 .../RegexpDefinitionPatternMatcherFactory.java}    |  32 +-
 .../definition/pattern/regexp/package-info.java}   |  26 +-
 .../wildcard/WildcardDefinitionPatternMatcher.java |  80 +++
 .../WildcardDefinitionPatternMatcherFactory.java   |  56 +++
 .../definition/pattern/wildcard/package-info.java} |  26 +-
 .../core/evaluator/AbstractAttributeEvaluator.java |  52 ++
 .../tiles/core/evaluator/AttributeEvaluator.java   |  52 ++
 .../core/evaluator/AttributeEvaluatorFactory.java  |  50 ++
 .../evaluator/AttributeEvaluatorFactoryAware.java} |  33 +-
 .../evaluator/BasicAttributeEvaluatorFactory.java  |  90 ++++
 .../core/evaluator/EvaluationException.java}       |  42 +-
 .../evaluator/impl/DirectAttributeEvaluator.java}  |  30 +-
 .../core/evaluator/impl/package-info.java}         |  26 +-
 .../core/evaluator/package-info.java}              |  26 +-
 .../factory/AbstractTilesContainerFactory.java}    |  37 +-
 .../core/factory/BasicTilesContainerFactory.java   | 408 +++++++++++++++
 .../factory/TilesContainerFactoryException.java}   |  35 +-
 .../core/factory/package-info.java}                |  26 +-
 .../tiles/core/impl/BasicTilesContainer.java       | 400 +++++++++++++++
 .../core/impl/InvalidTemplateException.java}       |  42 +-
 .../core/impl/mgmt/CachingTilesContainer.java      | 224 +++++++++
 .../core/impl/mgmt/package-info.java}              |  26 +-
 .../core/impl/package-info.java}                   |  26 +-
 .../core/locale/LocaleResolver.java}               |  36 +-
 .../core/locale/impl/DefaultLocaleResolver.java    |  57 +++
 .../core/locale/impl/package-info.java}            |  26 +-
 .../core/locale/package-info.java}                 |  27 +-
 .../core/prepare/factory/BasicPreparerFactory.java |  86 ++++
 .../prepare/factory/NoSuchPreparerException.java}  |  33 +-
 .../core/prepare/factory/PreparerFactory.java      |  51 ++
 .../core/prepare/factory/package-info.java}        |  28 +-
 .../tiles/core/renderer/DefinitionRenderer.java    |  69 +++
 .../core/renderer/package-info.java}               |  26 +-
 .../core/startup/AbstractTilesInitializer.java     | 112 +++++
 .../tiles/core/startup/TilesInitializer.java       |  47 ++
 .../core/startup/package-info.java}                |  28 +-
 .../apache/tiles/core/util/CombinedBeanInfo.java   |  97 ++++
 .../org/apache/tiles/core/util/WildcardHelper.java | 545 +++++++++++++++++++++
 .../core/util/package-info.java}                   |  26 +-
 .../org/apache/tiles/el/ELAttributeEvaluator.java  |  94 ++++
 .../java/org/apache/tiles/el/ELContextImpl.java    | 146 ++++++
 .../el/ExpressionFactoryFactory.java}              |  33 +-
 .../tiles/el/JspExpressionFactoryFactory.java      |  65 +++
 .../java/org/apache/tiles/el/ScopeELResolver.java  | 145 ++++++
 .../tiles/el/TilesContextBeanELResolver.java       | 174 +++++++
 .../apache/tiles/el/TilesContextELResolver.java    | 156 ++++++
 .../el/package-info.java}                          |  26 +-
 .../freemarker/package-info.java}                  |  26 +-
 .../freemarker/template/AddAttributeFMModel.java   |  86 ++++
 .../template/AddListAttributeFMModel.java          |  81 +++
 .../freemarker/template/DefinitionFMModel.java     |  84 ++++
 .../freemarker/template/GetAsStringFMModel.java    |  91 ++++
 .../template/ImportAttributeFMModel.java           |  81 +++
 .../template/InsertAttributeFMModel.java           | 105 ++++
 .../template/InsertDefinitionFMModel.java          | 110 +++++
 .../freemarker/template/InsertTemplateFMModel.java | 109 +++++
 .../freemarker/template/PutAttributeFMModel.java   | 109 +++++
 .../template/PutListAttributeFMModel.java          |  84 ++++
 .../template/SetCurrentContainerFMModel.java       |  71 +++
 .../template/TilesFMModelRepository.java           |  59 +++
 .../tiles/ognl/AnyScopePropertyAccessor.java       |  91 ++++
 .../tiles/ognl/DelegatePropertyAccessor.java       |  86 ++++
 .../ognl/NestedObjectDelegatePropertyAccessor.java |  95 ++++
 .../ognl/NestedObjectExtractor.java}               |  35 +-
 .../apache/tiles/ognl/OGNLAttributeEvaluator.java  |  47 ++
 .../ognl/PropertyAccessorDelegateFactory.java}     |  39 +-
 .../apache/tiles/ognl/ScopePropertyAccessor.java   |  70 +++
 ...esApplicationContextNestedObjectExtractor.java} |  29 +-
 ...ilesContextPropertyAccessorDelegateFactory.java | 105 ++++
 .../ognl/package-info.java}                        |  26 +-
 .../tiles/request/AbstractClientRequest.java       |  93 ++++
 .../org/apache/tiles/request/AbstractRequest.java  |  56 +++
 .../apache/tiles/request/AbstractViewRequest.java  |  62 +++
 .../apache/tiles/request/ApplicationAccess.java    |  49 ++
 .../apache/tiles/request/ApplicationContext.java   |  81 +++
 .../request/ApplicationContextAware.java}          |  32 +-
 .../apache/tiles/request/ApplicationResource.java  |  82 ++++
 .../org/apache/tiles/request/DispatchRequest.java  |  53 ++
 .../tiles/request/DispatchRequestWrapper.java      | 141 ++++++
 .../request/NotAvailableFeatureException.java}     |  32 +-
 .../java/org/apache/tiles/request/Request.java     | 163 ++++++
 .../request/RequestException.java}                 |  41 +-
 .../request/RequestWrapper.java}                   |  31 +-
 .../request/attribute/Addable.java}                |  33 +-
 .../request/attribute/AttributeExtractor.java}     |  27 +-
 .../attribute/EnumeratedValuesExtractor.java}      |  33 +-
 .../request/attribute/HasAddableKeys.java}         |  27 +-
 .../request/attribute/HasKeys.java}                |  38 +-
 .../request/attribute/HasRemovableKeys.java}       |  32 +-
 .../request/attribute/package-info.java}           |  30 +-
 .../tiles/request/collection/CollectionUtil.java   |  68 +++
 .../tiles/request/collection/HeaderValuesMap.java  | 518 ++++++++++++++++++++
 .../apache/tiles/request/collection/KeySet.java    | 164 +++++++
 .../apache/tiles/request/collection/MapEntry.java  | 126 +++++
 .../request/collection/MapEntryArrayValues.java    |  97 ++++
 .../request/collection/ReadOnlyEnumerationMap.java | 421 ++++++++++++++++
 .../tiles/request/collection/RemovableKeySet.java  |  93 ++++
 .../apache/tiles/request/collection/ScopeMap.java  | 171 +++++++
 .../request/collection/package-info.java}          |  36 +-
 .../request/freemarker/EnvironmentScopeMap.java    |  60 +++
 .../request/freemarker/FreemarkerRequest.java      | 145 ++++++
 .../freemarker/FreemarkerRequestException.java}    |  33 +-
 .../request/freemarker/FreemarkerRequestUtil.java  |  84 ++++
 .../NotAvailableFreemarkerServletException.java}   |  33 +-
 .../autotag/FreemarkerAutotagException.java}       |  34 +-
 .../autotag/FreemarkerAutotagRuntime.java          |  70 +++
 .../freemarker/autotag/FreemarkerModelBody.java    |  64 +++
 .../request/freemarker/autotag/FreemarkerUtil.java |  62 +++
 .../request/freemarker/autotag/package-info.java}  |  26 +-
 .../extractor/EnvironmentScopeExtractor.java       |  89 ++++
 .../freemarker/extractor/package-info.java}        |  26 +-
 .../request/freemarker/package-info.java}          |  26 +-
 .../render/AttributeValueFreemarkerServlet.java    |  53 ++
 .../request/freemarker/render/package-info.java}   |  26 +-
 .../freemarker/servlet/SharedVariableFactory.java} |  32 +-
 .../SharedVariableLoaderFreemarkerServlet.java     | 202 ++++++++
 .../servlet/WebappClassTemplateLoader.java         |  85 ++++
 .../request/freemarker/servlet/package-info.java}  |  26 +-
 .../tiles/request/jsp/JspPrintWriterAdapter.java   | 436 +++++++++++++++++
 .../org/apache/tiles/request/jsp/JspRequest.java   | 201 ++++++++
 .../java/org/apache/tiles/request/jsp/JspUtil.java |  54 ++
 .../request/jsp/autotag/JspAutotagRuntime.java     |  71 +++
 .../tiles/request/jsp/autotag/JspModelBody.java    |  65 +++
 .../request/jsp/autotag/package-info.java}         |  26 +-
 .../request/jsp/extractor/ScopeExtractor.java      |  73 +++
 .../jsp/extractor/SessionScopeExtractor.java       |  78 +++
 .../request/jsp/extractor/package-info.java}       |  26 +-
 .../request/jsp/package-info.java}                 |  26 +-
 .../apache/tiles/request/locale/LocaleUtil.java    |  60 +++
 .../locale/PostfixedApplicationResource.java       | 237 +++++++++
 .../request/locale/URLApplicationResource.java     | 201 ++++++++
 .../reflect/CannotInstantiateObjectException.java} |  34 +-
 .../apache/tiles/request/reflect/ClassUtil.java    | 125 +++++
 .../request/reflect/package-info.java}             |  26 +-
 .../tiles/request/render/BasicRendererFactory.java |  81 +++
 .../request/render/CannotRenderException.java}     |  40 +-
 .../request/render/ChainedDelegateRenderer.java    |  82 ++++
 .../tiles/request/render/DispatchRenderer.java     |  65 +++
 .../request/render/NoSuchRendererException.java}   |  33 +-
 .../request/render/RenderException.java}           |  40 +-
 .../org/apache/tiles/request/render/Renderer.java  |  50 ++
 .../request/render/RendererFactory.java}           |  39 +-
 .../request/render/StringRenderer.java}            |  37 +-
 .../servlet/NotAServletEnvironmentException.java}  |  34 +-
 .../request/servlet/ServletApplicationContext.java | 129 +++++
 .../tiles/request/servlet/ServletRequest.java      | 345 +++++++++++++
 .../apache/tiles/request/servlet/ServletUtil.java  | 119 +++++
 .../extractor/ApplicationScopeExtractor.java       |  66 +++
 .../request/servlet/extractor/HeaderExtractor.java |  74 +++
 .../servlet/extractor/InitParameterExtractor.java  |  57 +++
 .../servlet/extractor/ParameterExtractor.java      |  56 +++
 .../servlet/extractor/RequestScopeExtractor.java   |  66 +++
 .../servlet/extractor/SessionScopeExtractor.java   |  79 +++
 .../request/servlet/extractor/package-info.java}   |  26 +-
 .../request/servlet/package-info.java}             |  26 +-
 .../apache/tiles/template/AddAttributeModel.java   | 124 +++++
 .../tiles/template/AddListAttributeModel.java      |  62 +++
 .../apache/tiles/template/AttributeResolver.java   |  60 +++
 .../apache/tiles/template/ComposeStackUtil.java    |  85 ++++
 .../tiles/template/DefaultAttributeResolver.java   |  87 ++++
 .../org/apache/tiles/template/DefinitionModel.java | 141 ++++++
 .../apache/tiles/template/GetAsStringModel.java    | 217 ++++++++
 .../tiles/template/ImportAttributeModel.java       | 196 ++++++++
 .../tiles/template/InsertAttributeModel.java       | 208 ++++++++
 .../tiles/template/InsertDefinitionModel.java      | 151 ++++++
 .../apache/tiles/template/InsertTemplateModel.java | 143 ++++++
 .../template/NoSuchAttributeException.java}        |  34 +-
 .../apache/tiles/template/PutAttributeModel.java   | 167 +++++++
 .../tiles/template/PutListAttributeModel.java      |  90 ++++
 .../template/SetCurrentContainerModel.java}        |  35 +-
 .../template/package-info.java}                    |  26 +-
 .../tiles/web/jsp/taglib/UseAttributeTag.java      | 221 +++++++++
 .../web/jsp/taglib/package-info.java}              |  27 +-
 .../tiles/web/startup/AbstractTilesListener.java   |  71 +++
 .../web/startup/package-info.java}                 |  26 +-
 .../web/util/AttributeContextMutator.java}         |  36 +-
 .../tiles/web/util/TilesDispatchServlet.java       | 150 ++++++
 .../web/util/package-info.java}                    |  26 +-
 .../resources/META-INF/tld/tiles-extras-jsp.tld    | 105 ++++
 .../tiles/StrutsTilesAnnotationProcessorTest.java  |   6 +-
 pom.xml                                            |  62 +--
 253 files changed, 19997 insertions(+), 1886 deletions(-)

diff --git a/apps/showcase/pom.xml b/apps/showcase/pom.xml
index add8be9a5..994ae103c 100644
--- a/apps/showcase/pom.xml
+++ b/apps/showcase/pom.xml
@@ -68,12 +68,6 @@
             <artifactId>struts2-json-plugin</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-jsp</artifactId>
-            <scope>runtime</scope>
-        </dependency>
-
         <dependency>
             <groupId>org.apache.struts</groupId>
             <artifactId>struts2-convention-plugin</artifactId>
diff --git a/plugins/portlet-tiles/pom.xml b/plugins/portlet-tiles/pom.xml
index 4c26ddc55..3ce787962 100644
--- a/plugins/portlet-tiles/pom.xml
+++ b/plugins/portlet-tiles/pom.xml
@@ -40,10 +40,6 @@
              <groupId>org.apache.struts</groupId>
              <artifactId>struts2-portlet-plugin</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-request-portlet</artifactId>
-        </dependency>
         <dependency>
             <groupId>javax.servlet.jsp</groupId>
             <artifactId>jsp-api</artifactId>
@@ -54,11 +50,6 @@
             <artifactId>portlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-jsp</artifactId>
-            <scope>runtime</scope>
-        </dependency>
     </dependencies>
     <properties>
     	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/plugins/portlet-tiles/src/main/java/org/apache/struts2/views/tiles/PortletTilesResult.java b/plugins/portlet-tiles/src/main/java/org/apache/struts2/views/tiles/PortletTilesResult.java
index 82249ccc9..ef1f82f76 100644
--- a/plugins/portlet-tiles/src/main/java/org/apache/struts2/views/tiles/PortletTilesResult.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/struts2/views/tiles/PortletTilesResult.java
@@ -22,9 +22,9 @@ import com.opensymphony.xwork2.ActionInvocation;
 import org.apache.struts2.portlet.PortletConstants;
 import org.apache.struts2.portlet.context.PortletActionContext;
 import org.apache.struts2.result.ServletDispatcherResult;
-import org.apache.tiles.TilesContainer;
-import org.apache.tiles.TilesException;
-import org.apache.tiles.access.TilesAccess;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.TilesException;
+import org.apache.tiles.api.access.TilesAccess;
 import org.apache.tiles.request.ApplicationContext;
 import org.apache.tiles.request.Request;
 import org.apache.tiles.request.portlet.RenderPortletRequest;
diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 79daada9f..807bd1f3d 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -33,44 +33,8 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-servlet</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-request-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-request-jsp</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-request-servlet</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-jsp</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-freemarker</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-ognl</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-el</artifactId>
+            <groupId>commons-digester</groupId>
+            <artifactId>commons-digester</artifactId>
         </dependency>
         <dependency>
             <groupId>org.glassfish</groupId>
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/I18NAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/I18NAttributeEvaluator.java
index 04673f294..e566f5747 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/I18NAttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/I18NAttributeEvaluator.java
@@ -25,7 +25,7 @@ import com.opensymphony.xwork2.config.ConfigurationException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.struts2.ServletActionContext;
-import org.apache.tiles.evaluator.AbstractAttributeEvaluator;
+import org.apache.tiles.core.evaluator.AbstractAttributeEvaluator;
 import org.apache.tiles.request.Request;
 import org.apache.tiles.request.servlet.ServletUtil;
 
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsAttributeEvaluator.java
index b0cdb95ba..7b3e7624f 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsAttributeEvaluator.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsAttributeEvaluator.java
@@ -25,8 +25,8 @@ import ognl.OgnlException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.struts2.ServletActionContext;
-import org.apache.tiles.evaluator.AbstractAttributeEvaluator;
-import org.apache.tiles.evaluator.EvaluationException;
+import org.apache.tiles.core.evaluator.AbstractAttributeEvaluator;
+import org.apache.tiles.core.evaluator.EvaluationException;
 import org.apache.tiles.request.Request;
 import org.apache.tiles.request.servlet.ServletUtil;
 
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsFreeMarkerAttributeRenderer.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsFreeMarkerAttributeRenderer.java
index cb6e0d403..e39fed4c6 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsFreeMarkerAttributeRenderer.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsFreeMarkerAttributeRenderer.java
@@ -33,9 +33,9 @@ import org.apache.struts2.views.freemarker.FreemarkerManager;
 import org.apache.struts2.views.freemarker.FreemarkerResult;
 import org.apache.struts2.views.freemarker.StrutsBeanWrapper;
 import org.apache.tiles.freemarker.template.TilesFMModelRepository;
-import org.apache.tiles.impl.InvalidTemplateException;
 import org.apache.tiles.request.Request;
 import org.apache.tiles.request.render.Renderer;
+import org.apache.tiles.core.impl.InvalidTemplateException;
 import org.apache.tiles.request.servlet.ServletUtil;
 
 import javax.servlet.ServletContext;
@@ -44,7 +44,7 @@ import java.io.IOException;
 
 public class StrutsFreeMarkerAttributeRenderer implements Renderer {
 
-    private static Logger LOG = LogManager.getLogger(StrutsFreeMarkerAttributeRenderer.class);
+    private static final Logger LOG = LogManager.getLogger(StrutsFreeMarkerAttributeRenderer.class);
 
     @Override
     public void render(String path, Request request) throws IOException {
@@ -75,7 +75,7 @@ public class StrutsFreeMarkerAttributeRenderer implements Renderer {
     }
 
     /**
-     * Depending how Tiles definition was defined, request can an instance of JspRequest (for JSPs)
+     * Depending on how Tiles definition was defined, request can an instance of JspRequest (for JSPs)
      * or a ServletRequest (FreeMarker)
      */
     protected ActionContext readActionContext(Request request) {
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsPreparerFactory.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsPreparerFactory.java
index e279adcb4..8630a061f 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsPreparerFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsPreparerFactory.java
@@ -23,8 +23,8 @@ import com.opensymphony.xwork2.ObjectFactory;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.tiles.preparer.ViewPreparer;
-import org.apache.tiles.preparer.factory.BasicPreparerFactory;
+import org.apache.tiles.api.preparer.ViewPreparer;
+import org.apache.tiles.core.prepare.factory.BasicPreparerFactory;
 
 /**
  * This is a basic ViewPreparer factory that uses {@link ObjectFactory} to create the ViewPreparer
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesAnnotationProcessor.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesAnnotationProcessor.java
index e36b75d16..8842578af 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesAnnotationProcessor.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesAnnotationProcessor.java
@@ -25,10 +25,10 @@ import org.apache.struts2.tiles.annotation.TilesDefinition;
 import org.apache.struts2.tiles.annotation.TilesDefinitions;
 import org.apache.struts2.tiles.annotation.TilesPutAttribute;
 import org.apache.struts2.tiles.annotation.TilesPutListAttribute;
-import org.apache.tiles.Attribute;
-import org.apache.tiles.Definition;
-import org.apache.tiles.Expression;
-import org.apache.tiles.ListAttribute;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.api.ListAttribute;
 
 /**
  * Processes tiles annotations to create {@link Definition}s and
@@ -123,7 +123,7 @@ public class StrutsTilesAnnotationProcessor {
         String templateType = getValueOrNull(tilesDef.templateType());
         if (templateType != null) {
             attribute.setRenderer(templateType);
-        } else if (getValueOrNull(tilesDef.extend()) != null && templateType == null) {
+        } else if (getValueOrNull(tilesDef.extend()) != null) {
             attribute.setRenderer(null);
         }
         return attribute;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java
index 41b93a38f..205476467 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesContainerFactory.java
@@ -24,25 +24,31 @@ import ognl.OgnlRuntime;
 import ognl.PropertyAccessor;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.tiles.TilesContainer;
-import org.apache.tiles.definition.DefinitionsFactory;
-import org.apache.tiles.definition.pattern.DefinitionPatternMatcherFactory;
-import org.apache.tiles.definition.pattern.PatternDefinitionResolver;
-import org.apache.tiles.definition.pattern.PrefixedPatternDefinitionResolver;
-import org.apache.tiles.definition.pattern.regexp.RegexpDefinitionPatternMatcherFactory;
-import org.apache.tiles.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.render.BasicRendererFactory;
+import org.apache.tiles.request.render.ChainedDelegateRenderer;
+import org.apache.tiles.core.definition.DefinitionsFactory;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcherFactory;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.PrefixedPatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.regexp.RegexpDefinitionPatternMatcherFactory;
+import org.apache.tiles.core.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory;
+import org.apache.tiles.core.evaluator.AttributeEvaluatorFactory;
+import org.apache.tiles.core.evaluator.BasicAttributeEvaluatorFactory;
+import org.apache.tiles.core.evaluator.impl.DirectAttributeEvaluator;
+import org.apache.tiles.core.factory.BasicTilesContainerFactory;
+import org.apache.tiles.core.factory.TilesContainerFactoryException;
+import org.apache.tiles.core.impl.mgmt.CachingTilesContainer;
+import org.apache.tiles.core.locale.LocaleResolver;
+import org.apache.tiles.core.prepare.factory.PreparerFactory;
 import org.apache.tiles.el.ELAttributeEvaluator;
 import org.apache.tiles.el.JspExpressionFactoryFactory;
 import org.apache.tiles.el.ScopeELResolver;
 import org.apache.tiles.el.TilesContextBeanELResolver;
 import org.apache.tiles.el.TilesContextELResolver;
-import org.apache.tiles.evaluator.AttributeEvaluatorFactory;
-import org.apache.tiles.evaluator.BasicAttributeEvaluatorFactory;
-import org.apache.tiles.evaluator.impl.DirectAttributeEvaluator;
-import org.apache.tiles.factory.BasicTilesContainerFactory;
-import org.apache.tiles.factory.TilesContainerFactoryException;
-import org.apache.tiles.impl.mgmt.CachingTilesContainer;
-import org.apache.tiles.locale.LocaleResolver;
 import org.apache.tiles.ognl.AnyScopePropertyAccessor;
 import org.apache.tiles.ognl.DelegatePropertyAccessor;
 import org.apache.tiles.ognl.NestedObjectDelegatePropertyAccessor;
@@ -51,12 +57,6 @@ import org.apache.tiles.ognl.PropertyAccessorDelegateFactory;
 import org.apache.tiles.ognl.ScopePropertyAccessor;
 import org.apache.tiles.ognl.TilesApplicationContextNestedObjectExtractor;
 import org.apache.tiles.ognl.TilesContextPropertyAccessorDelegateFactory;
-import org.apache.tiles.preparer.factory.PreparerFactory;
-import org.apache.tiles.request.ApplicationContext;
-import org.apache.tiles.request.ApplicationResource;
-import org.apache.tiles.request.Request;
-import org.apache.tiles.request.render.BasicRendererFactory;
-import org.apache.tiles.request.render.ChainedDelegateRenderer;
 import org.apache.tiles.request.render.Renderer;
 
 import javax.el.ArrayELResolver;
@@ -81,7 +81,7 @@ import java.util.Set;
  * - S2 ro access Struts' ValueStack
  * - OGNL
  * - EL
- *
+ * <p>
  * If you need additional features create your own listener and factory,
  * you can base on code from Tiles' CompleteAutoloadTilesContainerFactory
  */
@@ -270,4 +270,4 @@ public class StrutsTilesContainerFactory extends BasicTilesContainerFactory {
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesInitializer.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesInitializer.java
index 5170003a4..cb471a1ab 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesInitializer.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesInitializer.java
@@ -20,11 +20,11 @@ package org.apache.struts2.tiles;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.tiles.definition.DefinitionsFactory;
-import org.apache.tiles.factory.AbstractTilesContainerFactory;
+import org.apache.tiles.core.definition.DefinitionsFactory;
+import org.apache.tiles.core.factory.AbstractTilesContainerFactory;
+import org.apache.tiles.core.startup.AbstractTilesInitializer;
 import org.apache.tiles.request.ApplicationContext;
 import org.apache.tiles.request.servlet.ServletApplicationContext;
-import org.apache.tiles.startup.AbstractTilesInitializer;
 
 import javax.servlet.ServletContext;
 
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
index 38e506552..5ebe36237 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
@@ -20,7 +20,7 @@ package org.apache.struts2.tiles;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
+import org.apache.tiles.core.startup.TilesInitializer;
 import org.apache.tiles.web.startup.AbstractTilesListener;
 
 /**
@@ -37,4 +37,4 @@ public class StrutsTilesListener extends AbstractTilesListener {
         LOG.info("Starting Struts Tiles 3 integration ...");
         return new StrutsTilesInitializer();
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesLocaleResolver.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesLocaleResolver.java
index 3e6524fa4..0d3d3ec33 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesLocaleResolver.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesLocaleResolver.java
@@ -24,7 +24,7 @@ import com.opensymphony.xwork2.config.ConfigurationException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.struts2.ServletActionContext;
-import org.apache.tiles.locale.LocaleResolver;
+import org.apache.tiles.core.locale.LocaleResolver;
 import org.apache.tiles.request.Request;
 import org.apache.tiles.request.servlet.ServletUtil;
 
@@ -33,7 +33,7 @@ import java.util.Locale;
 
 public class StrutsTilesLocaleResolver implements LocaleResolver {
 
-    private static Logger LOG = LogManager.getLogger(StrutsTilesLocaleResolver.class);
+    private static final Logger LOG = LogManager.getLogger(StrutsTilesLocaleResolver.class);
 
     @Override
     public Locale resolveLocale(Request request) {
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/views/tiles/TilesResult.java b/plugins/tiles/src/main/java/org/apache/struts2/views/tiles/TilesResult.java
index 4c801f4aa..fefad2482 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/views/tiles/TilesResult.java
+++ b/plugins/tiles/src/main/java/org/apache/struts2/views/tiles/TilesResult.java
@@ -29,58 +29,41 @@ import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.result.ServletDispatcherResult;
 import org.apache.struts2.tiles.StrutsTilesAnnotationProcessor;
 import org.apache.struts2.tiles.annotation.TilesDefinition;
-import org.apache.tiles.Definition;
-import org.apache.tiles.TilesContainer;
-import org.apache.tiles.TilesException;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.TilesException;
 
 import com.opensymphony.xwork2.ActionInvocation;
-import org.apache.tiles.access.TilesAccess;
-import org.apache.tiles.mgmt.MutableTilesContainer;
+import org.apache.tiles.api.access.TilesAccess;
+import org.apache.tiles.api.mgmt.MutableTilesContainer;
 import org.apache.tiles.request.ApplicationContext;
 import org.apache.tiles.request.Request;
 import org.apache.tiles.request.servlet.ServletRequest;
 import org.apache.tiles.request.servlet.ServletUtil;
 
 /**
- * <!-- START SNIPPET: description -->
- * Renders a view using struts-tiles.
- * <!-- END SNIPPET: description -->
- *
- * <!-- START SNIPPET: webxml -->
- * In your web.xml file, you need to add a TilesListener.
- *
+ * Renders a view using struts-tiles. In your web.xml file, you need to add a TilesListener.
+ * <p>
  * &lt;listener&gt;
  *      &lt;listener-class&gt;org.apache.struts2.tiles.StrutsTilesListener&lt;/listener-class&gt;
  * &lt;/listener&gt;
- * <!-- END SNIPPET: webxml -->
- *
- * <!-- START SNIPPET: strutsxml -->
+ * <p>
  * In struts.xml, use type="tiles" on your &lt;result&gt;.
- *
+ * <p>
  * &lt;action name="editUser" class="userAction" method="edit"&gt;
  *      &lt;result name="success" type="tiles"&gt;userForm&lt;/result&gt;
  *      &lt;result name="input" type="tiles"&gt;userList&lt;/result&gt;
  * &lt;/action&gt;
- * <!-- END SNIPPET: strutsxml -->
- *
- *
- * <!-- START SNIPPET: packageconfig -->
- *
+ * <p>
  * Making this result type the default for the current package.
- *
+ * <p>
  * &lt;result-types&gt;
  *      &lt;result-type name="tiles"
  * class="org.apache.struts2.views.tiles.TilesResult" default="true" /&gt;
  * &lt;/result-types&gt;
- * <!-- END SNIPPET: packageconfig -->
- *
- *
- * <!-- START SNIPPET: tilesconfig -->
- * You have to configure tiles itself. Therefore you can add <code>tiles.xml</code> either 
+ * <p>
+ * You have to configure tiles itself. Therefore you can add <code>tiles.xml</code> either
  * to resources or WEB-INF. You may also use annotations like {@link TilesDefinition}.
- *
- * <!-- END SNIPPET: tilesconfig -->
- *
  */
 public class TilesResult extends ServletDispatcherResult {
 
@@ -114,8 +97,7 @@ public class TilesResult extends ServletDispatcherResult {
         if (StringUtils.isEmpty(location)) {
             LOG.trace("location not set -> action must have one @TilesDefinition");
             tilesDefinition = annotationProcessor.findAnnotation(action, null);
-            String tileName = StringUtils.isNotEmpty(tilesDefinition.name()) ? tilesDefinition.name() : actionName;
-            location = tileName;
+            location = StringUtils.isNotEmpty(tilesDefinition.name()) ? tilesDefinition.name() : actionName;
             LOG.debug("using new location name '{}' and @TilesDefinition '{}'", location, tilesDefinition);
         }
         setLocation(location);
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
new file mode 100644
index 000000000..60a09df9f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -0,0 +1,366 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import org.apache.tiles.request.Request;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
+import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
+
+/**
+ * Common implementation of attribute definition.
+ */
+public class Attribute implements Serializable, Cloneable {
+
+    /**
+     * The name of the template renderer.
+     */
+    private static final String TEMPLATE_RENDERER = "template";
+
+    /**
+     * The roles that can render this attribute.
+     * @since 2.0.6
+     */
+    protected Set<String> roles = null;
+
+    /**
+     * The value of the attribute.
+     */
+    protected Object value = null;
+
+    /**
+     * The expression to evaluate. Ignored if {@link #value} is not
+     * <code>null</code>.
+     *
+     * @since 2.2.0
+     */
+    protected Expression expressionObject = null;
+
+    /**
+     * The renderer name of the attribute. Default names are <code>string</code>,
+     * <code>template</code>, <code>definition</code>, <code>object</code>.
+     */
+    private String renderer = null;
+
+    /**
+     * Constructor.
+     *
+     */
+    public Attribute() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param value Object to store.
+     */
+    public Attribute(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @param attribute The attribute to copy from.
+     */
+    public Attribute(Attribute attribute) {
+        this.roles = attribute.roles;
+        this.value = attribute.getValue();
+        if (attribute.expressionObject != null) {
+            this.expressionObject = new Expression(attribute.expressionObject);
+        } else {
+            this.expressionObject = null;
+        }
+        this.renderer = attribute.renderer;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param value Object to store.
+     * @param role  Asociated role.
+     */
+    public Attribute(Object value, String role) {
+        this.value = value;
+        setRole(role);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param value Object to store. If specified, the <code>expression</code>
+     * parameter will be ignored.
+     * @param expression The expression to be evaluated. Ignored if the
+     * <code>value</code> is not null.
+     * @param role Associated role.
+     * @param rendererName The renderer name.
+     * @since 2.2.0
+     */
+    public Attribute(Object value, Expression expression, String role, String rendererName) {
+        this.value = value;
+        this.expressionObject = expression;
+        this.renderer = rendererName;
+        setRole(role);
+    }
+
+    /**
+     * Creates a template attribute, starting from the name of the template.
+     *
+     * @param template The template that will be rendered.
+     * @return The template attribute.
+     * @since 2.1.2
+     */
+    public static Attribute createTemplateAttribute(String template) {
+        Attribute attribute = new Attribute();
+        attribute.setValue(template);
+        attribute.setRenderer(TEMPLATE_RENDERER);
+        return attribute;
+    }
+
+    /**
+     * Creates a template attribute, starting from the name of the template.
+     *
+     * @param template The template that will be rendered.
+     * @param templateExpression The template expression that will be evaluated
+     * to a template.
+     * @param templateType The type, or renderer, of the template. If null, the
+     * default <code>template</code> will be used.
+     * @param role The comma-separated roles for which the template is
+     * authorized to be rendered.
+     * @return The template attribute.
+     * @since 2.2.2
+     */
+    public static Attribute createTemplateAttribute(String template,
+            String templateExpression, String templateType, String role) {
+        Attribute templateAttribute = createTemplateAttribute(template);
+        templateAttribute.setRole(role);
+        if (templateType != null) {
+            templateAttribute.setRenderer(templateType);
+        }
+        templateAttribute
+                .setExpressionObject(Expression
+                        .createExpressionFromDescribedExpression(templateExpression));
+        return templateAttribute;
+    }
+
+    /**
+     * Get role.
+     * @return the name of the required role(s)
+     */
+    public String getRole() {
+        String retValue = null;
+
+        if (roles != null && !roles.isEmpty()) {
+            StringBuilder builder = new StringBuilder();
+            Iterator<String> roleIt = roles.iterator();
+            if (roleIt.hasNext()) {
+                builder.append(roleIt.next());
+                while (roleIt.hasNext()) {
+                    builder.append(",");
+                    builder.append(roleIt.next());
+                }
+                retValue = builder.toString();
+            }
+        }
+
+        return retValue;
+    }
+
+    /**
+     * Returns the roles that can render this attribute.
+     *
+     * @return The enabled roles.
+     * @since 2.0.6
+     */
+    public Set<String> getRoles() {
+        return roles;
+    }
+
+    /**
+     * Set role.
+     *
+     * @param role Associated role.
+     */
+    public void setRole(String role) {
+        if (role != null && role.trim().length() > 0) {
+            String[] rolesStrings = role.split("\\s*,\\s*");
+            roles = new HashSet<>();
+            Collections.addAll(roles, rolesStrings);
+        } else {
+            roles = null;
+        }
+    }
+
+    /**
+     * Sets the roles that can render this attribute.
+     *
+     * @param roles The enabled roles.
+     * @since 2.0.6
+     */
+    public void setRoles(Set<String> roles) {
+        this.roles = roles;
+    }
+
+    /**
+     * Get value.
+     * @return the value
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Set value.
+     *
+     * @param value New value.
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Returns The expression to evaluate. Ignored if {@link #value} is not
+     * <code>null</code>.
+     *
+     * @return The expression to be evaluated.
+     * @since 2.2.0
+     */
+    public Expression getExpressionObject() {
+        return expressionObject;
+    }
+
+    /**
+     * Sets The expression to evaluate. Ignored if {@link #value} is not
+     * <code>null</code>.
+     *
+     * @param expressionObject The expression to be evaluated.
+     * @since 2.2.0
+     */
+    public void setExpressionObject(Expression expressionObject) {
+        this.expressionObject = expressionObject;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        if (value != null) {
+            return value.toString();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the renderer name to use.
+     *
+     * @return The renderer name.
+     * @since 2.1.0
+     */
+    public String getRenderer() {
+        return renderer;
+    }
+
+    /**
+     * Sets the renderer name to use.
+     *
+     * @param rendererName The renderer.
+     * @since 2.1.0
+     */
+    public void setRenderer(String rendererName) {
+        this.renderer = rendererName;
+    }
+
+    /**
+     * Inherits an attribute, i.e. overwrites null properties with the ones
+     * provided by the attribute.
+     *
+     * @param attribute The attribute to inherit.
+     * @since 2.1.2
+     */
+    public void inherit(Attribute attribute) {
+        if (value == null) {
+            value = attribute.getValue();
+        }
+        Expression targetExpressionObject = attribute.getExpressionObject();
+        if (targetExpressionObject != null
+                && (expressionObject == null || expressionObject
+                        .getExpression() == null)) {
+            expressionObject = new Expression(targetExpressionObject);
+        }
+        if (roles == null || roles.isEmpty()) {
+            roles = attribute.getRoles();
+        }
+        if (renderer == null) {
+            renderer = attribute.getRenderer();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        Attribute attribute = (Attribute) obj;
+        return nullSafeEquals(value, attribute.value)
+                && nullSafeEquals(renderer, attribute.renderer)
+                && nullSafeEquals(roles, attribute.roles)
+                && nullSafeEquals(expressionObject, attribute.expressionObject);
+    }
+
+    /**
+     * Checks if the current user can use this attribute.
+     *
+     * @param request The request context.
+     * @return <code>true</code> if the current user can see this attribute.
+     * @since 3.0.0
+     */
+    public boolean isPermitted(Request request) {
+        if (roles == null || roles.isEmpty()) {
+            return true;
+        }
+
+        boolean retValue = false;
+
+        for (Iterator<String> roleIt = roles.iterator(); roleIt.hasNext()
+                && !retValue;) {
+            retValue = request.isUserInRole(roleIt.next());
+        }
+
+        return retValue;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return nullSafeHashCode(value) + nullSafeHashCode(renderer)
+                + nullSafeHashCode(roles) + nullSafeHashCode(expressionObject);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Attribute clone() {
+        return new Attribute(this);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
new file mode 100644
index 000000000..23e4fc124
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
@@ -0,0 +1,164 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Encapsulation of the current state of execution.
+ *
+ * @since Tiles 2.0
+ * @version $Rev$ $Date$
+ */
+public interface AttributeContext {
+
+    /**
+     * Returns the attribute that will be used to render a template.
+     *
+     * @return The template attribute.
+     * @since 2.1.2
+     */
+    Attribute getTemplateAttribute();
+
+    /**
+     * Sets the template attribute, that will be used to render the template
+     * page.
+     *
+     * @param templateAttribute The template attribute.
+     * @since 2.1.2
+     */
+    void setTemplateAttribute(Attribute templateAttribute);
+
+    /**
+     * Get associated preparer instance.
+     *
+     * @return The preparer name.
+     * @since 2.1.0
+     */
+    String getPreparer();
+
+    /**
+     * Set associated preparer instance.
+     *
+     * @param url The preparer name.
+     * @since 2.1.0
+     */
+    void setPreparer(String url);
+
+    /**
+     * Add all attributes to the context.
+     *
+     * @param newAttributes the attributes to be added.
+     */
+    void addAll(Map<String, Attribute> newAttributes);
+
+    /**
+     * Copies the cascaded attributes to this attribute context.
+     *
+     * @param parent The parent context to be used.
+     * @since 2.1.0
+     */
+    void inheritCascadedAttributes(AttributeContext parent);
+
+    /**
+     * Copies all missing attributes from the <code>parent</code> attribute
+     * context to this one.
+     *
+     * @param parent The attribute context to copy attributes from.
+     * @since 2.1.0
+     */
+    void inherit(AttributeContext parent);
+
+    /**
+     * Retrieve the named attribute, either cascaded or not.
+     *
+     * @param name key name for the attribute.
+     * @return Attribute associated with the given name.
+     */
+    Attribute getAttribute(String name);
+
+    /**
+     * Retrieve the attribute that has been defined in this context (i.e. not
+     * cascaded).
+     *
+     * @param name key name for the attribute.
+     * @return Attribute The local attribute associated with the given name, if
+     * present, or <code>null</code> otherwise.
+     * @since 2.1.0
+     */
+    Attribute getLocalAttribute(String name);
+
+    /**
+     * Retrieve the attribute that has been cascaded at upper levels.
+     *
+     * @param name key name for the attribute.
+     * @return Attribute The cascaded attribute associated with the given name,
+     * if present, or <code>null</code> otherwise.
+     * @since 2.1.0
+     */
+    Attribute getCascadedAttribute(String name);
+
+    /**
+     * Returns the names of the local attributes, i.e. the one that have not
+     * been cascaded.
+     *
+     * @return The local attribute names.
+     * @since 2.1.0
+     */
+    Set<String> getLocalAttributeNames();
+
+    /**
+     * Returns the names of the cascaded attributes.
+     *
+     * @return The cascaded attribute names.
+     * @since 2.1.0
+     */
+    Set<String> getCascadedAttributeNames();
+
+    /**
+     * Add the specified attribute. The attribute value will be available only
+     * in the current context, i.e. it is like calling
+     * {@link AttributeContext#putAttribute(String, Attribute, boolean)} with
+     * <code>cascade = false</code>.
+     *
+     * @param name name of the attribute
+     * @param value value of the attribute
+     */
+    void putAttribute(String name, Attribute value);
+
+    /**
+     * Add the specified attribute.
+     *
+     * @param name name of the attribute
+     * @param value value of the attribute
+     * @param cascade If <code>true</code>, the attribute value will be
+     * available in all nested contexts. If <code>false</code>, it will be
+     * available only in the current context.
+     * @since 2.1.0
+     */
+    void putAttribute(String name, Attribute value, boolean cascade);
+
+    /**
+     * Clear the attributes.
+     */
+    void clear();
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
new file mode 100644
index 000000000..17d650754
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
@@ -0,0 +1,434 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
+import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
+
+/**
+ * Basic implementation for <code>AttributeContext</code>.
+ *
+ * @since 2.1.0
+ */
+public class BasicAttributeContext implements AttributeContext, Serializable {
+
+    /**
+     * The template attribute, to render a template.
+     *
+     * @since 2.1.2
+     */
+    protected Attribute templateAttribute;
+
+    /**
+     * Associated ViewPreparer URL or classname, if defined.
+     *
+     * @since 2.1.0
+     */
+    protected String preparer = null;
+
+    /**
+     * Template attributes.
+     * @since 2.1.0
+     */
+    protected Map<String, Attribute> attributes = null;
+
+    /**
+     * Cascaded template attributes.
+     * @since 2.1.0
+     */
+    protected Map<String, Attribute> cascadedAttributes = null;
+
+    /**
+     * Constructor.
+     *
+     * @since 2.1.0
+     */
+    public BasicAttributeContext() {
+    }
+
+    /**
+     * Constructor.
+     * Create a context and set specified attributes.
+     *
+     * @param attributes Attributes to initialize context.
+     * @since 2.1.0
+     */
+    public BasicAttributeContext(Map<String, Attribute> attributes) {
+        if (attributes != null) {
+            this.attributes = deepCopyAttributeMap(attributes);
+        }
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @param context The constructor to copy.
+     * @since 2.1.0
+     */
+    public BasicAttributeContext(AttributeContext context) {
+        if (context instanceof BasicAttributeContext) {
+            copyBasicAttributeContext((BasicAttributeContext) context);
+        } else {
+            Attribute parentTemplateAttribute = context.getTemplateAttribute();
+            if (parentTemplateAttribute != null) {
+                this.templateAttribute = new Attribute(parentTemplateAttribute);
+            }
+            this.preparer = context.getPreparer();
+            this.attributes = new HashMap<>();
+            Set<String> parentAttributeNames = context.getLocalAttributeNames();
+            if (parentAttributeNames != null) {
+                for (String name : parentAttributeNames) {
+                    attributes.put(name, new Attribute(context.getLocalAttribute(name)));
+                }
+            }
+            inheritCascadedAttributes(context);
+        }
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @param context The constructor to copy.
+     * @since 2.1.0
+     */
+    public BasicAttributeContext(BasicAttributeContext context) {
+        copyBasicAttributeContext(context);
+    }
+
+    /** {@inheritDoc} */
+    public Attribute getTemplateAttribute() {
+        return templateAttribute;
+    }
+
+    /** {@inheritDoc} */
+    public void setTemplateAttribute(Attribute templateAttribute) {
+        this.templateAttribute = templateAttribute;
+    }
+
+    /** {@inheritDoc} */
+    public String getPreparer() {
+        return preparer;
+    }
+
+    /** {@inheritDoc} */
+    public void setPreparer(String url) {
+        this.preparer = url;
+    }
+
+    /** {@inheritDoc} */
+    public void inheritCascadedAttributes(AttributeContext context) {
+        if (context instanceof BasicAttributeContext) {
+            copyCascadedAttributes((BasicAttributeContext) context);
+        } else {
+            this.cascadedAttributes = new HashMap<>();
+            Set<String> parentAttributeNames = context.getCascadedAttributeNames();
+            if (parentAttributeNames != null) {
+                for (String name : parentAttributeNames) {
+                    cascadedAttributes.put(name, new Attribute(context
+                            .getCascadedAttribute(name)));
+                }
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void inherit(AttributeContext parent) {
+        if (parent instanceof BasicAttributeContext) {
+            inherit((BasicAttributeContext) parent);
+        } else {
+            // Inheriting template, roles and preparer.
+            Attribute parentTemplateAttribute = parent.getTemplateAttribute();
+            inheritParentTemplateAttribute(parentTemplateAttribute);
+            if (preparer == null) {
+                preparer = parent.getPreparer();
+            }
+
+            // Inheriting attributes.
+            Set<String> names = parent.getCascadedAttributeNames();
+            if (names != null && !names.isEmpty()) {
+                for (String name : names) {
+                    Attribute attribute = parent.getCascadedAttribute(name);
+                    Attribute destAttribute = getCascadedAttribute(name);
+                    if (destAttribute == null) {
+                        putAttribute(name, attribute, true);
+                    } else if (attribute instanceof ListAttribute
+                            && destAttribute instanceof ListAttribute
+                            && ((ListAttribute) destAttribute).isInherit()) {
+                        ((ListAttribute) destAttribute).inherit((ListAttribute) attribute);
+                    }
+                }
+            }
+            names = parent.getLocalAttributeNames();
+            if (names != null && !names.isEmpty()) {
+                for (String name : names) {
+                    Attribute attribute = parent.getLocalAttribute(name);
+                    Attribute destAttribute = getLocalAttribute(name);
+                    if (destAttribute == null) {
+                        putAttribute(name, attribute, false);
+                    } else if (attribute instanceof ListAttribute
+                            && destAttribute instanceof ListAttribute
+                            && ((ListAttribute) destAttribute).isInherit()) {
+                        ((ListAttribute) destAttribute).inherit((ListAttribute) attribute);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Inherits the attribute context, inheriting, i.e. copying if not present,
+     * the attributes.
+     *
+     * @param parent The attribute context to inherit.
+     * @since 2.1.0
+     */
+    public void inherit(BasicAttributeContext parent) {
+        // Set template, roles and preparer if not set.
+        inheritParentTemplateAttribute(parent.getTemplateAttribute());
+        if (preparer == null) {
+            preparer = parent.preparer;
+        }
+
+        // Sets attributes.
+        cascadedAttributes = addMissingAttributes(parent.cascadedAttributes,
+                cascadedAttributes);
+        attributes = addMissingAttributes(parent.attributes, attributes);
+    }
+
+    /**
+     * Add all attributes to this context.
+     * Copies all of the mappings from the specified attribute map to this context.
+     * New attribute mappings will replace any mappings that this context had for any of the keys
+     * currently in the specified attribute map.
+     *
+     * @param newAttributes Attributes to add.
+     * @since 2.1.0
+     */
+    public void addAll(Map<String, Attribute> newAttributes) {
+        if (newAttributes == null) {
+            return;
+        }
+
+        if (attributes == null) {
+            attributes = new HashMap<>(newAttributes);
+            return;
+        }
+
+        attributes.putAll(newAttributes);
+    }
+
+    /** {@inheritDoc} */
+    public Attribute getAttribute(String name) {
+        Attribute retValue = null;
+        if (attributes != null) {
+            retValue = attributes.get(name);
+        }
+
+        if (retValue == null && cascadedAttributes != null) {
+            retValue = cascadedAttributes.get(name);
+        }
+
+        return retValue;
+    }
+
+    /** {@inheritDoc} */
+    public Attribute getLocalAttribute(String name) {
+        if (attributes == null) {
+            return null;
+        }
+
+        return attributes.get(name);
+    }
+
+    /** {@inheritDoc} */
+    public Attribute getCascadedAttribute(String name) {
+        if (cascadedAttributes == null) {
+            return null;
+        }
+
+        return cascadedAttributes.get(name);
+    }
+
+    /** {@inheritDoc} */
+    public Set<String> getLocalAttributeNames() {
+        if (attributes != null && !attributes.isEmpty()) {
+            return attributes.keySet();
+        }
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public Set<String> getCascadedAttributeNames() {
+        if (cascadedAttributes != null && !cascadedAttributes.isEmpty()) {
+            return cascadedAttributes.keySet();
+        }
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void putAttribute(String name, Attribute value) {
+        if (attributes == null) {
+            attributes = new HashMap<>();
+        }
+
+        attributes.put(name, value);
+    }
+
+    /** {@inheritDoc} */
+    public void putAttribute(String name, Attribute value, boolean cascade) {
+        Map<String, Attribute> mapToUse;
+        if (cascade) {
+            if (cascadedAttributes == null) {
+                cascadedAttributes = new HashMap<>();
+            }
+            mapToUse = cascadedAttributes;
+        } else {
+            if (attributes == null) {
+                attributes = new HashMap<>();
+            }
+            mapToUse = attributes;
+        }
+        mapToUse.put(name, value);
+    }
+
+    /** {@inheritDoc} */
+    public void clear() {
+        templateAttribute = null;
+        preparer = null;
+        attributes.clear();
+        cascadedAttributes.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        BasicAttributeContext bac = (BasicAttributeContext) obj;
+        return nullSafeEquals(templateAttribute, bac.templateAttribute)
+                && nullSafeEquals(preparer, bac.preparer)
+                && nullSafeEquals(attributes, bac.attributes)
+                && nullSafeEquals(cascadedAttributes, bac.cascadedAttributes);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return nullSafeHashCode(templateAttribute) + nullSafeHashCode(preparer)
+                + nullSafeHashCode(attributes)
+                + nullSafeHashCode(cascadedAttributes);
+    }
+
+    /**
+     * Inherits the parent template attribute.
+     *
+     * @param parentTemplateAttribute The parent template attribute.
+     */
+    private void inheritParentTemplateAttribute(
+            Attribute parentTemplateAttribute) {
+        if (parentTemplateAttribute != null) {
+            if (templateAttribute == null) {
+                templateAttribute = new Attribute(parentTemplateAttribute);
+            } else {
+                templateAttribute.inherit(parentTemplateAttribute);
+            }
+        }
+    }
+
+    /**
+     * Copies a BasicAttributeContext in an easier way.
+     *
+     * @param context The context to copy.
+     */
+    private void copyBasicAttributeContext(BasicAttributeContext context) {
+        Attribute parentTemplateAttribute = context.getTemplateAttribute();
+        if (parentTemplateAttribute != null) {
+            this.templateAttribute = new Attribute(parentTemplateAttribute);
+        }
+        preparer = context.preparer;
+        if (context.attributes != null && !context.attributes.isEmpty()) {
+            attributes = deepCopyAttributeMap(context.attributes);
+        }
+        copyCascadedAttributes(context);
+    }
+
+    /**
+     * Copies the cascaded attributes to the current context.
+     *
+     * @param context The context to copy from.
+     */
+    private void copyCascadedAttributes(BasicAttributeContext context) {
+        if (context.cascadedAttributes != null
+                && !context.cascadedAttributes.isEmpty()) {
+            cascadedAttributes = deepCopyAttributeMap(context.cascadedAttributes);
+        }
+    }
+
+    /**
+     * Adds missing attributes to the destination map.
+     *
+     * @param source The source attribute map.
+     * @param destination The destination attribute map.
+     * @return The destination attribute map if not null, a new one otherwise.
+     */
+    private Map<String, Attribute> addMissingAttributes(Map<String, Attribute> source, Map<String, Attribute> destination) {
+        if (source != null && !source.isEmpty()) {
+            if (destination == null) {
+                destination = new HashMap<>();
+            }
+            for (Map.Entry<String, Attribute> entry : source.entrySet()) {
+                String key = entry.getKey();
+                Attribute destAttribute = destination.get(key);
+                if (destAttribute == null) {
+                    destination.put(key, entry.getValue());
+                } else if (destAttribute instanceof ListAttribute
+                        && entry.getValue() instanceof ListAttribute
+                        && ((ListAttribute) destAttribute).isInherit()) {
+                    ((ListAttribute) destAttribute)
+                            .inherit((ListAttribute) entry.getValue());
+                }
+            }
+        }
+
+        return destination;
+    }
+
+    /**
+     * Deep copies the attribute map, by creating clones (using copy
+     * constructors) of the attributes.
+     *
+     * @param attributes The attribute map to copy.
+     * @return The copied map.
+     */
+    private Map<String, Attribute> deepCopyAttributeMap(Map<String, Attribute> attributes) {
+        Map<String, Attribute> retValue = new HashMap<>(attributes.size());
+        for (Map.Entry<String, Attribute> entry : attributes.entrySet()) {
+            Attribute toCopy = entry.getValue();
+            if (toCopy != null) {
+                retValue.put(entry.getKey(), toCopy.clone());
+            }
+        }
+        return retValue;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/CompareUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/api/CompareUtil.java
new file mode 100644
index 000000000..cf9b643a6
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/CompareUtil.java
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+/**
+ * Utilities to work with comparator between objects.
+ *
+ * @version $Rev$ $Date$
+ * @since 2.2.0
+ */
+public final class CompareUtil {
+
+    /**
+     * Private constructor to avoid instantiation.
+     */
+    private CompareUtil() { }
+
+    /**
+     * Checks if two objects (eventually null) are the same. They are considered the same
+     * even if they are both null.
+     *
+     * @param obj1 The first object to check.
+     * @param obj2 The second object to check.
+     * @return <code>true</code> if the objects are the same.
+     * @since 2.2.0
+     */
+    public static boolean nullSafeEquals(Object obj1, Object obj2) {
+        if (obj1 != null) {
+            return obj1.equals(obj2);
+        }
+        return obj2 == null;
+    }
+
+    /**
+     * Returns <code>0</code> if the object is null, the hash code of the object
+     * otherwise.
+     *
+     * @param obj The object from which the hash code must be calculated.
+     * @return The hash code.
+     * @since 2.2.0
+     */
+    public static int nullSafeHashCode(Object obj) {
+        if (obj != null) {
+            return obj.hashCode();
+        }
+        return 0;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
new file mode 100644
index 000000000..0843f1aca
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
@@ -0,0 +1,162 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import java.util.Map;
+
+import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
+import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
+
+/**
+ * A definition, i.e. a template with (completely or not) filled attributes.
+ * Attributes of a template can be defined with the help of this class.<br>
+ * It can be used as a data transfer object used for registering new
+ * definitions with the Container.
+ *
+ * @since Tiles 2.0
+ */
+public class Definition extends BasicAttributeContext {
+    /**
+     * Extends attribute value.
+     */
+    protected String inherit;
+    /**
+     * Definition name.
+     */
+    protected String name = null;
+
+    /**
+     * Constructor.
+     */
+    public Definition() {
+    }
+
+    /**
+     * Copy Constructor.
+     * Create a new definition initialized with parent definition.
+     * Do a shallow copy : attributes are shared between copies, but not the Map
+     * containing attributes.
+     *
+     * @param definition The definition to copy.
+     */
+    public Definition(Definition definition) {
+        super(definition);
+        this.name = definition.name;
+        this.inherit = definition.inherit;
+    }
+
+    /**
+     * Constructor.
+     * @param name The name of the definition.
+     * @param templateAttribute The template attribute of the definition.
+     * @param attributes The attribute map of the definition.
+     *
+     * @since 2.1.2
+     */
+    public Definition(String name, Attribute templateAttribute,
+                               Map<String, Attribute> attributes) {
+        super(attributes);
+        this.name = name;
+        this.templateAttribute = templateAttribute;
+    }
+
+    /**
+     * Access method for the name property.
+     *
+     * @return the current value of the name property
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     *
+     * @param aName the new value of the name property
+     */
+    public void setName(String aName) {
+        name = aName;
+    }
+
+    /**
+     * Set extends.
+     *
+     * @param name Name of the extended definition.
+     */
+    public void setExtends(String name) {
+        inherit = name;
+    }
+
+    /**
+     * Get extends.
+     *
+     * @return Name of the extended definition.
+     */
+    public String getExtends() {
+        return inherit;
+    }
+
+
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        Definition def = (Definition) obj;
+        return nullSafeEquals(name, def.name)
+                && nullSafeEquals(inherit, def.inherit) && super.equals(def);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return nullSafeHashCode(name) + nullSafeHashCode(inherit)
+                + super.hashCode();
+    }
+
+    /**
+     * Get extends flag.
+     *
+     * @return <code>true</code> if this definition extends another.
+     */
+    public boolean isExtending() {
+        return inherit != null;
+    }
+
+    /**
+     * Returns a description of the attributes.
+     *
+     * @return A string representation of the content of this definition.
+     */
+    @Override
+    public String toString() {
+        return "{name="
+            + name
+            + ", template="
+            + (templateAttribute != null ? templateAttribute.getValue() : "<null>")
+            + ", role="
+            + (templateAttribute != null ? templateAttribute.getRoles() : "<null>")
+            + ", preparerInstance="
+            + preparer
+            + ", attributes="
+            + attributes
+            + "}";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
new file mode 100644
index 000000000..439a2c2e8
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
@@ -0,0 +1,157 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.api;
+
+import static org.apache.tiles.api.CompareUtil.nullSafeEquals;
+import static org.apache.tiles.api.CompareUtil.nullSafeHashCode;
+
+/**
+ * It is an expression, along with the expression language (e.g. EL, MVEL, OGNL)
+ * it is expressed with.
+ *
+ * @since 2.2.0
+ */
+public class Expression {
+
+    /**
+     * The expression itself.
+     */
+    private final String expression;
+
+    /**
+     * The language of the expression.
+     */
+    private final String language;
+
+    /**
+     * Constructor.
+     *
+     * @param expression The expression itself.
+     * @param language The language of the expression.
+     * @since 2.2.0
+     */
+    public Expression(String expression, String language) {
+        this.expression = expression;
+        this.language = language;
+    }
+
+    /**
+     * Constructor, using the default (i.e. <code>null</code>) language.
+     *
+     * @param expression The expression itself.
+     * @since 2.2.0
+     */
+    public Expression(String expression) {
+        this(expression, null);
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @param toCopy The expression to copy.
+     * @since 2.2.0
+     */
+    public Expression(Expression toCopy) {
+        this.expression = toCopy.expression;
+        this.language = toCopy.language;
+    }
+
+    /**
+     * Creates an Expression object from a string in the form
+     * <code>LANGUAGE:EXPRESSION</code>.
+     *
+     * @param describedExpression The expression in the form
+     * <code>LANGUAGE:EXPRESSION</code>. The LANGUAGE part should be expressed
+     * only with letters and numbers.
+     * @return The created object, or <code>null</code> if the expression is null.
+     * @since 2.2.0
+     */
+    public static Expression createExpressionFromDescribedExpression(String describedExpression) {
+        if (describedExpression != null) {
+            String language = null;
+            String expression = describedExpression;
+            if (describedExpression.matches("[a-zA-Z0-9]+:.+")) {
+                language = describedExpression.substring(0, describedExpression.indexOf(':'));
+                expression = describedExpression.substring(describedExpression.indexOf(':') + 1);
+            }
+            return new Expression(expression, language);
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates an Expression object from the expression and its language.
+     *
+     * @param expression The expression itself.
+     * @param language The language of the expression.
+     * @return The created object, or <code>null</code> if the expression is null.
+     * @since 2.2.0
+     */
+    public static Expression createExpression(String expression, String language) {
+        if (expression != null) {
+            return new Expression(expression, language);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the expression string.
+     *
+     * @return The expression itself.
+     * @since 2.2.0
+     */
+    public String getExpression() {
+        return expression;
+    }
+
+    /**
+     * Returns the language in which the expression is expressed.
+     *
+     * @return The expression language.
+     * @since 2.2.0
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        Expression exp = (Expression) obj;
+        return nullSafeEquals(expression, exp.expression)
+                && nullSafeEquals(language, exp.language);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return nullSafeHashCode(expression) + nullSafeHashCode(language);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return (language == null ? "DEFAULT" : language) + ":" + expression;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
new file mode 100644
index 000000000..d618b66ec
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.java
@@ -0,0 +1,166 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An attribute as a <code>List</code>.
+ * This attribute associates a name with a list. The list can be found by the
+ * property name.
+ * Elements in list are retrieved using List methods.
+ * This class is used to read configuration files.
+ *
+ * @since 2.1.0
+ */
+public class ListAttribute extends Attribute {
+
+    /**
+     * If true, the attribute will put the elements of the attribute with the
+     * same name of the parent definition before the ones specified here. By
+     * default, it is 'false'.
+     */
+    private boolean inherit = false;
+
+    /**
+     * Constructor.
+     *
+     * @since 2.1.0
+     */
+    public ListAttribute() {
+        setValue(new ArrayList<Object>());
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @param toCopy The list attribute to copy.
+     * @since 2.1.3
+     */
+    public ListAttribute(ListAttribute toCopy) {
+        super(toCopy);
+        List<Attribute> attributesToCopy = toCopy.getValue();
+        if (attributesToCopy != null) {
+            List<Attribute> attributes = new ArrayList<>(attributesToCopy.size());
+            for (Attribute attribute : attributesToCopy) {
+                if (attribute != null) {
+                    attributes.add(attribute.clone());
+                } else {
+                    attributes.add(null);
+                }
+            }
+            setValue(attributes);
+        }
+        this.inherit = toCopy.inherit;
+    }
+
+    /**
+     * Sets the list of the attributes that are elements of this attribute.
+     *
+     * @param attributes The attributes.
+     * @since 3.0.0
+     */
+    public void setValue(List<Attribute> attributes) {
+        super.setValue(attributes);
+    }
+
+    /**
+     * Returns the list of the attributes that are elements of this attribute.
+     *
+     * @return The attributes.
+     * @since 3.0.0
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<Attribute> getValue() {
+        return (List<Attribute>) super.getValue();
+    }
+
+    /**
+     * Add an element in list.
+     * We use a property to avoid rewriting a new class.
+     *
+     * @param element XmlAttribute to add.
+     * @since 2.1.0
+     */
+    public void add(Attribute element) {
+        getValue().add(element);
+    }
+
+    /**
+     * If true, the attribute will put the elements of the attribute with the
+     * same name of the parent definition before the ones specified here. By
+     * default, it is 'false'
+     *
+     * @param inherit The "inherit" value.
+     * @since 2.1.0
+     */
+    public void setInherit(boolean inherit) {
+        this.inherit = inherit;
+    }
+
+    /**
+     * If true, the attribute will put the elements of the attribute with the
+     * same name of the parent definition before the ones specified here. By
+     * default, it is 'false'
+     *
+     * @return inherit The "inherit" value.
+     * @since 2.1.0
+     */
+    public boolean isInherit() {
+        return inherit;
+    }
+
+    /**
+     * Inherits elements present in a "parent" list attribute. The elements will
+     * be put before the ones already present.
+     *
+     * @param parent The parent list attribute.
+     * @since 2.1.0
+     */
+    @SuppressWarnings("unchecked")
+    public void inherit(ListAttribute parent) {
+        List<Attribute> tempList = new ArrayList<>();
+        tempList.addAll((List<Attribute>) parent.value);
+        tempList.addAll((List<Attribute>) value);
+        setValue(tempList);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        ListAttribute attribute = (ListAttribute) obj;
+        return super.equals(attribute) && this.inherit == attribute.inherit;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + Boolean.valueOf(inherit).hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ListAttribute clone() {
+        return new ListAttribute(this);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
index 38e506552..858db324d 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/NoSuchContainerException.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.api;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Indicates that a keyed container has not been found.
  *
- * @since Struts 2.0.2
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public class NoSuchContainerException extends TilesException {
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * Constructor.
+     *
+     * @param message The detail message.
+     * @since 2.1.0
+     */
+    public NoSuchContainerException(String message) {
+        super(message);
     }
-}
\ No newline at end of file
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java
new file mode 100644
index 000000000..20199772d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java
@@ -0,0 +1,139 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+
+import java.io.IOException;
+
+/**
+ * An encapsulation of the Tiles framework.  This interface is
+ * used to expose tiles features to frameworks which leverage
+ * it as a plugin.  It can alternately be used by web applications
+ * which would like a programmatic interface.
+ *
+ * @since 2.0
+ */
+public interface TilesContainer {
+
+    /**
+     * Retrieve the container's context.
+     *
+     * @return current application context
+     */
+    ApplicationContext getApplicationContext();
+
+    /**
+     * Retrieve the attribute context of the current request.
+     * @param request The request.
+     * @return map of the attributes in the current attribute context.
+     */
+    AttributeContext getAttributeContext(Request request);
+
+    /**
+     * Starts a new context, where attribute values are stored independently of others.<br>
+     * When the use of the contexts is finished, call{@link TilesContainer#endContext(Request)}
+     *
+     * @param request The request.
+     * @return The newly created context.
+     */
+    AttributeContext startContext(Request request);
+
+    /**
+     * Ends a context, where attribute values are stored independently of others.<br>
+     * It must be called after a {@link TilesContainer#startContext(Request)} call.
+     *
+     * @param request The request.
+     */
+    void endContext(Request request);
+
+    /**
+     * Renders the current context, as it is.
+     * @param request The request.
+     *
+     * @since 2.1.0
+     */
+    void renderContext(Request request);
+
+    /**
+     * Executes a preparer.
+     *
+     * @param preparer The name of the preparer to execute.
+     * @param request The request.
+     */
+    void prepare(String preparer, Request request);
+
+    /**
+     * Render the given tiles request.
+     *
+     * @param definition the current definition.
+     * @param request The request.
+     */
+    void render(String definition, Request request);
+
+    /**
+     * Renders the specified definition.
+     * @param definition The definition to render.
+     * @param request The request context.
+     */
+    void render(Definition definition, Request request);
+
+    /**
+     * Render the given Attribute.
+     *
+     * @param attribute The attribute to render.
+     * @param request The request.
+     * @throws IOException If something goes wrong during writing to the output.
+     * @since 2.1.2
+     */
+    void render(Attribute attribute, Request request)
+        throws IOException;
+
+    /**
+     * Evaluates the given attribute.
+     *
+     * @param attribute The attribute to evaluate.
+     * @param request The request.
+     * @return The evaluated object.
+     * @since 2.1.0
+     */
+    Object evaluate(Attribute attribute, Request request);
+
+    /**
+     * Returns a definition specifying its name.
+     *
+     * @param definitionName The name of the definition to find.
+     * @param request The request context.
+     * @return The definition, if found.
+     */
+    Definition getDefinition(String definitionName,
+                             Request request);
+
+    /**
+     * Determine whether the definition exists.
+     *
+     * @param definition the name of the definition.
+     * @param request The request.
+     * @return true if the definition is found.
+     */
+    boolean isValidDefinition(String definition, Request request);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java
new file mode 100644
index 000000000..28687c194
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.java
@@ -0,0 +1,109 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+
+import java.io.IOException;
+
+/**
+ * Wraps a Tiles container to allow easy decoration.
+ */
+public class TilesContainerWrapper implements TilesContainer {
+
+    /**
+     * The container to wrap.
+     */
+    protected TilesContainer container;
+
+    /**
+     * Constructor.
+     *
+     * @param container The container to wrap.
+     */
+    public TilesContainerWrapper(TilesContainer container) {
+        this.container = container;
+        if (container == null) {
+            throw new NullPointerException("The wrapped container must be not null");
+        }
+    }
+
+    @Override
+    public void endContext(Request request) {
+        container.endContext(request);
+    }
+
+    @Override
+    public Object evaluate(Attribute attribute, Request request) {
+        return container.evaluate(attribute, request);
+    }
+
+    @Override
+    public ApplicationContext getApplicationContext() {
+        return container.getApplicationContext();
+    }
+
+    @Override
+    public AttributeContext getAttributeContext(Request request) {
+        return container.getAttributeContext(request);
+    }
+
+    @Override
+    public Definition getDefinition(String definitionName, Request request) {
+        return container.getDefinition(definitionName, request);
+    }
+
+    @Override
+    public boolean isValidDefinition(String definition, Request request) {
+        return container.isValidDefinition(definition, request);
+    }
+
+    @Override
+    public void prepare(String preparer, Request request) {
+        container.prepare(preparer, request);
+    }
+
+    @Override
+    public void render(String definition, Request request) {
+        container.render(definition, request);
+    }
+
+    @Override
+    public void render(Definition definition, Request request) {
+        container.render(definition, request);
+    }
+
+    @Override
+    public void render(Attribute attribute, Request request) throws IOException {
+        container.render(attribute, request);
+    }
+
+    @Override
+    public void renderContext(Request request) {
+        container.renderContext(request);
+    }
+
+    @Override
+    public AttributeContext startContext(Request request) {
+        return container.startContext(request);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java
new file mode 100644
index 000000000..77088c3d5
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java
@@ -0,0 +1,68 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api;
+
+/**
+ * Root class for all Tiles-exceptions.
+ */
+public class TilesException extends RuntimeException {
+
+    /**
+     * Constructor.
+     */
+    public TilesException() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The error or warning message.
+     */
+    public TilesException(String message) {
+        super(message);
+    }
+
+    /**
+     * Create a new <code>TilesException</code> wrapping an existing exception.
+     * <p/>
+     * <p>The existing exception will be embedded in the new
+     * one, and its message will become the default message for
+     * the TilesException.</p>
+     *
+     * @param e The cause to be wrapped.
+     */
+    public TilesException(Throwable e) {
+        super(e);
+    }
+
+    /**
+     * Create a new <code>TilesException</code> from an existing exception.
+     * <p/>
+     * <p>The existing exception will be embedded in the new
+     * one, but the new exception will have its own message.</p>
+     *
+     * @param message The detail message.
+     * @param e       The cause to be wrapped.
+     */
+    public TilesException(String message, Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java b/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java
new file mode 100644
index 000000000..cdfaa753e
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java
@@ -0,0 +1,160 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api.access;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tiles.api.NoSuchContainerException;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+
+import java.util.Map;
+
+/**
+ * Provides static access to the Tiles container.
+ */
+public final class TilesAccess {
+
+    private static final Logger LOG = LogManager.getLogger(TilesAccess.class);
+
+    /**
+     * Name of the attribute used to store the current used container.
+     */
+    public static final String CURRENT_CONTAINER_ATTRIBUTE_NAME =
+        "org.apache.tiles.servlet.context.ServletTilesRequestContext.CURRENT_CONTAINER_KEY";
+
+    /**
+     * Constructor, private to avoid instantiation.
+     */
+    private TilesAccess() {
+    }
+
+    /**
+     * The name of the attribute to use when getting and setting the container
+     * object in a context.
+     */
+    public static final String CONTAINER_ATTRIBUTE =
+        "org.apache.tiles.CONTAINER";
+
+    /**
+     * Configures the container to be used in the application.
+     *
+     * @param context   The Tiles application context object to use.
+     * @param container The container object to set.
+     * @param key       The key under which the container will be stored.
+     * @since 2.1.2
+     */
+    public static void setContainer(ApplicationContext context, TilesContainer container, String key) {
+        if (key == null) {
+            key = CONTAINER_ATTRIBUTE;
+        }
+
+        if (container == null) {
+            LOG.info("Removing TilesContext for context: {}", context.getClass().getName());
+            context.getApplicationScope().remove(key);
+        } else {
+            LOG.info("Publishing TilesContext for context: {}", context.getClass().getName());
+            context.getApplicationScope().put(key, container);
+        }
+    }
+
+    /**
+     * Returns default the container to be used in the application.
+     *
+     * @param context The Tiles application context object to use.
+     * @return The default container object.
+     * @since 3.0.0
+     */
+    public static TilesContainer getContainer(ApplicationContext context) {
+        return getContainer(context, CONTAINER_ATTRIBUTE);
+    }
+
+    /**
+     * Returns the container to be used in the application registered under a specific key.
+     *
+     * @param context The Tiles application context object to use.
+     * @param key     The key under which the container will be stored.
+     * @return The container object.
+     * @since 3.0.0
+     */
+    public static TilesContainer getContainer(ApplicationContext context,
+                                              String key) {
+        if (key == null) {
+            key = CONTAINER_ATTRIBUTE;
+        }
+
+        return (TilesContainer) context.getApplicationScope().get(key);
+    }
+
+    /**
+     * Sets the current container to use in web pages.
+     *
+     * @param request The request to use.
+     * @param key     The key under which the container is stored.
+     * @since 2.1.0
+     */
+    public static void setCurrentContainer(Request request,
+                                           String key) {
+        ApplicationContext applicationContext = request.getApplicationContext();
+        TilesContainer container = getContainer(applicationContext, key);
+        if (container != null) {
+            request.getContext("request").put(CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        } else {
+            throw new NoSuchContainerException("The container with the key '"
+                + key + "' cannot be found");
+        }
+    }
+
+    /**
+     * Sets the current container to use in web pages.
+     *
+     * @param request   The request to use.
+     * @param container The container to use as the current container.
+     * @since 2.1.0
+     */
+    public static void setCurrentContainer(Request request, TilesContainer container) {
+        if (container != null) {
+            request.getContext("request").put(CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        } else {
+            throw new NullPointerException("The container cannot be null");
+        }
+    }
+
+    /**
+     * Returns the current container that has been set, or the default one.
+     *
+     * @param request The request to use.
+     * @return The current Tiles container to use in web pages.
+     * @since 2.1.0
+     */
+    public static TilesContainer getCurrentContainer(Request request) {
+        ApplicationContext context = request.getApplicationContext();
+        Map<String, Object> requestScope = request.getContext("request");
+        TilesContainer container = (TilesContainer) requestScope.get(CURRENT_CONTAINER_ATTRIBUTE_NAME);
+        if (container == null) {
+            container = getContainer(context);
+            requestScope.put(CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
+        }
+
+        return container;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/api/access/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/api/access/package-info.java
index 38e506552..f6090a574 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/access/package-info.java
@@ -7,7 +7,7 @@
  * "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
+ * 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
@@ -16,25 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Tiles access package. Utility classes to access Tiles funcionality from an application.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+package org.apache.tiles.api.access;
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java
index 38e506552..6e8765cc2 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/MutableTilesContainer.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.api.mgmt;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.Request;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Defines a mutable version of the TilesContainer.
  *
- * @since Struts 2.0.2
+ * @since Tiles 2.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface MutableTilesContainer extends TilesContainer {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Register a new definition with the container.
+     *
+     * @param definition The definition to register.
+     * @param request TODO
+     */
+    void register(Definition definition, Request request);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/package-info.java
index 38e506552..8a22e1cb5 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/mgmt/package-info.java
@@ -7,7 +7,7 @@
  * "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
+ * 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
@@ -16,25 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Classes and interfaces to be used when it is needed to create Tiles definitions
+ * during the execution of the application.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+package org.apache.tiles.api.mgmt;
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/api/package-info.java
new file mode 100644
index 000000000..f19af6def
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/package-info.java
@@ -0,0 +1,385 @@
+/*
+ * 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.
+ */
+/**
+ * The Tiles taglib and framework allows building web pages by assembling reusable
+ pieces of pages, called Tiles. A Tiles is usually a simple JSP page.
+
+ <div class="section">
+ <h2>Introduction</h2>
+
+ <p>The Tiles framework allows building pages by assembling reusable Tiles.
+ As an example, the page in the next figure can be build by assembling a
+ header, a footer, a menu and a body.</p>
+
+ <p><img src="doc-files/image001.gif" height="169" width="145" alt="doc-files/image001"></p>
+
+ <p>Each Tiles (header, menu, body, ...) is a JSP page and can itself be build
+ by assembling other Tiles.</p>
+
+ <p>Using Tiles can be compared as using Java methods: You need to define the Tiles (the method body), and then you
+ can &quot;call&quot; this body anywhere you want, passing it some parameters. In Tiles, parameters are called
+ &quot;attributes&quot; in order to avoid confusion with the request parameters.</p>
+
+ <p>The Tiles body can be a simple JSP page, a Struts action or any URI pointing
+ to a resource inside the current web site.</p>
+
+ <p>Inserting the body, or calling it, is done with the tag &lt;tiles:insert
+ ...&gt; anywhere in a JSP page. Insertion can also be done by specifying
+ a <em>definition name </em>as the path of a Struts forward or as input,
+ forward or include attributes of a Struts action.</p>
+
+ <p>Tiles bodies are used to create layouts, reusable parts, ... Tiles insertions
+ are used to insert Tiles. The same Tiles can be reused several times in
+ the same site, or even in the same page.</p>
+
+ <p>Insertion of a Tiles body can be associated to a logical name in what Tiles calls a &quot;definition&quot;. A
+ definition contains a logical name, a page used as body and some attribute values. The definition declaration
+ doesn't insert the associated Tiles body. It just associates it with the name. A definition name can be used
+ anywhere insertion of a Tiles body can occur. The associated Tiles body is then inserted with associated
+ attributes.</p>
+
+ <p>The definition declarations can be done in JSP pages or in one or more
+ centralized files. A definition can extend another one, overload some attributes,
+ add new attributes ... This allows the declaration of a &quot;master&quot; definition
+ declaring the common layout, header, menu and footer. All other definitions
+ extend this master layout thereby making it possible to change the entire
+ site look &amp; feel simply by changing the master definition. </p>
+ </div>
+ <div class="section">
+ <h2>Simple Examples</h2>
+
+ <div class="subsection1">
+ <h3>Insert a JSP page</h3>
+ <pre>&lt;tiles:insert <strong>page</strong>=&quot;/layouts/commonLayout.jsp&quot; flush=&quot;true&quot; /&gt;
+ </pre>
+ <p>This example inserts the specified page in place of the tag. The page attribute is any valid URL pointing to
+ a resource inside the current site.</p>
+ </div>
+ <div class="subsection1">
+ <a name="doc.InsertPageWithAttributes"></a>
+
+ <h3>Insert a Tiles passing some attributes</h3>
+ <pre>
+ &lt;tiles:insert page=&quot;/layouts/classicLayout.jsp&quot; flush=&amp;quot;true&quot;&gt;
+ &lt;tiles:put name=&quot;title&quot;  value=&quot;Page Title&quot; /&gt;
+ &lt;tiles:put name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ &lt;tiles:put name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ &lt;tiles:put name=&quot;menu&quot;   value=&quot;/common/menu.jsp&quot; /&gt;
+ &lt;tiles:put name=&quot;body&quot;   value=&quot;/tiles/mainBody.jsp&quot; /&gt;
+ &lt;/tiles:insert&gt;
+ </pre>
+ <p>This example inserts the specified page, passing it the attributes. Attributes
+ are stored in a Tiles context which is passed to the inserted pag and
+ can then be accesssed by their names.</p>
+ </div>
+ <div class="subsection1">
+ <h3>Retrieve an attribute value as String</h3>
+ <pre>
+ &lt;tiles:getAsString name=&quot;title&quot; /&gt;
+ </pre>
+ <p>This example retrieves the value of the attribute &quot;title&quot; and prints it as a String in the current
+ output stream. The method toString() is applied on the attribute value, allowing to pass any kind of object
+ as value.</p>
+ </div>
+ <div class="subsection1">
+ <h3>Insert Tiles referenced by an attribute</h3>
+ <pre>
+ &lt;tiles:insert attribute='menu' /&gt;
+ </pre>
+ <p>This inserts the Tiles referenced by the attribute &quot;menu&quot; value. The
+ specified attribute value is first retrieved from current Tiles's context,
+ and then the value is used as a page target to insert.</p>
+ </div>
+ <div class="subsection1">
+ <h3>Classic Layout </h3>
+
+ <p>This example is a layout assembling a page in the classic header-footer-menu-body
+ fashion.</p>
+ <pre>
+ &lt;%@ taglib uri=&quot;http://tiles.apache.org/tags-tiles&quot; prefix=&quot;tiles&quot; %&gt;
+ &lt;HTML&gt;
+ &lt;HEAD&gt;
+ &lt;link rel=&quot;stylesheet&quot; href=&quot;&lt;%=request.getContextPath()%&gt;/layouts/stylesheet.css&quot;
+ type=&quot;text/css&quot;/&gt;
+ &lt;title&gt;&lt;tiles:getAsString name=&quot;title&quot;/&gt;&lt;/title&gt;
+ &lt;/HEAD&gt;
+ &lt;body&gt;
+ &lt;table border=&quot;0&quot; width=&quot;100%&quot; cellspacing=&quot;5&quot;&gt;
+ &lt;tr&gt;
+ &lt;td colspan=&quot;2&quot;&gt;&lt;tiles:insert attribute=&quot;header&quot; /&gt;&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td width=&quot;140&quot; valign=&quot;top&quot;&gt;
+ &lt;tiles:insert attribute='menu' /&gt;
+ &lt;/td&gt;
+ &lt;td valign=&quot;top&quot;  align=&quot;left&quot;&gt;
+ &lt;tiles:insert attribute='body' /&gt;
+ &lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td colspan=&quot;2&quot;&gt;
+ &lt;tiles:insert attribute=&quot;footer&quot; /&gt;
+ &lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;/table&gt;
+ &lt;/body&gt;
+ &lt;/html&gt;
+ </pre>
+ <p>The layout is declared in a JSP page (ex: /layouts/classicLayout.jsp).
+ It can be used in conjunction with the tag described in &quot;<a href="#doc.InsertPageWithAttributes">Insert
+ a page passing some attributes</a>&quot;. </p>
+ </div>
+ </div>
+ <div class="section">
+ <h2>Definitions</h2>
+
+ <p>A definition associates a logical name with the URL of a Tiles to be inserted
+ and some attribute values. A definition doesn't insert the Tiles. This is
+ done later using the definition name. A definition name can be inserted
+ as often as you want in your site, making it easy to reuse a Tiles. </p>
+
+ <p>A definition can extend another definition and overload some attributes
+ or add new ones. This makes easy factorization of definitions differing
+ by some attributes. For example, you can define a master definition declaring
+ the main header, menu, footer, and a default title. Then let each of your
+ page definitions extend this master definition and overload the title and
+ the body.</p>
+
+ <p>Definitions can be declared in a JSP page, or in one or more centralized
+ files. To enable the definitions from centralized files, you need to initialize
+ the &quot;definitions factory&amp;&amp;quot; which will parse the definitions from the files
+ and provide them to the Tiles framework.</p>
+
+ <div class="subsection1">
+ <h3>Enabling Definition Factory</h3>
+
+ <p>To enable Tiles definitions described in one or more files, you need to write these files and to initialize the
+ definition factory. </p>
+
+ <p>Initialization is different depending on the Struts version you use,
+ or if you do not use Struts at all.</p>
+
+ <div class="subsection2">
+ <h4>Struts1.1</h4>
+
+ <p>Use the Tiles plug-in to enable Tiles definitions. This plug-in creates
+ the definition factory and passese it a configuration object populated
+ with parameters. Parameters can be specified in the web.xml file or
+ as plug-in parameters. The plug-in first reads parameters from web.xml,
+ and then overloads them with the ones found in the plug-in. All parameters
+ are optional and can be omitted. The plug-in should be declared in each
+ struts-config file:</p>
+ <pre>
+ &lt;plug-in className=&amp;&amp;quot;org.apache.struts.tiles.TilesPlugin&amp;&amp;quot; &gt;
+ &lt;set-property property=&amp;&amp;quot;definitions-config&amp;&amp;quot;
+ value=&amp;&amp;quot;/WEB-INF/tiles-defs.xml,
+ /WEB-INF/tiles-tests-defs.xml,/WEB-INF/tiles-tutorial-defs.xml,
+ /WEB-INF/tiles-examples-defs.xml&amp;&amp;quot; /&gt;
+ &lt;set-property property=&amp;&amp;quot;moduleAware&amp;&amp;quot; value=&amp;&amp;quot;true&amp;&amp;quot; /&gt;
+ &lt;set-property
+ property=&amp;&amp;quot;org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE&amp;&amp;quot;
+ value=&amp;&amp;quot;true&amp;&amp;quot; /&gt;
+ &lt;/plug-in&gt;
+ </pre>
+ <ul>
+ <li>definitions-config: (optional)
+ <ul>
+ <li>Specify configuration file names. There can be several comma separated file names (default: ?? )
+ </li>
+ </ul>
+ </li>
+ <li>org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE: (optional)
+ <ul>
+ <li>Specify if XML parser should validate the Tiles configuration
+ file
+ <ul>
+ <li>true : validate. DTD should be specified in file header (default)</li>
+ <li>false : no validation</li>
+
+ </ul>
+ </li>
+ </ul>
+ </li>
+
+ <li>moduleAware: (optional)
+ <ul>
+ <li>Specify if the Tiles definition factory is module aware. If true (default),
+ there will be one factory for each Struts module.
+ If false, there will be one common factory for all module. In this later case,
+ it is still needed to declare one plugin per module. The factory will be
+ initialized with parameters found in the first initialized plugin (generally the
+ one associated with the default module).
+ <ul>
+ <li>true : Tiles framework is module aware</li>
+ <li>false :Tiles framework has one single factoy shared among modules (default)</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+
+ <li>tilesUtilImplClassname: (optional - for advanced user)
+ <ul>
+ <li>Specify The classname of the TilesUtil implementation to use. The specified class should
+ be a subclass of TilesUtilStrutsImpl. This option disable the moduleAware option.
+ <br>Specifying &amp;&amp;&quot;TilesUtilStrutsImpl&amp;&amp;&quot; is equivalent to moduleAware =
+ false.
+ <br>Specifying &amp;&amp;&quot;TilesUtilStrutsModuleImpl&amp;&amp;&quot; is equivalent to moduleAware
+ = true.
+ This option is taken into account only once, when it is first encountered. To avoid problems,
+ it is advice to specify the same values in all TilesPlugin declaration.
+ </li>
+ </ul>
+ </li>
+
+ </ul>
+ <p>The TilesPlugin class creates one definition factory for each struts module.
+ </p>
+
+ <p>
+ If the flag moduleAware is false, only one shared factory is created for all modules.
+ In this later case, the factory is initialized with parameters found in the first plugin.
+ The plugins should be declared in all modules, and the moduleAware flag should be
+ the same for the entire application.</p>
+
+ <p>
+ Paths found in Tiles definitions are relative to the main context.</p>
+
+ <p>You don't need to specify a TilesRequestProcessor, this is automatically
+ done by the plug-in. If, however, you want to specify your own RequestProcessor,
+ it should extend the TilesRequestProcessor. The plug-in checks this
+ constraint.</p>
+ </div>
+ <div class="subsection2">
+ <h4>Struts1.0.x</h4>
+
+ <p>You need to use a special servlet extending the Struts servlet. This is specified in the web.xml file of your
+ application:</p>
+ <pre>
+ &lt;servlet&gt;
+ &lt;servlet-name&gt;action&lt;/servlet-name&gt;
+ &lt;servlet-class&gt;org.apache.tiles.web.startup.TilesServlet&lt;/servlet-class&gt;
+ &lt;!-- Tiles Servlet parameter
+ Specify configuration file names. There can be several comma
+ separated file names
+ --&gt;
+ &lt;init-param&gt;
+ &lt;param-name&gt;definitions-config&lt;/param-name&gt;
+ &lt;param-value&gt;/WEB-INF/tiles-defs.xml&lt;/param-value&gt;
+ &lt;/init-param&gt;
+ &lt;!-- Tiles Servlet parameter
+ Specify if XML parser should validate the Tiles configuration file(s).
+ true : validate. DTD should be specified in file header.
+ false : no validation
+ --&gt;
+ &lt;init-param&gt;
+ &lt;param-name&gt;org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE&lt;/param-name&gt;
+ &lt;param-value&gt;true&lt;/param-value&gt;
+ &lt;/init-param&gt;
+ ...
+ &lt;/servlet&gt;
+ </pre>
+ </div>
+ <div class="subsection2">
+ <h4>Without Struts</h4>
+
+ <p>Tiles can be used without Struts. To initialize the definition factory, you can use the provided servlet. Declare
+ it in the web.xml file of your application:</p>
+ <pre>
+ &lt;servlet&gt;
+ &lt;servlet-name&gt;action&lt;/servlet-name&gt;
+ &lt;servlet-class&gt;org.apache.struts.tiles.TilesServlet&lt;/servlet-class&gt;
+
+
+ &lt;init-param&gt;
+ &lt;param-name&gt;definitions-config&lt;/param-name&gt;
+ &lt;param-value&gt;/WEB-INF/tiles-defs.xml&lt;/param-value&gt;
+ &lt;/init-param&gt;
+ &lt;init-param&gt;
+ &lt;param-name&gt;org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE&lt;/param-name&gt;
+ &lt;param-value&gt;true&lt;/param-value&gt;
+ &lt;/init-param&gt;
+ ...
+ </pre>
+ <p>The parameters are the same as for Struts1.1 or 1.0.</p>
+ </div>
+ </div>
+ <div class="subsection1">
+ <h3>Definition File Syntax</h3>
+
+ <p>The definition file syntax can be found in the
+ <a href="http://tiles.apache.org/dtds/tiles-config_2_0.dtd">tiles-config_2_0.dtd file</a>.
+ </p>
+
+ <p>Following is a simple example:</p>
+ <pre>
+ &lt;!DOCTYPE tiles-definitions PUBLIC
+ &amp;&amp;quot;-//Apache Software Foundation//DTD Tiles Configuration//EN&amp;&amp;quot;
+ &amp;&amp;quot;http://tiles.apache.org/dtds/tiles-config_2_0.dtd&amp;&amp;quot;&gt;
+
+ &lt;!-- Definitions for Tiles documentation   --&gt;
+ &lt;tiles-definitions&gt;
+
+ &lt;!-- ========================================================== --&gt;
+ &lt;!-- Master definition                                          --&gt;
+ &lt;!-- ========================================================== --&gt;
+ &lt;!-- Main page layout used as a root for other page definitions --&gt;
+
+ &lt;definition name=&amp;&amp;quot;site.mainLayout&amp;&amp;quot;
+   template=&amp;&amp;quot;/layouts/classicLayout.jsp&amp;&amp;quot;&gt;
+ &lt;put name=&amp;&amp;quot;title&amp;&amp;quot;  value=&amp;&amp;quot;Tiles Blank Site&amp;&amp;quot; /&gt;
+ &lt;put name=&amp;&amp;quot;header&amp;&amp;quot; value=&amp;&amp;quot;/tiles/common/header.jsp&amp;&amp;quot; /&gt;
+ &lt;put name=&amp;&amp;quot;menu&amp;&amp;quot;   value=&amp;&amp;quot;site.menu.bar&amp;&amp;quot; /&gt;
+ &lt;put name=&amp;&amp;quot;footer&amp;&amp;quot; value=&amp;&amp;quot;/tiles/common/footer.jsp&amp;&amp;quot; /&gt;
+ &lt;put name=&amp;&amp;quot;body&amp;&amp;quot;   value=&amp;&amp;quot;/tiles/body.jsp&amp;&amp;quot; /&gt;
+ &lt;/definition&gt;
+
+ &lt;!-- ========================================================== --&gt;
+ &lt;!-- Index page definition                                      --&gt;
+ &lt;!-- ========================================================== --&gt;
+ &lt;!-- This definition inherits from the main definition.
+ It overloads the page title and the body used.
+ Use the same mechanism to define new pages sharing common
+ properties (here header, menu, footer, layout)
+ --&gt;
+
+ &lt;definition name=&amp;&amp;quot;site.index.page&amp;&amp;quot;
+   extends=&amp;&amp;quot;site.mainLayout&amp;&amp;quot; &gt;
+ &lt;put name=&amp;&amp;quot;title&amp;&amp;quot;  value=&amp;&amp;quot;Tiles Blank Site Index&amp;&amp;quot; /&gt;
+ &lt;put name=&amp;&amp;quot;body&amp;&amp;quot;   value=&amp;&amp;quot;/tiles/body.jsp&amp;&amp;quot; /&gt;
+ &lt;/definition&gt;
+
+ &lt;/tiles-definition&gt;
+ </pre>
+ </div>
+ <div class="subsection1">
+ <h3>Debugging</h3>
+
+ <p>To debug a page made of Tiles, you can use following advices:</p>
+ <ul>
+ <li>Check each Tiles separatly. Try to access nested Tiles directly to test
+ if thes work properly.
+ </li>
+ <li>Enable Tiles logging. See the commons-logging package help.</li>
+ </ul>
+ </div>
+ </div>
+
+ */
+package org.apache.tiles.api;
+
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/PreparerException.java b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/PreparerException.java
new file mode 100644
index 000000000..87ba1f1f3
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/PreparerException.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.api.preparer;
+
+import org.apache.tiles.api.TilesException;
+
+/**
+ * <p>
+ * Thrown when an exception occurs while processing
+ * a prepare request.
+ * </p>
+ *
+ * @since Tiles 2.0
+ */
+public class PreparerException extends TilesException {
+
+    /**
+     * Constructor.
+     */
+    public PreparerException() {
+        super();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param e The cause exception.
+     */
+    public PreparerException(Throwable e) {
+        super(e);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The message to include.
+     */
+    public PreparerException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The message to include.
+     * @param e The cause exception.
+     */
+    public PreparerException(String message, Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
new file mode 100644
index 000000000..14bd08308
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.java
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.api.preparer;
+
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.request.Request;
+
+/**
+ * <p>
+ * Executed prior to rendering a view.
+ * </p>
+ *
+ * <p>
+ * A view preparer is typically used to provide last minute
+ * translations of the data within the attribute context.
+ * A preparer is not intended to replace the controller within an
+ * MVC architecture.
+ * </p>
+ *
+ * See
+ * <ul>
+ * <li>&lt;insert&gt;</li>
+ * <li>&lt;definition&gt;</li>
+ * </ul>>
+ *
+ * @version $Rev$ $Date$
+ */
+public interface ViewPreparer {
+
+    /**
+     * Method associated to a tile and called immediately before the tile
+     * is included.
+     *
+     * @param tilesContext     Current tiles application context.
+     * @param attributeContext Current tile context.
+     * @throws PreparerException If something goes wrong during execution.
+     */
+    void execute(Request tilesContext,
+        AttributeContext attributeContext);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/api/preparer/package-info.java
index 38e506552..a8fcab1fd 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/package-info.java
@@ -7,7 +7,7 @@
  * "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
+ * 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
@@ -16,25 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * "View preparers" are objects that allows the "preparation" of a Tiles artifact
+ * (definition, template or attribute) before it is rendered.<br>
+ * It is useful, for example, when a view item should be built and stored in a
+ * particular context (e.g. a menu) and then rendered.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+package org.apache.tiles.api.preparer;
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
new file mode 100644
index 000000000..3e3f1ede7
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
@@ -0,0 +1,87 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.core.runtime;
+
+import org.apache.tiles.autotag.core.runtime.util.NullWriter;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.regex.Pattern;
+
+/**
+ * Base class for the abstraction of the body.
+ *
+ * @version $Rev$ $Date$
+ */
+public abstract class AbstractModelBody implements ModelBody {
+
+    // precompiled the pattern to avoid compiling on every method call
+    private static final Pattern PATTERN = Pattern.compile("^\\s*|\\s*$");
+
+    /**
+     * The default writer to use.
+     */
+    private Writer defaultWriter;
+
+    /**
+     * Constructor.
+     *
+     * @param defaultWriter The default writer to use.
+     */
+    public AbstractModelBody(Writer defaultWriter) {
+        this.defaultWriter = defaultWriter;
+    }
+
+    @Override
+    public void evaluate() throws IOException {
+        evaluate(defaultWriter);
+    }
+
+    @Override
+    public String evaluateAsString() throws IOException {
+        StringWriter writer = new StringWriter();
+        try {
+            evaluate(writer);
+        } finally {
+            writer.close();
+        }
+        String body = writer.toString();
+        if (body != null) {
+            body = PATTERN.matcher(body).replaceAll("");
+            if (body.length() <= 0) {
+                body = null;
+            }
+        }
+        return body;
+    }
+
+    @Override
+    public void evaluateWithoutWriting() throws IOException {
+        NullWriter writer = new NullWriter();
+        try {
+            evaluate(writer);
+        } finally {
+            writer.close();
+        }
+    }
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java
new file mode 100644
index 000000000..4d5c818d7
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java
@@ -0,0 +1,51 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.core.runtime;
+
+/**
+ * Builder interface for creating requests.
+ * The implementations are expected to provide a default constructor,
+ * and to implement another interface that can be used to provide the
+ * parameters needed to build the actual request object.
+ */
+public interface AutotagRuntime<R> {
+    /**
+     * Creates a new Request instance.
+     *
+     * @return The Request.
+     */
+    R createRequest();
+
+    /**
+     * Creates a new ModelBody instance to match the request.
+     *
+     * @return The ModelBody.
+     */
+    ModelBody createModelBody();
+
+    /**
+     * Extracts a parameter from the tag.
+     * @param name The name of the parameter.
+     * @param defaultValue The default value if none is specified.
+     * @return The value of the parameter.
+     */
+    <T> T getParameter(String name, Class<T> type, T defaultValue);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
new file mode 100644
index 000000000..81178eedd
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.java
@@ -0,0 +1,62 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.core.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstracts a tag/directive body.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface ModelBody {
+
+    /**
+     * Evaluates a body and returns it as a string.
+     *
+     * @return The body, as a string.
+     * @throws IOException If something goes wrong.
+     */
+    String evaluateAsString() throws IOException;
+
+    /**
+     * Evaluates a body, but discards result.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    void evaluateWithoutWriting() throws IOException;
+
+    /**
+     * Evaluates the body and writes in the default writer.
+     *
+     * @throws IOException If something goes wrong.
+     */
+    void evaluate() throws IOException;
+
+    /**
+     * Evaluates the body and writes the result in the writer.
+     *
+     * @param writer The writer to write the result into.
+     * @throws IOException If something goes wrong.
+     */
+    void evaluate(Writer writer) throws IOException;
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
new file mode 100644
index 000000000..6f9c99b8c
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.core.runtime.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Specifies behaviour for a parameter of the "execute" method of a template class.
+ *
+ * @version $Rev$ $Date$
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.PARAMETER)
+public @interface Parameter {
+
+    /**
+     * Indicates to use the parameter name itself for the exported name.
+     */
+    String SAME_NAME = "USE THE SAME NAME";
+
+    /**
+     * Returns the name of the exported property name.
+     */
+    String name() default SAME_NAME;
+
+    /**
+     * Indicates that this parameter is required.
+     */
+    boolean required() default false;
+
+    /**
+     * Indicates the default value, as it will be written in Java code.
+     */
+    String defaultValue() default "null";
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java
index 38e506552..261b48ebd 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Annotations to be used in template classes.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.autotag.core.runtime.annotation;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java
index 38e506552..1e8324a66 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Runtime part for all Autotag generated code.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.autotag.core.runtime;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
similarity index 54%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
index 38e506552..6a66fb3a3 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/NullWriter.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.autotag.core.runtime.util;
+
+import java.io.Writer;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * A writer that does not write anything.
  *
- * @since Struts 2.0.2
+ * @version $Rev$ $Date$
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public class NullWriter extends Writer {
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+    /** {@inheritDoc} */
+    @Override
+    public void close() {
+        // Does nothing
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void flush() {
+        // Does nothing
+    }
 
+    /** {@inheritDoc} */
     @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    public void write(char[] cbuf, int off, int len) {
+        // Does nothing
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java
index 38e506552..7f2e35629 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/util/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Utilities for Autotag core runtime.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.autotag.core.runtime.util;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
new file mode 100644
index 000000000..f869c9526
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
@@ -0,0 +1,195 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * It represents a parsed template class.
+ *
+ * @version $Rev$ $Date$
+ */
+public class TemplateClass {
+
+    /**
+     * The class name.
+     */
+    private String name;
+
+    /**
+     * The name of the tag.
+     */
+    private String tagName;
+
+    /**
+     * The prefix of the tag class.
+     */
+    private String tagClassPrefix;
+
+    /**
+     * Documentation about this tag.
+     */
+    private String documentation;
+
+    /**
+     * The method that executes the template class.
+     */
+    private TemplateMethod executeMethod;
+
+    /**
+     * Constructor.
+     *
+     * @param name The name of the template class.
+     */
+    public TemplateClass(String name) {
+        this(name, null, null, null);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name The name of the template class.
+     * @param tagName The name of the tag.
+     * @param tagClassPrefix The tag class prefix.
+     * @param executeMethod The method that executes the template class.
+     */
+    public TemplateClass(String name, String tagName, String tagClassPrefix,
+            TemplateMethod executeMethod) {
+        this.name = name;
+        this.tagName = tagName;
+        this.tagClassPrefix = tagClassPrefix;
+        this.executeMethod = executeMethod;
+    }
+
+    /**
+     * The name of the parsed class.
+     *
+     * @return The name of the class.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the name of the class, without the package part.
+     *
+     * @return The simple class name.
+     */
+    public String getSimpleName() {
+        int pos = name.lastIndexOf('.');
+        if (pos >= 0) {
+            return name.substring(pos + 1);
+        }
+        return name;
+    }
+
+    /**
+     * Returns the tag name.
+     *
+     * @return The tag name.
+     */
+    public String getTagName() {
+        return tagName;
+    }
+
+    /**
+     * Returns the tag class prefix.
+     *
+     * @return The tag class prefix.
+     */
+    public String getTagClassPrefix() {
+        return tagClassPrefix;
+    }
+
+    /**
+     * Returns the documentation for this class.
+     *
+     * @return The documentation.
+     */
+    public String getDocumentation() {
+        return documentation;
+    }
+
+    /**
+     * Sets the documentation for this class.
+     *
+     * @param documentation The documentation.
+     */
+    public void setDocumentation(String documentation) {
+        this.documentation = documentation;
+    }
+
+    /**
+     * Returns the method that execute this class.
+     *
+     * @return The execute method.
+     */
+    public TemplateMethod getExecuteMethod() {
+        return executeMethod;
+    }
+
+    /**
+     * Returns the collection of regular parameters (no request, no body)
+     * of the execute method.
+     *
+     * @return The regular parameters.
+     */
+    public Collection<TemplateParameter> getParameters() {
+        Map<String, TemplateParameter> params = new LinkedHashMap<String, TemplateParameter>();
+        fillRegularParameters(params, executeMethod);
+        return params.values();
+    }
+
+    /**
+     * Indicates that this class needs a tag body.
+     *
+     * @return <code>true</code> if tag body is needed.
+     */
+    public boolean hasBody() {
+        return executeMethod.hasBody();
+    }
+
+    @Override
+    public String toString() {
+        return "TemplateClass [name=" + name + ", tagName=" + tagName
+                + ", tagClassPrefix=" + tagClassPrefix + ", documentation="
+                + documentation + ", executeMethod=" + executeMethod + "]";
+    }
+
+    /**
+     * Creates regular parameters map.
+     *
+     * @param params The map to fill.
+     * @param method The method to analyze.
+     */
+    private void fillRegularParameters(Map<String, TemplateParameter> params,
+            TemplateMethod method) {
+        if (method != null) {
+            for (TemplateParameter param : method.getParameters()) {
+                if (!param.isRequest() && !param.isBody()) {
+                    params.put(param.getName(), param);
+                }
+            }
+        }
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
new file mode 100644
index 000000000..d5703c54e
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
@@ -0,0 +1,131 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * It represents a parsed method in a parsed template class.
+ *
+ * @version $Rev$ $Date$
+ */
+public class TemplateMethod {
+
+    /**
+     * The name of the method.
+     */
+    private String name;
+
+    /**
+     * Documentation about the method.
+     */
+    private String documentation;
+
+    /**
+     * The map of parameters.
+     */
+    private Map<String, TemplateParameter> parameters;
+
+    /**
+     * Constructor.
+     *
+     * @param name The name of the method.
+     * @param parameters The map of parameters.
+     */
+    public TemplateMethod(String name,
+            Iterable<? extends TemplateParameter> parameters) {
+        this.name = name;
+        this.parameters = new LinkedHashMap<String, TemplateParameter>();
+        for (TemplateParameter parameter : parameters) {
+            this.parameters.put(parameter.getName(), parameter);
+        }
+    }
+
+    /**
+     * Returns the name of the method.
+     *
+     * @return The name of the method.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the documentation for this method.
+     *
+     * @return The documentation.
+     */
+    public String getDocumentation() {
+        return documentation;
+    }
+
+    /**
+     * Sets the documentation for this method.
+     *
+     * @param documentation The documentation.
+     */
+    public void setDocumentation(String documentation) {
+        this.documentation = documentation;
+    }
+
+    /**
+     * Returns the parameters of this method.
+     *
+     * @return The parameters.
+     */
+    public Collection<TemplateParameter> getParameters() {
+        return parameters.values();
+    }
+
+    /**
+     * Returns a parameter given its name.
+     *
+     * @param name The name of the parameter.
+     * @return The parameter.
+     */
+    public TemplateParameter getParameterByName(String name) {
+        return parameters.get(name);
+    }
+
+    /**
+     * Indicates that this method needs a tag body.
+     *
+     * @return <code>true</code> if tag body is needed.
+     */
+    public boolean hasBody() {
+        if (parameters.size() >= 2) {
+            for (TemplateParameter param : parameters.values()) {
+                if (param.isBody()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "TemplateMethod [name=" + name + ", documentation="
+                + documentation + ", parameters=" + parameters + "]";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
new file mode 100644
index 000000000..360e019ee
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
@@ -0,0 +1,186 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+
+/**
+ * It represents a parameter in a method in a parsed template class.
+ *
+ * @version $Rev$ $Date$
+ */
+public class TemplateParameter {
+
+    /**
+     * The name of the parameter.
+     */
+    private String name;
+
+    /**
+     * The exported name, i.e. the name of the parameter in created code. Usually
+     * helpful if this exported name is a reserved word.
+     */
+    private String exportedName;
+
+    /**
+     * The parameter documentation.
+     */
+    private String documentation;
+
+    /**
+     * The type of the parameter.
+     */
+    private String type;
+
+    /**
+     * The default value, as it will be written in Java code.
+     */
+    private String defaultValue;
+
+    /**
+     * Indicates that this parameter is required.
+     */
+    private boolean required;
+
+    /**
+     * Indicates that this parameter is the request.
+     */
+    private boolean request;
+
+    /**
+     * Constructor.
+     *
+     * @param name The name of the parameter.
+     * @param exportedName The exported name, i.e. the name of the parameter in created code. Usually
+     * helpful if this exported name is a reserved word.
+     * @param type The type of the parameter.
+     * @param defaultValue The default value, as it will be written in Java code.
+     * @param required Indicates that this parameter is required.
+     */
+    public TemplateParameter(String name, String exportedName, String type, String defaultValue, boolean required, boolean request) {
+        this.name = name;
+        this.exportedName = exportedName;
+        this.type = type;
+        this.defaultValue = defaultValue;
+        this.required = required;
+        this.request = request;
+    }
+
+    /**
+     * Returns the documentation for this parameter.
+     *
+     * @return The documentation.
+     */
+    public String getDocumentation() {
+        return documentation;
+    }
+
+    /**
+     * Sets the documentation for this parameter.
+     *
+     * @param documentation The documentation.
+     */
+    public void setDocumentation(String documentation) {
+        this.documentation = documentation;
+    }
+
+    /**
+     * Returns the name of the parameter.
+     *
+     * @return The name of the parameter.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the exported name, i.e. the name of the parameter in created code. Usually
+     * helpful if this exported name is a reserved word.
+     *
+     * @return The exported name.
+     */
+    public String getExportedName() {
+        return exportedName;
+    }
+
+    /**
+     * Returns the type of the parameter.
+     *
+     * @return The type.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Returns the default value, as it will be written in Java code.
+     *
+     * @return The default value.
+     */
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Indicates that this parameter is required.
+     *
+     * @return <code>true</code> if the parameter is required.
+     */
+    public boolean isRequired() {
+        return required;
+    }
+
+    /**
+     * Indicates that this parameter implements {@link ModelBody}.
+     *
+     * @return <code>true</code> if the parameter is a body.
+     */
+    public boolean isBody() {
+        return ModelBody.class.getName().equals(type);
+    }
+
+    /**
+     * Indicates that this parameter implements {@link Request}.
+     *
+     * @return <code>true</code> if the parameter is a request.
+     */
+    public boolean isRequest() {
+        return request;
+    }
+
+    /**
+     * Returns the suffix for getter and setter of the property generated by
+     * this parameter.
+     *
+     * @return The getter and setter suffix.
+     */
+    public String getGetterSetterSuffix() {
+        return exportedName.substring(0, 1).toUpperCase() + exportedName.substring(1);
+    }
+
+    @Override
+    public String toString() {
+        return "TemplateParameter [name=" + name + ", exportedName="
+                + exportedName + ", documentation=" + documentation + ", type="
+                + type + ", defaultValue=" + defaultValue + ", required="
+                + required + ", request=" + request + "]";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
new file mode 100644
index 000000000..25361c866
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.java
@@ -0,0 +1,129 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.autotag.model;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * It represents a suite of template classes.
+ *
+ * @version $Rev$ $Date$
+ */
+public class TemplateSuite {
+
+    /**
+     * The name of the suite.
+     */
+    private String name;
+
+    /**
+     * The documentation of this suite.
+     */
+    private String documentation;
+
+    /**
+     * The map of template classes.
+     */
+    private Map<String, TemplateClass> templateClasses;
+
+    /**
+     * Constructor.
+     *
+     * @param name The name of the suite.
+     * @param documentation The documentation.
+     */
+    public TemplateSuite(String name, String documentation) {
+        this(name, documentation, null);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name The name of the suite.
+     * @param documentation The documentation.
+     * @param classes The template classes.
+     */
+    public TemplateSuite(String name, String documentation,
+            Iterable<? extends TemplateClass> classes) {
+        this.name = name;
+        this.documentation = documentation;
+        templateClasses = new LinkedHashMap<String, TemplateClass>();
+        if (classes != null) {
+            for (TemplateClass templateClass : classes) {
+                templateClasses.put(templateClass.getName(), templateClass);
+            }
+        }
+    }
+
+    /**
+     * Returns the template suite name.
+     *
+     * @return The name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the documentation.
+     *
+     * @return The documentation.
+     */
+    public String getDocumentation() {
+        return documentation;
+    }
+
+    /**
+     * Adds a new template class.
+     *
+     * @param clazz The template class.
+     */
+    public void addTemplateClass(TemplateClass clazz) {
+        templateClasses.put(clazz.getName(), clazz);
+    }
+
+    /**
+     * Returns the template classes.
+     *
+     * @return The template classes.
+     */
+    public Collection<TemplateClass> getTemplateClasses() {
+        return templateClasses.values();
+    }
+
+    /**
+     * Returns a template class given its name.
+     *
+     * @param name The name of the class.
+     * @return The template class instance.
+     */
+    public TemplateClass getTemplateClassByName(String name) {
+        return templateClasses.get(name);
+    }
+
+    @Override
+    public String toString() {
+        return "TemplateSuite [name=" + name + ", documentation="
+                + documentation + ", templateClasses=" + templateClasses + "]";
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java
index 38e506552..a1130d2aa 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Domain model classes representing a parsed template suite.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.autotag.model;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
new file mode 100644
index 000000000..150d66294
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactory.java
@@ -0,0 +1,79 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.request.Request;
+
+/**
+ * Interface for creating a {@link Definition}s and managing their contents.
+ * <p/>
+ * <p>
+ * DefinitionsFactory implementations are responsible for maintaining the data
+ * sources of Tiles configuration data and using the data to create Definitions
+ * sets. Implementations also know how to append locale-specific configuration
+ * data to an existing Definitions set.
+ * </p>
+ *
+ * @version $Rev$ $Date$
+ */
+public interface DefinitionsFactory {
+
+    /**
+     * Property name that specifies the implementation of the DefinitionsReader.
+     */
+    String READER_IMPL_PROPERTY =
+        "org.apache.tiles.definition.DefinitionsReader";
+
+    /**
+     * Property name that specifies the implementation of
+     * {@link org.apache.tiles.core.locale.LocaleResolver}.
+     */
+    String LOCALE_RESOLVER_IMPL_PROPERTY =
+        "org.apache.tiles.locale.LocaleResolver";
+
+    /**
+     * Constant representing the configuration parameter
+     * used to define the tiles definition resources.
+     *
+     * @since 2.1.0
+     */
+    String DEFINITIONS_CONFIG = "org.apache.tiles.definition.DefinitionsFactory.DEFINITIONS_CONFIG";
+
+    /**
+     * Constant representing the configuration parameter used to define the
+     * definition DAO to use.
+     */
+    String DEFINITION_DAO_INIT_PARAM =
+        "org.apache.tiles.definition.DefinitionsFactory.DefinitionDAO";
+
+    /**
+     * Returns a Definition object that matches the given name and
+     * Tiles context.
+     *
+     * @param name         The name of the Definition to return.
+     * @param tilesContext The Tiles context to use to resolve the definition.
+     * @return the Definition matching the given name or null if none
+     *         is found.
+     */
+    Definition getDefinition(String name, Request tilesContext);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java
new file mode 100644
index 000000000..cc7468e3f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsFactoryException.java
@@ -0,0 +1,74 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition;
+
+import org.apache.tiles.api.TilesException;
+
+/**
+ * Exception thrown when an error occurs while the impl tries to
+ * create a new instance mapper.
+ */
+public class DefinitionsFactoryException extends TilesException {
+
+    /**
+     * Constructor.
+     */
+    public DefinitionsFactoryException() {
+        super();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message The error or warning message.
+     */
+    public DefinitionsFactoryException(String message) {
+        super(message);
+    }
+
+
+    /**
+     * Create a new <code>DefinitionsFactoryException</code> wrapping an existing exception.
+     * <p/>
+     * <p>The existing exception will be embedded in the new
+     * one and its message will become the default message for
+     * the DefinitionsFactoryException.</p>
+     *
+     * @param e The exception to be wrapped.
+     */
+    public DefinitionsFactoryException(Throwable e) {
+        super(e);
+    }
+
+
+    /**
+     * Create a new <code>DefinitionsFactoryException</code> from an existing exception.
+     * <p/>
+     * <p>The existing exception will be embedded in the new
+     * one, but the new exception will have its own message.</p>
+     *
+     * @param message The detail message.
+     * @param e       The exception to be wrapped.
+     */
+    public DefinitionsFactoryException(String message, Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
new file mode 100644
index 000000000..3369f6aa0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/DefinitionsReader.java
@@ -0,0 +1,54 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition;
+
+import org.apache.tiles.api.Definition;
+
+import java.util.Map;
+
+/**
+ * Interface for reading <code>{@link Definition}</code> from a source.
+ * <p/>
+ * <p>This interface provides a standard way to read
+ * <code>{@link Definition}</code> objects from a source.  Implementations
+ * should define what the source is, whether it be a persistent store such as a
+ * configuration file or database, or something like a web service.  The
+ * DefinitionsReader is responsible for reading from a single location.  It does
+ * not perform any internationalization duties or inheritance of Definitions.
+ * It only reads from the source and returns a Map of objects read.</p>
+ */
+public interface DefinitionsReader {
+
+    /**
+     * Reads <code>{@link Definition}</code> objects from a source.
+     * <p/>
+     * Implementations should publish what type of source object is expected.
+     *
+     * @param source The source from which definitions will be read.
+     * @return a Map of <code>Definition</code> objects read from
+     * the source.
+     * @throws DefinitionsFactoryException if the source is invalid or
+     *                                     an error occurs when reading definitions.
+     */
+    Map<String, Definition> read(Object source);
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
index 38e506552..460dcd78b 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/NoSuchDefinitionException.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.core.definition;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Exception thrown when a definition is not found.
  *
- * @since Struts 2.0.2
+ * @version $Rev$ $Date$
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public class NoSuchDefinitionException extends DefinitionsFactoryException {
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * Constructor.
+     *
+     * @param msg Message.
+     */
+    public NoSuchDefinitionException(String msg) {
+        super(msg);
     }
-}
\ No newline at end of file
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java
index 38e506552..bcd5569d9 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/RefreshMonitor.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.core.definition;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Implementing this interface means that the object monitors the sources it
+ * uses to check when they change.
  *
- * @since Struts 2.0.2
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface RefreshMonitor {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Indicates whether the sources are out of date and need to be reloaded.
+     *
+     * @return <code>true</code> if the sources need to be refreshed.
+     * @since 2.1.0
+     */
+    boolean refreshRequired();
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
new file mode 100644
index 000000000..4fac31f71
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/UnresolvingLocaleDefinitionsFactory.java
@@ -0,0 +1,90 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.core.definition.dao.DefinitionDAO;
+import org.apache.tiles.core.locale.LocaleResolver;
+
+import java.util.Locale;
+
+/**
+ * {@link DefinitionsFactory DefinitionsFactory} implementation that manages
+ * Definitions configuration data from URLs, without resolving definition
+ * inheritance when a definition is returned.<p/>
+ * <p>
+ * The Definition objects are read from the
+ * {@link org.apache.tiles.core.definition.digester.DigesterDefinitionsReader}
+ * class unless another implementation is specified.
+ * </p>
+ *
+ * @version $Rev$ $Date$
+ * @since 2.2.1
+ */
+public class UnresolvingLocaleDefinitionsFactory implements DefinitionsFactory {
+
+    /**
+     * The definition DAO that extracts the definitions from the sources.
+     *
+     * @since 2.2.1
+     */
+    protected DefinitionDAO<Locale> definitionDao;
+
+    /**
+     * The locale resolver object.
+     *
+     * @since 2.2.1
+     */
+    protected LocaleResolver localeResolver;
+
+    /**
+     * Sets the locale resolver to use.
+     *
+     * @param localeResolver The locale resolver.
+     * @since 2.2.1
+     */
+    public void setLocaleResolver(LocaleResolver localeResolver) {
+        this.localeResolver = localeResolver;
+    }
+
+    /**
+     * Sets the definition DAO to use. It must be locale-based.
+     *
+     * @param definitionDao The definition DAO.
+     * @since 2.2.1
+     */
+    public void setDefinitionDAO(DefinitionDAO<Locale> definitionDao) {
+        this.definitionDao = definitionDao;
+    }
+
+    /** {@inheritDoc} */
+    public Definition getDefinition(String name, Request tilesContext) {
+        Locale locale = null;
+
+        if (tilesContext != null) {
+            locale = localeResolver.resolveLocale(tilesContext);
+        }
+
+        return definitionDao.getDefinition(name, locale);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
new file mode 100644
index 000000000..d5766fc7d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/BaseLocaleUrlDefinitionDAO.java
@@ -0,0 +1,164 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.dao;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.DefinitionsFactoryException;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.apache.tiles.core.definition.RefreshMonitor;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Base abstract class for a DAO that is based on URLs and locale as a
+ * customization key.
+ *
+ * @since 2.1.0
+ */
+public abstract class BaseLocaleUrlDefinitionDAO implements DefinitionDAO<Locale>, RefreshMonitor {
+
+    /**
+     * The logging object.
+     */
+    private static final Logger LOG = LogManager.getLogger(BaseLocaleUrlDefinitionDAO.class);
+
+    /**
+     * Contains the URL objects identifying where configuration data is found.
+     *
+     * @since 2.1.0
+     */
+    protected List<ApplicationResource> sources;
+
+    /**
+     * Contains the dates that the URL sources were last modified.
+     *
+     * @since 2.1.0
+     */
+    protected Map<String, Long> lastModifiedDates;
+
+    /**
+     * Reader used to get definitions from the sources.
+     *
+     * @since 2.1.0
+     */
+    protected DefinitionsReader reader;
+
+    /**
+     * ApplicationContext to locate the source files.
+     *
+     * @since 3.0.0
+     */
+    protected ApplicationContext applicationContext;
+
+    /**
+     * Constructor.
+     */
+    public BaseLocaleUrlDefinitionDAO(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+        lastModifiedDates = new HashMap<>();
+    }
+
+    public void setSources(List<ApplicationResource> sources) {
+        // filter out any sources that are already localized
+        ArrayList<ApplicationResource> defaultSources = new ArrayList<>();
+        for(ApplicationResource source: sources) {
+            if(Locale.ROOT.equals(source.getLocale())) {
+                defaultSources.add(source);
+            }
+        }
+        this.sources = defaultSources;
+    }
+
+    public void setReader(DefinitionsReader reader) {
+        this.reader = reader;
+    }
+
+    /** {@inheritDoc} */
+    public boolean refreshRequired() {
+        boolean status = false;
+
+        Set<String> paths = lastModifiedDates.keySet();
+
+        try {
+            for (String path : paths) {
+                Long lastModifiedDate = lastModifiedDates.get(path);
+                ApplicationResource resource = applicationContext.getResource(path);
+                long newModDate = resource.getLastModified();
+                if (newModDate != lastModifiedDate) {
+                    status = true;
+                    break;
+                }
+            }
+        } catch (IOException e) {
+            LOG.warn("Exception while monitoring update times.", e);
+            return true;
+        }
+        return status;
+    }
+
+    /**
+     * Loads definitions from an URL without loading from "parent" URLs.
+     *
+     * @param resource The URL to read.
+     * @return The definition map that has been read.
+     */
+    protected Map<String, Definition> loadDefinitionsFromResource(ApplicationResource resource) {
+        Map<String, Definition> defsMap = null;
+
+        InputStream stream = null;
+        try {
+            lastModifiedDates.put(resource.getLocalePath(), resource
+                    .getLastModified());
+
+            // Definition must be collected, starting from the base
+            // source up to the last localized file.
+            stream = resource.getInputStream();
+            defsMap = reader.read(stream);
+        } catch (FileNotFoundException e) {
+            // File not found. continue.
+            LOG.debug("File {} not found, continue", resource);
+        } catch (IOException e) {
+            throw new DefinitionsFactoryException("I/O error processing configuration.", e);
+        } finally {
+            try {
+                if (stream != null) {
+                    stream.close();
+                }
+            } catch (IOException e) {
+                throw new DefinitionsFactoryException("I/O error closing " + resource, e);
+            }
+        }
+
+        return defsMap;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java
new file mode 100644
index 000000000..84c44f949
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/CachingLocaleUrlDefinitionDAO.java
@@ -0,0 +1,275 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.dao;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolverAware;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.locale.LocaleUtil;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * <p>
+ * A definitions DAO (loading URLs and using Locale as a customization key) that
+ * caches definitions that have been loaded in a raw way (i.e. with inheritance
+ * that is not resolved).
+ * </p>
+ * <p>
+ * It can check if the URLs change, but by default this feature is turned off.
+ * </p>
+ *
+ * @since 2.1.0
+ */
+public class CachingLocaleUrlDefinitionDAO extends BaseLocaleUrlDefinitionDAO implements PatternDefinitionResolverAware<Locale> {
+
+    /**
+     * Initialization parameter to set whether we want to refresh URLs when they
+     * change.
+     *
+     * @since 2.1.0
+     */
+    public static final String CHECK_REFRESH_INIT_PARAMETER = "org.apache.tiles.definition.dao.LocaleUrlDefinitionDAO.CHECK_REFRESH";
+
+    /**
+     * The locale-specific set of definitions objects.
+     *
+     * @since 2.1.0
+     */
+    protected Map<Locale, Map<String, Definition>> locale2definitionMap;
+
+    /**
+     * Flag that, when <code>true</code>, enables automatic checking of URLs
+     * changing.
+     *
+     * @since 2.1.0
+     */
+    protected boolean checkRefresh = false;
+
+    /**
+     * Resolves definitions using patterns.
+     *
+     * @since 2.2.0
+     */
+    protected PatternDefinitionResolver<Locale> definitionResolver;
+
+    /**
+     * Constructor.
+     *
+     * @since 2.1.0
+     */
+    public CachingLocaleUrlDefinitionDAO(ApplicationContext applicationContext) {
+        super(applicationContext);
+        locale2definitionMap = new HashMap<>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setPatternDefinitionResolver(
+        PatternDefinitionResolver<Locale> definitionResolver) {
+        this.definitionResolver = definitionResolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Definition getDefinition(String name, Locale customizationKey) {
+        Definition retValue = null;
+        if (customizationKey == null) {
+            customizationKey = Locale.ROOT;
+        }
+        Map<String, Definition> definitions = getDefinitions(customizationKey);
+        if (definitions != null) {
+            retValue = definitions.get(name);
+
+            if (retValue == null) {
+                retValue = getDefinitionFromResolver(name, customizationKey);
+
+                if (retValue != null) {
+                    synchronized (definitions) {
+                        definitions.put(name, retValue);
+                    }
+                }
+            }
+        }
+
+        return retValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Definition> getDefinitions(Locale customizationKey) {
+        if (customizationKey == null) {
+            customizationKey = Locale.ROOT;
+        }
+        Map<String, Definition> retValue = locale2definitionMap
+            .get(customizationKey);
+        if (retValue == null || (checkRefresh && refreshRequired())) {
+            retValue = checkAndloadDefinitions(customizationKey);
+        }
+        return retValue;
+    }
+
+    /**
+     * Sets the flag to check source refresh. If not called, the default is
+     * <code>false</code>.
+     *
+     * @param checkRefresh When <code>true</code>, enables automatic checking
+     *                     of sources changing.
+     * @since 2.1.0
+     */
+    public void setCheckRefresh(boolean checkRefresh) {
+        this.checkRefresh = checkRefresh;
+    }
+
+    /**
+     * Returns a definition from the definition resolver.
+     *
+     * @param name             The name of the definition.
+     * @param customizationKey The customization key to use.
+     * @return The resolved definition.
+     */
+    protected Definition getDefinitionFromResolver(String name,
+                                                   Locale customizationKey) {
+        return definitionResolver.resolveDefinition(name,
+            customizationKey);
+    }
+
+    /**
+     * Checks if sources have changed. If yes, it clears the cache. Then continues
+     * loading definitions.
+     *
+     * @param customizationKey The locale to use when loading sources.
+     * @return The loaded definitions.
+     * @since 2.1.0
+     */
+    protected synchronized Map<String, Definition> checkAndloadDefinitions(Locale customizationKey) {
+        Map<String, Definition> existingDefinitions = locale2definitionMap.get(customizationKey);
+        boolean definitionsAlreadyLoaded = existingDefinitions != null;
+        if (definitionsAlreadyLoaded) {
+            return existingDefinitions;
+        }
+        if (checkRefresh && refreshRequired()) {
+            locale2definitionMap.clear();
+            definitionResolver.clearPatternPaths(customizationKey);
+        }
+        loadDefinitions(customizationKey);
+        return locale2definitionMap.get(customizationKey);
+    }
+
+    /**
+     * Tries to load definitions if necessary.
+     *
+     * @param customizationKey The locale to use when loading sources.
+     * @return The loaded definitions.
+     * @since 2.1.0
+     */
+    protected Map<String, Definition> loadDefinitions(Locale customizationKey) {
+        Map<String, Definition> localeDefsMap = locale2definitionMap
+            .get(customizationKey);
+        if (localeDefsMap != null) {
+            return localeDefsMap;
+        }
+
+        return loadDefinitionsFromResources(customizationKey);
+    }
+
+    /**
+     * Loads definitions from the sources.
+     *
+     * @param customizationKey The locale to use when loading Resources.
+     * @return The loaded definitions.
+     * @since 2.1.0
+     */
+    protected Map<String, Definition> loadDefinitionsFromResources(Locale customizationKey) {
+        Map<String, Definition> localeDefsMap = loadRawDefinitionsFromResources(customizationKey);
+        Map<String, Definition> defsMap = definitionResolver
+            .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap),
+                customizationKey);
+        locale2definitionMap.put(customizationKey, defsMap);
+        return localeDefsMap;
+    }
+
+    /**
+     * Loads the raw definitions from the sources associated with a locale.
+     *
+     * @param customizationKey The locale to use when loading Resources.
+     * @return The loaded definitions.
+     * @since 2.1.3
+     */
+    protected Map<String, Definition> loadRawDefinitionsFromResources(
+        Locale customizationKey) {
+        Map<String, Definition> localeDefsMap;
+
+        Locale parentLocale = LocaleUtil.getParentLocale(customizationKey);
+        localeDefsMap = new LinkedHashMap<>();
+        if (parentLocale != null) {
+            Map<String, Definition> parentDefs = loadRawDefinitionsFromResources(parentLocale);
+            if (parentDefs != null) {
+                localeDefsMap.putAll(parentDefs);
+            }
+        }
+        // For each source, the resource must be loaded.
+        for (ApplicationResource resource : sources) {
+            ApplicationResource newResource = applicationContext.getResource(resource, customizationKey);
+            if (newResource != null) {
+                Map<String, Definition> defsMap = loadDefinitionsFromResource(newResource);
+                if (defsMap != null) {
+                    localeDefsMap.putAll(defsMap);
+                }
+            }
+        }
+        return localeDefsMap;
+    }
+
+    /**
+     * Loads parent definitions, i.e. definitions mapped to a parent locale.
+     *
+     * @param parentLocale The locale to use when loading URLs.
+     * @return The loaded parent definitions.
+     * @since 2.1.0
+     */
+    protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
+        return loadDefinitions(parentLocale);
+    }
+
+    /**
+     * Copies the definition map to be passed to a higher level of customization
+     * key.
+     *
+     * @param localeDefsMap The map of definition to be copied.
+     * @return The copy of the definition map. This particular implementation
+     * return the <code>localeDefsMap</code> itself.
+     * @since 2.1.4
+     */
+    protected Map<String, Definition> copyDefinitionMap(
+        Map<String, Definition> localeDefsMap) {
+        return localeDefsMap;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
new file mode 100644
index 000000000..e42772fe6
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/DefinitionDAO.java
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.dao;
+
+import org.apache.tiles.api.Definition;
+
+import java.util.Map;
+
+/**
+ * It represents an object that provides definitions, depending on a
+ * customization key.
+ *
+ * @param <K> The customization key class.
+ * @version $Rev$ $Date$
+ * @since 2.1.0
+ */
+public interface DefinitionDAO<K> {
+
+    /**
+     * Returns a definition, given its name and the customization key.
+     *
+     * @param name The name of the definition.
+     * @param customizationKey The customization key.
+     * @return The requested definition, if found, otherwise <code>null</code>.
+     * The inheritance of the definition must not be resolved.
+     * @since 2.1.0
+     */
+    Definition getDefinition(String name, K customizationKey);
+
+    /**
+     * Returns all the definitions used of a customization key.
+     *
+     * @param customizationKey The customization key.
+     * @return All the definitions that are connected to the customization key.
+     * The inheritance of the definitions must not be resolved.
+     * @since 2.1.0
+     */
+    Map<String, Definition> getDefinitions(K customizationKey);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java
new file mode 100644
index 000000000..df7eef304
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/ResolvingLocaleUrlDefinitionDAO.java
@@ -0,0 +1,174 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.dao;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.NoSuchDefinitionException;
+import org.apache.tiles.request.ApplicationContext;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>
+ * A definitions DAO (loading URLs and using Locale as a customization key) that
+ * caches definitions that have been loaded and resolves inheritances.
+ * </p>
+ * <p>
+ * It can check if the URLs change, but by default this feature is turned off.
+ * </p>
+ *
+ * @since 2.1.0
+ */
+public class ResolvingLocaleUrlDefinitionDAO extends CachingLocaleUrlDefinitionDAO {
+
+    /**
+     * The logging object.
+     */
+    private static final Logger LOG = LogManager.getLogger(ResolvingLocaleUrlDefinitionDAO.class);
+
+    public ResolvingLocaleUrlDefinitionDAO(ApplicationContext applicationContext) {
+        super(applicationContext);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
+        return loadRawDefinitionsFromResources(parentLocale);
+    }
+
+    @Override
+    protected Map<String, Definition> loadDefinitions(Locale customizationKey) {
+        Map<String, Definition> localeDefsMap = super.loadDefinitions(customizationKey);
+        Map<String, Definition> defsMap = definitionResolver
+                .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap),
+                        customizationKey);
+        resolveInheritances(defsMap, customizationKey);
+        locale2definitionMap.put(customizationKey, defsMap);
+        return defsMap;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Definition getDefinitionFromResolver(String name,
+            Locale customizationKey) {
+        Definition retValue = super.getDefinitionFromResolver(name, customizationKey);
+        if (retValue != null && retValue.getExtends() != null) {
+            Definition parent = getDefinition(retValue.getExtends(), customizationKey);
+            retValue.inherit(parent);
+        }
+
+        return retValue;
+    }
+
+    /**
+     * Resolve locale-specific extended instances.
+     *
+     * @param map The definition map containing the definitions to resolve.
+     * @param locale The locale to use.
+     * @throws NoSuchDefinitionException If a parent definition is not found.
+     * @since 2.1.0
+     */
+    protected void resolveInheritances(Map<String, Definition> map, Locale locale) {
+        if (map != null) {
+            Set<String> alreadyResolvedDefinitions = new HashSet<>();
+            for (Definition definition : map.values()) {
+                resolveInheritance(definition, map, locale,
+                        alreadyResolvedDefinitions);
+            }  // end loop
+        }
+    }
+
+    /**
+     * Resolve locale-specific inheritance. First, resolve parent's inheritance,
+     * then set template to the parent's template. Also copy attributes setted
+     * in parent, and not set in child If instance doesn't extend anything, do
+     * nothing.
+     *
+     * @param definition The definition to resolve
+     * @param definitions The definitions to take when obtaining a parent
+     * definition.
+     * @param locale The locale to use.
+     * @param alreadyResolvedDefinitions The set of the definitions that have
+     * been already resolved.
+     * @throws NoSuchDefinitionException If an inheritance can not be solved.
+     * @since 2.1.0
+     */
+    protected void resolveInheritance(Definition definition,
+            Map<String, Definition> definitions, Locale locale,
+            Set<String> alreadyResolvedDefinitions) {
+        // Already done, or not needed ?
+        if (!definition.isExtending() || alreadyResolvedDefinitions.contains(definition.getName())) {
+            return;
+        }
+
+        LOG.debug("Resolve definition for child name='{}' extends='{}.", definition.getName(), definition.getExtends());
+
+        // Set as visited to avoid endless recursivity.
+        alreadyResolvedDefinitions.add(definition.getName());
+
+        // Resolve parent before itself.
+        Definition parent = definitions.get(definition.getExtends());
+        if (parent == null) { // error
+            String msg = "Error while resolving definition inheritance: child '"
+                + definition.getName()
+                + "' can't find its ancestor '"
+                + definition.getExtends()
+                + "'. Please check your description file.";
+            // to do : find better exception
+            throw new NoSuchDefinitionException(msg);
+        }
+
+        resolveInheritance(parent, definitions, locale,
+                alreadyResolvedDefinitions);
+
+        definition.inherit(parent);
+    }
+
+    /**
+     * Copies the definition map to be passed to a higher level of customization
+     * key.
+     *
+     * @param localeDefsMap The map of definition to be copied.
+     * @return The copy of the definition map. This particular implementation
+     * deep-copies the <code>localeDefsMap</code> into a {@link LinkedHashMap}.
+     * @since 2.1.4
+     */
+    @Override
+    protected Map<String, Definition> copyDefinitionMap(
+            Map<String, Definition> localeDefsMap) {
+        Map<String, Definition> retValue = new LinkedHashMap<>(
+            localeDefsMap.size());
+
+        for (Map.Entry<String, Definition> entry : localeDefsMap.entrySet()) {
+            Definition definition = new Definition(entry.getValue());
+            retValue.put(entry.getKey(), definition);
+        }
+
+        return retValue;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java
index 38e506552..225d581ba 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/dao/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Classes to simply load definitions depending on a customization key.
+ * The package contains also basic implementations.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.definition.dao;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
new file mode 100644
index 000000000..9fd3700f0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java
@@ -0,0 +1,468 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.digester;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.core.definition.DefinitionsFactoryException;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.xml.sax.Attributes;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Reads {@link Definition} objects from
+ * an XML InputStream using Digester. <p/>
+ * <p>
+ * This <code>DefinitionsReader</code> implementation expects the source to be
+ * passed as an <code>InputStream</code>. It parses XML data from the source
+ * and builds a Map of Definition objects.
+ * </p>
+ * <p/>
+ * <p>
+ * The Digester object can be configured by passing in initialization
+ * parameters. Currently the only parameter that is supported is the
+ * <code>validating</code> parameter. This value is set to <code>false</code>
+ * by default. To enable DTD validation for XML Definition files, give the init
+ * method a parameter with a key of
+ * <code>org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE</code>
+ * and a value of <code>&quot;true&quot;</code>. <p/>
+ * <p>
+ * The Definition objects are stored internally in a Map. The Map is stored as
+ * an instance variable rather than a local variable in the <code>read</code>
+ * method. This means that instances of this class are <strong>not</strong>
+ * thread-safe and access by multiple threads must be synchronized.
+ * </p>
+ *
+ * @version $Rev$ $Date$
+ */
+public class DigesterDefinitionsReader implements DefinitionsReader {
+
+    /**
+     * Digester validation parameter name.
+     */
+    public static final String PARSER_VALIDATE_PARAMETER_NAME = "org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE";
+
+    // Digester rules constants for tag interception.
+
+    /**
+     * Intercepts a &lt;definition&gt; tag.
+     */
+    private static final String DEFINITION_TAG = "tiles-definitions/definition";
+
+    /**
+     * Intercepts a &lt;put-attribute&gt; tag.
+     */
+    private static final String PUT_TAG = "*/definition/put-attribute";
+
+    /**
+     * Intercepts a &lt;definition&gt; inside a  &lt;put-attribute&gt; tag.
+     */
+    private static final String PUT_DEFINITION_TAG = "*/put-attribute/definition";
+
+    /**
+     * Intercepts a &lt;definition&gt; inside an &lt;add-attribute&gt; tag.
+     */
+    private static final String ADD_DEFINITION_TAG = "*/add-attribute/definition";
+
+    /**
+     * Intercepts a &lt;put-list-attribute&gt; tag inside a %lt;definition&gt;
+     * tag.
+     */
+    private static final String DEF_LIST_TAG = "*/definition/put-list-attribute";
+
+    /**
+     * Intercepts a &lt;add-attribute&gt; tag.
+     */
+    private static final String ADD_LIST_ELE_TAG = "*/add-attribute";
+
+    /**
+     * Intercepts a &lt;add-list-attribute&gt; tag.
+     */
+    private static final String NESTED_LIST = "*/add-list-attribute";
+
+    // Handler class names.
+
+    /**
+     * The handler to create definitions.
+     *
+     * @since 2.1.0
+     */
+    protected static final String DEFINITION_HANDLER_CLASS =
+        Definition.class.getName();
+
+    /**
+     * The handler to create attributes.
+     *
+     * @since 2.1.0
+     */
+    protected static final String PUT_ATTRIBUTE_HANDLER_CLASS =
+        Attribute.class.getName();
+
+    /**
+     * The handler to create list attributes.
+     *
+     * @since 2.1.0
+     */
+    protected static final String LIST_HANDLER_CLASS =
+        ListAttribute.class.getName();
+
+    /**
+     * Digester rule to manage definition filling.
+     *
+     * @since 2.1.2
+     */
+    public static class FillDefinitionRule extends Rule {
+
+        /** {@inheritDoc} */
+        @Override
+        public void begin(String namespace, String name, Attributes attributes) {
+            Definition definition = (Definition) digester.peek();
+            definition.setName(attributes.getValue("name"));
+            definition.setPreparer(attributes.getValue("preparer"));
+            String extendsAttribute = attributes.getValue("extends");
+            definition.setExtends(extendsAttribute);
+
+            String template = attributes.getValue("template");
+            Attribute attribute = Attribute.createTemplateAttribute(template);
+            attribute.setExpressionObject(Expression
+                    .createExpressionFromDescribedExpression(attributes
+                            .getValue("templateExpression")));
+            attribute.setRole(attributes.getValue("role"));
+            String templateType = attributes.getValue("templateType");
+            if (templateType != null) {
+                attribute.setRenderer(templateType);
+            } else if (extendsAttribute != null) {
+                attribute.setRenderer(null);
+            }
+            definition.setTemplateAttribute(attribute);
+        }
+    }
+
+    /**
+     * Digester rule to manage attribute filling.
+     *
+     * @since 2.1.0
+     */
+    public static class FillAttributeRule extends Rule {
+
+        /** {@inheritDoc} */
+        @Override
+        public void begin(String namespace, String name, Attributes attributes) {
+            Attribute attribute = (Attribute) digester.peek();
+            attribute.setValue(attributes.getValue("value"));
+            String expression = attributes.getValue("expression");
+            attribute.setExpressionObject(Expression
+                    .createExpressionFromDescribedExpression(expression));
+            attribute.setRole(attributes.getValue("role"));
+            attribute.setRenderer(attributes.getValue("type"));
+        }
+    }
+
+    /**
+     * Digester rule to manage assignment of the attribute to the parent
+     * element.
+     *
+     * @since 2.1.0
+     */
+    public static class PutAttributeRule extends Rule {
+
+        /** {@inheritDoc} */
+        @Override
+        public void begin(String namespace, String name, Attributes attributes) {
+            Attribute attribute = (Attribute) digester.peek(0);
+            Definition definition = (Definition) digester.peek(1);
+            definition.putAttribute(attributes.getValue("name"), attribute,
+                    "true".equals(attributes.getValue("cascade")));
+        }
+    }
+
+    /**
+     * Digester rule to manage assignment of a nested definition in an attribute
+     * value.
+     *
+     * @since 2.1.0
+     */
+    public class AddNestedDefinitionRule extends Rule {
+
+        /** {@inheritDoc} */
+        @Override
+        public void begin(String namespace, String name, Attributes attributes) {
+            Definition definition = (Definition) digester.peek(0);
+            if (definition.getName() == null) {
+                definition.setName(getNextUniqueDefinitionName(definitions));
+            }
+            Attribute attribute = (Attribute) digester.peek(1);
+            attribute.setValue(definition.getName());
+            attribute.setRenderer("definition");
+        }
+    }
+
+    /**
+     * <code>Digester</code> object used to read Definition data
+     * from the source.
+     */
+    protected Digester digester;
+
+    /**
+     * The set of public identifiers, and corresponding resource names for
+     * the versions of the configuration file DTDs we know about.  There
+     * <strong>MUST</strong> be an even number of Strings in this list!
+     */
+    protected String[] registrations;
+
+    /**
+     * Stores Definition objects.
+     */
+    private Map<String, Definition> definitions;
+
+    /**
+     * Index to be used to create unique definition names for anonymous
+     * (nested) definitions.
+     */
+    private int anonymousDefinitionIndex = 1;
+
+    /**
+     * Creates a new instance of DigesterDefinitionsReader.
+     */
+    public DigesterDefinitionsReader() {
+        digester = new Digester();
+        digester.setNamespaceAware(true);
+        digester.setUseContextClassLoader(true);
+        digester.setErrorHandler(new ThrowingErrorHandler());
+
+        // Register our local copy of the DTDs that we can find
+        String[] registrations = getRegistrations();
+        for (int i = 0; i < registrations.length; i += 2) {
+            URL url = this.getClass().getResource(
+                registrations[i + 1]);
+            if (url != null) {
+                digester.register(registrations[i], url.toString());
+            }
+        }
+
+        initSyntax(digester);
+    }
+
+    /**
+     * Sets the validation of XML files.
+     *
+     * @param validating <code>true</code> means that XML validation is turned
+     * on. <code>false</code> otherwise.
+     * @since 3.3.0
+     */
+    public void setValidating(boolean validating) {
+        digester.setValidating(validating);
+    }
+
+    /**
+     * Reads <code>{@link Definition}</code> objects from a source.
+     * <p/>
+     * Implementations should publish what type of source object is expected.
+     *
+     * @param source The <code>InputStream</code> source from which definitions
+     *               will be read.
+     * @return a Map of <code>Definition</code> objects read from
+     *         the source.
+     * @throws DefinitionsFactoryException If the source is invalid or
+     *          an error occurs when reading definitions.
+     */
+    public Map<String, Definition> read(Object source) {
+        // This is an instance variable instead of a local variable because
+        // we want to be able to call the addDefinition method to populate it.
+        // But we reset the Map here, which, of course, has threading implications.
+        definitions = new LinkedHashMap<>();
+
+        if (source == null) {
+            // Perhaps we should throw an exception here.
+            return null;
+        }
+
+        InputStream input;
+        try {
+            input = (InputStream) source;
+        } catch (ClassCastException e) {
+            throw new DefinitionsFactoryException(
+                "Invalid source type.  Requires java.io.InputStream.", e);
+        }
+
+        try {
+            // set first object in stack
+            //digester.clear();
+            digester.push(this);
+            // parse
+            digester.parse(input);
+
+        } catch (SAXException e) {
+            throw new DefinitionsFactoryException(
+                "XML error reading definitions.", e);
+        } catch (IOException e) {
+            throw new DefinitionsFactoryException(
+                "I/O Error reading definitions.", e);
+        } finally {
+            digester.clear();
+        }
+
+        return definitions;
+    }
+
+    /**
+     * Initialised the syntax for reading XML files containing Tiles
+     * definitions.
+     *
+     * @param digester The digester to initialize.
+     */
+    protected void initSyntax(Digester digester) {
+        initDigesterForTilesDefinitionsSyntax(digester);
+    }
+
+
+    /**
+     * Init digester for Tiles syntax with first element = tiles-definitions.
+     *
+     * @param digester Digester instance to use.
+     */
+    private void initDigesterForTilesDefinitionsSyntax(Digester digester) {
+        // syntax rules
+        digester.addObjectCreate(DEFINITION_TAG, DEFINITION_HANDLER_CLASS);
+        digester.addRule(DEFINITION_TAG, new FillDefinitionRule());
+        digester.addSetNext(DEFINITION_TAG, "addDefinition", DEFINITION_HANDLER_CLASS);
+
+        // nested definition rules
+        digester.addObjectCreate(PUT_DEFINITION_TAG, DEFINITION_HANDLER_CLASS);
+        digester.addRule(PUT_DEFINITION_TAG, new FillDefinitionRule());
+        digester.addSetRoot(PUT_DEFINITION_TAG, "addDefinition");
+        digester.addRule(PUT_DEFINITION_TAG, new AddNestedDefinitionRule());
+        digester.addObjectCreate(ADD_DEFINITION_TAG, DEFINITION_HANDLER_CLASS);
+        digester.addRule(ADD_DEFINITION_TAG, new FillDefinitionRule());
+        digester.addSetRoot(ADD_DEFINITION_TAG, "addDefinition");
+        digester.addRule(ADD_DEFINITION_TAG, new AddNestedDefinitionRule());
+
+        // put / putAttribute rules
+        // Rules for a same pattern are called in order, but rule.end() are called
+        // in reverse order.
+        // SetNext and CallMethod use rule.end() method. So, placing SetNext in
+        // first position ensure it will be called last (sic).
+        digester.addObjectCreate(PUT_TAG, PUT_ATTRIBUTE_HANDLER_CLASS);
+        digester.addRule(PUT_TAG, new FillAttributeRule());
+        digester.addRule(PUT_TAG, new PutAttributeRule());
+        // Definition level list rules
+        // This is rules for lists nested in a definition
+        digester.addObjectCreate(DEF_LIST_TAG, LIST_HANDLER_CLASS);
+        digester.addSetProperties(DEF_LIST_TAG);
+        digester.addRule(DEF_LIST_TAG, new PutAttributeRule());
+        // list elements rules
+        // We use Attribute class to avoid rewriting a new class.
+        // Name part can't be used in listElement attribute.
+        digester.addObjectCreate(ADD_LIST_ELE_TAG, PUT_ATTRIBUTE_HANDLER_CLASS);
+        digester.addRule(ADD_LIST_ELE_TAG, new FillAttributeRule());
+        digester.addSetNext(ADD_LIST_ELE_TAG, "add", PUT_ATTRIBUTE_HANDLER_CLASS);
+
+        // nested list elements rules
+        // Create a list handler, and add it to parent list
+        digester.addObjectCreate(NESTED_LIST, LIST_HANDLER_CLASS);
+        digester.addSetProperties(NESTED_LIST);
+        digester.addSetNext(NESTED_LIST, "add", PUT_ATTRIBUTE_HANDLER_CLASS);
+    }
+
+    /**
+     * Adds a new <code>Definition</code> to the internal Map or replaces
+     * an existing one.
+     *
+     * @param definition The Definition object to be added.
+     */
+    public void addDefinition(Definition definition) {
+        String name = definition.getName();
+        if (name == null) {
+            throw new DigesterDefinitionsReaderException("A root definition has been defined with no name");
+        }
+
+        definitions.put(name, definition);
+    }
+
+    /**
+     * Error Handler that throws every exception it receives.
+     */
+    private static class ThrowingErrorHandler implements ErrorHandler {
+
+        /** {@inheritDoc} */
+        public void warning(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+
+        /** {@inheritDoc} */
+        public void error(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+
+        /** {@inheritDoc} */
+        public void fatalError(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+    }
+
+    /**
+     * Returns the registrations for local DTDs.
+     *
+     * @return An array containing the locations for registrations of local
+     * DTDs.
+     * @since 2.1.0
+     */
+    protected String[] getRegistrations() {
+        if (registrations == null) {
+            registrations = new String[] {
+                "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN",
+                "/org/apache/tiles/resources/tiles-config_3_0.dtd"};
+        }
+        return registrations;
+    }
+
+    /**
+     * Create a unique definition name usable to store anonymous definitions.
+     *
+     * @param definitions The already created definitions.
+     * @return The unique definition name to be used to store the definition.
+     * @since 2.1.0
+     */
+    protected String getNextUniqueDefinitionName(
+            Map<String, Definition> definitions) {
+        String candidate;
+
+        do {
+            candidate = "$anonymousDefinition" + anonymousDefinitionIndex;
+            anonymousDefinitionIndex++;
+        } while (definitions.containsKey(candidate));
+
+        return candidate;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
index 38e506552..cd9c1c6c5 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReaderException.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.definition.digester;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.TilesException;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Indicates that something went wrong during the use of
+ * {@link DigesterDefinitionsReader}.
  *
- * @since Struts 2.0.2
+ * @version $Rev$ $Date$
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public class DigesterDefinitionsReaderException extends TilesException {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * Constructor.
+     *
+     * @param message The detail message.
+     * @since 2.1.0
+     */
+    public DigesterDefinitionsReaderException(String message) {
+        super(message);
     }
-}
\ No newline at end of file
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java
index 38e506552..f76e46d68 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Allows reading definitions with the use of Jakarta Commons Digester.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.definition.digester;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java
index 38e506552..2e570e061 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * It contains classes and interfaces to allow manipulations of "definitions", i.e.
+ * objects made of a template page and a number of filled attributes.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.definition;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java
new file mode 100644
index 000000000..dae01776f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/AbstractPatternDefinitionResolver.java
@@ -0,0 +1,108 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Definition;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A pattern definition resolver that stores {@link DefinitionPatternMatcher}
+ * separated by customization key. <br>
+ * Implementations should provide a way to translate a definition to a
+ * {@link DefinitionPatternMatcher}.
+ *
+ * @param <T> The type of the customization key.
+ * @since 2.2.0
+ */
+public abstract class AbstractPatternDefinitionResolver<T> implements PatternDefinitionResolver<T> {
+
+    /**
+     * Stores patterns depending on the locale they refer to.
+     */
+    private final Map<T, List<DefinitionPatternMatcher>> localePatternPaths = new HashMap<>();
+
+    /** {@inheritDoc} */
+    public Definition resolveDefinition(String name, T customizationKey) {
+        Definition retValue = null;
+        if (localePatternPaths.containsKey(customizationKey)) {
+            retValue = searchAndResolveDefinition(localePatternPaths
+                    .get(customizationKey), name);
+        }
+        return retValue;
+    }
+
+    /** {@inheritDoc} */
+    public Map<String, Definition> storeDefinitionPatterns(Map<String, Definition> localeDefsMap, T customizationKey) {
+        List<DefinitionPatternMatcher> lpaths = localePatternPaths.computeIfAbsent(customizationKey, k -> new ArrayList<>());
+        return addDefinitionsAsPatternMatchers(lpaths, localeDefsMap);
+    }
+
+    /**
+     * Adds definitions, filtering and adding them to the list of definition
+     * pattern matchers. Only a subset of definitions will be transformed into
+     * definition pattern matchers.
+     *
+     * @param matchers The list containing the currently stored definition pattern
+     * matchers.
+     * @param defsMap The definition map to parse.
+     * @return The map of the definitions not recognized as containing
+     * definition patterns.
+     * @since 2.2.1
+     */
+    protected abstract Map<String, Definition> addDefinitionsAsPatternMatchers(List<DefinitionPatternMatcher> matchers, Map<String, Definition> defsMap);
+
+    /**
+     * Try to resolve a definition by iterating all pattern matchers.
+     *
+     * @param paths The list containing the currently stored paths.
+     * @param name The name of the definition to resolve.
+     * @return A definition, if found, or <code>null</code> if not.
+     */
+    private Definition searchAndResolveDefinition(List<DefinitionPatternMatcher> paths, String name) {
+        Definition d = null;
+
+        for (DefinitionPatternMatcher wm : paths) {
+            d = wm.createDefinition(name);
+            if (d != null) {
+                break;
+            }
+        }
+
+        return d;
+    }
+
+
+    /**
+     * Used to clear all entries in the localePatternPaths for a specific locale. Necessary when reloading definition
+     * files to ensure that the list is cleared first
+     *
+     * @param customizationKey customization key
+     */
+    @Override
+    public void clearPatternPaths(T customizationKey) {
+        if (localePatternPaths.get(customizationKey) != null)
+            localePatternPaths.get(customizationKey).clear();
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java
new file mode 100644
index 000000000..a2d5fbed7
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/BasicPatternDefinitionResolver.java
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Definition;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A pattern definition resolver that stores {@link org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher}
+ * separated by customization key. <br>
+ * It delegates creation of definition pattern matchers to a
+ * {@link DefinitionPatternMatcherFactory} and recgnizes patterns through the
+ * use of a {@link PatternRecognizer}.
+ *
+ * @param <T> The type of the customization key.
+ * @since 2.2.0
+ */
+public class BasicPatternDefinitionResolver<T> extends AbstractPatternDefinitionResolver<T> {
+
+    /**
+     * The factory of pattern matchers.
+     */
+    private final DefinitionPatternMatcherFactory definitionPatternMatcherFactory;
+
+    /**
+     * The pattern recognizer.
+     */
+    private final PatternRecognizer patternRecognizer;
+
+    /**
+     * Constructor.
+     *
+     * @param definitionPatternMatcherFactory The definition pattern matcher factory.
+     * @param patternRecognizer The pattern recognizer.
+     */
+    public BasicPatternDefinitionResolver(DefinitionPatternMatcherFactory definitionPatternMatcherFactory, PatternRecognizer patternRecognizer) {
+        this.definitionPatternMatcherFactory = definitionPatternMatcherFactory;
+        this.patternRecognizer = patternRecognizer;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Map<String, Definition> addDefinitionsAsPatternMatchers(List<DefinitionPatternMatcher> matchers, Map<String, Definition> defsMap) {
+        Set<String> excludedKeys = new LinkedHashSet<>();
+        for (Map.Entry<String, Definition> de : defsMap.entrySet()) {
+            String key = de.getKey();
+            if (patternRecognizer.isPatternRecognized(key)) {
+                matchers.add(definitionPatternMatcherFactory.createDefinitionPatternMatcher(key, de.getValue()));
+            } else {
+                excludedKeys.add(key);
+            }
+        }
+        return PatternUtil.createExtractedMap(defsMap, excludedKeys);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
index 38e506552..59461af25 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcher.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.definition.pattern;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.Definition;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Matches a definition name to a definition, through pattern-matching. The
+ * matched pattern should be a single one.
  *
- * @since Struts 2.0.2
+ * @version $Rev$ $Date$
+ * @since 2.2.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface DefinitionPatternMatcher {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Creates a definition, given the definition name, through the use of
+     * pattern matching.
+     *
+     * @param definitionName The definition name to match.
+     * @return The created definition, if matched, or <code>null</code> if not
+     * matched.
+     * @since 2.2.0
+     */
+    Definition createDefinition(String definitionName);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
new file mode 100644
index 000000000..454dada62
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/DefinitionPatternMatcherFactory.java
@@ -0,0 +1,45 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Definition;
+
+/**
+ * Creates a new definition pattern matcher for the given pattern and the given
+ * base definition with pattern expressions.
+ *
+ * @version $Rev$ $Date$
+ * @since 2.2.0
+ */
+public interface DefinitionPatternMatcherFactory {
+
+    /**
+     * Creates a new definition pattern matcher.
+     *
+     * @param pattern The pattern to be matched.
+     * @param definition The base definition. Created definitions by
+     * {@link DefinitionPatternMatcher#createDefinition(String)} will created
+     * with this one as a basis.
+     * @return The definition pattern matcher.
+     * @since 2.2.0
+     */
+    DefinitionPatternMatcher createDefinitionPatternMatcher(String pattern, Definition definition);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
new file mode 100644
index 000000000..07c78157d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolver.java
@@ -0,0 +1,66 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Definition;
+
+import java.util.Map;
+
+/**
+ * Resolves a definition starting from patterns stored in definition maps.
+ *
+ * @param <T> The type of the customization key.
+ * @version $Rev$ $Date$
+ * @since 2.2.0
+ */
+public interface PatternDefinitionResolver<T> {
+
+    /**
+     * Stores definition patterns.
+     *
+     * @param localeDefsMap The map of definitions that may contain also
+     * patterns.
+     * @param customizationKey The customization key.
+     * @return The map of the definitions not recognized as containing
+     * definition patterns.
+     * @since 2.2.1
+     */
+    Map<String, Definition> storeDefinitionPatterns(Map<String, Definition> localeDefsMap, T customizationKey);
+
+    /**
+     * Resolves a definition searching in all patterns for the requested
+     * customization key.
+     *
+     * @param name The name of the definition.
+     * @param customizationKey The customization key.
+     * @return The resolved definition.
+     * @since 2.2.0
+     */
+    Definition resolveDefinition(String name, T customizationKey);
+
+    /**
+     * Used to clear all entries in the localePatternPaths for a specific locale. Necessary when reloading definition
+     * files to ensure that the list is cleared first
+     *
+     * @param customizationKey customization key
+     */
+    void clearPatternPaths(T customizationKey);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java
index 38e506552..790a64e8c 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternDefinitionResolverAware.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.core.definition.pattern;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * It indicates an object that uses a {@link org.apache.tiles.core.definition.pattern.PatternDefinitionResolver}.
  *
- * @since Struts 2.0.2
+ * @param <T> The type of the customization key.
+ * @since 2.2.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface PatternDefinitionResolverAware<T> {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Sets the pattern definition resolver to use.
+     *
+     * @param definitionResolver The pattern definition resolver.
+     * @since 2.2.0
+     */
+    void setPatternDefinitionResolver(PatternDefinitionResolver<T> definitionResolver);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java
index 38e506552..3ae899f9e 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternRecognizer.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.core.definition.pattern;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Checks if a pattern (or a candidate one) is recognized as a pattern.
  *
- * @since Struts 2.0.2
+ * @since 2.2.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface PatternRecognizer {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Checks if a pattern is recognized as a pattern.
+     *
+     * @param candidatePattern The pattern to check.
+     * @return <code>true</code> if the pattern has been recognized.
+     * @since 2.2.0
+     */
+    boolean isPatternRecognized(String candidatePattern);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java
new file mode 100644
index 000000000..d7894b922
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PatternUtil.java
@@ -0,0 +1,242 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.api.ListAttribute;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utilities for pattern matching and substitution.
+ *
+ * @since 2.2.0
+ */
+public final class PatternUtil {
+
+    /**
+     * The root locale. Notice that this is a replacement for {@link Locale#ROOT} for
+     * Java 1.6.
+     */
+    private static final Locale ROOT_LOCALE = new Locale("", "");
+
+    /** Pattern to find {.*} occurrences that do not match {[0-9]+} so to prevent MessageFormat from crashing.
+     */
+    private static final Pattern INVALID_FORMAT_ELEMENT = Pattern.compile("\\{[^}0-9]+}");
+
+    /**
+     * Private constructor to avoid instantiation.
+     */
+    private PatternUtil() {
+    }
+
+    /**
+     * Creates a definition given its representation with wildcards and
+     * attribute values with placeholders, replacing real values into
+     * placeholders.
+     *
+     * @param d The definition to replace.
+     * @param name The name of the definition to be created.
+     * @param varsOrig The variables to be substituted.
+     * @return The definition that can be rendered.
+     * @since 2.2.0
+     */
+    public static Definition replacePlaceholders(Definition d, String name,
+                                                 Object... varsOrig) {
+
+        Object[] vars = replaceNullsWithBlank(varsOrig);
+
+        Definition nudef = new Definition();
+
+        nudef.setExtends(replace(d.getExtends(), vars));
+        nudef.setName(name);
+        nudef.setPreparer(replace(d.getPreparer(), vars));
+        Attribute templateAttribute = d.getTemplateAttribute();
+        if (templateAttribute != null) {
+            nudef.setTemplateAttribute(replaceVarsInAttribute(
+                    templateAttribute, vars));
+        }
+
+        Set<String> attributeNames = d.getLocalAttributeNames();
+        if (attributeNames != null && !attributeNames.isEmpty()) {
+            for (String attributeName : attributeNames) {
+                Attribute attr = d.getLocalAttribute(attributeName);
+                Attribute nuattr = replaceVarsInAttribute(attr, vars);
+
+                nudef.putAttribute(replace(attributeName, vars), nuattr);
+            }
+        }
+
+        attributeNames = d.getCascadedAttributeNames();
+        if (attributeNames != null && !attributeNames.isEmpty()) {
+            for (String attributeName : attributeNames) {
+                Attribute attr = d.getCascadedAttribute(attributeName);
+                Attribute nuattr = replaceVarsInAttribute(attr, vars);
+
+                nudef.putAttribute(replace(attributeName, vars), nuattr, true);
+            }
+        }
+
+        return nudef;
+    }
+
+    /**
+     * Creates a new map that contains all the entries of the
+     * <code>defsMap</code> whose keys are contained in <code>keys</code>.
+     *
+     * @param map The map to read.
+     * @param keys The keys to extract.
+     * @param <K> The key of the map.
+     * @param <V> The value of the map.
+     * @return The extracted map.
+     * @since 2.2.1
+     */
+    public static <K, V> Map<K, V> createExtractedMap(Map<K, V> map, Set<K> keys) {
+        Map<K, V> retValue = new LinkedHashMap<>();
+        for (K key : keys) {
+            retValue.put(key, map.get(key));
+        }
+        return retValue;
+    }
+
+    /**
+     * Replaces variables into an attribute.
+     *
+     * @param attr The attribute to be used as a basis, containing placeholders
+     * for variables.
+     * @param vars The variables to replace.
+     * @return A new instance of an attribute, whose properties have been
+     * replaced with variables' values.
+     */
+    private static Attribute replaceVarsInAttribute(Attribute attr,
+            Object... vars) {
+        Attribute nuattr;
+        if (attr instanceof ListAttribute) {
+            nuattr = replaceVarsInListAttribute((ListAttribute) attr, vars);
+        } else {
+            nuattr = replaceVarsInSimpleAttribute(attr, vars);
+        }
+        return nuattr;
+    }
+
+    /**
+     * Replaces variables into a simple (not list) attribute.
+     *
+     * @param attr The attribute to be used as a basis, containing placeholders
+     * for variables.
+     * @param vars The variables to replace.
+     * @return A new instance of an attribute, whose properties have been
+     * replaced with variables' values.
+     */
+    private static Attribute replaceVarsInSimpleAttribute(Attribute attr,
+            Object... vars) {
+        Attribute nuattr;
+        nuattr = new Attribute();
+
+        nuattr.setRole(replace(attr.getRole(), vars));
+        nuattr.setRenderer(attr.getRenderer());
+        Expression expressionObject = attr.getExpressionObject();
+        if (expressionObject != null) {
+            Expression newExpressionObject = Expression
+                    .createExpression(replace(expressionObject.getExpression(), vars), expressionObject.getLanguage());
+            nuattr.setExpressionObject(newExpressionObject);
+        }
+
+        Object value = attr.getValue();
+        if (value instanceof String) {
+            value = replace((String) value, vars);
+        }
+        nuattr.setValue(value);
+        return nuattr;
+    }
+
+    /**
+     * Replaces variables into a list attribute.
+     *
+     * @param listAttr The attribute to be used as a basis, containing attributes
+     * that may contain placeholders for variables.
+     * @param vars The variables to replace.
+     * @return A new instance of an attribute, whose properties have been
+     * replaced with variables' values.
+     */
+    private static Attribute replaceVarsInListAttribute(ListAttribute listAttr,
+            Object... vars) {
+        Attribute nuattr;
+        ListAttribute nuListAttr = new ListAttribute();
+        nuListAttr.setInherit(listAttr.isInherit());
+        List<Attribute> nuItems = nuListAttr.getValue();
+        for (Attribute item : listAttr.getValue()) {
+            Attribute child = item;
+            child = replaceVarsInAttribute(child, vars);
+            nuItems.add(child);
+        }
+        nuattr = nuListAttr;
+        return nuattr;
+    }
+
+    /**
+     * Replaces a string with placeholders using values of a variable map.
+     *
+     * @param st The string to replace.
+     * @param vars The variables.
+     * @return The replaced string.
+     */
+    private static String replace(String st, Object... vars) {
+        if (st != null && st.indexOf('{') >= 0) {
+
+            // replace them with markers
+            List<String> originals = new ArrayList<>();
+            for(Matcher m = INVALID_FORMAT_ELEMENT.matcher(st); m.find() ; m = INVALID_FORMAT_ELEMENT.matcher(st)) {
+                originals.add(m.group());
+                st = m.replaceFirst("INVALID_FORMAT_ELEMENT");
+            }
+
+            // do the MessageFormat replacement (escaping quote characters)
+            st = new MessageFormat(st.replaceAll("'", "'''"), ROOT_LOCALE)
+                    .format(vars, new StringBuffer(), null).toString();
+
+            // return the markers to their original invalid occurrences
+            for (String original : originals) {
+                st = st.replaceFirst("INVALID_FORMAT_ELEMENT", original);
+            }
+        }
+        return st;
+    }
+
+    private static Object[] replaceNullsWithBlank(Object[] varsOrig) {
+        Object[] vars = new Object[varsOrig.length];
+        for(int i = 0; i < varsOrig.length; ++i) {
+            vars[i] = null != varsOrig[i] ? varsOrig[i] : "";
+        }
+        return vars;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
new file mode 100644
index 000000000..f50f4498b
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/PrefixedPatternDefinitionResolver.java
@@ -0,0 +1,106 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.Expression;
+
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This resolver allows the use of multiple pattern matching languages. The
+ * syntax of definition names must be <code>LANGUAGENAME:expression</code>.<br>
+ * The different languages must be registered through the use of
+ * {@link #registerDefinitionPatternMatcherFactory(String, DefinitionPatternMatcherFactory)}
+ * method before using this resolver.
+ *
+ * @param <T> The type of the customization key.
+ * @version $Rev$ $Date$
+ * @since 2.2.0
+ */
+public class PrefixedPatternDefinitionResolver<T> extends AbstractPatternDefinitionResolver<T> {
+
+    /**
+     * The logging object.
+     */
+    private static final Logger LOG = LogManager.getLogger(PrefixedPatternDefinitionResolver.class);
+
+    /**
+     * Matches languages names to the corresponding
+     * {@link DefinitionPatternMatcherFactory}.
+     */
+    private final Map<String, DefinitionPatternMatcherFactory> language2matcherFactory;
+
+    /**
+     * Constructor.
+     *
+     * @since 2.2.0
+     */
+    public PrefixedPatternDefinitionResolver() {
+        language2matcherFactory = new HashMap<>();
+    }
+
+    /**
+     * Registers a {@link DefinitionPatternMatcherFactory} connected to a
+     * particular language.
+     *
+     * @param language The name of the language.
+     * @param factory The pattern matcher factory to register.
+     * @since 2.2.0
+     */
+    public void registerDefinitionPatternMatcherFactory(String language,
+            DefinitionPatternMatcherFactory factory) {
+        language2matcherFactory.put(language, factory);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Map<String, Definition> addDefinitionsAsPatternMatchers(List<DefinitionPatternMatcher> matchers, Map<String, Definition> defsMap) {
+        Set<String> excludedKeys = new LinkedHashSet<String>();
+        for (Map.Entry<String, Definition> entry : defsMap.entrySet()) {
+            String key = entry.getKey();
+            Expression expression = Expression
+                    .createExpressionFromDescribedExpression(key);
+            if (expression.getLanguage() != null) {
+                DefinitionPatternMatcherFactory factory = language2matcherFactory
+                        .get(expression.getLanguage());
+                if (factory != null) {
+                    DefinitionPatternMatcher matcher = factory
+                            .createDefinitionPatternMatcher(expression
+                                    .getExpression(), new Definition(entry
+                                    .getValue()));
+                    matchers.add(matcher);
+                } else {
+                    LOG.warn("Cannot find a DefinitionPatternMatcherFactory for expression '{}'", key);
+                }
+            } else {
+                excludedKeys.add(key);
+            }
+        }
+        return PatternUtil.createExtractedMap(defsMap, excludedKeys);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java
index 38e506552..13c53ec83 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Classes to manage pattern matching in definition names, and substitution in attributes.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.definition.pattern;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java
new file mode 100644
index 000000000..b575c2a27
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcher.java
@@ -0,0 +1,74 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.definition.pattern.regexp;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
+import org.apache.tiles.core.definition.pattern.PatternUtil;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Matches regular expression patterns in definitions.
+ *
+ * @since 2.2.0
+ */
+public class RegexpDefinitionPatternMatcher implements DefinitionPatternMatcher {
+
+    /**
+     * The pattern to match.
+     */
+    private final Pattern pattern;
+
+    /**
+     * The definition to use as a basis.
+     */
+    private final Definition definition;
+
+    /**
+     * Constructor.
+     *
+     * @param pattern The pattern to use, in string form.
+     * @param definition The definition to use as a basis.
+     * @since 2.2.0
+     */
+    public RegexpDefinitionPatternMatcher(String pattern, Definition definition) {
+        this.pattern = Pattern.compile(pattern);
+        this.definition = definition;
+    }
+
+    /** {@inheritDoc} */
+    public Definition createDefinition(String definitionName) {
+        Definition retValue = null;
+        Matcher matcher = pattern.matcher(definitionName);
+        if (matcher.matches()) {
+            int groupCount = matcher.groupCount() + 1;
+            Object[] vars = new Object[groupCount];
+            for (int i = 0; i < groupCount; i++) {
+                vars[i] = matcher.group(i);
+            }
+            retValue = PatternUtil.replacePlaceholders(definition, definitionName, vars);
+        }
+        return retValue;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
index 38e506552..3cbffaf99 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/RegexpDefinitionPatternMatcherFactory.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.definition.pattern.regexp;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcherFactory;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Creates instances of {@link RegexpDefinitionPatternMatcher}.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public class RegexpDefinitionPatternMatcherFactory implements DefinitionPatternMatcherFactory {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * {@inheritDoc}
+     */
+    public DefinitionPatternMatcher createDefinitionPatternMatcher(String pattern, Definition definition) {
+        return new RegexpDefinitionPatternMatcher(pattern, definition);
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java
index 38e506552..15389afdb 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/regexp/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * In Tiles it is possible to use regular expression patterns thanks to this package.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.definition.pattern.regexp;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java
new file mode 100644
index 000000000..fe2d54349
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcher.java
@@ -0,0 +1,80 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern.wildcard;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
+import org.apache.tiles.core.definition.pattern.PatternUtil;
+import org.apache.tiles.core.util.WildcardHelper;
+
+import java.util.List;
+
+/**
+ * Matches wildcard patterns in definitions.
+ *
+ * @since 2.2.0
+ */
+public class WildcardDefinitionPatternMatcher implements DefinitionPatternMatcher {
+
+    /**
+     * Allows to parse wildcard expressions and to recognize substitution
+     * variables.
+     */
+    private final WildcardHelper wildcardHelper;
+
+    /**
+     * The definition to use as a basis.
+     */
+    private final Definition definition;
+
+    /**
+     * The pattern to use.
+     */
+    private final int[] pattern;
+
+    /**
+     * Constructor.
+     *
+     * @param pattern The pattern to use, in string form.
+     * @param definition The definition to use as a basis.
+     * @param wildcardHelper The object that parses wildcard expressions and
+     * recognized substitution variables.
+     * @since 2.2.0
+     */
+    public WildcardDefinitionPatternMatcher(String pattern,
+            Definition definition, WildcardHelper wildcardHelper) {
+        this.wildcardHelper = wildcardHelper;
+        this.definition = definition;
+        this.pattern = wildcardHelper.compilePattern(pattern);
+    }
+
+    /** {@inheritDoc} */
+    public Definition createDefinition(String definitionName) {
+        List<String> vars = wildcardHelper.match(definitionName, pattern);
+        Definition d = null;
+
+        if (vars != null) {
+            d = PatternUtil.replacePlaceholders(definition, definitionName, vars.toArray());
+        }
+
+        return d;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java
new file mode 100644
index 000000000..0804a9d21
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/WildcardDefinitionPatternMatcherFactory.java
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.definition.pattern.wildcard;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcher;
+import org.apache.tiles.core.definition.pattern.DefinitionPatternMatcherFactory;
+import org.apache.tiles.core.definition.pattern.PatternRecognizer;
+import org.apache.tiles.core.util.WildcardHelper;
+
+/**
+ * Creates instances of {@link WildcardDefinitionPatternMatcher}.
+ *
+ * @since 2.2.0
+ */
+public class WildcardDefinitionPatternMatcherFactory implements DefinitionPatternMatcherFactory, PatternRecognizer {
+
+    /**
+     * Allows to parse wildcard expressions and to recognize substitution
+     * variables.
+     */
+    private final WildcardHelper wildcardHelper = new WildcardHelper();
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefinitionPatternMatcher createDefinitionPatternMatcher(
+        String pattern, Definition definition) {
+        return new WildcardDefinitionPatternMatcher(pattern, definition, wildcardHelper);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isPatternRecognized(String candidatePattern) {
+        return candidatePattern.indexOf('*') >= 0;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java
index 38e506552..dfbb05225 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/definition/pattern/wildcard/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * In Tiles it is possible to use wildcard patterns thanks to this package.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.definition.pattern.wildcard;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java
new file mode 100644
index 000000000..702ba5a6d
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AbstractAttributeEvaluator.java
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.evaluator;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.request.Request;
+
+/**
+ * Abstract class to link a correct evaluation of an attribute, by evaluating
+ * {@link Attribute#getValue()} and then {@link Attribute#getExpressionObject()}.
+ *
+ * @since 2.1.2
+ */
+public abstract class AbstractAttributeEvaluator implements AttributeEvaluator {
+
+    /** {@inheritDoc} */
+    public Object evaluate(Attribute attribute, Request request) {
+        if (attribute == null) {
+            throw new IllegalArgumentException("The attribute cannot be null");
+        }
+
+        Object retValue = attribute.getValue();
+
+        if (retValue == null) {
+            Expression expression = attribute.getExpressionObject();
+            if (expression != null) {
+                retValue = evaluate(attribute.getExpressionObject().getExpression(), request);
+            }
+        }
+
+        return retValue;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java
new file mode 100644
index 000000000..93feb168a
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluator.java
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.evaluator;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.request.Request;
+
+/**
+ * It represents an object that resolves a string to return an object.
+ *
+ * @since 2.1.0
+ */
+public interface AttributeEvaluator {
+
+    /**
+     * Evaluates an expression.
+     *
+     * @param expression The expression to evaluate.
+     * @param request    The request object.
+     * @return The evaluated object.
+     * @since 2.1.0
+     */
+    Object evaluate(String expression, Request request);
+
+    /**
+     * Evaluates an attribute value.
+     *
+     * @param attribute The attribute to evaluate.
+     * @param request   The request object.
+     * @return The evaluated object.
+     * @since 2.1.0
+     */
+    Object evaluate(Attribute attribute, Request request);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java
new file mode 100644
index 000000000..efac52ed4
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactory.java
@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+
+package org.apache.tiles.core.evaluator;
+
+import org.apache.tiles.api.Attribute;
+
+/**
+ * Creates an attribute evaluator using the language or an attribute.
+ *
+ * @since 2.2.0
+ */
+public interface AttributeEvaluatorFactory {
+
+    /**
+     * Creates and attribute evaluator using an attribute.
+     *
+     * @param attribute The attribute used to obtain the evaluator.
+     * @return The attribute evaluator. It must not be <code>null</code>.
+     * @since 2.2.0
+     */
+    AttributeEvaluator getAttributeEvaluator(Attribute attribute);
+
+    /**
+     * Creates and attribute evaluator for the given expression language.
+     *
+     * @param language The name of the expression language.
+     * @return The attribute evaluator. It must not be <code>null</code>.
+     * @since 2.2.0
+     */
+    AttributeEvaluator getAttributeEvaluator(String language);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java
index 38e506552..9e472c555 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/AttributeEvaluatorFactoryAware.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+package org.apache.tiles.core.evaluator;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * It represents an object that can use an {@link AttributeEvaluatorFactory}.
  *
- * @since Struts 2.0.2
+ * @since 2.2.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface AttributeEvaluatorFactoryAware {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Sets the attribute evaluator factory.
+     *
+     * @param attributeEvaluatorFactory The attribute evaluator factory to use.
+     * @since 2.2.0
+     */
+    void setAttributeEvaluatorFactory(AttributeEvaluatorFactory attributeEvaluatorFactory);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java
new file mode 100644
index 000000000..e6f8a47b4
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/BasicAttributeEvaluatorFactory.java
@@ -0,0 +1,90 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.evaluator;
+
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Expression;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Basic implementation of {@link AttributeEvaluatorFactory}. It supports a
+ * default attribute evaluator, in case the language is not recognized.
+ *
+ * @since 2.2.0
+ */
+public class BasicAttributeEvaluatorFactory implements AttributeEvaluatorFactory {
+
+    /**
+     * The default evaluator to return if it is not found in the map of known
+     * languages.
+     */
+    private final AttributeEvaluator defaultEvaluator;
+
+    /**
+     * Maps names of expression languages to their attribute evaluator.
+     *
+     * @since 2.2.0
+     */
+    private final Map<String, AttributeEvaluator> language2evaluator;
+
+    /**
+     * Constructor.
+     *
+     * @param defaultEvaluator The default evaluator to return if it is not
+     * found in the map of known languages.
+     * @since 2.2.0
+     */
+    public BasicAttributeEvaluatorFactory(AttributeEvaluator defaultEvaluator) {
+        this.defaultEvaluator = defaultEvaluator;
+        language2evaluator = new HashMap<>();
+    }
+
+    /**
+     * Registers a known expression language with its attribute evaluator.
+     *
+     * @param language The name of the expression language.
+     * @param evaluator The associated attribute evaluator.
+     * @since 2.2.0
+     */
+    public void registerAttributeEvaluator(String language, AttributeEvaluator evaluator) {
+        language2evaluator.put(language, evaluator);
+    }
+
+    /** {@inheritDoc} */
+    public AttributeEvaluator getAttributeEvaluator(String language) {
+        AttributeEvaluator retValue = language2evaluator.get(language);
+        if (retValue == null) {
+            retValue = defaultEvaluator;
+        }
+        return retValue;
+    }
+
+    /** {@inheritDoc} */
+    public AttributeEvaluator getAttributeEvaluator(Attribute attribute) {
+        Expression expression = attribute.getExpressionObject();
+        if (expression != null) {
+            return getAttributeEvaluator(expression.getLanguage());
+        }
+        return defaultEvaluator;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java
index 38e506552..7f5cb9c80 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/EvaluationException.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.evaluator;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.TilesException;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Exception raised when an expression language evaluation fails.
  *
- * @since Struts 2.0.2
+ * @since 2.2.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public class EvaluationException extends TilesException {
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+    /**
+     * Constructor.
+     *
+     * @param e The cause.
+     * @since 2.2.0
+     */
+    public EvaluationException(Throwable e) {
+        super(e);
+    }
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * Constructor.
+     *
+     * @param message The message-
+     * @param e       The cause.
+     * @since 2.2.0
+     */
+    public EvaluationException(String message, Throwable e) {
+        super(message, e);
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java
index 38e506552..35157812d 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/DirectAttributeEvaluator.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.evaluator.impl;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.core.evaluator.AbstractAttributeEvaluator;
+import org.apache.tiles.request.Request;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Resolves a string and returns the string itself. It is useful for backward
+ * compatibility.
  *
- * @since Struts 2.0.2
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public class DirectAttributeEvaluator extends AbstractAttributeEvaluator {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /** {@inheritDoc} */
+    public Object evaluate(String expression, Request request) {
+        return expression;
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java
index 38e506552..40bc521ec 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/impl/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Classes to manage attribute value evaluation.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.evaluator.impl;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java
index 38e506552..da5b4bc26 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/evaluator/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Interfaces to manage attribute value evaluation.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.evaluator;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java
index 38e506552..fc5ca1f17 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/AbstractTilesContainerFactory.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.factory;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.request.ApplicationContext;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Abstract Factory that creates instances of {@link TilesContainer}.
  *
- * @since Struts 2.0.2
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public abstract class AbstractTilesContainerFactory {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Creates a Tiles container.
+     *
+     * @param applicationContext The Tiles application context object.
+     * @return The created container.
+     * @throws TilesContainerFactoryException If something goes wrong during
+     * instantiation.
+     * @since 2.1.1
+     */
+    public abstract TilesContainer createContainer(ApplicationContext applicationContext);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java
new file mode 100644
index 000000000..311172e28
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/BasicTilesContainerFactory.java
@@ -0,0 +1,408 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.factory;
+
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.core.definition.DefinitionsFactory;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.apache.tiles.core.definition.UnresolvingLocaleDefinitionsFactory;
+import org.apache.tiles.core.definition.dao.BaseLocaleUrlDefinitionDAO;
+import org.apache.tiles.core.definition.dao.DefinitionDAO;
+import org.apache.tiles.core.definition.dao.ResolvingLocaleUrlDefinitionDAO;
+import org.apache.tiles.core.definition.digester.DigesterDefinitionsReader;
+import org.apache.tiles.core.definition.pattern.BasicPatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolver;
+import org.apache.tiles.core.definition.pattern.PatternDefinitionResolverAware;
+import org.apache.tiles.core.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory;
+import org.apache.tiles.core.evaluator.AttributeEvaluatorFactory;
+import org.apache.tiles.core.evaluator.BasicAttributeEvaluatorFactory;
+import org.apache.tiles.core.evaluator.impl.DirectAttributeEvaluator;
+import org.apache.tiles.core.impl.BasicTilesContainer;
+import org.apache.tiles.core.locale.LocaleResolver;
+import org.apache.tiles.core.locale.impl.DefaultLocaleResolver;
+import org.apache.tiles.core.prepare.factory.BasicPreparerFactory;
+import org.apache.tiles.core.prepare.factory.PreparerFactory;
+import org.apache.tiles.core.renderer.DefinitionRenderer;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.ApplicationResource;
+import org.apache.tiles.request.render.BasicRendererFactory;
+import org.apache.tiles.request.render.ChainedDelegateRenderer;
+import org.apache.tiles.request.render.DispatchRenderer;
+import org.apache.tiles.request.render.Renderer;
+import org.apache.tiles.request.render.RendererFactory;
+import org.apache.tiles.request.render.StringRenderer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Factory that builds a standard Tiles container using only Java code.
+ *
+ * @since 2.1.0
+ */
+public class BasicTilesContainerFactory extends AbstractTilesContainerFactory {
+
+    /**
+     * The string renderer name.
+     */
+    protected static final String STRING_RENDERER_NAME = "string";
+
+    /**
+     * The template renderer name.
+     */
+    protected static final String TEMPLATE_RENDERER_NAME = "template";
+
+    /**
+     * The definition renderer name.
+     */
+    protected static final String DEFINITION_RENDERER_NAME = "definition";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TilesContainer createContainer(ApplicationContext applicationContext) {
+        BasicTilesContainer container = instantiateContainer(applicationContext);
+        container.setApplicationContext(applicationContext);
+        LocaleResolver resolver = createLocaleResolver(applicationContext);
+        container.setDefinitionsFactory(createDefinitionsFactory(applicationContext, resolver));
+        AttributeEvaluatorFactory attributeEvaluatorFactory = createAttributeEvaluatorFactory(applicationContext, resolver);
+        container.setAttributeEvaluatorFactory(attributeEvaluatorFactory);
+        container.setPreparerFactory(createPreparerFactory(applicationContext));
+        TilesContainer injectedContainer = createDecoratedContainer(container, applicationContext);
+        container.setRendererFactory(createRendererFactory(applicationContext, injectedContainer, attributeEvaluatorFactory));
+        return injectedContainer;
+    }
+
+    /**
+     * Instantiate the container, without initialization.
+     *
+     * @param context The Tiles application context object.
+     * @return The instantiated container.
+     * @since 2.1.1
+     */
+    protected BasicTilesContainer instantiateContainer(ApplicationContext context) {
+        return new BasicTilesContainer();
+    }
+
+    /**
+     * Instantiate the container that will be injected to child objects.
+     *
+     * @param originalContainer The original instantiated container.
+     * @param context           The Tiles application context object.
+     * @return The instantiated container.
+     * @since 3.0.0
+     */
+    protected TilesContainer createDecoratedContainer(
+        TilesContainer originalContainer,
+        ApplicationContext context
+    ) {
+        return originalContainer;
+    }
+
+    /**
+     * Creates the definitions factory. By default it creates a
+     * {@link UnresolvingLocaleDefinitionsFactory} with default dependencies.
+     *
+     * @param applicationContext The Tiles application context.
+     * @param resolver           The locale resolver.
+     * @return The definitions factory.
+     * @since 2.1.1
+     */
+    protected DefinitionsFactory createDefinitionsFactory(
+        ApplicationContext applicationContext,
+        LocaleResolver resolver
+    ) {
+        UnresolvingLocaleDefinitionsFactory factory = instantiateDefinitionsFactory(applicationContext, resolver);
+        factory.setLocaleResolver(resolver);
+        factory.setDefinitionDAO(createLocaleDefinitionDao(applicationContext, resolver));
+        return factory;
+    }
+
+    /**
+     * Instantiate a new definitions factory based on Locale.
+     *
+     * @param applicationContext The Tiles application context.
+     * @param resolver           The locale resolver.
+     * @return The definitions factory.
+     * @since 2.2.1
+     */
+    protected UnresolvingLocaleDefinitionsFactory instantiateDefinitionsFactory(
+        ApplicationContext applicationContext,
+        LocaleResolver resolver
+    ) {
+        return new UnresolvingLocaleDefinitionsFactory();
+    }
+
+
+    /**
+     * Instantiate (and does not initialize) a Locale-based definition DAO.
+     *
+     * @param applicationContext The Tiles application context.
+     * @param resolver           The locale resolver.
+     * @return The definition DAO.
+     * @since 2.1.1
+     */
+    protected BaseLocaleUrlDefinitionDAO instantiateLocaleDefinitionDao(
+        ApplicationContext applicationContext,
+        LocaleResolver resolver
+    ) {
+        return new ResolvingLocaleUrlDefinitionDAO(applicationContext);
+    }
+
+    /**
+     * Creates a Locale-based definition DAO.
+     *
+     * @param applicationContext The Tiles application context.
+     * @param resolver           The locale resolver.
+     * @return The definition DAO.
+     * @since 2.1.1
+     */
+    @SuppressWarnings("unchecked")
+    protected DefinitionDAO<Locale> createLocaleDefinitionDao(ApplicationContext applicationContext, LocaleResolver resolver) {
+        BaseLocaleUrlDefinitionDAO definitionDao = instantiateLocaleDefinitionDao(applicationContext, resolver);
+        definitionDao.setReader(createDefinitionsReader(applicationContext));
+        definitionDao.setSources(getSources(applicationContext));
+        if (definitionDao instanceof PatternDefinitionResolverAware) {
+            ((PatternDefinitionResolverAware<Locale>) definitionDao)
+                .setPatternDefinitionResolver(createPatternDefinitionResolver(Locale.class));
+        }
+        return definitionDao;
+    }
+
+    /**
+     * Creates the locale resolver. By default it creates a
+     * {@link DefaultLocaleResolver}.
+     *
+     * @param applicationContext The Tiles application context.
+     * @return The locale resolver.
+     * @since 2.1.1
+     */
+    protected LocaleResolver createLocaleResolver(ApplicationContext applicationContext) {
+        return new DefaultLocaleResolver();
+    }
+
+    /**
+     * Creates the definitions reader. By default it creates a
+     * {@link DigesterDefinitionsReader}.
+     *
+     * @param applicationContext The Tiles application context.
+     * @return The definitions reader.
+     * @since 2.1.1
+     */
+    protected DefinitionsReader createDefinitionsReader(ApplicationContext applicationContext) {
+        return new DigesterDefinitionsReader();
+    }
+
+    /**
+     * Returns a list containing the resources to be parsed. By default, it returns a
+     * list containing the resource at "/WEB-INF/tiles.xml".
+     *
+     * @param applicationContext The Tiles application context.
+     * @return The resources.
+     * @since 2.1.1
+     */
+    protected List<ApplicationResource> getSources(ApplicationContext applicationContext) {
+        List<ApplicationResource> retValue = new ArrayList<>(1);
+        retValue.add(applicationContext.getResource("/WEB-INF/tiles.xml"));
+        return retValue;
+    }
+
+    /**
+     * Creates the attribute evaluator factory to use. By default it returns a
+     * {@link BasicAttributeEvaluatorFactory} containing the
+     * {@link DirectAttributeEvaluator} as the default evaluator.
+     *
+     * @param applicationContext The Tiles application context.
+     * @param resolver           The locale resolver.
+     * @return The evaluator factory.
+     * @since 2.2.0
+     */
+    protected AttributeEvaluatorFactory createAttributeEvaluatorFactory(
+        ApplicationContext applicationContext,
+        LocaleResolver resolver) {
+        return new BasicAttributeEvaluatorFactory(new DirectAttributeEvaluator());
+    }
+
+    /**
+     * Creates the preparer factory to use. By default it returns a
+     * {@link BasicPreparerFactory}.
+     *
+     * @param applicationContext The Tiles application context.
+     * @return The preparer factory.
+     * @since 2.1.1
+     */
+    protected PreparerFactory createPreparerFactory(ApplicationContext applicationContext) {
+        return new BasicPreparerFactory();
+    }
+
+    /**
+     * Creates a renderer factory. By default, it returns a
+     * {@link BasicRendererFactory}, composed of an
+     * {@link ChainedDelegateRenderer} as default, and delegates of
+     * {@link StringRenderer}, {@link DispatchRenderer},
+     * {@link DefinitionRenderer}.
+     *
+     * @param applicationContext        The Tiles application context.
+     * @param container                 The container.
+     * @param attributeEvaluatorFactory The attribute evaluator factory.
+     * @return The renderer factory.
+     * @since 2.2.0
+     */
+    protected RendererFactory createRendererFactory(ApplicationContext applicationContext,
+                                                    TilesContainer container,
+                                                    AttributeEvaluatorFactory attributeEvaluatorFactory) {
+        BasicRendererFactory retValue = new BasicRendererFactory();
+        registerAttributeRenderers(retValue, applicationContext, container,
+            attributeEvaluatorFactory);
+        retValue.setDefaultRenderer(createDefaultAttributeRenderer(retValue,
+            applicationContext, container, attributeEvaluatorFactory));
+        return retValue;
+    }
+
+    /**
+     * Creates the default attribute renderer. By default it is an
+     * {@link ChainedDelegateRenderer}.
+     *
+     * @param rendererFactory           The renderer factory to configure.
+     * @param applicationContext        The Tiles application context.
+     * @param container                 The container.
+     * @param attributeEvaluatorFactory The attribute evaluator factory.
+     * @return The default attribute renderer.
+     * @since 3.0.0
+     */
+    protected Renderer createDefaultAttributeRenderer(
+        BasicRendererFactory rendererFactory,
+        ApplicationContext applicationContext,
+        TilesContainer container,
+        AttributeEvaluatorFactory attributeEvaluatorFactory) {
+        ChainedDelegateRenderer retValue = new ChainedDelegateRenderer();
+        retValue.addAttributeRenderer(rendererFactory.getRenderer(DEFINITION_RENDERER_NAME));
+        retValue.addAttributeRenderer(rendererFactory.getRenderer(TEMPLATE_RENDERER_NAME));
+        retValue.addAttributeRenderer(rendererFactory.getRenderer(STRING_RENDERER_NAME));
+        return retValue;
+    }
+
+    /**
+     * Creates a new pattern definition resolver. By default, it instantiate a
+     * {@link BasicPatternDefinitionResolver} with
+     * {@link WildcardDefinitionPatternMatcherFactory} to manage wildcard
+     * substitution.
+     *
+     * @param <T>                   The type of the customization key.
+     * @param customizationKeyClass The customization key class.
+     * @return The pattern definition resolver.
+     * @since 2.2.0
+     */
+    protected <T> PatternDefinitionResolver<T> createPatternDefinitionResolver(Class<T> customizationKeyClass) {
+        WildcardDefinitionPatternMatcherFactory definitionPatternMatcherFactory = new WildcardDefinitionPatternMatcherFactory();
+        return new BasicPatternDefinitionResolver<>(definitionPatternMatcherFactory, definitionPatternMatcherFactory);
+    }
+
+    /**
+     * Registers attribute renderers in a {@link BasicRendererFactory}. By
+     * default, it registers delegates to {@link StringRenderer},
+     * {@link DispatchRenderer} and {@link DefinitionRenderer}.
+     *
+     * @param rendererFactory           The renderer factory to configure.
+     * @param applicationContext        The Tiles application context.
+     * @param container                 The container.
+     * @param attributeEvaluatorFactory The attribute evaluator factory.
+     * @since 2.2.0
+     */
+    protected void registerAttributeRenderers(
+        BasicRendererFactory rendererFactory,
+        ApplicationContext applicationContext,
+        TilesContainer container,
+        AttributeEvaluatorFactory attributeEvaluatorFactory
+    ) {
+        rendererFactory.registerRenderer(
+            STRING_RENDERER_NAME,
+            createStringAttributeRenderer(rendererFactory, applicationContext, container, attributeEvaluatorFactory)
+        );
+        rendererFactory.registerRenderer(
+            TEMPLATE_RENDERER_NAME,
+            createTemplateAttributeRenderer(rendererFactory, applicationContext, container, attributeEvaluatorFactory)
+        );
+        rendererFactory.registerRenderer(
+            DEFINITION_RENDERER_NAME,
+            createDefinitionAttributeRenderer(rendererFactory, applicationContext, container, attributeEvaluatorFactory)
+        );
+    }
+
+    /**
+     * Creates an attribute renderer to render strings.
+     *
+     * @param rendererFactory           The renderer factory to configure.
+     * @param applicationContext        The Tiles application context.
+     * @param container                 The container.
+     * @param attributeEvaluatorFactory The attribute evaluator factory.
+     * @return The renderer.
+     * @since 3.0.0
+     */
+    protected Renderer createStringAttributeRenderer(
+        BasicRendererFactory rendererFactory,
+        ApplicationContext applicationContext,
+        TilesContainer container,
+        AttributeEvaluatorFactory attributeEvaluatorFactory
+    ) {
+        return new StringRenderer();
+    }
+
+    /**
+     * Creates a {@link Renderer} that uses a {@link DispatchRenderer}.
+     *
+     * @param rendererFactory           The renderer factory to configure.
+     * @param applicationContext        The Tiles application context.
+     * @param container                 The container.
+     * @param attributeEvaluatorFactory The attribute evaluator factory.
+     * @return The renderer.
+     * @since 2.2.1
+     */
+    protected Renderer createTemplateAttributeRenderer(
+        BasicRendererFactory rendererFactory,
+        ApplicationContext applicationContext,
+        TilesContainer container,
+        AttributeEvaluatorFactory attributeEvaluatorFactory
+    ) {
+        return new DispatchRenderer();
+    }
+
+    /**
+     * Creates a {@link Renderer} using a {@link DefinitionRenderer}.
+     *
+     * @param rendererFactory           The renderer factory to configure.
+     * @param applicationContext        The Tiles application context.
+     * @param container                 The container.
+     * @param attributeEvaluatorFactory The attribute evaluator factory.
+     * @return The renderer.
+     * @since 3.0.0
+     */
+    protected Renderer createDefinitionAttributeRenderer(
+        BasicRendererFactory rendererFactory,
+        ApplicationContext applicationContext,
+        TilesContainer container,
+        AttributeEvaluatorFactory attributeEvaluatorFactory
+    ) {
+        return new DefinitionRenderer(container);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java
index 38e506552..24d927788 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/TilesContainerFactoryException.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.factory;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.TilesException;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * Indicates that something went wrong in {@link AbstractTilesContainerFactory} use.
  *
- * @since Struts 2.0.2
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public class TilesContainerFactoryException extends TilesException {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * Constructor.
+     *
+     * @param message The detail message.
+     * @param e The exception to be wrapped.
+     * @since 2.1.0
+     */
+    public TilesContainerFactoryException(String message, Throwable e) {
+        super(message, e);
     }
-}
\ No newline at end of file
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java
index 38e506552..c305b60c7 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/factory/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Factory classes, to allow creation of container instances.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.factory;
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java
new file mode 100644
index 000000000..400c3bc44
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/BasicTilesContainer.java
@@ -0,0 +1,400 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.impl;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.AttributeContext;
+import org.apache.tiles.api.BasicAttributeContext;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.preparer.ViewPreparer;
+import org.apache.tiles.core.definition.DefinitionsFactory;
+import org.apache.tiles.core.definition.NoSuchDefinitionException;
+import org.apache.tiles.core.evaluator.AttributeEvaluator;
+import org.apache.tiles.core.evaluator.AttributeEvaluatorFactory;
+import org.apache.tiles.core.evaluator.AttributeEvaluatorFactoryAware;
+import org.apache.tiles.core.prepare.factory.NoSuchPreparerException;
+import org.apache.tiles.core.prepare.factory.PreparerFactory;
+import org.apache.tiles.request.ApplicationContext;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.render.CannotRenderException;
+import org.apache.tiles.request.render.Renderer;
+import org.apache.tiles.request.render.RendererFactory;
+
+import java.io.IOException;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * Basic implementation of the tiles container interface.
+ * In most cases, this container will be customized by
+ * injecting customized services, not necessarily by
+ * override the container
+ *
+ * @since 2.0
+ */
+public class BasicTilesContainer implements TilesContainer, AttributeEvaluatorFactoryAware {
+
+    /**
+     * Name used to store attribute context stack.
+     */
+    private static final String ATTRIBUTE_CONTEXT_STACK =
+        "org.apache.tiles.AttributeContext.STACK";
+
+    /**
+     * Log instance for all BasicTilesContainer
+     * instances.
+     */
+    private static final Logger LOG = LogManager.getLogger(BasicTilesContainer.class);
+
+    /**
+     * The Tiles application context object.
+     */
+    private ApplicationContext context;
+
+    /**
+     * The definitions factory.
+     */
+    private DefinitionsFactory definitionsFactory;
+
+    /**
+     * The preparer factory.
+     */
+    private PreparerFactory preparerFactory;
+
+    /**
+     * The renderer factory.
+     */
+    private RendererFactory rendererFactory;
+
+    /**
+     * The attribute evaluator.
+     */
+    private AttributeEvaluatorFactory attributeEvaluatorFactory;
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeContext startContext(Request request) {
+        AttributeContext context = new BasicAttributeContext();
+        Deque<AttributeContext> stack = getContextStack(request);
+        if (!stack.isEmpty()) {
+            AttributeContext parent = stack.peek();
+            context.inheritCascadedAttributes(parent);
+        }
+        stack.push(context);
+        return context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void endContext(Request request) {
+        popContext(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renderContext(Request request) {
+        AttributeContext attributeContext = getAttributeContext(request);
+
+        render(request, attributeContext);
+    }
+
+    /**
+     * Returns the Tiles application context used by this container.
+     *
+     * @return the application context for this container.
+     */
+    public ApplicationContext getApplicationContext() {
+        return context;
+    }
+
+    /**
+     * Sets the Tiles application context to use.
+     *
+     * @param context The Tiles application context.
+     */
+    public void setApplicationContext(ApplicationContext context) {
+        this.context = context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeContext getAttributeContext(Request request) {
+        AttributeContext context = getContext(request);
+        if (context == null) {
+            context = new BasicAttributeContext();
+            pushContext(context, request);
+        }
+        return context;
+
+    }
+
+    /**
+     * Set the definitions factory. This method first ensures
+     * that the container has not yet been initialized.
+     *
+     * @param definitionsFactory the definitions factory for this instance.
+     */
+    public void setDefinitionsFactory(DefinitionsFactory definitionsFactory) {
+        this.definitionsFactory = definitionsFactory;
+    }
+
+    /**
+     * Set the preparerInstance factory.  This method first ensures
+     * that the container has not yet been initialized.
+     *
+     * @param preparerFactory the preparerInstance factory for this conainer.
+     */
+    public void setPreparerFactory(PreparerFactory preparerFactory) {
+        this.preparerFactory = preparerFactory;
+    }
+
+    /**
+     * Sets the renderer instance factory.
+     *
+     * @param rendererFactory the renderer instance factory for this container.
+     * @since 2.1.0
+     */
+    public void setRendererFactory(RendererFactory rendererFactory) {
+        this.rendererFactory = rendererFactory;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAttributeEvaluatorFactory(
+        AttributeEvaluatorFactory attributeEvaluatorFactory) {
+        this.attributeEvaluatorFactory = attributeEvaluatorFactory;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void prepare(String preparer, Request request) {
+        prepare(request, preparer, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void render(String definitionName, Request request) {
+        LOG.debug("Render request received for definition '{}'", definitionName);
+
+        Definition definition = getDefinition(definitionName, request);
+
+        if (definition == null) {
+            throw new NoSuchDefinitionException("Unable to find the definition '" + definitionName + "'");
+        }
+
+        render(definition, request);
+    }
+
+    /**
+     * Renders the specified definition.
+     *
+     * @param definition The definition to render.
+     * @param request    The request context.
+     * @since 2.1.3
+     */
+    public void render(Definition definition, Request request) {
+        AttributeContext originalContext = getAttributeContext(request);
+        BasicAttributeContext subContext = new BasicAttributeContext(originalContext);
+        subContext.inherit(definition);
+
+        pushContext(subContext, request);
+
+        try {
+            render(request, subContext);
+        } finally {
+            popContext(request);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void render(Attribute attr, Request request)
+        throws IOException {
+        if (attr == null) {
+            throw new CannotRenderException("Cannot render a null attribute");
+        }
+
+        if (attr.isPermitted(request)) {
+            Renderer renderer = rendererFactory.getRenderer(attr.getRenderer());
+            Object value = evaluate(attr, request);
+            if (!(value instanceof String)) {
+                throw new CannotRenderException(
+                    "Cannot render an attribute that is not a string, toString returns: "
+                        + value);
+            }
+            renderer.render((String) value, request);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object evaluate(Attribute attribute, Request request) {
+        AttributeEvaluator evaluator = attributeEvaluatorFactory.getAttributeEvaluator(attribute);
+        return evaluator.evaluate(attribute, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidDefinition(String definitionName, Request request) {
+        try {
+            Definition definition = getDefinition(definitionName, request);
+            return definition != null;
+        } catch (NoSuchDefinitionException nsde) {
+            LOG.debug("Cannot find definition '{}'", definitionName);
+            LOG.debug("Exception related to the not found definition", nsde);
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Definition getDefinition(String definitionName, Request request) {
+        return definitionsFactory.getDefinition(definitionName, request);
+    }
+
+    /**
+     * Returns the context stack.
+     *
+     * @param tilesContext The Tiles context object to use.
+     * @return The needed stack of contexts.
+     * @since 2.0.6
+     */
+    @SuppressWarnings("unchecked")
+    protected Deque<AttributeContext> getContextStack(Request tilesContext) {
+        Map<String, Object> requestScope = tilesContext.getContext("request");
+        Deque<AttributeContext> contextStack = (Deque<AttributeContext>) requestScope
+            .get(ATTRIBUTE_CONTEXT_STACK);
+        if (contextStack == null) {
+            contextStack = new LinkedList<>();
+            requestScope.put(ATTRIBUTE_CONTEXT_STACK, contextStack);
+        }
+
+        return contextStack;
+    }
+
+    /**
+     * Pushes a context object in the stack.
+     *
+     * @param context      The context to push.
+     * @param tilesContext The Tiles context object to use.
+     * @since 2.0.6
+     */
+    protected void pushContext(AttributeContext context,
+                               Request tilesContext) {
+        Deque<AttributeContext> contextStack = getContextStack(tilesContext);
+        contextStack.push(context);
+    }
+
+    /**
+     * Pops a context object out of the stack.
+     *
+     * @param tilesContext The Tiles context object to use.
+     * @return The popped context object.
+     * @since 2.0.6
+     */
+    protected AttributeContext popContext(Request tilesContext) {
+        Deque<AttributeContext> contextStack = getContextStack(tilesContext);
+        return contextStack.pop();
+    }
+
+    /**
+     * Get attribute context from request.
+     *
+     * @param tilesContext current Tiles application context.
+     * @return BasicAttributeContext or null if context is not found.
+     * @since 2.0.6
+     */
+    protected AttributeContext getContext(Request tilesContext) {
+        Deque<AttributeContext> contextStack = getContextStack(tilesContext);
+        if (!contextStack.isEmpty()) {
+            return contextStack.peek();
+        }
+        return null;
+    }
+
+    /**
+     * Execute a preparer.
+     *
+     * @param context       The request context.
+     * @param preparerName  The name of the preparer.
+     * @param ignoreMissing If <code>true</code> if the preparer is not found,
+     *                      it ignores the problem.
+     * @throws NoSuchPreparerException If the preparer is not found (and
+     *                                 <code>ignoreMissing</code> is not set) or if the preparer itself threw an
+     *                                 exception.
+     */
+    private void prepare(Request context, String preparerName, boolean ignoreMissing) {
+
+        LOG.debug("Prepare request received for '{}'", preparerName);
+
+        ViewPreparer preparer = preparerFactory.getPreparer(preparerName, context);
+        if (preparer == null && ignoreMissing) {
+            return;
+        }
+
+        if (preparer == null) {
+            throw new NoSuchPreparerException("Preparer '" + preparerName + " not found");
+        }
+
+        AttributeContext attributeContext = getContext(context);
+
+        preparer.execute(context, attributeContext);
+    }
+
+    /**
+     * Renders the specified attribute context.
+     *
+     * @param request          The request context.
+     * @param attributeContext The context to render.
+     * @throws InvalidTemplateException If the template is not valid.
+     * @throws CannotRenderException    If something goes wrong during rendering.
+     * @since 2.1.3
+     */
+    protected void render(Request request,
+                          AttributeContext attributeContext) {
+
+        try {
+            if (attributeContext.getPreparer() != null) {
+                prepare(request, attributeContext.getPreparer(), true);
+            }
+
+            render(attributeContext.getTemplateAttribute(), request);
+        } catch (IOException e) {
+            throw new CannotRenderException(e.getMessage(), e);
+        }
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java
similarity index 53%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java
index 38e506552..51c46b215 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/InvalidTemplateException.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.impl;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import org.apache.tiles.api.TilesException;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
+ * An invalid template has been identified.
  *
- * @since Struts 2.0.2
+ * @since 2.1.0
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public class InvalidTemplateException extends TilesException {
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+    /**
+     * Constructor.
+     *
+     * @param message The detail message.
+     * @since 2.1.0
+     */
+    public InvalidTemplateException(String message) {
+        super(message);
+    }
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    /**
+     * Constructor.
+     *
+     * @param e The exception to be wrapped.
+     * @since 2.1.0
+     */
+    public InvalidTemplateException(Throwable e) {
+        super(e);
     }
-}
\ No newline at end of file
+
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java
new file mode 100644
index 000000000..40e64c906
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/CachingTilesContainer.java
@@ -0,0 +1,224 @@
+/*
+ * $Id$
+ *
+ * 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.
+ */
+package org.apache.tiles.core.impl.mgmt;
+
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.TilesContainer;
+import org.apache.tiles.api.TilesContainerWrapper;
+import org.apache.tiles.api.mgmt.MutableTilesContainer;
+import org.apache.tiles.core.definition.NoSuchDefinitionException;
+import org.apache.tiles.request.Request;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manages custom and configured definitions, so they can be used by the
+ * container, instead of using a simple {@link org.apache.tiles.core.definition.DefinitionsFactory}.
+ */
+public class CachingTilesContainer extends TilesContainerWrapper implements MutableTilesContainer {
+
+    /**
+     * The default name of the attribute in which storing custom definitions.
+     */
+    private static final String DEFAULT_DEFINITIONS_ATTRIBUTE_NAME = "org.apache.tiles.impl.mgmt.DefinitionManager.DEFINITIONS";
+
+    /**
+     * The name of the attribute in which storing custom definitions.
+     */
+    private final String definitionsAttributeName;
+
+    /**
+     * Constructor.
+     *
+     * @param originalContainer The original container to wrap.
+     */
+    public CachingTilesContainer(TilesContainer originalContainer) {
+        super(originalContainer);
+        definitionsAttributeName = DEFAULT_DEFINITIONS_ATTRIBUTE_NAME;
+    }
+
+    /**
+     * Returns a definition by name.
+     *
+     * @param definition The name of the definition.
+     * @param request    The current request.
+     * @return The requested definition, either main or custom.
+     */
+    public Definition getDefinition(String definition, Request request) {
+        Definition retValue;
+        retValue = getCustomDefinition(definition, request);
+        if (retValue == null) {
+            retValue = super.getDefinition(definition, request);
+        }
+        return retValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValidDefinition(String definition, Request request) {
+        if (getCustomDefinition(definition, request) != null) {
+            return true;
+        }
+        return super.isValidDefinition(definition, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void register(Definition definition, Request request) {
+        Map<String, Definition> definitions = getOrCreateDefinitions(request);
+        if (definition.getName() == null) {
+            definition.setName(getNextUniqueDefinitionName(definitions));
+        }
+
+        if (definition.isExtending()) {
+            this.resolveInheritance(definition, request);
+        }
+
+        definitions.put(definition.getName(), definition);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void render(String definition, Request request) {
+        Definition toRender = getDefinition(definition, request);
+        if (toRender == null) {
+            throw new NoSuchDefinitionException("Cannot find definition named '" + definition + "'");
+        }
+        super.render(toRender, request);
+    }
+
+    /**
+     * Resolve inheritance.
+     * First, resolve parent's inheritance, then set template to the parent's
+     * template.
+     * Also copy attributes set in parent, and not set in child
+     * If instance doesn't extend anything, do nothing.
+     *
+     * @param definition The definition that needs to have its inheritances
+     *                   resolved.
+     * @param request    The current request.
+     * @throws org.apache.tiles.core.definition.DefinitionsFactoryException If an
+     *                                                                      inheritance can not be solved.
+     */
+    private void resolveInheritance(Definition definition,
+                                    Request request) {
+        // Already done, or not needed ?
+        if (!definition.isExtending()) {
+            return;
+        }
+
+        String parentDefinitionName = definition.getExtends();
+
+        boolean recurse = true;
+        Definition parent = getCustomDefinition(parentDefinitionName, request);
+        if (parent == null) {
+            parent = container.getDefinition(parentDefinitionName, request);
+            recurse = false;
+        }
+
+        if (parent == null) {
+            throw new NoSuchDefinitionException(
+                "Error while resolving definition inheritance: child '"
+                    + definition.getName()
+                    + "' can't find its ancestor '"
+                    + parentDefinitionName
+                    + "'. Please check your description file.");
+        }
+
+        // Resolve parent before itself.
+        if (recurse) {
+            resolveInheritance(parent, request);
+        }
+        definition.inherit(parent);
+    }
+
+    /**
+     * Returns the map with custom definitions for the current request.
+     *
+     * @param request The current request.
+     * @return A map that connects a definition name to a definition.
+     */
+    @SuppressWarnings("unchecked")
+    private Map<String, Definition> getDefinitions(
+        Request request) {
+        return (Map<String, Definition>) request.getContext("request")
+            .get(definitionsAttributeName);
+    }
+
+    /**
+     * Returns a map of type "definition name -> definition" and, if it has not
+     * been defined before, creates one.
+     *
+     * @param request The current request.
+     * @return A map that connects a definition name to a definition.
+     */
+    @SuppressWarnings("unchecked")
+    private Map<String, Definition> getOrCreateDefinitions(Request request) {
+        Map<String, Definition> definitions = (Map<String, Definition>) request.getContext("request").get(definitionsAttributeName);
+        if (definitions == null) {
+            definitions = new HashMap<>();
+            request.getContext("request").put(definitionsAttributeName, definitions);
+        }
+
+        return definitions;
+    }
+
+    /**
+     * Create a unique definition name usable to store anonymous definitions.
+     *
+     * @param definitions The already created definitions.
+     * @return The unique definition name to be used to store the definition.
+     * @since 2.1.0
+     */
+    private String getNextUniqueDefinitionName(Map<String, Definition> definitions) {
+        String candidate;
+        int anonymousDefinitionIndex = 1;
+
+        do {
+            candidate = "$anonymousMutableDefinition" + anonymousDefinitionIndex;
+            anonymousDefinitionIndex++;
+        } while (definitions.containsKey(candidate));
+
+        return candidate;
+    }
+
+    /**
+     * Returns a custom definition from the cache.
+     *
+     * @param definition The definition to search.
+     * @param request    The request.
+     * @return The requested definition.
+     */
+    private Definition getCustomDefinition(String definition, Request request) {
+        Map<String, Definition> definitions = getDefinitions(request);
+        if (definitions != null) {
+            return definitions.get(definition);
+        }
+        return null;
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java
index 38e506552..ad44a742f 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/mgmt/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * It contains the basic implementations of mutable Tiles containers.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.impl.mgmt;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java
index 38e506552..638599c00 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/impl/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
-
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * It contains the basic implementations of Tiles container.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
-
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+package org.apache.tiles.core.impl;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java
index 38e506552..e377fa8d6 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/LocaleResolver.java
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * 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
@@ -7,7 +9,7 @@
  * "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
+ * 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
@@ -16,25 +18,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.core.locale;
+
+import org.apache.tiles.request.Request;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.tiles.startup.TilesInitializer;
-import org.apache.tiles.web.startup.AbstractTilesListener;
+import java.util.Locale;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * It represents an object able to resolve the current locale for the current
+ * request, where its strategy depends on its implementation.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface LocaleResolver {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Resolves the locale.
+     *
+     * @param request The Tiles request object.
+     * @return The current locale for the current request.
+     */
+    Locale resolveLocale(Request request);
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java
new file mode 100644
index 000000000..b592978a0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/core/locale/impl/DefaultLocaleResolver.java
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * 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
... 15824 lines suppressed ...


[struts] 18/23: Add missing classes and tld definition.

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5233-tiles
in repository https://gitbox.apache.org/repos/asf/struts.git

commit fff3cc8acb88453df51356e9e72a3868cf392586
Author: Greg Huber <gh...@apache.org>
AuthorDate: Fri Oct 7 09:57:10 2022 +0100

    Add missing classes and tld definition.
---
 .../apache/tiles/template/GetAsStringModel.java    |   9 +
 .../tiles/web/jsp/taglib/AddAttributeTag.java      | 166 ++++
 .../tiles/web/jsp/taglib/AddListAttributeTag.java  |  88 ++
 .../apache/tiles/web/jsp/taglib/DefinitionTag.java | 185 +++++
 .../tiles/web/jsp/taglib/GetAsStringTag.java       | 266 ++++++
 .../tiles/web/jsp/taglib/ImportAttributeTag.java   | 167 ++++
 .../tiles/web/jsp/taglib/InsertAttributeTag.java   | 303 +++++++
 .../tiles/web/jsp/taglib/InsertDefinitionTag.java  | 260 ++++++
 .../tiles/web/jsp/taglib/InsertTemplateTag.java    | 233 ++++++
 .../tiles/web/jsp/taglib/PutAttributeTag.java      | 234 ++++++
 .../tiles/web/jsp/taglib/PutListAttributeTag.java  | 164 ++++
 .../web/jsp/taglib/SetCurrentContainerTag.java     |  81 ++
 .../tiles/web/jsp/taglib/UseAttributeTag.java      |  21 +-
 .../apache/tiles/web/jsp/taglib/package-info.java  |   4 +-
 .../resources/META-INF/tld/tiles-extras-jsp.tld    |  16 +-
 .../src/main/resources/META-INF/tld/tiles-jsp.tld  | 894 +++++++++++++++++++++
 16 files changed, 3067 insertions(+), 24 deletions(-)

diff --git a/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java b/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java
index b2d7db437..1bf1de742 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/template/GetAsStringModel.java
@@ -56,6 +56,15 @@ public class GetAsStringModel {
      * The attribute resolver to use.
      */
     private final AttributeResolver attributeResolver;
+    
+    /**
+     * Constructor that uses the defaut attribute resolver.
+     *
+     * @since 3.0.0
+     */
+    public GetAsStringModel() {
+        this(new DefaultAttributeResolver());
+    }
 
     /**
      * Constructor.
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
new file mode 100644
index 000000000..a5bd36b04
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddAttributeTag.java
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.AddAttributeModel;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Add an element to the surrounding list. Equivalent to 'putAttribute', but for
+ * list element.
+ * </p>
+ * 
+ * <p>
+ * Add an element to the surrounding list. This tag can only be used inside
+ * 'putListAttribute' or 'addListAttribute' tags. Value can come from a direct
+ * assignment (value="aValue")
+ * </p>
+ */
+public class AddAttributeTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private AddAttributeModel model = new AddAttributeModel();
+
+    /**
+     * The value of the attribute. Use this parameter, or expression, or body.
+     */
+    private Object value;
+
+    /**
+     * The expression to calculate the value from. Use this parameter, or value, or
+     * body.
+     */
+    private String expression;
+
+    /**
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The type (renderer) of the attribute.
+     */
+    private String type;
+
+    /**
+     * Getter for value property.
+     *
+     * @return The value of the attribute. Use this parameter, or expression, or
+     *         body.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Setter for value property.
+     *
+     * @param value The value of the attribute. Use this parameter, or expression,
+     *              or body.
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Getter for expression property.
+     *
+     * @return The expression to calculate the value from. Use this parameter, or
+     *         value, or body.
+     */
+    public String getExpression() {
+        return expression;
+    }
+
+    /**
+     * Setter for expression property.
+     *
+     * @param expression The expression to calculate the value from. Use this
+     *                   parameter, or value, or body.
+     */
+    public void setExpression(String expression) {
+        this.expression = expression;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for type property.
+     *
+     * @return The type (renderer) of the attribute.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Setter for type property.
+     *
+     * @param type The type (renderer) of the attribute.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(value, expression, role, type, request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
new file mode 100644
index 000000000..5f17d8145
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/AddListAttributeTag.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.AddListAttributeModel;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Declare a list that will be pass as an attribute.
+ * </p>
+ * <p>
+ * Declare a list that will be pass as an attribute . List elements are added
+ * using the tag 'addAttribute' or 'addListAttribute'. This tag can only be used
+ * inside 'insertTemplate', 'insertDefinition' or 'definition' tag.
+ * </p>
+ */
+public class AddListAttributeTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private AddListAttributeModel model = new AddListAttributeModel();
+
+    /**
+     * The comma-separated list of roles that can use the list attribute.
+     */
+    private String role;
+
+    /**
+     * Getter for role property.
+     *
+     * @return The comma-separated list of roles that can use the list attribute.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role The comma-separated list of roles that can use the list
+     *             attribute.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(role, request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
new file mode 100644
index 000000000..340917369
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/DefinitionTag.java
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.DefinitionModel;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Create a definition at runtime.
+ * </p>
+ * <p>
+ * Create a new definition at runtime. Newly created definition will be
+ * available across the entire request.
+ * </p>
+ */
+public class DefinitionTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private DefinitionModel model = new DefinitionModel();
+
+    /**
+     * The name of the definition to create. If not specified, an anonymous
+     * definition will be created.
+     */
+    private String name;
+
+    /**
+     * The template of this definition.
+     */
+    private String template;
+
+    /**
+     * A comma-separated list of roles. If present, the definition will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The definition name that this definition extends.
+     */
+    private String extendsParam;
+
+    /**
+     * The preparer to use to invoke before the definition is rendered.
+     */
+    private String preparer;
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the definition to create. If not specified, an anonymous
+     *         definition will be created.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param name The name of the definition to create. If not specified, an
+     *             anonymous definition will be created.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Getter for template property.
+     *
+     * @return The template of this definition.
+     */
+    public String getTemplate() {
+        return template;
+    }
+
+    /**
+     * Setter for template property.
+     *
+     * @param template The template of this definition.
+     */
+    public void setTemplate(String template) {
+        this.template = template;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the definition will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the definition will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for extends property.
+     *
+     * @return The definition name that this definition extends.
+     */
+    public String getExtends() {
+        return extendsParam;
+    }
+
+    /**
+     * Setter for extends property.
+     *
+     * @param extendsParam The definition name that this definition extends.
+     */
+    public void setExtends(String extendsParam) {
+        this.extendsParam = extendsParam;
+    }
+
+    /**
+     * Getter for preparer property.
+     *
+     * @return The preparer to use to invoke before the definition is rendered.
+     */
+    public String getPreparer() {
+        return preparer;
+    }
+
+    /**
+     * Setter for preparer property.
+     *
+     * @param preparer The preparer to use to invoke before the definition is
+     *                 rendered.
+     */
+    public void setPreparer(String preparer) {
+        this.preparer = preparer;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(name, template, role, extendsParam, preparer, request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
new file mode 100644
index 000000000..5cd777819
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/GetAsStringTag.java
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.GetAsStringModel;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Render the value of the specified template attribute to the current Writer
+ * </p>
+ * 
+ * <p>
+ * Retrieve the value of the specified template attribute property, and render
+ * it to the current Writer as a String. The usual toString() conversions is
+ * applied on found value.
+ * </p>
+ */
+public class GetAsStringTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private GetAsStringModel model = new GetAsStringModel();
+
+    /**
+     * If true, if an exception happens during rendering, of if the attribute is
+     * null, the problem will be ignored.
+     */
+    private boolean ignore;
+
+    /**
+     * The preparer to invoke before rendering the attribute.
+     */
+    private String preparer;
+
+    /**
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The default value of the attribute. To use only if the attribute was not
+     * computed.
+     */
+    private Object defaultValue;
+
+    /**
+     * The default comma-separated list of roles. To use only if the attribute was
+     * not computed.
+     */
+    private String defaultValueRole;
+
+    /**
+     * The default type of the attribute. To use only if the attribute was not
+     * computed.
+     */
+    private String defaultValueType;
+
+    /**
+     * The name of the attribute.
+     */
+    private String name;
+
+    /**
+     * The attribute to use immediately, if not null.
+     */
+    private Attribute value;
+
+    /**
+     * Getter for ignore property.
+     *
+     * @return If true, if an exception happens during rendering, of if the
+     *         attribute is null, the problem will be ignored.
+     */
+    public boolean isIgnore() {
+        return ignore;
+    }
+
+    /**
+     * Setter for ignore property.
+     *
+     * @param ignore If true, if an exception happens during rendering, of if the
+     *               attribute is null, the problem will be ignored.
+     */
+    public void setIgnore(boolean ignore) {
+        this.ignore = ignore;
+    }
+
+    /**
+     * Getter for preparer property.
+     *
+     * @return The preparer to invoke before rendering the attribute.
+     */
+    public String getPreparer() {
+        return preparer;
+    }
+
+    /**
+     * Setter for preparer property.
+     *
+     * @param preparer The preparer to invoke before rendering the attribute.
+     */
+    public void setPreparer(String preparer) {
+        this.preparer = preparer;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for defaultValue property.
+     *
+     * @return The default value of the attribute. To use only if the attribute was
+     *         not computed.
+     */
+    public Object getDefaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Setter for defaultValue property.
+     *
+     * @param defaultValue The default value of the attribute. To use only if the
+     *                     attribute was not computed.
+     */
+    public void setDefaultValue(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    /**
+     * Getter for defaultValueRole property.
+     *
+     * @return The default comma-separated list of roles. To use only if the
+     *         attribute was not computed.
+     */
+    public String getDefaultValueRole() {
+        return defaultValueRole;
+    }
+
+    /**
+     * Setter for defaultValueRole property.
+     *
+     * @param defaultValueRole The default comma-separated list of roles. To use
+     *                         only if the attribute was not computed.
+     */
+    public void setDefaultValueRole(String defaultValueRole) {
+        this.defaultValueRole = defaultValueRole;
+    }
+
+    /**
+     * Getter for defaultValueType property.
+     *
+     * @return The default type of the attribute. To use only if the attribute was
+     *         not computed.
+     */
+    public String getDefaultValueType() {
+        return defaultValueType;
+    }
+
+    /**
+     * Setter for defaultValueType property.
+     *
+     * @param defaultValueType The default type of the attribute. To use only if the
+     *                         attribute was not computed.
+     */
+    public void setDefaultValueType(String defaultValueType) {
+        this.defaultValueType = defaultValueType;
+    }
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the attribute.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param name The name of the attribute.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Getter for value property.
+     *
+     * @return The attribute to use immediately, if not null.
+     */
+    public Attribute getValue() {
+        return value;
+    }
+
+    /**
+     * Setter for value property.
+     *
+     * @param value The attribute to use immediately, if not null.
+     */
+    public void setValue(Attribute value) {
+        this.value = value;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(ignore, preparer, role, defaultValue, defaultValueRole, defaultValueType, name, value, request,
+                modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
new file mode 100644
index 000000000..3468f3865
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/ImportAttributeTag.java
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.ImportAttributeModel;
+
+/**
+ * <p>
+ * Import attribute(s) in specified context.
+ * </p>
+ * <p>
+ * Import attribute(s) to requested scope. Attribute name and scope are
+ * optional. If not specified, all attributes are imported in page scope. Once
+ * imported, an attribute can be used as any other beans from jsp contexts.
+ * </p>
+ */
+public class ImportAttributeTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private ImportAttributeModel model = new ImportAttributeModel();
+
+    /**
+     * The name of the attribute to import. If it is null, all the attributes will
+     * be imported.
+     */
+    private String name;
+
+    /**
+     * The scope into which the attribute(s) will be imported. If null, the import
+     * will go in page scope.
+     */
+    private String scope;
+
+    /**
+     * The name of the attribute into which the attribute will be imported. To be
+     * used in conjunction to name. If null, the value of name will be used.
+     */
+    private String toName;
+
+    /**
+     * If true, if the attribute is not present, the problem will be ignored.
+     */
+    private boolean ignore;
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the attribute to import. If it is null, all the
+     *         attributes will be imported.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param name The name of the attribute to import. If it is null, all the
+     *             attributes will be imported.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Getter for scope property.
+     *
+     * @return The scope into which the attribute(s) will be imported. If null, the
+     *         import will go in page scope.
+     */
+    public String getScope() {
+        return scope;
+    }
+
+    /**
+     * Setter for scope property.
+     *
+     * @param scope The scope into which the attribute(s) will be imported. If null,
+     *              the import will go in page scope.
+     */
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+    /**
+     * Getter for toName property.
+     *
+     * @return The name of the attribute into which the attribute will be imported.
+     *         To be used in conjunction to name. If null, the value of name will be
+     *         used.
+     */
+    public String getToName() {
+        return toName;
+    }
+
+    /**
+     * Setter for toName property.
+     *
+     * @param toName The name of the attribute into which the attribute will be
+     *               imported. To be used in conjunction to name. If null, the value
+     *               of name will be used.
+     */
+    public void setToName(String toName) {
+        this.toName = toName;
+    }
+
+    /**
+     * Getter for ignore property.
+     *
+     * @return If true, if the attribute is not present, the problem will be
+     *         ignored.
+     */
+    public boolean isIgnore() {
+        return ignore;
+    }
+
+    /**
+     * Setter for ignore property.
+     *
+     * @param ignore If true, if the attribute is not present, the problem will be
+     *               ignored.
+     */
+    public void setIgnore(boolean ignore) {
+        this.ignore = ignore;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        model.execute(name, scope, toName, ignore, request);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
new file mode 100644
index 000000000..58909fc6c
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertAttributeTag.java
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.InsertAttributeModel;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Inserts the value of an attribute into the page.
+ * </p>
+ * <p>
+ * This tag can be flexibly used to insert the value of an attribute into a
+ * page. As in other usages in Tiles, every attribute can be determined to have
+ * a "type", either set explicitly when it was defined, or "computed". If the
+ * type is not explicit, then if the attribute value is a valid definition, it
+ * will be inserted as such. Otherwise, if it begins with a "/" character, it
+ * will be treated as a "template". Finally, if it has not otherwise been
+ * assigned a type, it will be treated as a String and included without any
+ * special handling.
+ * </p>
+ * 
+ * <p>
+ * Example :
+ * </p>
+ * 
+ * <pre>
+ *   &lt;code&gt;
+ *     &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
+ *   &lt;/code&gt;
+ * </pre>
+ */
+public class InsertAttributeTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private InsertAttributeModel model = new InsertAttributeModel();
+
+    /**
+     * If true, if an exception happens during rendering, of if the attribute is
+     * null, the problem will be ignored.
+     */
+    private boolean ignore;
+
+    /**
+     * The preparer to invoke before rendering the attribute.
+     */
+    private String preparer;
+
+    /**
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The default value of the attribute. To use only if the attribute was not
+     * computed.
+     */
+    private Object defaultValue;
+
+    /**
+     * The default comma-separated list of roles. To use only if the attribute was
+     * not computed.
+     */
+    private String defaultValueRole;
+
+    /**
+     * The default type of the attribute. To use only if the attribute was not
+     * computed.
+     */
+    private String defaultValueType;
+
+    /**
+     * The name of the attribute.
+     */
+    private String name;
+
+    /**
+     * The attribute to use immediately, if not null.
+     */
+    private Attribute value;
+
+    /**
+     * If true, the response will be flushed after the insert.
+     */
+    private boolean flush;
+
+    /**
+     * Getter for ignore property.
+     *
+     * @return If true, if an exception happens during rendering, of if the
+     *         attribute is null, the problem will be ignored.
+     */
+    public boolean isIgnore() {
+        return ignore;
+    }
+
+    /**
+     * Setter for ignore property.
+     *
+     * @param ignore If true, if an exception happens during rendering, of if the
+     *               attribute is null, the problem will be ignored.
+     */
+    public void setIgnore(boolean ignore) {
+        this.ignore = ignore;
+    }
+
+    /**
+     * Getter for preparer property.
+     *
+     * @return The preparer to invoke before rendering the attribute.
+     */
+    public String getPreparer() {
+        return preparer;
+    }
+
+    /**
+     * Setter for preparer property.
+     *
+     * @param preparer The preparer to invoke before rendering the attribute.
+     */
+    public void setPreparer(String preparer) {
+        this.preparer = preparer;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for defaultValue property.
+     *
+     * @return The default value of the attribute. To use only if the attribute was
+     *         not computed.
+     */
+    public Object getDefaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Setter for defaultValue property.
+     *
+     * @param defaultValue The default value of the attribute. To use only if the
+     *                     attribute was not computed.
+     */
+    public void setDefaultValue(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    /**
+     * Getter for defaultValueRole property.
+     *
+     * @return The default comma-separated list of roles. To use only if the
+     *         attribute was not computed.
+     */
+    public String getDefaultValueRole() {
+        return defaultValueRole;
+    }
+
+    /**
+     * Setter for defaultValueRole property.
+     *
+     * @param defaultValueRole The default comma-separated list of roles. To use
+     *                         only if the attribute was not computed.
+     */
+    public void setDefaultValueRole(String defaultValueRole) {
+        this.defaultValueRole = defaultValueRole;
+    }
+
+    /**
+     * Getter for defaultValueType property.
+     *
+     * @return The default type of the attribute. To use only if the attribute was
+     *         not computed.
+     */
+    public String getDefaultValueType() {
+        return defaultValueType;
+    }
+
+    /**
+     * Setter for defaultValueType property.
+     *
+     * @param defaultValueType The default type of the attribute. To use only if the
+     *                         attribute was not computed.
+     */
+    public void setDefaultValueType(String defaultValueType) {
+        this.defaultValueType = defaultValueType;
+    }
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the attribute.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param name The name of the attribute.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Getter for value property.
+     *
+     * @return The attribute to use immediately, if not null.
+     */
+    public Attribute getValue() {
+        return value;
+    }
+
+    /**
+     * Setter for value property.
+     *
+     * @param value The attribute to use immediately, if not null.
+     */
+    public void setValue(Attribute value) {
+        this.value = value;
+    }
+
+    /**
+     * Getter for flush property.
+     *
+     * @return If true, the response will be flushed after the insert.
+     */
+    public boolean isFlush() {
+        return flush;
+    }
+
+    /**
+     * Setter for flush property.
+     *
+     * @param flush If true, the response will be flushed after the insert.
+     */
+    public void setFlush(boolean flush) {
+        this.flush = flush;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(ignore, preparer, role, defaultValue, defaultValueRole, defaultValueType, name, value, flush,
+                request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
new file mode 100644
index 000000000..bd42a4b78
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertDefinitionTag.java
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.InsertDefinitionModel;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Insert a definition.
+ * </p>
+ * <p>
+ * Insert a definition with the possibility to override and specify parameters
+ * (called attributes). A definition can be seen as a (partially or totally)
+ * filled template that can override or complete attribute values.
+ * &lt;tiles:insertDefinition&gt; allows to define these attributes and pass
+ * them to the inserted jsp page, called template. Attributes are defined using
+ * nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+ * </p>
+ * <p>
+ * You must specify name tag attribute, for inserting a definition from
+ * definitions factory.
+ * </p>
+ * <p>
+ * Example :
+ * </p>
+ * 
+ * <pre>
+ *   &lt;code&gt;
+ *     &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
+ *     &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *     &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;/tiles:insertDefinition&gt;
+ *   &lt;/code&gt;
+ * </pre>
+ */
+public class InsertDefinitionTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private InsertDefinitionModel model = new InsertDefinitionModel();
+
+    /**
+     * The name of the definition to render.
+     */
+    private String definitionName;
+
+    /**
+     * If specified, this template will be used instead of the one used by the
+     * definition.
+     */
+    private String template;
+
+    /**
+     * The type of the template attribute.
+     */
+    private String templateType;
+
+    /**
+     * The expression to evaluate to get the value of the template.
+     */
+    private String templateExpression;
+
+    /**
+     * A comma-separated list of roles. If present, the definition will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The preparer to use to invoke before the definition is rendered. If
+     * specified, it overrides the preparer specified in the definition itself.
+     */
+    private String preparer;
+
+    /**
+     * If true, the response will be flushed after the insert.
+     */
+    private boolean flush;
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the definition to render.
+     */
+    public String getName() {
+        return definitionName;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param definitionName The name of the definition to render.
+     */
+    public void setName(String definitionName) {
+        this.definitionName = definitionName;
+    }
+
+    /**
+     * Getter for template property.
+     *
+     * @return If specified, this template will be used instead of the one used by
+     *         the definition.
+     */
+    public String getTemplate() {
+        return template;
+    }
+
+    /**
+     * Setter for template property.
+     *
+     * @param template If specified, this template will be used instead of the one
+     *                 used by the definition.
+     */
+    public void setTemplate(String template) {
+        this.template = template;
+    }
+
+    /**
+     * Getter for templateType property.
+     *
+     * @return The type of the template attribute.
+     */
+    public String getTemplateType() {
+        return templateType;
+    }
+
+    /**
+     * Setter for templateType property.
+     *
+     * @param templateType The type of the template attribute.
+     */
+    public void setTemplateType(String templateType) {
+        this.templateType = templateType;
+    }
+
+    /**
+     * Getter for templateExpression property.
+     *
+     * @return The expression to evaluate to get the value of the template.
+     */
+    public String getTemplateExpression() {
+        return templateExpression;
+    }
+
+    /**
+     * Setter for templateExpression property.
+     *
+     * @param templateExpression The expression to evaluate to get the value of the
+     *                           template.
+     */
+    public void setTemplateExpression(String templateExpression) {
+        this.templateExpression = templateExpression;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the definition will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the definition will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for preparer property.
+     *
+     * @return The preparer to use to invoke before the definition is rendered. If
+     *         specified, it overrides the preparer specified in the definition
+     *         itself.
+     */
+    public String getPreparer() {
+        return preparer;
+    }
+
+    /**
+     * Setter for preparer property.
+     *
+     * @param preparer The preparer to use to invoke before the definition is
+     *                 rendered. If specified, it overrides the preparer specified
+     *                 in the definition itself.
+     */
+    public void setPreparer(String preparer) {
+        this.preparer = preparer;
+    }
+
+    /**
+     * Getter for flush property.
+     *
+     * @return If true, the response will be flushed after the insert.
+     */
+    public boolean isFlush() {
+        return flush;
+    }
+
+    /**
+     * Setter for flush property.
+     *
+     * @param flush If true, the response will be flushed after the insert.
+     */
+    public void setFlush(boolean flush) {
+        this.flush = flush;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(definitionName, template, templateType, templateExpression, role, preparer, flush, request,
+                modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
new file mode 100644
index 000000000..aaa187068
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/InsertTemplateTag.java
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.InsertTemplateModel;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Insert a template.
+ * </p>
+ * <p>
+ * Insert a template with the possibility to pass parameters (called
+ * attributes). A template can be seen as a procedure that can take parameters
+ * or attributes. &lt;tiles:insertTemplate&gt; allows to define these attributes
+ * and pass them to the inserted jsp page, called template. Attributes are
+ * defined using nested tag &lt;tiles:putAttribute&gt; or
+ * &lt;tiles:putListAttribute&gt;.
+ * </p>
+ * <p>
+ * You must specify template attribute, for inserting a template
+ * </p>
+ * 
+ * <p>
+ * Example :
+ * </p>
+ * 
+ * <pre>
+ *   &lt;code&gt;
+ *     &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
+ *       &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+ *       &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+ *       &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+ *       &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+ *       &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+ *     &lt;/tiles:insertTemplate&gt;
+ *   &lt;/code&gt;
+ * </pre>
+ */
+public class InsertTemplateTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private InsertTemplateModel model = new InsertTemplateModel();
+
+    /**
+     * The template to render.
+     */
+    private String template;
+
+    /**
+     * The type of the template attribute.
+     */
+    private String templateType;
+
+    /**
+     * The expression to evaluate to get the value of the template.
+     */
+    private String templateExpression;
+
+    /**
+     * A comma-separated list of roles. If present, the template will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The preparer to use to invoke before the definition is rendered. If
+     * specified, it overrides the preparer specified in the definition itself.
+     */
+    private String preparer;
+
+    /**
+     * If true, the response will be flushed after the insert.
+     */
+    private boolean flush;
+
+    /**
+     * Getter for template property.
+     *
+     * @return The template to render.
+     */
+    public String getTemplate() {
+        return template;
+    }
+
+    /**
+     * Setter for template property.
+     *
+     * @param template The template to render.
+     */
+    public void setTemplate(String template) {
+        this.template = template;
+    }
+
+    /**
+     * Getter for templateType property.
+     *
+     * @return The type of the template attribute.
+     */
+    public String getTemplateType() {
+        return templateType;
+    }
+
+    /**
+     * Setter for templateType property.
+     *
+     * @param templateType The type of the template attribute.
+     */
+    public void setTemplateType(String templateType) {
+        this.templateType = templateType;
+    }
+
+    /**
+     * Getter for templateExpression property.
+     *
+     * @return The expression to evaluate to get the value of the template.
+     */
+    public String getTemplateExpression() {
+        return templateExpression;
+    }
+
+    /**
+     * Setter for templateExpression property.
+     *
+     * @param templateExpression The expression to evaluate to get the value of the
+     *                           template.
+     */
+    public void setTemplateExpression(String templateExpression) {
+        this.templateExpression = templateExpression;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the template will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the template will be
+     *             rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for preparer property.
+     *
+     * @return The preparer to use to invoke before the definition is rendered. If
+     *         specified, it overrides the preparer specified in the definition
+     *         itself.
+     */
+    public String getPreparer() {
+        return preparer;
+    }
+
+    /**
+     * Setter for preparer property.
+     *
+     * @param preparer The preparer to use to invoke before the definition is
+     *                 rendered. If specified, it overrides the preparer specified
+     *                 in the definition itself.
+     */
+    public void setPreparer(String preparer) {
+        this.preparer = preparer;
+    }
+
+    /**
+     * Getter for flush property.
+     *
+     * @return If true, the response will be flushed after the insert.
+     */
+    public boolean isFlush() {
+        return flush;
+    }
+
+    /**
+     * Setter for flush property.
+     *
+     * @param flush If true, the response will be flushed after the insert.
+     */
+    public void setFlush(boolean flush) {
+        this.flush = flush;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(template, templateType, templateExpression, role, preparer, flush, request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
new file mode 100644
index 000000000..f687d7e49
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutAttributeTag.java
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.PutAttributeModel;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Put an attribute in enclosing attribute container tag.
+ * </p>
+ * <p>
+ * Enclosing attribute container tag can be :
+ * <ul>
+ * <li>&lt;initContainer&gt;</li>
+ * <li>&lt;definition&gt;</li>
+ * <li>&lt;insertAttribute&gt;</li>
+ * <li>&lt;insertDefinition&gt;</li>
+ * <li>&lt;putListAttribute&gt;</li>
+ * </ul>
+ * (or any other tag which implements the PutAttributeTagParent interface.
+ * Exception is thrown if no appropriate tag can be found.
+ * </p>
+ * <p>
+ * Put tag can have following atributes :
+ * <ul>
+ * <li>name : Name of the attribute</li>
+ * <li>value : value to put as attribute</li>
+ * <li>type : value type. Possible type are : string (value is used as direct
+ * string), template (value is used as a page url to insert), definition (value
+ * is used as a definition name to insert), object (value is used as it is)</li>
+ * <li>role : Role to check when 'insertAttribute' will be called.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Value can also come from tag body. Tag body is taken into account only if
+ * value is not set by one of the tag attributes. In this case Attribute type is
+ * "string", unless tag body define another type.
+ * </p>
+ */
+public class PutAttributeTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private PutAttributeModel model = new org.apache.tiles.template.PutAttributeModel();
+
+    /**
+     * The name of the attribute to put.
+     */
+    private String name;
+
+    /**
+     * The value of the attribute. Use this parameter, or expression, or body.
+     */
+    private Object value;
+
+    /**
+     * The expression to calculate the value from. Use this parameter, or value, or
+     * body.
+     */
+    private String expression;
+
+    /**
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * The type (renderer) of the attribute.
+     */
+    private String type;
+
+    /**
+     * If true the attribute will be cascaded to all nested attributes.
+     */
+    private boolean cascade;
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the attribute to put.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param name The name of the attribute to put.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Getter for value property.
+     *
+     * @return The value of the attribute. Use this parameter, or expression, or
+     *         body.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Setter for value property.
+     *
+     * @param value The value of the attribute. Use this parameter, or expression,
+     *              or body.
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Getter for expression property.
+     *
+     * @return The expression to calculate the value from. Use this parameter, or
+     *         value, or body.
+     */
+    public String getExpression() {
+        return expression;
+    }
+
+    /**
+     * Setter for expression property.
+     *
+     * @param expression The expression to calculate the value from. Use this
+     *                   parameter, or value, or body.
+     */
+    public void setExpression(String expression) {
+        this.expression = expression;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for type property.
+     *
+     * @return The type (renderer) of the attribute.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Setter for type property.
+     *
+     * @param type The type (renderer) of the attribute.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Getter for cascade property.
+     *
+     * @return If true the attribute will be cascaded to all nested attributes.
+     */
+    public boolean isCascade() {
+        return cascade;
+    }
+
+    /**
+     * Setter for cascade property.
+     *
+     * @param cascade If true the attribute will be cascaded to all nested
+     *                attributes.
+     */
+    public void setCascade(boolean cascade) {
+        this.cascade = cascade;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(name, value, expression, role, type, cascade, request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
new file mode 100644
index 000000000..b60628f25
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/PutListAttributeTag.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.ModelBody;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+
+/**
+ * <p>
+ * Declare a list that will be pass as attribute to tile.
+ * </p>
+ * <p>
+ * Declare a list that will be pass as attribute to tile. List elements are
+ * added using the tags 'addAttribute' or 'addListAttribute'. This tag can only
+ * be used inside 'insertTemplate', 'insertDefinition', 'definition' tags.
+ * </p>
+ */
+public class PutListAttributeTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private org.apache.tiles.template.PutListAttributeModel model = new org.apache.tiles.template.PutListAttributeModel();
+
+    /**
+     * The name of the attribute to put.
+     */
+    private String name;
+
+    /**
+     * A comma-separated list of roles. If present, the attribute will be rendered
+     * only if the current user belongs to one of the roles.
+     */
+    private String role;
+
+    /**
+     * If true, the list attribute will use, as first elements, the list contained
+     * in the list attribute, put with the same name, of the containing definition.
+     */
+    private boolean inherit;
+
+    /**
+     * If true the attribute will be cascaded to all nested attributes.
+     */
+    private boolean cascade;
+
+    /**
+     * Getter for name property.
+     *
+     * @return The name of the attribute to put.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Setter for name property.
+     *
+     * @param name The name of the attribute to put.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Getter for role property.
+     *
+     * @return A comma-separated list of roles. If present, the attribute will be
+     *         rendered only if the current user belongs to one of the roles.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Setter for role property.
+     *
+     * @param role A comma-separated list of roles. If present, the attribute will
+     *             be rendered only if the current user belongs to one of the roles.
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Getter for inherit property.
+     *
+     * @return If true, the list attribute will use, as first elements, the list
+     *         contained in the list attribute, put with the same name, of the
+     *         containing definition.
+     */
+    public boolean isInherit() {
+        return inherit;
+    }
+
+    /**
+     * Setter for inherit property.
+     *
+     * @param inherit If true, the list attribute will use, as first elements, the
+     *                list contained in the list attribute, put with the same name,
+     *                of the containing definition.
+     */
+    public void setInherit(boolean inherit) {
+        this.inherit = inherit;
+    }
+
+    /**
+     * Getter for cascade property.
+     *
+     * @return If true the attribute will be cascaded to all nested attributes.
+     */
+    public boolean isCascade() {
+        return cascade;
+    }
+
+    /**
+     * Setter for cascade property.
+     *
+     * @param cascade If true the attribute will be cascaded to all nested
+     *                attributes.
+     */
+    public void setCascade(boolean cascade) {
+        this.cascade = cascade;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        ModelBody modelBody = runtime.createModelBody();
+        model.execute(name, role, inherit, cascade, request, modelBody);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
new file mode 100644
index 000000000..ee4877c38
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/SetCurrentContainerTag.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+package org.apache.tiles.web.jsp.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
+import org.apache.tiles.autotag.core.runtime.AutotagRuntime;
+import org.apache.tiles.request.Request;
+import org.apache.tiles.request.jsp.autotag.JspAutotagRuntime;
+import org.apache.tiles.template.SetCurrentContainerModel;
+
+/**
+ * Selects a container to be used as the "current" container.
+ */
+public class SetCurrentContainerTag extends SimpleTagSupport {
+
+    /**
+     * The template model.
+     */
+    private SetCurrentContainerModel model = new SetCurrentContainerModel();
+
+    /**
+     * The key of the container to be used as "current". If null, the default one
+     * will be used.
+     */
+    private String containerKey;
+
+    /**
+     * Getter for containerKey property.
+     *
+     * @return The key of the container to be used as "current". If null, the
+     *         default one will be used.
+     */
+    public String getContainerKey() {
+        return containerKey;
+    }
+
+    /**
+     * Setter for containerKey property.
+     *
+     * @param containerKey The key of the container to be used as "current". If
+     *                     null, the default one will be used.
+     */
+    public void setContainerKey(String containerKey) {
+        this.containerKey = containerKey;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void doTag() throws JspException, IOException {
+        AutotagRuntime<Request> runtime = new JspAutotagRuntime();
+        if (runtime instanceof SimpleTagSupport) {
+            SimpleTagSupport tag = (SimpleTagSupport) runtime;
+            tag.setJspContext(getJspContext());
+            tag.setJspBody(getJspBody());
+            tag.setParent(getParent());
+            tag.doTag();
+        }
+        Request request = runtime.createRequest();
+        model.execute(containerKey, request);
+    }
+}
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java
index 0262029d8..e2740e56c 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/UseAttributeTag.java
@@ -58,7 +58,7 @@ public class UseAttributeTag extends SimpleTagSupport {
     private String name = null;
 
     /**
-     * Flag that, if <code>true</code>, ignores exceptions.
+     * Flag that, if true, ignores exceptions.
      */
     private boolean ignore = false;
 
@@ -126,10 +126,8 @@ public class UseAttributeTag extends SimpleTagSupport {
     /**
      * Set ignore flag.
      *
-     * @param ignore default: <code>false</code>: Exception is thrown when
-     *               attribute is not found, set to <code>
-     *               true</code> to
-     *               ignore missing attributes silently
+     * @param ignore default: false: Exception is thrown when attribute is not
+     *               found, set to true to ignore missing attributes silently
      */
     public void setIgnore(boolean ignore) {
         this.ignore = ignore;
@@ -138,10 +136,8 @@ public class UseAttributeTag extends SimpleTagSupport {
     /**
      * Get ignore flag.
      *
-     * @return default: <code>false</code>: Exception is thrown when attribute
-     * is not found, set to <code>
-     * true</code> to ignore missing
-     * attributes silently
+     * @return default: false: Exception is thrown when attribute is not found, set
+     *         to true to ignore missing attributes silently
      */
     public boolean isIgnore() {
         return ignore;
@@ -191,8 +187,8 @@ public class UseAttributeTag extends SimpleTagSupport {
     }
 
     /**
-     * Implementation of <code>TagExtraInfo</code> which identifies the
-     * scripting object(s) to be made visible.
+     * Implementation of TagExtraInfo which identifies the scripting object(s) to be
+     * made visible.
      */
     public static class Tei extends TagExtraInfo {
 
@@ -211,8 +207,7 @@ public class UseAttributeTag extends SimpleTagSupport {
                 id = data.getAttributeString("name");
             }
 
-            return new VariableInfo[]{new VariableInfo(id, classname, true,
-                VariableInfo.AT_END)};
+            return new VariableInfo[] { new VariableInfo(id, classname, true, VariableInfo.AT_END) };
 
         }
     }
diff --git a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java
index c40a0a955..0c9e72cd0 100644
--- a/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/web/jsp/taglib/package-info.java
@@ -18,8 +18,6 @@
  */
 /**
  * The "tiles-jsp" tag library contains tags that are useful to create
- * templates, subpages other reusable view parts using the "tiles-core"
- * package.
+ * templates, subpages other reusable view parts using the "tiles-core" package.
  */
 package org.apache.tiles.web.jsp.taglib;
-
diff --git a/plugins/tiles/src/main/resources/META-INF/tld/tiles-extras-jsp.tld b/plugins/tiles/src/main/resources/META-INF/tld/tiles-extras-jsp.tld
index dfdb15332..4ba058ebe 100644
--- a/plugins/tiles/src/main/resources/META-INF/tld/tiles-extras-jsp.tld
+++ b/plugins/tiles/src/main/resources/META-INF/tld/tiles-extras-jsp.tld
@@ -34,11 +34,11 @@
    <tag>
       <description>
       <![CDATA[
-      <p><strong>Use attribute value inside page.</strong></p>
-      <p>Declare a Java variable, and an attribute in the specified scope,
-      using its attribute value.</p>
-      <p>Java variable and attribute will have the name specified by 'id',
-      or the original name if not specified.</p>
+      <p>Use attribute value inside page.</p>
+      <p>Declare a Java variable, and an attribute in the specified scope, using its attribute
+      value.</p>
+      <p>Java variable and attribute will have the name specified by 'id', or the original name
+      if not specified.</p>
       ]]>
       </description>
       <name>useAttribute</name>
@@ -89,9 +89,9 @@
          <description>
          <![CDATA[
          <p>
-         If this attribute is set to true, and the attribute specified by the name
-         does not exist, simply return without error. The default value is false, which will
-         cause a runtime exception to be thrown.
+         If this attribute is set to true, and the attribute specified by the name does not exist,
+         simply return without error. The default value is false, which will cause a runtime
+         exception to be thrown.
          </p>
          ]]>
          </description>
diff --git a/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld b/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
new file mode 100644
index 000000000..6a85017ac
--- /dev/null
+++ b/plugins/tiles/src/main/resources/META-INF/tld/tiles-jsp.tld
@@ -0,0 +1,894 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<taglib
+  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
+  xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  version="2.1">
+   <description>
+   <![CDATA[
+   <p>This tag library provides Tiles tags.</p>
+   ]]>
+   </description>
+   <tlib-version>1.2</tlib-version>
+   <short-name>tiles</short-name>
+   <uri>http://tiles.apache.org/tags-tiles</uri>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>Insert a definition.</p>
+      <p>
+      Insert a definition with the possibility to override and specify parameters (called attributes).
+      A definition can be seen as a (partially or totally) filled template that can override or
+      complete attribute values. &lt;tiles:insertDefinition&gt; allows to define these attributes
+      and pass them to the inserted jsp page, called template. Attributes are defined using nested
+      tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+      </p>
+      <p>
+      You must specify name tag attribute, for inserting a definition from definitions factory.
+      </p>
+      <p>
+      Example : 
+      </p>
+      <pre>
+        &lt;tiles:insertDefinition name=&quot;.my.tiles.defininition flush=&quot;true&quot;&gt;
+          &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+        &lt;/tiles:insertDefinition&gt;
+      </pre>
+      ]]>
+      </description>
+      <name>insertDefinition</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.InsertDefinitionTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the definition to render.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If specified, this template will be used instead of the one used by the definition.
+         ]]>
+         </description>
+         <name>template</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The type of the template attribute.
+         ]]>
+         </description>
+         <name>templateType</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The expression to evaluate to get the value of the template.
+         ]]>
+         </description>
+         <name>templateExpression</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the definition will be rendered only if
+         the current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The preparer to use to invoke before the definition is rendered. If specified, it
+         overrides the preparer specified in the definition itself.
+         ]]>
+         </description>
+         <name>preparer</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, the response will be flushed after the insert.
+         ]]>
+         </description>
+         <name>flush</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Import attribute(s) in specified context.
+      </p>
+      <p>
+      Import attribute(s) to requested scope. Attribute name and scope are optional. If not
+      specified, all attributes are imported in page scope. Once imported, an attribute can be
+      used as any other beans from jsp contexts.
+      </p>
+      ]]>
+      </description>
+      <name>importAttribute</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.ImportAttributeTag</tag-class>
+      <body-content>empty</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the attribute to import. If it is null, all the attributes will be imported.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The scope into which the attribute(s) will be imported. If null, the import will go in page
+         scope.
+         ]]>
+         </description>
+         <name>scope</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the attribute into which the attribute will be imported. To be used in conjunction
+         to name. If null, the value of name will be used.
+         ]]>
+         </description>
+         <name>toName</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, if the attribute is not present, the problem will be ignored.
+         ]]>
+         </description>
+         <name>ignore</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      Selects a container to be used as the "current" container.
+      ]]>
+      </description>
+      <name>setCurrentContainer</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.SetCurrentContainerTag</tag-class>
+      <body-content>empty</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The key of the container to be used as 'current'. If null, the default one will be used.
+         ]]>
+         </description>
+         <name>containerKey</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Declare a list that will be pass as an attribute. 
+      </p>
+      <p>
+      Declare a list that will be pass as an attribute . List elements are added using the tag
+      'addAttribute' or 'addListAttribute'. This tag can only be used inside 'insertTemplate',
+      'insertDefinition' or 'definition' tag.
+      </p>
+      ]]>
+      </description>
+      <name>addListAttribute</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.AddListAttributeTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The comma-separated list of roles that can use the list attribute.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Render the value of the specified template attribute to the current Writer
+      </p>
+      <p>
+      Retrieve the value of the specified template attribute property, and render it to the current
+      Writer as a String. The usual toString() conversions is applied on found value.
+      </p>
+      ]]>
+      </description>
+      <name>getAsString</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.GetAsStringTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, if an exception happens during rendering, of if the attribute is null, the problem
+         will be ignored.
+         ]]>
+         </description>
+         <name>ignore</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The preparer to invoke before rendering the attribute.
+         ]]>
+         </description>
+         <name>preparer</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the attribute will be rendered only if
+         the current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The default value of the attribute. To use only if the attribute was not computed.
+         ]]>
+         </description>
+         <name>defaultValue</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.Object</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The default comma-separated list of roles. To use only if the attribute was not computed.
+         ]]>
+         </description>
+         <name>defaultValueRole</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The default type of the attribute. To use only if the attribute was not computed.
+         ]]>
+         </description>
+         <name>defaultValueType</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the attribute.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The attribute to use immediately, if not null.
+         ]]>
+         </description>
+         <name>value</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>org.apache.tiles.Attribute</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Inserts the value of an attribute into the page.
+      </p>
+      <p>
+      This tag can be flexibly used to insert the value of an attribute into a page. As in other
+      usages in Tiles, every attribute can be determined to have a 'type', either set explicitly
+      when it was defined, or 'computed'. If the type is not explicit, then if the attribute value
+      is a valid definition, it will be inserted as such. Otherwise, if it begins with a '/' character,
+      it will be treated as a 'template'. Finally, if it has not otherwise been assigned a type,
+      it will be treated as a String and included without any special handling.
+      </p>
+      <p>
+      Example : 
+      </p>
+      <pre>
+        &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
+      </pre>
+      ]]>
+      </description>
+      <name>insertAttribute</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.InsertAttributeTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, if an exception happens during rendering, of if the attribute is null,
+         the problem will be ignored.
+         ]]>
+         </description>
+         <name>ignore</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The preparer to invoke before rendering the attribute.
+         ]]>
+         </description>
+         <name>preparer</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the attribute will be rendered only if
+         the current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The default value of the attribute. To use only if the attribute was not computed.
+         ]]>
+         </description>
+         <name>defaultValue</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.Object</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The default comma-separated list of roles. To use only if the attribute was not computed.
+         ]]>
+         </description>
+         <name>defaultValueRole</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The default type of the attribute. To use only if the attribute was not computed.
+         ]]>
+         </description>
+         <name>defaultValueType</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the attribute.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The attribute to use immediately, if not null.
+         ]]>
+         </description>
+         <name>value</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>org.apache.tiles.Attribute</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, the response will be flushed after the insert.
+         ]]>
+         </description>
+         <name>flush</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Put an attribute in enclosing attribute container tag.
+      </p>
+      <p>
+      Enclosing attribute container tag can be :
+      <ul>
+      <li>&lt;initContainer&gt;</li>
+      <li>&lt;definition&gt;</li>
+      <li>&lt;insertAttribute&gt;</li>
+      <li>&lt;insertDefinition&gt;</li>
+      <li>&lt;putListAttribute&gt;</li>
+      </ul>
+      or any other tag which implements the PutAttributeTagParent interface. Exception is thrown
+      if no appropriate tag can be found.
+      </p>
+      <p>
+      Put tag can have following atributes :
+      <ul>
+      <li>name : Name of the attribute</li>
+      <li>value : value to put as attribute</li>
+      <li>type : value type. Possible type are : string (value is used as direct string),
+      template (value is used as a page url to insert), definition (value is used as a definition
+      name to insert), object (value is used as it is)</li>
+      <li>role : Role to check when 'insertAttribute' will be called.</li>
+      </ul>
+      </p>
+      <p>
+      Value can also come from tag body. Tag body is taken into account only if value is not set
+      by one of the tag attributes. In this case Attribute type is 'string', unless tag body define
+      another type.
+      </p>
+      ]]>
+      </description>
+      <name>putAttribute</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.PutAttributeTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the attribute to put.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The value of the attribute. Use this parameter, or expression, or body.
+         ]]>
+         </description>
+         <name>value</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.Object</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The expression to calculate the value from. Use this parameter, or value, or body.
+         ]]>
+         </description>
+         <name>expression</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the attribute will be rendered only if
+         the current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The type (renderer) of the attribute.
+         ]]>
+         </description>
+         <name>type</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true the attribute will be cascaded to all nested attributes.
+         ]]>
+         </description>
+         <name>cascade</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Create a definition at runtime. 
+      </p>
+      <p>
+      Create a new definition at runtime. Newly created definition will be available across the
+      entire request.
+      </p>
+      ]]>
+      </description>
+      <name>definition</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.DefinitionTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the definition to create. If not specified, an anonymous definition will be created.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The template of this definition.
+         ]]>
+         </description>
+         <name>template</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the definition will be rendered only if the
+         current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The definition name that this definition extends.
+         ]]>
+         </description>
+         <name>extends</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The preparer to use to invoke before the definition is rendered.
+         ]]>
+         </description>
+         <name>preparer</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Add an element to the surrounding list. Equivalent to 'putAttribute', but for list element.
+      </p>
+      <p>
+      Add an element to the surrounding list. This tag can only be used inside 'putListAttribute'
+      or 'addListAttribute' tags. Value can come from a direct assignment (value="aValue")
+      </p>
+      ]]>
+      </description>
+      <name>addAttribute</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.AddAttributeTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The value of the attribute. Use this parameter, or expression, or body.
+         ]]>
+         </description>
+         <name>value</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.Object</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The expression to calculate the value from. Use this parameter, or value, or body.
+         ]]>
+         </description>
+         <name>expression</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the attribute will be rendered only if the
+         current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The type (renderer) of the attribute.
+         ]]>
+         </description>
+         <name>type</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Declare a list that will be pass as attribute to tile. 
+      </p>
+      <p>
+      Declare a list that will be pass as attribute to tile. List elements are added using the tags
+      'addAttribute' or 'addListAttribute'. This tag can only be used inside 'insertTemplate',
+      'insertDefinition', 'definition' tags.
+      </p>
+      ]]>
+      </description>
+      <name>putListAttribute</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.PutListAttributeTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The name of the attribute to put.
+         ]]>
+         </description>
+         <name>name</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the attribute will be rendered only if the
+         current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, the list attribute will use, as first elements, the list contained in the list
+         attribute, put with the same name, of the containing definition.
+         ]]>
+         </description>
+         <name>inherit</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true the attribute will be cascaded to all nested attributes.
+         ]]>
+         </description>
+         <name>cascade</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+   </tag>
+   <tag>
+      <description>
+      <![CDATA[
+      <p>
+      Insert a template.
+      </p>
+      <p>
+      Insert a template with the possibility to pass parameters (called attributes). A template can
+      be seen as a procedure that can take parameters or attributes. &lt;tiles:insertTemplate&gt;
+      allows to define these attributes and pass them to the inserted jsp page, called template.
+      Attributes are defined using nested tag &lt;tiles:putAttribute&gt; or &lt;tiles:putListAttribute&gt;.
+      </p>
+      <p>
+      You must specify template attribute, for inserting a template
+      </p>
+      <p>
+      Example : 
+      </p>
+      <pre>
+        &lt;tiles:insertTemplate template=&quot;/basic/myLayout.jsp&quot; flush=&quot;true&quot;&gt;
+          &lt;tiles:putAttribute name=&quot;title&quot; value=&quot;My first page&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;header&quot; value=&quot;/common/header.jsp&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;footer&quot; value=&quot;/common/footer.jsp&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;menu&quot; value=&quot;/basic/menu.jsp&quot; /&gt;
+          &lt;tiles:putAttribute name=&quot;body&quot; value=&quot;/basic/helloBody.jsp&quot; /&gt;
+        &lt;/tiles:insertTemplate&gt;
+      </pre>
+      ]]>
+      </description>
+      <name>insertTemplate</name>
+      <tag-class>org.apache.tiles.web.jsp.taglib.InsertTemplateTag</tag-class>
+      <body-content>scriptless</body-content>
+      <attribute>
+         <description>
+         <![CDATA[
+         The template to render.
+         ]]>
+         </description>
+         <name>template</name>
+         <required>true</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The type of the template attribute.
+         ]]>
+         </description>
+         <name>templateType</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The expression to evaluate to get the value of the template.
+         ]]>
+         </description>
+         <name>templateExpression</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         A comma-separated list of roles. If present, the template will be rendered only if the
+         current user belongs to one of the roles.
+         ]]>
+         </description>
+         <name>role</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         The preparer to use to invoke before the definition is rendered. If specified, it overrides
+         the preparer specified in the definition itself.
+         ]]>
+         </description>
+         <name>preparer</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>java.lang.String</type>
+      </attribute>
+      <attribute>
+         <description>
+         <![CDATA[
+         If true, the response will be flushed after the insert.
+         ]]>
+         </description>
+         <name>flush</name>
+         <required>false</required>
+         <rtexprvalue>true</rtexprvalue>
+         <type>boolean</type>
+      </attribute>
+   </tag>
+</taglib>