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