View Javadoc

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