1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts.taglib.nested;
22
23 import org.apache.struts.taglib.html.Constants;
24 import org.apache.struts.taglib.html.FormTag;
25
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.jsp.tagext.Tag;
28
29 import java.util.StringTokenizer;
30
31 /**
32 * <p>A simple helper class that does everything that needs to be done to get
33 * the nested tag extension to work. The tags will pass in their relative
34 * properties and this class will leverage the accessibility of the request
35 * object to calculate the nested references and manage them from a central
36 * place.</p>
37 *
38 * <p>The helper method {@link #setNestedProperties} takes a reference to the
39 * tag itself so all the simpler tags can have their references managed from a
40 * central location. From here, the reference to a provided name is also
41 * preserved for use.</p>
42 *
43 * <p>With all tags keeping track of themselves, we only have to seek to the
44 * next level, or parent tag, were a tag will append a dot and it's own
45 * property.</p>
46 *
47 * @version $Rev: 471754 $ $Date: 2004-10-16 12:38:42 -0400 (Sat, 16 Oct 2004)
48 * $
49 * @since Struts 1.1
50 */
51 public class NestedPropertyHelper {
52
53 public static final String NESTED_INCLUDES_KEY = "<nested-includes-key/>";
54
55 /**
56 * Returns the current nesting property from the request object.
57 *
58 * @param request object to fetch the property reference from
59 * @return String of the bean name to nest against
60 */
61 public static final String getCurrentProperty(HttpServletRequest request) {
62
63 NestedReference nr =
64 (NestedReference) request.getAttribute(NESTED_INCLUDES_KEY);
65
66
67 return (nr == null) ? null : nr.getNestedProperty();
68 }
69
70 /**
71 * <p>Returns the bean name from the request object that the properties
72 * are nesting against.</p>
73 *
74 * <p>The requirement of the tag itself could be removed in the future,
75 * but is required if support for the <html:form> tag is maintained.</p>
76 *
77 * @param request object to fetch the bean reference from
78 * @param nested tag from which to start the search from
79 * @return the string of the bean name to be nesting against
80 */
81 public static final String getCurrentName(HttpServletRequest request,
82 NestedNameSupport nested) {
83
84 NestedReference nr =
85 (NestedReference) request.getAttribute(NESTED_INCLUDES_KEY);
86
87
88 if (nr != null) {
89 return nr.getBeanName();
90 } else {
91
92 Tag tag = (Tag) nested;
93 Tag formTag = null;
94
95
96 do {
97 tag = tag.getParent();
98
99 if ((tag != null) && tag instanceof FormTag) {
100 formTag = tag;
101 }
102 } while ((formTag == null) && (tag != null));
103
104 if (formTag == null) {
105 return "";
106 }
107
108
109 return ((FormTag) formTag).getBeanName();
110 }
111 }
112
113 /**
114 * Get the adjusted property. Apply the provided property, to the property
115 * already stored in the request object.
116 *
117 * @param request to pull the reference from
118 * @param property to retrieve the evaluated nested property with
119 * @return String of the final nested property reference.
120 */
121 public static final String getAdjustedProperty(HttpServletRequest request,
122 String property) {
123
124 String parent = getCurrentProperty(request);
125
126 return calculateRelativeProperty(property, parent);
127 }
128
129 /**
130 * Sets the provided property into the request object for reference by the
131 * other nested tags.
132 *
133 * @param request object to set the new property into
134 * @param property String to set the property to
135 */
136 public static final void setProperty(HttpServletRequest request,
137 String property) {
138
139 NestedReference nr = referenceInstance(request);
140
141 nr.setNestedProperty(property);
142 }
143
144 /**
145 * Sets the provided name into the request object for reference by the
146 * other nested tags.
147 *
148 * @param request object to set the new name into
149 * @param name String to set the name to
150 */
151 public static final void setName(HttpServletRequest request, String name) {
152
153 NestedReference nr = referenceInstance(request);
154
155 nr.setBeanName(name);
156 }
157
158 /**
159 * Deletes the nested reference from the request object.
160 *
161 * @param request object to remove the reference from
162 */
163 public static final void deleteReference(HttpServletRequest request) {
164
165 request.removeAttribute(NESTED_INCLUDES_KEY);
166 }
167
168 /**
169 * Helper method that will set all the relevant nesting properties for the
170 * provided tag reference depending on the implementation.
171 *
172 * @param request object to pull references from
173 * @param tag to set the nesting values into
174 */
175 public static void setNestedProperties(HttpServletRequest request,
176 NestedPropertySupport tag) {
177 boolean adjustProperty = true;
178
179
180 if (tag instanceof NestedNameSupport) {
181 NestedNameSupport nameTag = (NestedNameSupport) tag;
182
183 if ((nameTag.getName() == null)
184 || Constants.BEAN_KEY.equals(nameTag.getName())) {
185 nameTag.setName(getCurrentName(request, (NestedNameSupport) tag));
186 } else {
187 adjustProperty = false;
188 }
189 }
190
191
192 String property = tag.getProperty();
193
194 if (adjustProperty) {
195 property = getAdjustedProperty(request, property);
196 }
197
198 tag.setProperty(property);
199 }
200
201 /**
202 * Pulls the current nesting reference from the request object, and if
203 * there isn't one there, then it will create one and set it.
204 *
205 * @param request object to manipulate the reference into
206 * @return current nesting reference as stored in the request object
207 */
208 private static final NestedReference referenceInstance(
209 HttpServletRequest request) {
210
211 NestedReference nr =
212 (NestedReference) request.getAttribute(NESTED_INCLUDES_KEY);
213
214
215 if (nr == null) {
216 nr = new NestedReference();
217 request.setAttribute(NESTED_INCLUDES_KEY, nr);
218 }
219
220
221 return nr;
222 }
223
224
225
226
227
228
229
230
231
232 private static String calculateRelativeProperty(String property,
233 String parent) {
234 if (parent == null) {
235 parent = "";
236 }
237
238 if (property == null) {
239 property = "";
240 }
241
242
243
244 if ("./".equals(property) || "this/".equals(property)) {
245 return parent;
246 }
247
248
249 String stepping;
250
251
252 if (property.endsWith("/")) {
253 stepping = property;
254 property = "";
255 } else {
256 stepping = property.substring(0, property.lastIndexOf('/') + 1);
257
258
259 property =
260 property.substring(property.lastIndexOf('/') + 1,
261 property.length());
262 }
263
264 if (stepping.startsWith("/")) {
265
266 return property;
267 } else {
268
269 StringTokenizer proT = new StringTokenizer(parent, ".");
270 int propCount = proT.countTokens();
271
272
273 StringTokenizer strT = new StringTokenizer(stepping, "/");
274 int count = strT.countTokens();
275
276 if (count >= propCount) {
277
278 return property;
279 } else {
280
281 count = propCount - count;
282
283 StringBuffer result = new StringBuffer();
284
285 for (int i = 0; i < count; i++) {
286 result.append(proT.nextToken());
287 result.append('.');
288 }
289
290 result.append(property);
291
292
293 if (result.charAt(result.length() - 1) == '.') {
294 return result.substring(0, result.length() - 1);
295 } else {
296 return result.toString();
297 }
298 }
299 }
300 }
301 }