View Javadoc

1   /*
2    * $Id: InsertAttributeModel.java 1305937 2012-03-27 18:15:15Z nlebas $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.tiles.template;
23  
24  import java.io.IOException;
25  import java.util.Deque;
26  
27  import org.apache.tiles.Attribute;
28  import org.apache.tiles.TilesContainer;
29  import org.apache.tiles.access.TilesAccess;
30  import org.apache.tiles.autotag.core.runtime.ModelBody;
31  import org.apache.tiles.request.Request;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  /**
36   * <p>
37   * <strong>Inserts the value of an attribute into the page.</strong>
38   * </p>
39   * <p>
40   * This tag can be flexibly used to insert the value of an attribute into a
41   * page. As in other usages in Tiles, every attribute can be determined to have
42   * a "type", either set explicitly when it was defined, or "computed". If the
43   * type is not explicit, then if the attribute value is a valid definition, it
44   * will be inserted as such. Otherwise, if it begins with a "/" character, it
45   * will be treated as a "template". Finally, if it has not otherwise been
46   * assigned a type, it will be treated as a String and included without any
47   * special handling.
48   * </p>
49   *
50   * <p>
51   * <strong>Example : </strong>
52   * </p>
53   *
54   * <pre>
55   * &lt;code&gt;
56   *           &lt;tiles:insertAttribute name=&quot;body&quot; /&gt;
57   *         &lt;/code&gt;
58   * </pre>
59   *
60   * @version $Rev: 1305937 $ $Date: 2012-03-28 05:15:15 +1100 (Wed, 28 Mar 2012) $
61   * @since 2.2.0
62   */
63  public class InsertAttributeModel {
64  
65      /**
66       * The logging object.
67       */
68      private Logger log = LoggerFactory.getLogger(getClass());
69  
70      /**
71       * The attribute resolver to use.
72       */
73      private AttributeResolver attributeResolver;
74  
75      /**
76       * Constructor that uses the defaut attribute resolver.
77       *
78       * @since 3.0.0
79       */
80      public InsertAttributeModel() {
81          this(new DefaultAttributeResolver());
82      }
83  
84      /**
85       * Constructor.
86       *
87       * @param attributeResolver The attribute resolver to use.
88       * @since 2.2.0
89       */
90      public InsertAttributeModel(AttributeResolver attributeResolver) {
91          this.attributeResolver = attributeResolver;
92      }
93  
94      /**
95       * Executes the operation.
96       * @param ignore If <code>true</code>, if an exception happens during
97       * rendering, of if the attribute is null, the problem will be ignored.
98       * @param preparer The preparer to invoke before rendering the attribute.
99       * @param role A comma-separated list of roles. If present, the attribute
100      * will be rendered only if the current user belongs to one of the roles.
101      * @param defaultValue The default value of the attribute. To use only if
102      * the attribute was not computed.
103      * @param defaultValueRole The default comma-separated list of roles. To use
104      * only if the attribute was not computed.
105      * @param defaultValueType The default type of the attribute. To use only if
106      * the attribute was not computed.
107      * @param name The name of the attribute.
108      * @param value The attribute to use immediately, if not null.
109      * @param flush If <code>true</code>, the response will be flushed after the insert.
110      * @param request The request.
111      * @param modelBody The body.
112      * @throws IOException If an I/O error happens during rendering.
113      * @since 2.2.0
114      */
115     public void execute(boolean ignore, String preparer,
116             String role, Object defaultValue, String defaultValueRole,
117             String defaultValueType, String name, Attribute value,
118             boolean flush, Request request, ModelBody modelBody) throws IOException {
119         TilesContainer container = TilesAccess.getCurrentContainer(request);
120         Deque<Object> composeStack = ComposeStackUtil.getComposeStack(request);
121         Attribute attribute = resolveAttribute(container, ignore, preparer,
122                 role, defaultValue, defaultValueRole, defaultValueType, name,
123                 value, request);
124         if (attribute != null) {
125             composeStack.push(attribute);
126         }
127         modelBody.evaluateWithoutWriting();
128         container = TilesAccess.getCurrentContainer(request);
129         if (attribute != null) {
130             attribute = (Attribute) composeStack.pop();
131         }
132         renderAttribute(container, ignore, attribute, request);
133         if (flush) {
134             request.getWriter().flush();
135         }
136     }
137 
138     /**
139      * Resolves the attribute. and starts the context.
140      *
141      * @param container The Tiles container to use.
142      * @param ignore If <code>true</code>, if an exception happens during
143      * rendering, of if the attribute is null, the problem will be ignored.
144      * @param preparer The preparer to invoke before rendering the attribute.
145      * @param role A comma-separated list of roles. If present, the attribute
146      * will be rendered only if the current user belongs to one of the roles.
147      * @param defaultValue The default value of the attribute. To use only if
148      * the attribute was not computed.
149      * @param defaultValueRole The default comma-separated list of roles. To use
150      * only if the attribute was not computed.
151      * @param defaultValueType The default type of the attribute. To use only if
152      * the attribute was not computed.
153      * @param name The name of the attribute.
154      * @param value The attribute to use immediately, if not null.
155      * @param request The request.
156      * @return The resolved attribute.
157      */
158     private Attribute resolveAttribute(TilesContainer container,
159             boolean ignore, String preparer, String role, Object defaultValue,
160             String defaultValueRole, String defaultValueType, String name,
161             Attribute value, Request request) {
162         if (preparer != null) {
163             container.prepare(preparer, request);
164         }
165         Attribute attribute = attributeResolver.computeAttribute(container,
166                 value, name, role, ignore, defaultValue, defaultValueRole,
167                 defaultValueType, request);
168         container.startContext(request);
169         return attribute;
170     }
171 
172     /**
173      * Renders the attribute as a string.
174      * @param container The Tiles container to use.
175      * @param ignore If <code>true</code>, if an exception happens during
176      * rendering, of if the attribute is null, the problem will be ignored.
177      * @param attribute The attribute to use, previously resolved.
178      * @param request The request.
179      *
180      * @throws IOException If an I/O error happens during rendering.
181      */
182     private void renderAttribute(TilesContainer container, boolean ignore,
183             Attribute attribute, Request request) throws IOException {
184         try {
185             if (attribute == null && ignore) {
186                 return;
187             }
188             container.render(attribute, request);
189         } catch (IOException e) {
190             if (!ignore) {
191                 throw e;
192             } else if (log.isDebugEnabled()) {
193                 log.debug("Ignoring exception", e);
194             }
195         } catch (RuntimeException e) {
196             if (!ignore) {
197                 throw e;
198             } else if (log.isDebugEnabled()) {
199                 log.debug("Ignoring exception", e);
200             }
201         } finally {
202             container.endContext(request);
203         }
204     }
205 }