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 2023/06/29 10:40:24 UTC

[struts] branch WW-5233-tiles updated (6f0df8045 -> a970d24bf)

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


 discard 6f0df8045 WW-5233 Introduces Tiles base code into the Tiles plugin
     new a970d24bf WW-5233 Introduces Tiles base code into the Tiles plugin

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   (6f0df8045)
            \
             N -- N -- N   refs/heads/WW-5233-tiles (a970d24bf)

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 1 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:
 bom/pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


[struts] 01/01: WW-5233 Introduces Tiles base code into the Tiles plugin

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 a970d24bfb3462094e542ac6f515251d3d9a2220
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sat Oct 1 16:48:18 2022 +0200

    WW-5233 Introduces Tiles base code into the Tiles plugin
    
    WW-5233 Copies a based set of Tiles classes used by Struts
    
    WW-5233 Copies Portlet related Tiles code base
    
    WW-5233 Copies Tiles API related tests
    
    WW-5233 Copies Tiles Core related tests
    
    WW-5233 Copies Tiles EL related tests
    
    WW-5233 Copies Tiles OGNL related tests
    
    WW-5233 Copies Tiles Template related tests
    
    WW-5233 Copies Tiles Servlet related tests
    
    WW-5233 Upgrades Easymock to version 4.3 to support Java 17
    
    WW-5233 Copies Tiles Request related tests
    
    WW-5233 Copies Tiles Autotag related tests
    
    WW-5233 Drops useless @version tag and addresses some potential RegEx vulnerabilities
    
    WW-5233 Addresses bugs reported by Sonar
    
    WW-5233 Addresses a few code smells
    
    WW-5233 Copies Tiles Portal related tests
    
    WW-5233 Fixes broken test
    
    WW-5233 Adds Tiles DTD definition
    
    Add missing classes and tld definition.
    
    Add generating of Autotags and tests.
    
    Make plugin standalone with all generated resources.
    
    Make plugin standalone with all generated resources for velocity.
    
    Make plugin standalone with all generated resources for velocity.
    
    WW-5233 Marks Velocity dependencies as optional
---
 apps/showcase/pom.xml                              |    6 -
 bom/pom.xml                                        |    4 +-
 plugins/portlet-tiles/pom.xml                      |   10 +-
 .../struts2/views/tiles/PortletTilesResult.java    |    6 +-
 .../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} |   37 +-
 .../request/portlet/delegate/ResponseDelegate.java |   70 ++
 .../request/portlet/delegate/package-info.java}    |   26 +-
 .../extractor/ApplicationScopeExtractor.java       |   66 ++
 .../request/portlet/extractor/HeaderExtractor.java |   74 ++
 .../portlet/extractor/InitParameterExtractor.java  |   57 +
 .../portlet/extractor/ParameterExtractor.java}     |   46 +-
 .../portlet/extractor/RequestScopeExtractor.java   |   66 ++
 .../portlet/extractor/SessionScopeExtractor.java   |   88 ++
 .../extractor/StateAwareParameterExtractor.java    |   53 +
 .../request/portlet/extractor/package-info.java}   |   26 +-
 .../tiles/request/portlet/package-info.java}       |   26 +-
 .../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          |   50 +
 plugins/tiles/pom.xml                              |   94 +-
 .../org/apache/struts2/tiles/BuildAutotags.java    |  229 ++++
 .../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 +-
 .../StrutsWildcardServletApplicationContext.java   |    1 -
 .../apache/struts2/views/tiles/TilesResult.java    |   44 +-
 .../main/java/org/apache/tiles/api/Attribute.java  |  366 ++++++
 .../org/apache/tiles/api/AttributeContext.java     |  161 +++
 .../apache/tiles/api/BasicAttributeContext.java    |  462 ++++++++
 .../main/java/org/apache/tiles/api/Definition.java |  165 +++
 .../main/java/org/apache/tiles/api/Expression.java |  165 +++
 .../java/org/apache/tiles/api/ListAttribute.java   |  169 +++
 .../api/NoSuchContainerException.java}             |   32 +-
 .../java/org/apache/tiles/api/TilesContainer.java  |  137 +++
 .../apache/tiles/api/TilesContainerWrapper.java    |  107 ++
 .../java/org/apache/tiles/api/TilesException.java  |   66 ++
 .../org/apache/tiles/api/access/TilesAccess.java   |  158 +++
 .../api/access/package-info.java}                  |   23 +-
 .../api/mgmt/MutableTilesContainer.java}           |   33 +-
 .../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    |   54 +
 .../api/preparer/package-info.java}                |   26 +-
 .../autotag/core/AutotagRuntimeException.java      |   60 +
 .../autotag/core/runtime/AbstractModelBody.java    |   80 ++
 .../tiles/autotag/core/runtime/AutotagRuntime.java |   49 +
 .../tiles/autotag/core/runtime/ModelBody.java      |   58 +
 .../autotag/core/runtime/annotation/Parameter.java |   52 +
 .../core/runtime/annotation/package-info.java}     |   24 +-
 .../autotag/core/runtime/package-info.java}        |   24 +-
 .../autotag/core/runtime/util/NullWriter.java}     |   36 +-
 .../autotag/core/runtime/util/package-info.java}   |   24 +-
 .../tiles/autotag/freemarker/FMModelGenerator.java |   63 ++
 .../freemarker/FMModelRepositoryGenerator.java     |   61 +
 .../freemarker/FMTemplateGeneratorFactory.java     |   69 ++
 .../autotag/freemarker/package-info.java}          |   26 +-
 .../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 +++
 .../generate/TemplateGeneratorFactory.java}        |   30 +-
 .../autotag/generate/TemplateSuiteGenerator.java}  |   36 +-
 .../autotag/generate/package-info.java}            |   24 +-
 .../autotag/jsp/JspTemplateGeneratorFactory.java   |   79 ++
 .../org/apache/tiles/autotag/jsp/TLDGenerator.java |   60 +
 .../tiles/autotag/jsp/TagClassGenerator.java       |   63 ++
 .../autotag/jsp/package-info.java}                 |   24 +-
 .../apache/tiles/autotag/model/TemplateClass.java  |  191 ++++
 .../apache/tiles/autotag/model/TemplateMethod.java |  127 +++
 .../tiles/autotag/model/TemplateParameter.java     |  182 +++
 .../apache/tiles/autotag/model/TemplateSuite.java  |  125 ++
 .../autotag/model/package-info.java}               |   24 +-
 .../org/apache/tiles/autotag/tool/StringTool.java  |  138 +++
 .../autotag/tool/package-info.java}                |   24 +-
 .../velocity/VelocityDirectiveGenerator.java       |   67 ++
 .../velocity/VelocityPropertiesGenerator.java      |   64 ++
 .../velocity/VelocityTemplateGeneratorFactory.java |   87 ++
 .../autotag/velocity/package-info.java}            |   26 +-
 .../tiles/core/definition/DefinitionsFactory.java  |   75 ++
 .../definition/DefinitionsFactoryException.java    |   72 ++
 .../tiles/core/definition/DefinitionsReader.java   |   52 +
 .../definition/NoSuchDefinitionException.java}     |   31 +-
 .../core/definition/RefreshMonitor.java}           |   32 +-
 .../UnresolvingLocaleDefinitionsFactory.java       |   86 ++
 .../definition/dao/BaseLocaleUrlDefinitionDAO.java |  163 +++
 .../dao/CachingLocaleUrlDefinitionDAO.java         |  272 +++++
 .../tiles/core/definition/dao/DefinitionDAO.java   |   54 +
 .../dao/ResolvingLocaleUrlDefinitionDAO.java       |  172 +++
 .../core/definition/dao/package-info.java}         |   25 +-
 .../digester/DigesterDefinitionsReader.java        |  464 ++++++++
 .../DigesterDefinitionsReaderException.java}       |   34 +-
 .../core/definition/digester/package-info.java}    |   24 +-
 .../core/definition/package-info.java}             |   25 +-
 .../pattern/AbstractPatternDefinitionResolver.java |  106 ++
 .../pattern/BasicPatternDefinitionResolver.java    |   75 ++
 .../pattern/DefinitionPatternMatcher.java}         |   36 +-
 .../pattern/DefinitionPatternMatcherFactory.java   |   41 +
 .../pattern/PatternDefinitionResolver.java         |   63 ++
 .../pattern/PatternDefinitionResolverAware.java}   |   32 +-
 .../definition/pattern/PatternRecognizer.java}     |   31 +-
 .../tiles/core/definition/pattern/PatternUtil.java |  240 ++++
 .../pattern/PrefixedPatternDefinitionResolver.java |  103 ++
 .../core/definition/pattern/package-info.java}     |   24 +-
 .../regexp/RegexpDefinitionPatternMatcher.java     |   72 ++
 .../RegexpDefinitionPatternMatcherFactory.java}    |   30 +-
 .../definition/pattern/regexp/package-info.java}   |   24 +-
 .../wildcard/WildcardDefinitionPatternMatcher.java |   78 ++
 .../WildcardDefinitionPatternMatcherFactory.java   |   54 +
 .../definition/pattern/wildcard/package-info.java} |   24 +-
 .../core/evaluator/AbstractAttributeEvaluator.java |   50 +
 .../tiles/core/evaluator/AttributeEvaluator.java   |   50 +
 .../core/evaluator/AttributeEvaluatorFactory.java  |   48 +
 .../evaluator/AttributeEvaluatorFactoryAware.java} |   31 +-
 .../evaluator/BasicAttributeEvaluatorFactory.java  |   88 ++
 .../core/evaluator/EvaluationException.java}       |   40 +-
 .../evaluator/impl/DirectAttributeEvaluator.java}  |   28 +-
 .../core/evaluator/impl/package-info.java}         |   24 +-
 .../core/evaluator/package-info.java}              |   24 +-
 .../factory/AbstractTilesContainerFactory.java}    |   35 +-
 .../core/factory/BasicTilesContainerFactory.java   |  406 +++++++
 .../factory/TilesContainerFactoryException.java}   |   33 +-
 .../core/factory/package-info.java}                |   24 +-
 .../tiles/core/impl/BasicTilesContainer.java       |  398 +++++++
 .../core/impl/InvalidTemplateException.java}       |   40 +-
 .../core/impl/mgmt/CachingTilesContainer.java      |  222 ++++
 .../core/impl/mgmt/package-info.java}              |   24 +-
 .../core/impl/package-info.java}                   |   24 +-
 .../core/locale/LocaleResolver.java}               |   34 +-
 .../core/locale/impl/DefaultLocaleResolver.java    |   55 +
 .../core/locale/impl/package-info.java}            |   24 +-
 .../core/locale/package-info.java}                 |   25 +-
 .../core/prepare/factory/BasicPreparerFactory.java |   84 ++
 .../prepare/factory/NoSuchPreparerException.java}  |   31 +-
 .../core/prepare/factory/PreparerFactory.java      |   49 +
 .../core/prepare/factory/package-info.java}        |   26 +-
 .../tiles/core/renderer/DefinitionRenderer.java    |   67 ++
 .../core/renderer/package-info.java}               |   24 +-
 .../core/startup/AbstractTilesInitializer.java     |  110 ++
 .../tiles/core/startup/TilesInitializer.java       |   45 +
 .../core/startup/package-info.java}                |   26 +-
 .../apache/tiles/core/util/CombinedBeanInfo.java   |   95 ++
 .../org/apache/tiles/core/util/WildcardHelper.java |  543 +++++++++
 .../core/util/package-info.java}                   |   24 +-
 .../org/apache/tiles/el/ELAttributeEvaluator.java  |   92 ++
 .../java/org/apache/tiles/el/ELContextImpl.java    |  144 +++
 .../el/ExpressionFactoryFactory.java}              |   31 +-
 .../tiles/el/JspExpressionFactoryFactory.java      |   63 ++
 .../java/org/apache/tiles/el/ScopeELResolver.java  |  143 +++
 .../tiles/el/TilesContextBeanELResolver.java       |  172 +++
 .../apache/tiles/el/TilesContextELResolver.java    |  156 +++
 .../el/package-info.java}                          |   24 +-
 .../freemarker/package-info.java}                  |   24 +-
 .../freemarker/template/AddAttributeFMModel.java   |   78 ++
 .../template/AddListAttributeFMModel.java          |   73 ++
 .../freemarker/template/DefinitionFMModel.java     |   76 ++
 .../freemarker/template/GetAsStringFMModel.java    |   81 ++
 .../template/ImportAttributeFMModel.java           |   74 ++
 .../template/InsertAttributeFMModel.java           |   94 ++
 .../template/InsertDefinitionFMModel.java          |   99 ++
 .../freemarker/template/InsertTemplateFMModel.java |   98 ++
 .../freemarker/template/PutAttributeFMModel.java   |  101 ++
 .../template/PutListAttributeFMModel.java          |   76 ++
 .../template/SetCurrentContainerFMModel.java       |   64 ++
 .../template/TilesFMModelRepository.java           |  199 ++++
 .../tiles/ognl/AnyScopePropertyAccessor.java       |   89 ++
 .../tiles/ognl/DelegatePropertyAccessor.java       |   84 ++
 .../ognl/NestedObjectDelegatePropertyAccessor.java |   93 ++
 .../ognl/NestedObjectExtractor.java}               |   33 +-
 .../apache/tiles/ognl/OGNLAttributeEvaluator.java  |   45 +
 .../ognl/PropertyAccessorDelegateFactory.java}     |   37 +-
 .../apache/tiles/ognl/ScopePropertyAccessor.java   |   68 ++
 ...esApplicationContextNestedObjectExtractor.java} |   27 +-
 ...ilesContextPropertyAccessorDelegateFactory.java |  103 ++
 .../ognl/package-info.java}                        |   24 +-
 .../tiles/request/AbstractClientRequest.java       |   91 ++
 .../org/apache/tiles/request/AbstractRequest.java  |   54 +
 .../apache/tiles/request/AbstractViewRequest.java  |   60 +
 .../apache/tiles/request/ApplicationAccess.java    |   47 +
 .../apache/tiles/request/ApplicationContext.java   |   79 ++
 .../request/ApplicationContextAware.java}          |   30 +-
 .../apache/tiles/request/ApplicationResource.java  |   80 ++
 .../org/apache/tiles/request/DispatchRequest.java  |   51 +
 .../tiles/request/DispatchRequestWrapper.java      |  139 +++
 .../request/NotAvailableFeatureException.java}     |   30 +-
 .../java/org/apache/tiles/request/Request.java     |  161 +++
 .../request/RequestException.java}                 |   39 +-
 .../request/RequestWrapper.java}                   |   29 +-
 .../request/attribute/Addable.java}                |   31 +-
 .../request/attribute/AttributeExtractor.java}     |   25 +-
 .../attribute/EnumeratedValuesExtractor.java}      |   31 +-
 .../request/attribute/HasAddableKeys.java}         |   25 +-
 .../request/attribute/HasKeys.java}                |   36 +-
 .../request/attribute/HasRemovableKeys.java}       |   30 +-
 .../request/attribute/package-info.java}           |   28 +-
 .../request/collection/AddableParameterMap.java    |   95 ++
 .../tiles/request/collection/CollectionUtil.java   |   66 ++
 .../tiles/request/collection/HeaderValuesMap.java  |  556 +++++++++
 .../apache/tiles/request/collection/KeySet.java    |  167 +++
 .../apache/tiles/request/collection/MapEntry.java  |  124 ++
 .../request/collection/MapEntryArrayValues.java    |   95 ++
 .../request/collection/ReadOnlyEnumerationMap.java |  461 ++++++++
 .../tiles/request/collection/RemovableKeySet.java  |   91 ++
 .../apache/tiles/request/collection/ScopeMap.java  |  169 +++
 .../request/collection/package-info.java}          |   34 +-
 .../request/freemarker/EnvironmentScopeMap.java    |   58 +
 .../request/freemarker/FreemarkerRequest.java      |  143 +++
 .../freemarker/FreemarkerRequestException.java}    |   31 +-
 .../request/freemarker/FreemarkerRequestUtil.java  |   82 ++
 .../NotAvailableFreemarkerServletException.java}   |   31 +-
 .../autotag/FreemarkerAutotagException.java}       |   32 +-
 .../autotag/FreemarkerAutotagRuntime.java          |   68 ++
 .../freemarker/autotag/FreemarkerModelBody.java    |   62 +
 .../request/freemarker/autotag/FreemarkerUtil.java |   60 +
 .../request/freemarker/autotag/package-info.java}  |   24 +-
 .../extractor/EnvironmentScopeExtractor.java       |   87 ++
 .../freemarker/extractor/package-info.java}        |   26 +-
 .../request/freemarker/package-info.java}          |   26 +-
 .../freemarker/servlet/SharedVariableFactory.java} |   30 +-
 .../servlet/WebappClassTemplateLoader.java         |   81 ++
 .../request/freemarker/servlet/package-info.java}  |   26 +-
 .../tiles/request/jsp/JspPrintWriterAdapter.java   |  432 +++++++
 .../org/apache/tiles/request/jsp/JspRequest.java   |  199 ++++
 .../java/org/apache/tiles/request/jsp/JspUtil.java |   52 +
 .../request/jsp/autotag/JspAutotagRuntime.java     |   69 ++
 .../tiles/request/jsp/autotag/JspModelBody.java    |   63 ++
 .../request/jsp/autotag/package-info.java}         |   24 +-
 .../request/jsp/extractor/ScopeExtractor.java      |   71 ++
 .../jsp/extractor/SessionScopeExtractor.java       |   76 ++
 .../request/jsp/extractor/package-info.java}       |   26 +-
 .../request/jsp/package-info.java}                 |   26 +-
 .../apache/tiles/request/locale/LocaleUtil.java    |   58 +
 .../locale/PostfixedApplicationResource.java       |  235 ++++
 .../request/locale/URLApplicationResource.java     |  213 ++++
 .../reflect/CannotInstantiateObjectException.java} |   32 +-
 .../apache/tiles/request/reflect/ClassUtil.java    |  123 ++
 .../request/reflect/package-info.java}             |   24 +-
 .../tiles/request/render/BasicRendererFactory.java |   79 ++
 .../request/render/CannotRenderException.java}     |   38 +-
 .../request/render/ChainedDelegateRenderer.java    |   80 ++
 .../tiles/request/render/DispatchRenderer.java     |   61 +
 .../request/render/NoSuchRendererException.java}   |   31 +-
 .../request/render/RenderException.java}           |   38 +-
 .../org/apache/tiles/request/render/Renderer.java  |   48 +
 .../request/render/RendererFactory.java}           |   37 +-
 .../request/render/StringRenderer.java}            |   35 +-
 .../servlet/ExternalWriterHttpServletResponse.java |   58 +
 .../servlet/NotAServletEnvironmentException.java}  |   32 +-
 .../request/servlet/ServletApplicationContext.java |  127 +++
 .../tiles/request/servlet/ServletRequest.java      |  343 ++++++
 .../apache/tiles/request/servlet/ServletUtil.java  |  117 ++
 .../extractor/ApplicationScopeExtractor.java       |   64 ++
 .../request/servlet/extractor/HeaderExtractor.java |   72 ++
 .../servlet/extractor/InitParameterExtractor.java  |   55 +
 .../servlet/extractor/ParameterExtractor.java      |   54 +
 .../servlet/extractor/RequestScopeExtractor.java   |   64 ++
 .../servlet/extractor/SessionScopeExtractor.java   |   77 ++
 .../request/servlet/extractor/package-info.java}   |   26 +-
 .../request/servlet/package-info.java}             |   26 +-
 .../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}    |   24 +-
 .../velocity/extractor/VelocityScopeExtractor.java |   99 ++
 .../request/velocity/extractor/package-info.java}  |   24 +-
 .../request/velocity/package-info.java}            |   24 +-
 .../render/ApplicationContextJeeConfig.java        |   77 ++
 .../request/velocity/render/VelocityRenderer.java  |   75 ++
 .../velocity/render/VelocityRendererBuilder.java   |   91 ++
 .../request/velocity/render/package-info.java}     |   24 +-
 .../apache/tiles/template/AddAttributeModel.java   |  124 ++
 .../tiles/template/AddListAttributeModel.java      |   60 +
 .../apache/tiles/template/AttributeResolver.java   |   58 +
 .../apache/tiles/template/ComposeStackUtil.java    |   83 ++
 .../tiles/template/DefaultAttributeResolver.java   |   85 ++
 .../org/apache/tiles/template/DefinitionModel.java |  139 +++
 .../apache/tiles/template/GetAsStringModel.java    |  224 ++++
 .../tiles/template/ImportAttributeModel.java       |  194 ++++
 .../tiles/template/InsertAttributeModel.java       |  204 ++++
 .../tiles/template/InsertDefinitionModel.java      |  147 +++
 .../apache/tiles/template/InsertTemplateModel.java |  141 +++
 .../template/NoSuchAttributeException.java}        |   32 +-
 .../apache/tiles/template/PutAttributeModel.java   |  165 +++
 .../tiles/template/PutListAttributeModel.java      |   88 ++
 .../template/SetCurrentContainerModel.java}        |   33 +-
 .../template/package-info.java}                    |   26 +-
 .../tiles/velocity/TilesVelocityException.java     |   71 ++
 .../velocity/package-info.java}                    |   24 +-
 .../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 ++++
 .../velocity/template/package-info.java}           |   24 +-
 .../tiles/web/jsp/taglib/AddAttributeTag.java      |  165 +++
 .../tiles/web/jsp/taglib/AddListAttributeTag.java  |   87 ++
 .../apache/tiles/web/jsp/taglib/DefinitionTag.java |  184 +++
 .../tiles/web/jsp/taglib/GetAsStringTag.java       |  264 +++++
 .../tiles/web/jsp/taglib/ImportAttributeTag.java   |  166 +++
 .../tiles/web/jsp/taglib/InsertAttributeTag.java   |  299 +++++
 .../tiles/web/jsp/taglib/InsertDefinitionTag.java  |  257 +++++
 .../tiles/web/jsp/taglib/InsertTemplateTag.java    |  230 ++++
 .../tiles/web/jsp/taglib/PutAttributeTag.java      |  233 ++++
 .../tiles/web/jsp/taglib/PutListAttributeTag.java  |  164 +++
 .../web/jsp/taglib/SetCurrentContainerTag.java     |   80 ++
 .../tiles/web/jsp/taglib/UseAttributeTag.java      |  214 ++++
 .../web/jsp/taglib/package-info.java}              |   25 +-
 .../tiles/web/startup/AbstractTilesListener.java   |   69 ++
 .../web/startup/package-info.java}                 |   26 +-
 .../web/util/AttributeContextMutator.java}         |   34 +-
 .../tiles/web/util/TilesDispatchServlet.java       |  148 +++
 .../web/util/package-info.java}                    |   26 +-
 .../src/main/resources/META-INF/template-suite.xml | 1188 ++++++++++++++++++++
 .../resources/META-INF/tld/tiles-extras-jsp.tld    |  105 ++
 .../src/main/resources/META-INF/tld/tiles-jsp.tld  |  922 +++++++++++++++
 .../main/resources/META-INF/velocity.properties    |   30 +
 .../org/apache/tiles/autotag/freemarker/fmModel.vm |   78 ++
 .../apache/tiles/autotag/freemarker/repository.vm  |   57 +
 .../org/apache/tiles/autotag/jsp/bodyTag.vm        |  102 ++
 .../resources/org/apache/tiles/autotag/jsp/tld.vm  |   66 ++
 .../org/apache/tiles/autotag/velocity.properties   |  101 ++
 .../tiles/autotag/velocity/velocityDirective.vm    |   76 ++
 .../tiles/autotag/velocity/velocityProperties.vm   |   21 +
 .../apache/tiles/resources/tiles-config_3_0.dtd    |  245 ++++
 plugins/tiles/src/main/resources/tools.xml         |   24 +
 .../tiles/StrutsTilesAnnotationProcessorTest.java  |    6 +-
 .../java/org/apache/tiles/api/AttributeTest.java   |  275 +++++
 .../tiles/api/BasicAttributeContextTest.java       |  681 +++++++++++
 .../java/org/apache/tiles/api/ExpressionTest.java  |  108 ++
 .../org/apache/tiles/api/ListAttributeTest.java    |  109 ++
 .../tiles/api/NoSuchContainerExceptionTest.java}   |   33 +-
 .../java/org/apache/tiles/api/TestDefinition.java  |  248 ++++
 .../tiles/api/TilesContainerWrapperTest.java       |  232 ++++
 .../org/apache/tiles/api/TilesExceptionTest.java   |   62 +
 .../apache/tiles/api/access/TilesAccessTest.java   |  206 ++++
 .../tiles/api/preparer/PreparerExceptionTest.java  |   74 ++
 .../autotag/freemarker/FMModelGeneratorTest.java   |  139 +++
 .../freemarker/FMModelRepositoryGeneratorTest.java |  126 +++
 .../freemarker/FMTemplateGeneratorFactoryTest.java |   58 +
 .../jsp/JspTemplateGeneratorFactoryTest.java       |   61 +
 .../apache/tiles/autotag/jsp/TLDGeneratorTest.java |  129 +++
 .../tiles/autotag/jsp/TagClassGeneratorTest.java   |  139 +++
 .../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     |  157 +++
 .../tiles/autotag/runtime/util/NullWriterTest.java |   71 ++
 .../velocity/VelocityDirectiveGeneratorTest.java   |  139 +++
 .../velocity/VelocityPropertiesGeneratorTest.java  |  125 ++
 .../VelocityTemplateGeneratorFactoryTest.java      |   60 +
 .../DefinitionsFactoryExceptionTest.java           |   74 ++
 .../core/definition/MockDefinitionsReader.java     |   44 +
 .../definition/NoSuchDefinitionExceptionTest.java} |   36 +-
 .../UnresolvingLocaleDefinitionsFactoryTest.java   |   63 ++
 .../dao/BaseLocaleUrlDefinitionDAOTest.java        |  156 +++
 .../dao/CachingLocaleUrlDefinitionDAOTest.java     |  371 ++++++
 .../dao/ResolvingLocaleUrlDefinitionDAOTest.java   |  391 +++++++
 .../DigesterDefinitionsReaderExceptionTest.java}   |   35 +-
 .../digester/TestDigesterDefinitionsReader.java    |  279 +++++
 .../AbstractPatternDefinitionResolverTest.java     |  119 ++
 .../BasicPatternDefinitionResolverTest.java        |   78 ++
 .../core/definition/pattern/PatternUtilTest.java   |  316 ++++++
 .../PrefixedPatternDefinitionResolverTest.java     |   77 ++
 .../RegexpDefinitionPatternMatcherFactoryTest.java |   49 +
 .../regexp/RegexpDefinitionPatternMatcherTest.java |   47 +
 ...ildcardDefinitionPatternMatcherFactoryTest.java |   61 +
 .../WildcardDefinitionPatternMatcherTest.java      |   53 +
 .../BasicAttributeEvaluatorFactoryTest.java        |   85 ++
 .../core/evaluator/EvaluatorExceptionTest.java     |   53 +
 .../impl/DirectAttributeEvaluatorTest.java         |   84 ++
 .../core/factory/BasicPreparerFactoryTest.java     |   72 ++
 .../factory/BasicTilesContainerFactoryTest.java    |  252 +++++
 .../core/factory/NoSuchPreparerExceptionTest.java} |   37 +-
 .../TilesContainerFactoryExceptionTest.java}       |   36 +-
 .../tiles/core/impl/BasicTilesContainerTest.java   |  126 +++
 .../core/impl/BasicTilesContainerUnitTest.java     |  836 ++++++++++++++
 .../tiles/core/impl/CannotRenderExceptionTest.java |   54 +
 .../tiles/core/impl/DefaultLocaleResolverTest.java |   58 +
 .../core/impl/InvalidTemplateExceptionTest.java    |   53 +
 .../core/impl/mgmt/CachingTilesContainerTest.java  |  305 +++++
 .../core/renderer/DefinitionRendererTest.java      |  106 ++
 .../core/startup/AbstractTilesInitializerTest.java |  130 +++
 .../tiles/core/util/CombinedBeanInfoTest.java      |   93 ++
 .../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 ++++
 .../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 ++++
 .../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} |   35 +-
 .../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        |  294 +++++
 .../collection/ReadOnlyEnumerationMapTest.java     |  306 +++++
 ...ReadOnlyEnumerationMapValuesCollectionTest.java |  312 +++++
 .../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}     |   35 +-
 .../tiles/request/reflect/ClassUtilTest.java       |  175 +++
 .../request/render/BasicRendererFactoryTest.java   |  100 ++
 .../render/ChainedDelegateRendererTest.java        |  178 +++
 .../tiles/request/render/DispatchRendererTest.java |   74 ++
 .../render/NoSuchRendererExceptionTest.java}       |   36 +-
 .../tiles/request/render/StringRendererTest.java   |   79 ++
 .../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 ++
 .../tiles/web/jsp/taglib/UseAttributeTagTest.java  |  220 ++++
 .../web/startup/AbstractTilesListenerTest.java     |   61 +
 .../autotag/freemarker/test/DoStuffFMModel.javat   |   72 ++
 .../freemarker/test/DoStuffNoBodyFMModel.javat     |   70 ++
 .../freemarker/test/TldtestFMModelRepository.javat |   64 ++
 .../tiles/autotag/jsp/test/DoStuffNoBodyTag.java   |  134 +++
 .../apache/tiles/autotag/jsp/test/DoStuffTag.java  |  136 +++
 .../autotag/velocity/test/DoStuffDirective.javat   |   70 ++
 .../velocity/test/DoStuffNoBodyDirective.javat     |   68 ++
 .../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}     |   38 +-
 .../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}      |   37 +-
 .../tiles/core/factory/test-defs-key-two.xml}      |   37 +-
 .../org/apache/tiles/core/factory/test-defs.xml}   |   37 +-
 .../tiles/request/locale/resource with space.txt}  |   27 +-
 .../org/apache/tiles/request/locale/resource.txt}  |   27 +-
 plugins/tiles/src/test/resources/tldtest-jsp.tld   |  121 ++
 .../src/test/resources/velocity.properties.test    |   21 +
 pom.xml                                            |   70 +-
 504 files changed, 49758 insertions(+), 2518 deletions(-)

diff --git a/apps/showcase/pom.xml b/apps/showcase/pom.xml
index 1c8e079b0..1a04728ce 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/bom/pom.xml b/bom/pom.xml
index c4ffbaf5e..6a9757382 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.3.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>struts2-bom</artifactId>
diff --git a/plugins/portlet-tiles/pom.xml b/plugins/portlet-tiles/pom.xml
index 60631ebc6..7caba1442 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>
@@ -55,9 +51,9 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-jsp</artifactId>
-            <scope>runtime</scope>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
     <properties>
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/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/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/RequestDelegate.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/RequestDelegate.java
index 38e506552..03846cc72 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/RequestDelegate.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.request.portlet.delegate;
 
-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.Map;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Exposes the parameters of a portlet request, if available.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public interface RequestDelegate {
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+    /**
+     * The parameters, as single values.
+     *
+     * @return The parameters.
+     */
+    Map<String, String> getParam();
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * 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/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/package-info.java
index 38e506552..5080dc3e0 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/delegate/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $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
@@ -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
+ * Delegations to map all the different types of request and responses.
  */
-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.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/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ParameterExtractor.java
similarity index 50%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ParameterExtractor.java
index 38e506552..e412a84c6 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/ParameterExtractor.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,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.request.portlet.extractor;
+
+import org.apache.tiles.request.attribute.HasKeys;
 
-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 javax.portlet.PortletRequest;
+import java.util.Enumeration;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Extracts parameters from a portlet request.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
+public class ParameterExtractor implements HasKeys<String> {
+
+    /**
+     * The portlet request.
+     */
+    private final PortletRequest request;
 
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+    /**
+     * Constructor.
+     *
+     * @param request The portlet request.
+     */
+    public ParameterExtractor(PortletRequest request) {
+        this.request = request;
+    }
+
+    @Override
+    public Enumeration<String> getKeys() {
+        return request.getParameterNames();
+    }
 
     @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
+    public String getValue(String key) {
+        return request.getParameter(key);
     }
-}
\ No newline at end of file
+}
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..a14f53a7b
--- /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 final 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/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/package-info.java
index 38e506552..a37ccbb9e 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/extractor/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $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
@@ -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
+ * Extractors to get scopes from Portlet requests.
  */
-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.request.portlet.extractor;
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/package-info.java
similarity index 52%
copy from plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
copy to plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/package-info.java
index 38e506552..b9eb0d168 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/portlet-tiles/src/main/java/org/apache/tiles/request/portlet/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $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
@@ -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
+ * Support of Tiles requests to portlets.
  */
-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.request.portlet;
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/test/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractorTest.java b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractorTest.java
new file mode 100644
index 000000000..5157b6fe6
--- /dev/null
+++ b/plugins/portlet-tiles/src/test/java/org/apache/tiles/request/portlet/extractor/StateAwareParameterExtractorTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.StateAwareParameterExtractor;
+import org.junit.Test;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.StateAwareResponse;
+
+import static org.easymock.EasyMock.*;
+
+/**
+ * Tests {@link StateAwareParameterExtractor}.
+ */
+public class StateAwareParameterExtractorTest {
+
+    /**
+     * Test method for {@link StateAwareParameterExtractor#setValue(String, String)}.
+     */
+    @Test
+    public void testSetValue() {
+        PortletRequest request = createMock(PortletRequest.class);
+        StateAwareResponse response = createMock(StateAwareResponse.class);
+
+        response.setRenderParameter("name", "value");
+
+        replay(request, response);
+        StateAwareParameterExtractor extractor = new StateAwareParameterExtractor(request, response);
+        extractor.setValue("name", "value");
+        verify(request, response);
+    }
+
+}
diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml
index 0c0488dc0..9716e7198 100644
--- a/plugins/tiles/pom.xml
+++ b/plugins/tiles/pom.xml
@@ -31,59 +31,87 @@
     <packaging>jar</packaging>
     <name>Struts 2 Tiles Plugin</name>
 
+    <!-- mvn -P build-autotags exec:java -->
+    <profiles>
+        <profile>
+            <id>build-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.BuildAutotags</mainClass>
+                            <arguments>
+                                <!-- Output folder -->
+                                <argument>${project.build.directory}</argument>
+                            </arguments>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
     <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>
+            <groupId>commons-digester</groupId>
+            <artifactId>commons-digester</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-request-jsp</artifactId>
+            <groupId>org.glassfish</groupId>
+            <artifactId>javax.el</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-request-servlet</artifactId>
+            <groupId>javax.servlet.jsp</groupId>
+            <artifactId>jsp-api</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-jsp</artifactId>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-freemarker</artifactId>
+            <groupId>org.apache.velocity.tools</groupId>
+            <artifactId>velocity-tools-view</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-ognl</artifactId>
+            <groupId>org.apache.velocity.tools</groupId>
+            <artifactId>velocity-tools-view-jsp</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.apache.tiles</groupId>
-            <artifactId>tiles-el</artifactId>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.glassfish</groupId>
-            <artifactId>javax.el</artifactId>
-            <optional>true</optional>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>javax.servlet.jsp</groupId>
-            <artifactId>jsp-api</artifactId>
-            <scope>provided</scope>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-jcl</artifactId>
+            <scope>test</scope>
         </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/BuildAutotags.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
new file mode 100644
index 000000000..4e90bb7ba
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/BuildAutotags.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.freemarker.FMTemplateGeneratorFactory;
+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;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
+/**
+ * Helper class for building/generating the classes and resources used in the
+ * plugin.
+ */
+public class BuildAutotags {
+
+    public BuildAutotags() {
+    }
+
+    /**
+     * The main method.
+     *
+     * @param args the arguments
+     */
+    public static void main(String[] args) {
+
+        BuildAutotags me = new BuildAutotags();
+
+        // Jsp classes
+        me.buildJsp(args[0]);
+
+        // Freemarker classes
+        me.buildFreemarker(args[0]);
+
+        // Velocity classes
+        me.buildVelocity(args[0]);
+
+    }
+
+    /**
+     * 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 outputDir the output dir
+     */
+    public void buildJsp(String outputDir) {
+
+        // Default values
+        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>();
+        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, runtime, requestClass);
+
+        } catch (Exception e) {
+            // ignored
+        }
+
+    }
+
+    /**
+     * 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
+     * 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
+        }
+
+    }
+
+    /**
+     * 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
+     * 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/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/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/struts2/views/tiles/TilesResult.java b/plugins/tiles/src/main/java/org/apache/struts2/views/tiles/TilesResult.java
index a1e1c69d7..3ca20e4c1 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 -->
+ * <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..65be6537a
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Attribute.java
@@ -0,0 +1,366 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 com.opensymphony.xwork2.util.TextParseUtil;
+import org.apache.tiles.request.Request;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Common implementation of attribute definition.
+ */
+public class Attribute {
+
+    /**
+     * The name of the template renderer.
+     */
+    private static final String TEMPLATE_RENDERER = "template";
+
+    /**
+     * The roles that can render this attribute.
+     *
+     * @since 2.0.6
+     */
+    private Set<String> roles = null;
+
+    /**
+     * The value of the attribute.
+     */
+    private Object value = null;
+
+    /**
+     * The expression to evaluate. Ignored if {@link #value} is not <code>null</code>.
+     *
+     * @since 2.2.0
+     */
+    private 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) {
+            roles = TextParseUtil.commaDelimitedStringToSet(role);
+        } 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() {
+        return Objects.toString(value);
+    }
+
+    /**
+     * 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) {
+        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)
+            && Objects.equals(roles, attribute.roles)
+            && Objects.equals(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 Objects.hashCode(value) + Objects.hashCode(renderer)
+            + Objects.hashCode(roles) + Objects.hashCode(expressionObject);
+    }
+
+    public Attribute copy() {
+        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..554bd9ec0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/AttributeContext.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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
+ */
+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..cd12ea860
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/BasicAttributeContext.java
@@ -0,0 +1,462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.Objects;
+import java.util.Set;
+
+/**
+ * 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) {
+            if (((BasicAttributeContext) context).cascadedAttributes != null && !((BasicAttributeContext) context).cascadedAttributes.isEmpty()) {
+                cascadedAttributes = deepCopyAttributeMap(((BasicAttributeContext) context).cascadedAttributes);
+            }
+        } 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 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) {
+        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)
+            && Objects.equals(attributes, bac.attributes)
+            && Objects.equals(cascadedAttributes, bac.cascadedAttributes);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(templateAttribute) + Objects.hashCode(preparer)
+            + Objects.hashCode(attributes)
+            + Objects.hashCode(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);
+        }
+        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.copy());
+            }
+        }
+        return retValue;
+    }
+}
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..54ac5e035
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Definition.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.Objects;
+
+/**
+ * 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) {
+        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);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(name) + Objects.hashCode(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..38d152ccb
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/Expression.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.Objects;
+
+/**
+ * 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) {
+        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);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(expression) + Objects.hashCode(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..67b329443
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/ListAttribute.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.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.copy());
+                } 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
+     */
+    public void inherit(ListAttribute parent) {
+        List<Attribute> tempList = new ArrayList<>();
+        tempList.addAll(parent.getValue());
+        tempList.addAll(getValue());
+        setValue(tempList);
+    }
+
+    /** {@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;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + Boolean.valueOf(inherit).hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ListAttribute copy() {
+        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..6d6d19307 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
@@ -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,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 {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public class NoSuchContainerException 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 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..00afe9dac
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainer.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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..e8707e34f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesContainerWrapper.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.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..520c24419
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/TilesException.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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..81cf48864
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/access/TilesAccess.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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..5348f239c 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
@@ -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,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 {
+public interface MutableTilesContainer extends TilesContainer {
 
-    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
+    /**
+     * 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..9abf720a6
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/api/preparer/ViewPreparer.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.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>>
+ */
+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/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/core/runtime/AbstractModelBody.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
new file mode 100644
index 000000000..b1a937e73
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AbstractModelBody.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.
+ */
+public abstract class AbstractModelBody implements ModelBody {
+
+    // precompiled the pattern to avoid compiling on every method call
+    private static final Pattern PATTERN = Pattern.compile("^\\s*$");
+
+    /**
+     * The default writer to use.
+     */
+    private final 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 {
+        try (NullWriter writer = new NullWriter()) {
+            evaluate(writer);
+        }
+    }
+
+}
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..f95e39d77
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/AutotagRuntime.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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..0f97ec0d0
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/ModelBody.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.core.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstracts a tag/directive body.
+ */
+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..8833eddeb
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/core/runtime/annotation/Parameter.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.
+ */
+@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..2b68de79d 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
@@ -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,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..8d7b72483 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
@@ -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,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 53%
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..4905e6c63 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
@@ -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,31 @@
  * 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
- *
- * @since Struts 2.0.2
+ * A writer that does not write anything.
  */
-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..76efc98f1 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
@@ -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,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/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/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/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/freemarker/package-info.java
index 38e506552..f891ee347 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/freemarker/package-info.java
@@ -1,4 +1,6 @@
 /*
+ * $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
@@ -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
+ * Autotag support for Freemarker.
  */
-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.freemarker;
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/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorFactory.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/generate/TemplateGeneratorFactory.java
index 38e506552..11fbf693f 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateGeneratorFactory.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,17 @@
  * 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.generate;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Creates a new template generator.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface TemplateGeneratorFactory {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * Creates a template generator.
+     *
+     * @return The newly created template generator.
+     */
+    TemplateGenerator createTemplateGenerator();
+}
diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateSuiteGenerator.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/generate/TemplateSuiteGenerator.java
index 38e506552..f8986779d 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/TemplateSuiteGenerator.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,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.tiles;
+package org.apache.tiles.autotag.generate;
 
-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.io.File;
+import java.util.Map;
+
+import org.apache.tiles.autotag.model.TemplateSuite;
 
 /**
- * Listener used to automatically tie Tiles support into Struts
- *
- * @since Struts 2.0.2
+ * Generates code from a template suite.
  */
-public class StrutsTilesListener extends AbstractTilesListener {
-
-    private static final Logger LOG = LogManager.getLogger(StrutsTilesListener.class);
+public interface TemplateSuiteGenerator {
 
-    @Override
-    protected TilesInitializer createTilesInitializer() {
-        LOG.info("Starting Struts Tiles 3 integration ...");
-        return new StrutsTilesInitializer();
-    }
-}
\ No newline at end of file
+    /**
+     * 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/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/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/generate/package-info.java
index 38e506552..2fbdf2ae0 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/generate/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,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
+ * The Autotag generation 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.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/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/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/jsp/package-info.java
index 38e506552..f142dabfa 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/jsp/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,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
+ * Autotag support for JavaServer Pages.
  */
-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.jsp;
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..0aeb990ce
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateClass.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.
+ */
+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..2bccf2ddd
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateMethod.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.
+ */
+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..0540954c1
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateParameter.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.
+ */
+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..de14b466f
--- /dev/null
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/model/TemplateSuite.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.model;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * It represents a suite of template classes.
+ */
+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..7eddcd1f5 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
@@ -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,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/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/struts2/tiles/StrutsTilesListener.java b/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/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/tool/package-info.java
index 38e506552..b58748ab0 100644
--- a/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesListener.java
+++ b/plugins/tiles/src/main/java/org/apache/tiles/autotag/tool/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,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
+ * Velocity tools to be used in Velocity templates.
  */
-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.tool;
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/";
+    }
+
... 48266 lines suppressed ...