View Javadoc

1   /*
2    * $Id: PutTag.java 421151 2006-07-12 06:07:14Z wsmoak $
3    *
4    * Copyright 1999-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.struts.tiles.taglib;
20  
21  import java.lang.reflect.InvocationTargetException;
22  
23  import javax.servlet.jsp.JspException;
24  import javax.servlet.jsp.tagext.BodyTagSupport;
25  
26  import org.apache.commons.beanutils.PropertyUtils;
27  import org.apache.struts.tiles.taglib.util.TagUtils;
28  import org.apache.struts.tiles.AttributeDefinition;
29  import org.apache.struts.tiles.DefinitionNameAttribute;
30  import org.apache.struts.tiles.DirectStringAttribute;
31  import org.apache.struts.tiles.PathAttribute;
32  
33  /***
34   * Put an attribute in enclosing attribute container tag.
35   * Enclosing attribute container tag can be : <insert> or <definition>.
36   * Exception is thrown if no appropriate tag can be found.
37   * Put tag can have following atributes :
38   * <li>
39   * <ul>name : Name of the attribute</ul>
40   * <ul>value | content : value to put as attribute</ul>
41   * <ul>type : value type. Only valid if value is a String and is set by
42   * value="something" or by a bean.
43   * Possible type are : string (value is used as direct string),
44   * page | template (value is used as a page url to insert),
45   * definition (value is used as a definition name to insert)</ul>
46   * <ul>direct : Specify if value is to be used as a direct string or as a
47   * page url to insert. This is another way to specify the type. It only apply
48   * if value is set as a string, and type is not present.</ul>
49   * <ul>beanName : Name of a bean used for setting value. Only valid if value is not set.
50   * If property is specified, value come from bean's property. Otherwise, bean
51   * itself is used for value.</ul>
52   * <ul>beanProperty : Name of the property used for retrieving value.</ul>
53   * <ul>beanScope : Scope containing bean. </ul>
54   * <ul>role : Role to check when 'insert' will be called. If enclosing tag is
55   * &lt;insert&gt;, role is checked immediately. If enclosing tag is
56   * &lt;definition&gt;, role will be checked when this definition will be
57   * inserted.</ul>
58   * </li>
59   * Value can also come from tag body. Tag body is taken into account only if
60   * value is not set by one of the tag attributes. In this case Attribute type is
61   * "string", unless tag body define another type.
62   */
63  public class PutTag extends BodyTagSupport implements ComponentConstants {
64  
65      /* JSP Tag attributes */
66  
67      /***
68       * Name of attribute to put in component context.
69       */
70      protected String attributeName = null;
71  
72      /***
73       * Associated attribute value.
74       */
75      private Object value = null;
76  
77      /***
78       * JSP Template compatibility.
79       */
80      private String direct = null;
81  
82      /***
83       * Requested type for the value.
84       */
85      private String valueType = null;
86  
87      /***
88       * Bean name attribute.
89       */
90      private String beanName = null;
91  
92      /***
93       * Bean property attribute.
94       */
95      private String beanProperty = null;
96  
97      /***
98       * Bean scope attribute.
99       */
100     private String beanScope = null;
101 
102     /***
103      * Role attribute.
104      */
105     private String role = null;
106 
107     /* Internal properties */
108 
109     /***
110      * Cached real value computed from tag attributes.
111      */
112     protected Object realValue = null;
113 
114     /***
115      * The body content of this tag.
116      */
117     protected String body = null;
118 
119     /***
120      * Default constructor.
121      */
122     public PutTag() {
123         super();
124     }
125 
126     /***
127      * Release all allocated resources.
128      */
129     public void release() {
130 
131         super.release();
132 
133         attributeName = null;
134         valueType = null;
135         direct = null;
136         value = null;
137         beanName = null;
138         beanProperty = null;
139         beanScope = null;
140         role = null;
141         body = null;
142     }
143 
144     /***
145      * Release internal properties.
146      */
147     protected void releaseInternal() {
148         realValue = null;
149     }
150 
151     /***
152      * Set name.
153      */
154     public void setName(String value) {
155         this.attributeName = value;
156     }
157 
158     /***
159      * Get name.
160      */
161     public String getName() {
162         return attributeName;
163     }
164 
165     /***
166      * Set value.
167      * Method added to satisfy Tomcat (bug ?).
168      */
169     public void setValue(String value) {
170         this.value = value;
171     }
172 
173     /***
174      * Get value.
175      * Method added to satisfy Tomcat (bug ?).
176      */
177     public String getValue() {
178         return (String) this.value;
179     }
180 
181     /***
182      * Set value.
183      */
184     public void setValue(Object value) {
185         this.value = value;
186     }
187 
188     /***
189      * Set property value as an object.
190      * Added because some web containers react badly to value as <code>Object</code>.
191      */
192     public void setObjectValue(Object value) {
193         this.value = value;
194     }
195 
196     /***
197      * Set content.
198      * Method added to satisfy Tomcat (bug ?).
199      */
200     public void setContent(String value) {
201         this.value = value;
202     }
203 
204     /***
205      * Get content.
206      * Method added to satisfy Tomcat (bug ?).
207      */
208     public String getContent() {
209         return (String) value;
210     }
211 
212     /***
213      * Set content.
214      */
215     public void setContent(Object value) {
216         this.value = value;
217     }
218 
219     /***
220      * Set direct.
221      * Method added for compatibility with JSP1.1.
222      */
223     public void setDirect(String isDirect) {
224         this.direct = isDirect;
225     }
226 
227     /***
228      * Set type.
229      */
230     public void setType(String value) {
231         this.valueType = value;
232     }
233 
234     /***
235      * Get type.
236      */
237     public String getType() {
238         return this.valueType;
239     }
240 
241     /***
242      * Set bean name.
243      */
244     public void setBeanName(String value) {
245         this.beanName = value;
246     }
247 
248     /***
249      * Get bean name.
250      */
251     public String getBeanName() {
252         return beanName;
253     }
254 
255     /***
256      * Set bean property.
257      */
258     public void setBeanProperty(String value) {
259         this.beanProperty = value;
260     }
261 
262     /***
263      * Get bean property.
264      */
265     public String getBeanProperty() {
266         return beanProperty;
267     }
268 
269     /***
270      * Set bean scope.
271      */
272     public void setBeanScope(String value) {
273         this.beanScope = value;
274     }
275 
276     /***
277      * Get bean scope.
278      */
279     public String getBeanScope() {
280         return beanScope;
281     }
282 
283     /***
284      * Set role attribute.
285      * @param role The role the user must be in to store content.
286      */
287     public void setRole(String role) {
288         this.role = role;
289     }
290 
291     /***
292      * Get role attribute
293      * @return The role defined in the tag or <code>null</code>.
294      */
295     public String getRole() {
296         return role;
297     }
298 
299     /***
300      * Get real value according to tag attribute.
301      * Real value is the value computed after attribute processing.
302      * @return Real value.
303      * @throws JspException If something goes wrong while getting value from bean.
304      */
305     public Object getRealValue() throws JspException {
306         if (realValue == null) {
307             computeRealValue();
308         }
309 
310         return realValue;
311     }
312 
313     /***
314      * Compute real value according to tag attributes.
315      * @throws JspException If something goes wrong while getting value from bean.
316      */
317     protected void computeRealValue() throws JspException {
318         // Compute real value from attributes set.
319         realValue = value;
320 
321         // If realValue is not set, value must come from body
322         if (value == null && beanName == null) {
323             // Test body content in case of empty body.
324             if (body != null) {
325                 realValue = body;
326             } else {
327                 realValue = "";
328             }
329         }
330 
331         // Does value comes from a bean ?
332         if (realValue == null && beanName != null) {
333             getRealValueFromBean();
334             return;
335         }
336 
337         // Is there a type set ?
338         // First check direct attribute, and translate it to a valueType.
339         // Then, evaluate valueType, and create requested typed attribute.
340         // If valueType is not set, use the value "as is".
341         if (valueType == null && direct != null) {
342             if (Boolean.valueOf(direct).booleanValue() == true) {
343                 valueType = "string";
344             } else {
345                 valueType = "page";
346             }
347         }
348 
349         if (realValue != null
350             && valueType != null
351             && !(value instanceof AttributeDefinition)) {
352 
353             String strValue = realValue.toString();
354             if (valueType.equalsIgnoreCase("string")) {
355                 realValue = new DirectStringAttribute(strValue);
356 
357             } else if (valueType.equalsIgnoreCase("page")) {
358                 realValue = new PathAttribute(strValue);
359 
360             } else if (valueType.equalsIgnoreCase("template")) {
361                 realValue = new PathAttribute(strValue);
362 
363             } else if (valueType.equalsIgnoreCase("instance")) {
364                 realValue = new DefinitionNameAttribute(strValue);
365 
366             } else if (valueType.equalsIgnoreCase("definition")) {
367                 realValue = new DefinitionNameAttribute(strValue);
368 
369             } else { // bad type
370                 throw new JspException(
371                     "Warning - Tag put : Bad type '" + valueType + "'.");
372             }
373         }
374 
375     }
376 
377     /***
378      * Extract real value from specified bean.
379      * @throws JspException If something goes wrong while getting value from bean.
380      */
381     protected void getRealValueFromBean() throws JspException {
382         try {
383             Object bean = TagUtils.retrieveBean(beanName, beanScope, pageContext);
384             if (bean != null && beanProperty != null) {
385                 realValue = PropertyUtils.getProperty(bean, beanProperty);
386             } else {
387                 realValue = bean; // value can be null
388             }
389 
390         } catch (NoSuchMethodException ex) {
391             throw new JspException(
392                 "Error - component.PutAttributeTag : Error while retrieving value from bean '"
393                     + beanName
394                     + "' with property '"
395                     + beanProperty
396                     + "' in scope '"
397                     + beanScope
398                     + "'. (exception : "
399                     + ex.getMessage(), ex);
400 
401         } catch (InvocationTargetException ex) {
402             throw new JspException(
403                 "Error - component.PutAttributeTag : Error while retrieving value from bean '"
404                     + beanName
405                     + "' with property '"
406                     + beanProperty
407                     + "' in scope '"
408                     + beanScope
409                     + "'. (exception : "
410                     + ex.getMessage(), ex);
411 
412         } catch (IllegalAccessException ex) {
413             throw new JspException(
414                 "Error - component.PutAttributeTag : Error while retrieving value from bean '"
415                     + beanName
416                     + "' with property '"
417                     + beanProperty
418                     + "' in scope '"
419                     + beanScope
420                     + "'. (exception : "
421                     + ex.getMessage(), ex);
422         }
423     }
424 
425     /***
426      * Do start tag.
427      */
428     public int doStartTag() throws JspException {
429 
430         // clear body content
431         body = null;
432 
433         // Do we need to evaluate body ?
434         if (value == null && beanName == null) {
435             return EVAL_BODY_TAG;
436         }
437 
438         // Value is set, don't evaluate body.
439         return SKIP_BODY;
440     }
441 
442     /***
443      * Save the body content of this tag (if any)
444      *
445      * @exception JspException if a JSP exception has occurred
446      */
447     public int doAfterBody() throws JspException {
448 
449         if (bodyContent != null) {
450             body = bodyContent.getString();
451         }
452         return (SKIP_BODY);
453 
454     }
455 
456     /***
457      * Do end tag.
458      */
459     public int doEndTag() throws JspException {
460         // Call parent tag which in turn does what it want
461         callParent();
462 
463         // clean up tag handler for reuse.
464         releaseInternal();
465 
466         return EVAL_PAGE;
467     }
468 
469     /***
470      * Find parent tag which must implement AttributeContainer.
471      * @throws JspException If we can't find an appropriate enclosing tag.
472      */
473     protected void callParent() throws JspException {
474         // Get enclosing parent
475         PutTagParent enclosingParent = findEnclosingPutTagParent();
476         enclosingParent.processNestedTag(this);
477     }
478 
479     /***
480      * Find parent tag which must implement AttributeContainer.
481      * @throws JspException If we can't find an appropriate enclosing tag.
482      */
483     protected PutTagParent findEnclosingPutTagParent() throws JspException {
484         try {
485             PutTagParent parent =
486                 (PutTagParent) findAncestorWithClass(this, PutTagParent.class);
487 
488             if (parent == null) {
489                 throw new JspException("Error - tag put : enclosing tag doesn't accept 'put' tag.");
490             }
491 
492             return parent;
493 
494         } catch (ClassCastException ex) {
495             throw new JspException("Error - tag put : enclosing tag doesn't accept 'put' tag.", ex);
496         }
497     }
498 
499 }