Repository: struts Updated Branches: refs/heads/support-2-3 85373951b -> 87979d282
WW-4606 cherry-picked @TilesDefinition and related classes Project: http://git-wip-us.apache.org/repos/asf/struts/repo Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/a6345e79 Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/a6345e79 Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/a6345e79 Branch: refs/heads/support-2-3 Commit: a6345e79c9d0ea0d5137a890af2df1f44e647908 Parents: 8537395 Author: cnenning <cnenn...@apache.org> Authored: Fri Jan 22 15:27:09 2016 +0100 Committer: cnenning <cnenn...@apache.org> Committed: Wed Feb 3 13:15:44 2016 +0100 ---------------------------------------------------------------------- .../tiles/StrutsTilesAnnotationProcessor.java | 176 +++++++++++++++++++ .../tiles/annotation/TilesAddAttribute.java | 30 ++++ .../tiles/annotation/TilesAddListAttribute.java | 28 +++ .../tiles/annotation/TilesDefinition.java | 45 +++++ .../tiles/annotation/TilesDefinitions.java | 36 ++++ .../tiles/annotation/TilesPutAttribute.java | 32 ++++ .../tiles/annotation/TilesPutListAttribute.java | 32 ++++ .../apache/struts2/views/tiles/TilesResult.java | 72 ++++++-- 8 files changed, 438 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesAnnotationProcessor.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..2ae3ba4 --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/StrutsTilesAnnotationProcessor.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles; + +import org.apache.commons.lang3.StringUtils; +import org.apache.struts2.tiles.annotation.TilesAddAttribute; +import org.apache.struts2.tiles.annotation.TilesAddListAttribute; +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; + +/** + * Processes tiles annotations to create {@link Definition}s and + * {@link Attribute}s in a way as close to <code>tiles.xml</code> as possible. + * + */ +public class StrutsTilesAnnotationProcessor { + + /** + * Search strategy is as follows: + * <ul> + * <li>Check if action has Annotation {@link TilesDefinition}</li> + * <li>If not, check if action has Annotation {@link TilesDefinitions}</li> + * <li>If given tileName is not null and present in {@link TilesDefinitions}, return it</li> + * <li>Return first element of {@link TilesDefinitions}</li> + * <li>Return null</li> + * </ul> + * + * @param action + * Annotated action. + * @param tileName + * Tilename to search for. May be null in some circumstances. + * @return {@link TilesDefinition} + */ + public TilesDefinition findAnnotation(Object action, String tileName) { + Class<? extends Object> clazz = action.getClass(); + TilesDefinition tilesDefinition = clazz.getAnnotation(TilesDefinition.class); + TilesDefinitions tilesDefinitions = clazz.getAnnotation(TilesDefinitions.class); + + if (tilesDefinition == null && tilesDefinitions != null) { + if (!StringUtils.isEmpty(tileName)) { + for (TilesDefinition i : tilesDefinitions.value()) { + if (i.name() != null && i.name().equals(tileName)) { + tilesDefinition = i; + break; + } + } + } + if (tilesDefinitions.value().length > 0) { + tilesDefinition = tilesDefinitions.value()[0]; + } + } + + return tilesDefinition; + } + + /** + * Builds a {@link Definition} based on given {@link TilesDefinition} with + * given name. + * + * @param tileName + * name for resulting {@link Definition}. + * @param tilesDefinition + * {@link TilesDefinition} to process. + * @return {@link Definition} represented by given {@link TilesDefinition}. + */ + public Definition buildTilesDefinition(String tileName, TilesDefinition tilesDefinition) { + Definition definition = new Definition(); + + definition.setName(tileName); + + String extend = getValueOrNull(tilesDefinition.extend()); + if (extend != null) { + definition.setExtends(extend); + } + String preparer = getValueOrNull(tilesDefinition.preparer()); + if (preparer != null) { + definition.setPreparer(preparer); + } + definition.setTemplateAttribute(buildTemplateAttribute(tilesDefinition)); + + for (TilesPutAttribute putAttribute : tilesDefinition.putAttributes()) { + Attribute attribute = buildPutAttribute(putAttribute); + definition.putAttribute(putAttribute.name(), attribute, putAttribute.cascade()); + } + for (TilesPutListAttribute putListAttribute : tilesDefinition.putListAttributes()) { + Attribute attribute = buildPutListAttribute(putListAttribute); + definition.putAttribute(putListAttribute.name(), attribute, putListAttribute.cascade()); + } + + return definition; + } + + protected Attribute buildTemplateAttribute(TilesDefinition tilesDef) { + // see tiles DigesterDefinitionsReader + Attribute attribute = Attribute.createTemplateAttribute(getValueOrNull(tilesDef.template())); + String templateExpression = getValueOrNull(tilesDef.templateExpression()); + Expression expression = Expression.createExpressionFromDescribedExpression(templateExpression); + attribute.setExpressionObject(expression); + attribute.setRole(getValueOrNull(tilesDef.role())); + String templateType = getValueOrNull(tilesDef.templateType()); + if (templateType != null) { + attribute.setRenderer(templateType); + } else if (getValueOrNull(tilesDef.extend()) != null && templateType == null) { + attribute.setRenderer(null); + } + return attribute; + } + + protected Attribute buildPutAttribute(TilesPutAttribute putAttribute) { + Attribute attribute = new Attribute(); + attribute.setValue(getValueOrNull(putAttribute.value())); + String expression = getValueOrNull(putAttribute.expression()); + attribute.setExpressionObject(Expression.createExpressionFromDescribedExpression(expression)); + attribute.setRole(getValueOrNull(putAttribute.role())); + attribute.setRenderer(getValueOrNull(putAttribute.type())); + return attribute; + } + + protected Attribute buildPutListAttribute(TilesPutListAttribute putListAttribute) { + ListAttribute attribute = new ListAttribute(); + attribute.setRole(getValueOrNull(putListAttribute.role())); + attribute.setInherit(putListAttribute.inherit()); + for (TilesAddAttribute addAttribute : putListAttribute.addAttributes()) { + attribute.add(buildAddAttribute(addAttribute)); + } + for (TilesAddListAttribute addListAttribute : putListAttribute.addListAttributes()) { + attribute.add(buildAddListAttribute(addListAttribute)); + } + return attribute; + } + + protected Attribute buildAddAttribute(TilesAddAttribute addAttribute) { + Attribute attribute = new Attribute(); + attribute.setValue(getValueOrNull(addAttribute.value())); + String expression = getValueOrNull(addAttribute.expression()); + attribute.setExpressionObject(Expression.createExpressionFromDescribedExpression(expression)); + attribute.setRole(getValueOrNull(addAttribute.role())); + attribute.setRenderer(getValueOrNull(addAttribute.type())); + return attribute; + } + + protected Attribute buildAddListAttribute(TilesAddListAttribute addListAttribute) { + ListAttribute attribute = new ListAttribute(); + attribute.setRole(getValueOrNull(addListAttribute.role())); + for (TilesAddAttribute addAttribute : addListAttribute.addAttributes()) { + attribute.add(buildAddAttribute(addAttribute)); + } + return attribute; + } + + protected String getValueOrNull(String value) { + return value != null && value.length() > 0 ? value : null; + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddAttribute.java ---------------------------------------------------------------------- diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddAttribute.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddAttribute.java new file mode 100644 index 0000000..0e668de --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddAttribute.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles.annotation; + +/** + * Represents a <code><add-attribute></code> element in <code>tiles.xml</code>. + * + */ +public @interface TilesAddAttribute { + String expression() default ""; + String role() default ""; + String type() default ""; + String value() default ""; +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddListAttribute.java ---------------------------------------------------------------------- diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddListAttribute.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddListAttribute.java new file mode 100644 index 0000000..d65066f --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesAddListAttribute.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles.annotation; + +/** + * Represents a <code><add-list-attribute></code> element in <code>tiles.xml</code>. + * + */ +public @interface TilesAddListAttribute { + String role() default ""; + TilesAddAttribute[] addAttributes() default {}; +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinition.java ---------------------------------------------------------------------- diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinition.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinition.java new file mode 100644 index 0000000..a71bbc3 --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinition.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Represents a <code><definition></code> element in <code>tiles.xml</code>. + * + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = { ElementType.TYPE }) +@Inherited +public @interface TilesDefinition { + + String extend() default ""; + String name() default ""; + String preparer() default ""; + String role() default ""; + String template() default ""; + String templateExpression() default ""; + String templateType() default ""; + TilesPutAttribute[] putAttributes() default {}; + TilesPutListAttribute[] putListAttributes() default {}; +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinitions.java ---------------------------------------------------------------------- diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinitions.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinitions.java new file mode 100644 index 0000000..fb5cc95 --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesDefinitions.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An array of {@link TilesDefinition}s. + * + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = { ElementType.TYPE }) +@Inherited +public @interface TilesDefinitions { + TilesDefinition[] value(); +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutAttribute.java ---------------------------------------------------------------------- diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutAttribute.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutAttribute.java new file mode 100644 index 0000000..c31d49e --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutAttribute.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles.annotation; + +/** + * Represents a <code><put-attribute></code> element in <code>tiles.xml</code>. + * + */ +public @interface TilesPutAttribute { + boolean cascade() default false; + String expression() default ""; + String name() default ""; + String role() default ""; + String type() default ""; + String value() default ""; +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutListAttribute.java ---------------------------------------------------------------------- diff --git a/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutListAttribute.java b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutListAttribute.java new file mode 100644 index 0000000..be7a507 --- /dev/null +++ b/plugins/tiles/src/main/java/org/apache/struts2/tiles/annotation/TilesPutListAttribute.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.tiles.annotation; + +/** + * Represents a <code><put-list-attribute></code> element in <code>tiles.xml</code>. + * + */ +public @interface TilesPutListAttribute { + boolean cascade() default false; + boolean inherit() default false; + String name() default ""; + String role() default ""; + TilesAddAttribute[] addAttributes() default {}; + TilesAddListAttribute[] addListAttributes() default {}; +} http://git-wip-us.apache.org/repos/asf/struts/blob/a6345e79/plugins/tiles/src/main/java/org/apache/struts2/views/tiles/TilesResult.java ---------------------------------------------------------------------- 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 1e62672..1cea77b 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 @@ -25,12 +25,20 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.dispatcher.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.mgmt.MutableTilesContainer; +import org.apache.tiles.servlet.context.ServletUtil; import com.opensymphony.xwork2.ActionInvocation; -import org.apache.tiles.servlet.context.ServletUtil; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; /** * <!-- START SNIPPET: description --> @@ -38,19 +46,11 @@ import org.apache.tiles.servlet.context.ServletUtil; * <!-- END SNIPPET: description --> * * <!-- START SNIPPET: webxml --> - * In your web.xml file, you need to add a servlet entry for TilesServlet to load the tiles - * definitions into the ServletContext. + * In your web.xml file, you need to add a TilesListener. * - * <servlet> - * <servlet-name>tiles</servlet-name> - * <servlet-class>org.apache.tiles.servlets.TilesServlet</servlet-class> - * <init-param> - * <param-name>definitions-config</param-name> - * <param-value>/WEB-INF/tiles-config.xml</param-value> - * </init-param> - * <load-on-startup>1</load-on-startup> - * </servlet> - * <!-- END SNIPPET: webxml --> + * <listener> + * <listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class> + * </listener> * <!-- END SNIPPET: webxml --> * * <!-- START SNIPPET: strutsxml --> * In struts.xml, use type="tiles" on your <result>. @@ -72,11 +72,20 @@ import org.apache.tiles.servlet.context.ServletUtil; * </result-types> * <!-- END SNIPPET: packageconfig --> * + * <!-- START SNIPPET: tilesconfig --> + * 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 { private static final long serialVersionUID = -3806939435493086244L; + private static final Logger LOG = LoggerFactory.getLogger(TilesResult.class); + public TilesResult() { super(); } @@ -95,6 +104,18 @@ public class TilesResult extends ServletDispatcherResult { * HTTP request. */ public void doExecute(String location, ActionInvocation invocation) throws Exception { + StrutsTilesAnnotationProcessor annotationProcessor = new StrutsTilesAnnotationProcessor(); + TilesDefinition tilesDefinition = null; + Object action = invocation.getAction(); + String actionName = invocation.getInvocationContext().getName(); + + 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; + LOG.debug("using new location name '{}' and @TilesDefinition '{}'", location, tilesDefinition); + } setLocation(location); ServletContext servletContext = ServletActionContext.getServletContext(); @@ -104,6 +125,31 @@ public class TilesResult extends ServletDispatcherResult { HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); + boolean definitionValid = false; + try { + LOG.debug("checking if tiles definition exists '{}'", location); + definitionValid = container.isValidDefinition(location, request); + } catch (TilesException e) { + LOG.warn("got TilesException while checking if definiton exists, ignoring it", e); + } + if (!definitionValid) { + if (tilesDefinition == null) { + LOG.trace("tilesDefinition not found yet, searching in action"); + tilesDefinition = annotationProcessor.findAnnotation(action, location); + } + if (tilesDefinition != null) { + Definition definition = annotationProcessor.buildTilesDefinition(location, tilesDefinition); + if (container instanceof MutableTilesContainer) { + LOG.debug("registering tiles definition with name '{}'", definition.getName()); + ((MutableTilesContainer)container).register(definition, request); + } else { + LOG.error("cannot register tiles definition as tiles container is not mutable!"); + } + } else { + LOG.warn("could not find @TilesDefinition for action: {}", actionName); + } + } + container.render(location, request, response); } }