1 /*
2 * $Id: GetAsStringModel.java 1625204 2014-09-16 02:21:04Z 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.io.Writer;
26 import java.util.Deque;
27
28 import org.apache.tiles.Attribute;
29 import org.apache.tiles.TilesContainer;
30 import org.apache.tiles.access.TilesAccess;
31 import org.apache.tiles.autotag.core.runtime.ModelBody;
32 import org.apache.tiles.autotag.core.runtime.annotation.Parameter;
33 import org.apache.tiles.request.Request;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38 * <p>
39 * <strong> Render the value of the specified template attribute to the current
40 * Writer</strong>
41 * </p>
42 *
43 * <p>
44 * Retrieve the value of the specified template attribute property, and render
45 * it to the current Writer as a String. The usual toString() conversions is
46 * applied on found value.
47 * </p>
48 *
49 * @version $Rev: 1625204 $ $Date: 2014-09-16 12:21:04 +1000 (Tue, 16 Sep 2014) $
50 * @since 2.2.0
51 */
52 public class GetAsStringModel {
53
54 /**
55 * The logging object.
56 */
57 private Logger log = LoggerFactory.getLogger(getClass());
58
59 /**
60 * The attribute resolver to use.
61 */
62 private AttributeResolver attributeResolver;
63
64 /**
65 * Constructor that uses the defaut attribute resolver.
66 *
67 * @since 3.0.0
68 */
69 public GetAsStringModel() {
70 this(new DefaultAttributeResolver());
71 }
72
73 /**
74 * Constructor.
75 *
76 * @param attributeResolver The attribute resolver to use.
77 * @since 2.2.0
78 */
79 public GetAsStringModel(AttributeResolver attributeResolver) {
80 this.attributeResolver = attributeResolver;
81 }
82
83 /**
84 * Executes the operation.
85 * @param ignore If <code>true</code>, if an exception happens during
86 * rendering, of if the attribute is null, the problem will be ignored.
87 * @param preparer The preparer to invoke before rendering the attribute.
88 * @param role A comma-separated list of roles. If present, the attribute
89 * will be rendered only if the current user belongs to one of the roles.
90 * @param defaultValue The default value of the attribute. To use only if
91 * the attribute was not computed.
92 * @param defaultValueRole The default comma-separated list of roles. To use
93 * only if the attribute was not computed.
94 * @param defaultValueType The default type of the attribute. To use only if
95 * the attribute was not computed.
96 * @param name The name of the attribute.
97 * @param value The attribute to use immediately, if not null.
98 * @param request The request.
99 * @param modelBody The body.
100 * @throws IOException If an I/O error happens during rendering.
101 * @since 2.2.0
102 */
103 public void execute(boolean ignore, String preparer, String role,
104 Object defaultValue, String defaultValueRole,
105 String defaultValueType, @Parameter(required = true) String name,
106 Attribute value, Request request, ModelBody modelBody)
107 throws IOException {
108 TilesContainer container = TilesAccess.getCurrentContainer(request);
109 Deque<Object> composeStack = ComposeStackUtil.getComposeStack(request);
110 Attribute attribute = resolveAttribute(container, ignore, preparer,
111 role, defaultValue, defaultValueRole, defaultValueType, name,
112 value, request);
113 if (attribute != null) {
114 composeStack.push(attribute);
115 }
116 modelBody.evaluateWithoutWriting();
117 container = TilesAccess.getCurrentContainer(request);
118 Writer writer = request.getWriter();
119 if (attribute != null) {
120 attribute = (Attribute) composeStack.pop();
121 }
122 renderAttribute(attribute, container, writer, ignore, request);
123 }
124
125 /**
126 * Resolves the attribute. and starts the context.
127 *
128 * @param container The Tiles container to use.
129 * @param ignore If <code>true</code>, if an exception happens during
130 * rendering, of if the attribute is null, the problem will be ignored.
131 * @param preparer The preparer to invoke before rendering the attribute.
132 * @param role A comma-separated list of roles. If present, the attribute
133 * will be rendered only if the current user belongs to one of the roles.
134 * @param defaultValue The default value of the attribute. To use only if
135 * the attribute was not computed.
136 * @param defaultValueRole The default comma-separated list of roles. To use
137 * only if the attribute was not computed.
138 * @param defaultValueType The default type of the attribute. To use only if
139 * the attribute was not computed.
140 * @param name The name of the attribute.
141 * @param value The attribute to use immediately, if not null.
142 * @param request The request.
143 * @return The resolved attribute.
144 */
145 private Attribute resolveAttribute(TilesContainer container,
146 boolean ignore, String preparer, String role, Object defaultValue,
147 String defaultValueRole, String defaultValueType, String name,
148 Attribute value, Request request) {
149 if (preparer != null) {
150 container.prepare(preparer, request);
151 }
152 Attribute attribute = attributeResolver.computeAttribute(container,
153 value, name, role, ignore, defaultValue, defaultValueRole,
154 defaultValueType, request);
155 container.startContext(request);
156 return attribute;
157 }
158
159 /**
160 * Renders the attribute as a string.
161 *
162 * @param attribute The attribute to use, previously resolved.
163 * @param container The Tiles container to use.
164 * @param writer The writer into which the attribute will be written.
165 * @param ignore If <code>true</code>, if an exception happens during
166 * rendering, of if the attribute is null, the problem will be ignored.
167 * @param request The request.
168 * @throws IOException If an I/O error happens during rendering.
169 */
170 private void renderAttribute(Attribute attribute, TilesContainer container,
171 Writer writer, boolean ignore, Request request)
172 throws IOException {
173 try {
174 if (attribute == null && ignore) {
175 return;
176 }
177 Object value = container.evaluate(attribute, request);
178 if(value != null) {
179 writer.write(value.toString());
180 }
181 } catch (IOException e) {
182 if (!ignore) {
183 throw e;
184 } else if (log.isDebugEnabled()) {
185 log.debug("Ignoring exception", e);
186 }
187 } catch (RuntimeException e) {
188 if (!ignore) {
189 throw e;
190 } else if (log.isDebugEnabled()) {
191 log.debug("Ignoring exception", e);
192 }
193 } finally {
194 container.endContext(request);
195 }
196 }
197 }