View Javadoc

1   /*
2    * $Id: InsertTag.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.io.IOException;
25  import java.io.PrintWriter;
26  import java.util.Map;
27  import java.util.StringTokenizer;
28  
29  import javax.servlet.ServletException;
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  import javax.servlet.jsp.JspException;
33  import javax.servlet.jsp.PageContext;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.struts.Globals;
38  import org.apache.struts.tiles.taglib.util.TagUtils;
39  import org.apache.struts.tiles.AttributeDefinition;
40  import org.apache.struts.tiles.ComponentContext;
41  import org.apache.struts.tiles.ComponentDefinition;
42  import org.apache.struts.tiles.Controller;
43  import org.apache.struts.tiles.DefinitionAttribute;
44  import org.apache.struts.tiles.DefinitionNameAttribute;
45  import org.apache.struts.tiles.DefinitionsFactoryException;
46  import org.apache.struts.tiles.DirectStringAttribute;
47  import org.apache.struts.tiles.FactoryNotFoundException;
48  import org.apache.struts.tiles.NoSuchDefinitionException;
49  import org.apache.struts.tiles.TilesUtil;
50  
51  /**
52   * This is the tag handler for <tiles:insert>, which includes
53   * a template. The tag's body content consists of <tiles:put>
54   * tags, which are accessed by <tiles:get> in the template.
55   *
56   * @version $Rev: 471754 $ $Date: 2006-11-06 08:55:09 -0600 (Mon, 06 Nov 2006) $
57   */
58  public class InsertTag
59      extends DefinitionTagSupport
60      implements PutTagParent, ComponentConstants, PutListTagParent {
61  
62      /**
63       * The role delimiter.
64       * @deprecated This will be removed in a release after Struts 1.2.
65       */
66      public static final String ROLE_DELIMITER = ",";
67  
68      /**
69       * Commons Logging instance.
70       */
71      protected static Log log = LogFactory.getLog(InsertTag.class);
72  
73      /* JSP Tag attributes */
74  
75      /**
76       * Flush attribute value.
77       */
78      protected boolean flush = true;
79  
80      /**
81       * Name to insert.
82       */
83      protected String name = null;
84  
85      /**
86       * Name of attribute from which to read page name to include.
87       */
88      protected String attribute = null;
89  
90      /**
91       * Name of bean used as entity to include.
92       */
93      protected String beanName = null;
94  
95      /**
96       * Name of bean property, if any.
97       */
98      protected String beanProperty = null;
99  
100     /**
101      * Scope of bean, if any.
102      */
103     protected String beanScope = null;
104 
105     /**
106      * Are errors ignored. This is the property for attribute 'ignore'.
107      * Default value is false, which throw an exception.
108      * Only 'attribute not found' errors are ignored.
109      */
110     protected boolean isErrorIgnored = false;
111 
112     /**
113      * Name of component instance to include.
114      */
115     protected String definitionName = null;
116 
117     /* Internal properties */
118     /**
119      * Does the end tag need to be processed.
120      * Default value is true. Boolean set in case of ignored errors.
121      */
122     protected boolean processEndTag = true;
123 
124     /**
125      * Current component context.
126      */
127     protected ComponentContext cachedCurrentContext;
128 
129     /**
130      * Final handler of tag methods.
131      */
132     protected TagHandler tagHandler = null;
133 
134     /**
135      * Trick to allows inner classes to access pageContext.
136      */
137     protected PageContext pageContext = null;
138 
139     /**
140      * Reset member values for reuse. This method calls super.release(),
141      * which invokes TagSupport.release(), which typically does nothing.
142      */
143     public void release() {
144 
145         super.release();
146         attribute = null;
147         beanName = null;
148         beanProperty = null;
149         beanScope = null;
150 
151         definitionName = null;
152         flush = true;
153         name = null;
154         page = null;
155         role = null;
156         isErrorIgnored = false;
157 
158         releaseInternal();
159     }
160 
161     /**
162      * Reset internal member values for reuse.
163      */
164     protected void releaseInternal() {
165         cachedCurrentContext = null;
166         processEndTag = true;
167         // pageContext = null;  // orion doesn't set it between two tags
168         tagHandler = null;
169     }
170 
171     /**
172      * Set the current page context.
173      * Called by the page implementation prior to doStartTag().
174      * <p>
175      * Needed to allow inner classes to access pageContext.
176      */
177     public void setPageContext(PageContext pc) {
178         this.pageContext = pc;
179         super.setPageContext(pc);
180     }
181 
182     /**
183      * Get the pageContext property.
184      */
185     public PageContext getPageContext() {
186         return pageContext;
187     }
188 
189     /**
190      * Set name.
191      */
192     public void setName(String value) {
193         this.name = value;
194     }
195 
196     /**
197      * Get name.
198      */
199     public String getName() {
200         return name;
201     }
202 
203     /**
204      * Set component.
205      */
206     public void setComponent(String name) {
207         this.page = name;
208     }
209 
210     /**
211      * Set definition.
212      */
213     public void setDefinition(String name) {
214         this.definitionName = name;
215     }
216 
217     /**
218      * Get definition name.
219      */
220     public String getDefinitionName() {
221         return definitionName;
222     }
223 
224     /**
225      * Set attribute.
226      */
227     public void setAttribute(String value) {
228         this.attribute = value;
229     }
230 
231     /**
232      * Set bean name.
233      */
234     public void setBeanName(String value) {
235         this.beanName = value;
236     }
237 
238     /**
239      * Get bean name.
240      */
241     public String getBeanName() {
242         return beanName;
243     }
244 
245     /**
246      * Set bean property.
247      */
248     public void setBeanProperty(String value) {
249         this.beanProperty = value;
250     }
251 
252     /**
253      * Get bean property.
254      */
255     public String getBeanProperty() {
256         return beanProperty;
257     }
258 
259     /**
260      * Set bean scope.
261      */
262     public void setBeanScope(String value) {
263         this.beanScope = value;
264     }
265 
266     /**
267      * Get bean scope.
268      */
269     public String getBeanScope() {
270         return beanScope;
271     }
272 
273     /**
274      * Set flush.
275      */
276     public void setFlush(boolean flush) {
277         this.flush = flush;
278     }
279 
280     /**
281      * Get flush.
282      */
283     public boolean getFlush() {
284         return flush;
285     }
286 
287     /**
288      * Set flush.
289      * Method added for compatibility with JSP1.1
290      */
291     public void setFlush(String flush) {
292         this.flush = (Boolean.valueOf(flush).booleanValue());
293     }
294 
295     /**
296      * Set ignore.
297      */
298     public void setIgnore(boolean ignore) {
299         this.isErrorIgnored = ignore;
300     }
301 
302     /**
303      * Get ignore.
304      */
305     public boolean getIgnore() {
306         return isErrorIgnored;
307     }
308 
309     /////////////////////////////////////////////////////////////////////////
310 
311     /**
312      * Add a body attribute.
313      * Erase any attribute with same name previously set.
314      */
315     public void putAttribute(String name, Object value) {
316         tagHandler.putAttribute(name, value);
317     }
318 
319     /**
320      * Process nested &lg;put&gt; tag.
321      * Method calls by nested &lg;put&gt; tags.
322      * Nested list is added to current list.
323      * If role is defined, it is checked immediately.
324      */
325     public void processNestedTag(PutTag nestedTag) throws JspException {
326         // Check role
327         HttpServletRequest request =
328             (HttpServletRequest) pageContext.getRequest();
329         String role = nestedTag.getRole();
330         if (role != null && !request.isUserInRole(role)) {
331             // not allowed : skip attribute
332             return;
333         }
334 
335         putAttribute(nestedTag.getName(), nestedTag.getRealValue());
336     }
337 
338     /**
339      * Process nested &lg;putList&gt; tag.
340      * Method calls by nested &lg;putList&gt; tags.
341      * Nested list is added to sub-component attributes
342      * If role is defined, it is checked immediately.
343      */
344     public void processNestedTag(PutListTag nestedTag) throws JspException {
345         // Check role
346         HttpServletRequest request =
347             (HttpServletRequest) pageContext.getRequest();
348         String role = nestedTag.getRole();
349         if (role != null && !request.isUserInRole(role)) {
350             // not allowed : skip attribute
351             return;
352         }
353 
354         // Check if a name is defined
355         if (nestedTag.getName() == null) {
356             throw new JspException("Error - PutList : attribute name is not defined. It is mandatory as the list is added as attribute of 'insert'.");
357         }
358 
359         // now add attribute to enclosing parent (i.e. : this object).
360         putAttribute(nestedTag.getName(), nestedTag.getList());
361     }
362 
363     /**
364      * Method calls by nested &lg;putList&gt; tags.
365      * A new list is added to current insert object.
366      */
367     public void putAttribute(PutListTag nestedTag) throws JspException {
368         // Check role
369         HttpServletRequest request =
370             (HttpServletRequest) pageContext.getRequest();
371         String role = nestedTag.getRole();
372         if (role != null && !request.isUserInRole(role)) {
373             // not allowed : skip attribute
374             return;
375         }
376 
377         putAttribute(nestedTag.getName(), nestedTag.getList());
378     }
379 
380     /**
381      * Get current component context.
382      */
383     private ComponentContext getCurrentContext() {
384         if (cachedCurrentContext == null) {
385             cachedCurrentContext =
386                 (ComponentContext) pageContext.getAttribute(
387                     ComponentConstants.COMPONENT_CONTEXT,
388                     PageContext.REQUEST_SCOPE);
389         }
390 
391         return cachedCurrentContext;
392     }
393 
394     /**
395      * Get instantiated Controller.
396      * Return controller denoted by controllerType, or <code>null</code> if controllerType
397      * is null.
398      * @throws JspException If controller can't be created.
399      */
400     private Controller getController() throws JspException {
401         if (controllerType == null) {
402             return null;
403         }
404 
405         try {
406             return ComponentDefinition.createController(
407                 controllerName,
408                 controllerType);
409 
410         } catch (InstantiationException ex) {
411             throw new JspException(ex);
412         }
413     }
414 
415     /**
416      * Process the start tag by checking tag's attributes and creating appropriate handler.
417      * Possible handlers :
418      * <ul>
419      * <li> URL
420      * <li> definition
421      * <li> direct String
422      * </ul>
423      * Handlers also contain sub-component context.
424      */
425     public int doStartTag() throws JspException {
426 
427             // Additional fix for Bug 20034 (2005-04-28)
428             cachedCurrentContext = null;
429 
430         // Check role immediatly to avoid useless stuff.
431         // In case of insertion of a "definition", definition's role still checked later.
432         // This lead to a double check of "role" ;-(
433         HttpServletRequest request =
434             (HttpServletRequest) pageContext.getRequest();
435         if (role != null && !request.isUserInRole(role)) {
436             processEndTag = false;
437             return SKIP_BODY;
438         }
439 
440         try {
441             tagHandler = createTagHandler();
442 
443         } catch (JspException e) {
444             if (isErrorIgnored) {
445                 processEndTag = false;
446                 return SKIP_BODY;
447             } else {
448                 throw e;
449             }
450         }
451 
452         return tagHandler.doStartTag();
453     }
454 
455     /**
456      * Process the end tag by including the template.
457      * Simply call the handler doEndTag
458      */
459     public int doEndTag() throws JspException {
460         if (!processEndTag) {
461             releaseInternal();
462             return EVAL_PAGE;
463         }
464 
465         int res = tagHandler.doEndTag();
466         // Reset properties used by object, in order to be able to reuse object.
467         releaseInternal();
468         return res;
469     }
470 
471     /**
472      * Process tag attribute and create corresponding tag handler.
473      */
474     public TagHandler createTagHandler() throws JspException {
475         // Check each tag attribute.
476         // page Url attribute must be the last checked  because it can appears concurrently
477         // with others attributes.
478         if (definitionName != null) {
479             return processDefinitionName(definitionName);
480         } else if (attribute != null) {
481             return processAttribute(attribute);
482         } else if (beanName != null) {
483             return processBean(beanName, beanProperty, beanScope);
484         } else if (name != null) {
485             return processName(name);
486         } else if (page != null) {
487             return processUrl(page);
488         } else {
489             throw new JspException("Error - Tag Insert : At least one of the following attribute must be defined : template|page|attribute|definition|name|beanName. Check tag syntax");
490         }
491     }
492 
493     /**
494      * Process an object retrieved as a bean or attribute.
495      * Object can be a typed attribute, a String, or anything else.
496      * If typed attribute, use associated type.
497      * Otherwise, apply toString() on object, and use returned string as a name.
498      * @throws JspException - Throws by underlying nested call to
499      * processDefinitionName()
500      */
501     public TagHandler processObjectValue(Object value) throws JspException {
502         // First, check if value is one of the Typed Attribute
503         if (value instanceof AttributeDefinition) {
504             // We have a type => return appropriate IncludeType
505             return processTypedAttribute((AttributeDefinition) value);
506 
507         } else if (value instanceof ComponentDefinition) {
508             return processDefinition((ComponentDefinition) value);
509         }
510 
511         // Value must denote a valid String
512         return processAsDefinitionOrURL(value.toString());
513     }
514 
515     /**
516      * Process name.
517      * Search in following order :
518      * <ul>
519      * <li>Component context -  if found, process it as value.</li>
520      * <li>definitions factory</li>
521      * <li>URL</li>
522      * <li></li>
523      * </ul>
524      *
525      * @return appropriate tag handler.
526      * @throws JspException - Throws by underlying nested call to
527      * processDefinitionName()
528      */
529     public TagHandler processName(String name) throws JspException {
530         Object attrValue = getCurrentContext().getAttribute(name);
531 
532         if (attrValue != null) {
533             return processObjectValue(attrValue);
534         }
535 
536         return processAsDefinitionOrURL(name);
537     }
538 
539     /**
540      * Process the url.
541      * @throws JspException If failed to create controller
542      */
543     public TagHandler processUrl(String url) throws JspException {
544         return new InsertHandler(url, role, getController());
545     }
546 
547     /**
548      * Process tag attribute "definition".
549      * First, search definition in the factory, then create handler from this definition.
550      * @param name Name of the definition.
551      * @return Appropriate TagHandler.
552      * @throws JspException- NoSuchDefinitionException No Definition  found for name.
553      * @throws JspException- FactoryNotFoundException Can't find Definitions factory.
554      * @throws JspException- DefinedComponentFactoryException General error in factory.
555      * @throws JspException InstantiationException Can't create requested controller
556      */
557     protected TagHandler processDefinitionName(String name)
558         throws JspException {
559 
560         try {
561             ComponentDefinition definition =
562                 TilesUtil.getDefinition(
563                     name,
564                     (HttpServletRequest) pageContext.getRequest(),
565                     pageContext.getServletContext());
566 
567             if (definition == null) { // is it possible ?
568                 throw new NoSuchDefinitionException();
569             }
570 
571             return processDefinition(definition);
572 
573         } catch (NoSuchDefinitionException ex) {
574             throw new JspException(
575                 "Error -  Tag Insert : Can't get definition '"
576                     + definitionName
577                     + "'. Check if this name exist in definitions factory.", ex);
578 
579         } catch (FactoryNotFoundException ex) {
580             throw new JspException(ex.getMessage());
581 
582         } catch (DefinitionsFactoryException ex) {
583             if (log.isDebugEnabled()) {
584                 ex.printStackTrace();
585             }
586 
587             // Save exception to be able to show it later
588             pageContext.setAttribute(
589                 Globals.EXCEPTION_KEY,
590                 ex,
591                 PageContext.REQUEST_SCOPE);
592             throw new JspException(ex);
593         }
594     }
595 
596     /**
597      * End of Process tag attribute "definition".
598      * Overload definition with tag attributes "template" and "role".
599      * Then, create appropriate tag handler.
600      * @param definition Definition to process.
601      * @return Appropriate TagHandler.
602      * @throws JspException InstantiationException Can't create requested controller
603      */
604     protected TagHandler processDefinition(ComponentDefinition definition)
605         throws JspException {
606         // Declare local variable in order to not change Tag attribute values.
607         String role = this.role;
608         String page = this.page;
609         Controller controller = null;
610 
611         try {
612             controller = definition.getOrCreateController();
613 
614             // Overload definition with tag's template and role.
615             if (role == null) {
616                 role = definition.getRole();
617             }
618 
619             if (page == null) {
620                 page = definition.getTemplate();
621             }
622 
623             if (controllerName != null) {
624                 controller =
625                     ComponentDefinition.createController(
626                         controllerName,
627                         controllerType);
628             }
629 
630             // Can check if page is set
631             return new InsertHandler(
632                 definition.getAttributes(),
633                 page,
634                 role,
635                 controller);
636 
637         } catch (InstantiationException ex) {
638             throw new JspException(ex);
639         }
640     }
641 
642     /**
643      * Process a bean.
644      * Get bean value, eventually using property and scope. Found value is process by processObjectValue().
645      * @param beanName Name of the bean
646      * @param beanProperty Property in the bean, or null.
647      * @param beanScope bean scope, or null.
648      * @return Appropriate TagHandler.
649      * @throws JspException - NoSuchDefinitionException No value associated to bean.
650      * @throws JspException an error occur while reading bean, or no definition found.
651      * @throws JspException - Throws by underlying nested call to processDefinitionName()
652      */
653     protected TagHandler processBean(
654         String beanName,
655         String beanProperty,
656         String beanScope)
657         throws JspException {
658 
659         Object beanValue =
660             TagUtils.getRealValueFromBean(
661                 beanName,
662                 beanProperty,
663                 beanScope,
664                 pageContext);
665 
666         if (beanValue == null) {
667             throw new JspException(
668                 "Error - Tag Insert : No value defined for bean '"
669                     + beanName
670                     + "' with property '"
671                     + beanProperty
672                     + "' in scope '"
673                     + beanScope
674                     + "'.");
675         }
676 
677         return processObjectValue(beanValue);
678     }
679 
680     /**
681      * Process tag attribute "attribute".
682      * Get value from component attribute.
683      * Found value is process by processObjectValue().
684      * @param name Name of the attribute.
685      * @return Appropriate TagHandler.
686      * @throws JspException - NoSuchDefinitionException No Definition  found for name.
687      * @throws JspException - Throws by underlying nested call to processDefinitionName()
688      */
689     public TagHandler processAttribute(String name) throws JspException {
690         Object attrValue = getCurrentContext().getAttribute(name);
691 
692         if (attrValue == null) {
693             throw new JspException(
694                 "Error - Tag Insert : No value found for attribute '"
695                     + name
696                     + "'.");
697         }
698 
699         return processObjectValue(attrValue);
700     }
701 
702     /**
703      * Try to process name as a definition, or as an URL if not found.
704      * @param name Name to process.
705      * @return appropriate TagHandler
706      * @throws JspException InstantiationException Can't create requested controller
707      */
708     public TagHandler processAsDefinitionOrURL(String name)
709         throws JspException {
710         try {
711             ComponentDefinition definition =
712                 TilesUtil.getDefinition(
713                     name,
714                     pageContext.getRequest(),
715                     pageContext.getServletContext());
716 
717             if (definition != null) {
718                 return processDefinition(definition);
719             }
720 
721         } catch (DefinitionsFactoryException ex) {
722             // silently failed, because we can choose to not define a factory.
723         }
724 
725         // no definition found, try as url
726         return processUrl(name);
727     }
728 
729     /**
730      * Process typed attribute according to its type.
731      * @param value Typed attribute to process.
732      * @return appropriate TagHandler.
733      * @throws JspException - Throws by underlying nested call to processDefinitionName()
734      */
735     public TagHandler processTypedAttribute(AttributeDefinition value)
736         throws JspException {
737         if (value instanceof DirectStringAttribute) {
738             return new DirectStringHandler((String) value.getValue());
739 
740         } else if (value instanceof DefinitionAttribute) {
741             return processDefinition((ComponentDefinition) value.getValue());
742 
743         } else if (value instanceof DefinitionNameAttribute) {
744             return processDefinitionName((String) value.getValue());
745         }
746 
747         return new InsertHandler(
748             (String) value.getValue(),
749             role,
750             getController());
751     }
752 
753     /**
754      * Do an include of specified page.
755      * This method is used internally to do all includes from this class. It delegates
756      * the include call to the TilesUtil.doInclude().
757      * @param page The page that will be included
758      * @param flush If the writer should be flushed before the include
759      * @throws ServletException - Thrown by call to pageContext.include()
760      * @throws IOException - Thrown by call to pageContext.include()
761      */
762     protected void doInclude(String page, boolean flush)
763         throws ServletException, IOException {
764         TilesUtil.doInclude(page, pageContext, flush);
765     }
766 
767     /////////////////////////////////////////////////////////////////////////////
768 
769     /**
770      * Inner Interface.
771      * Sub handler for tag.
772      */
773     protected interface TagHandler {
774         /**
775          * Create ComponentContext for type depicted by implementation class.
776          */
777         public int doStartTag() throws JspException;
778         /**
779          * Do include for type depicted by implementation class.
780          */
781         public int doEndTag() throws JspException;
782         /**
783          * Add a component parameter (attribute) to subContext.
784          */
785         public void putAttribute(String name, Object value);
786     } // end inner interface
787 
788     /////////////////////////////////////////////////////////////////////////////
789 
790     /**
791      * Real handler, after attribute resolution.
792      * Handle include sub-component.
793      */
794     protected class InsertHandler implements TagHandler {
795         protected String page;
796         protected ComponentContext currentContext;
797         protected ComponentContext subCompContext;
798         protected String role;
799         protected Controller controller;
800 
801         /**
802          * Constructor.
803          * Create insert handler using Component definition.
804          */
805         public InsertHandler(
806             Map attributes,
807             String page,
808             String role,
809             Controller controller) {
810 
811             this.page = page;
812             this.role = role;
813             this.controller = controller;
814             subCompContext = new ComponentContext(attributes);
815         }
816 
817         /**
818          * Constructor.
819          * Create insert handler to insert page at specified location.
820          */
821         public InsertHandler(String page, String role, Controller controller) {
822             this.page = page;
823             this.role = role;
824             this.controller = controller;
825             subCompContext = new ComponentContext();
826         }
827 
828         /**
829          * Create a new empty context.
830          */
831         public int doStartTag() throws JspException {
832             // Check role
833             HttpServletRequest request =
834                 (HttpServletRequest) pageContext.getRequest();
835 
836             if (role != null && !request.isUserInRole(role)) {
837                 return SKIP_BODY;
838             }
839 
840             // save current context
841             this.currentContext = getCurrentContext();
842             return EVAL_BODY_INCLUDE;
843         }
844 
845         /**
846          * Add attribute to sub context.
847          * Do nothing.
848          */
849         public void putAttribute(String name, Object value) {
850             subCompContext.putAttribute(name, value);
851         }
852 
853         /**
854          * Include requested page.
855          */
856         public int doEndTag() throws JspException {
857             // Check role
858             HttpServletRequest request =
859                 (HttpServletRequest) pageContext.getRequest();
860 
861             if (role != null && !request.isUserInRole(role)) {
862                 return EVAL_PAGE;
863             }
864 
865             try {
866                 if (log.isDebugEnabled()) {
867                     log.debug("insert page='" + page + "'.");
868                 }
869 
870                 // set new context for included component.
871                 pageContext.setAttribute(
872                     ComponentConstants.COMPONENT_CONTEXT,
873                     subCompContext,
874                     PageContext.REQUEST_SCOPE);
875 
876                 // Call controller if any
877                 if (controller != null) {
878                     try {
879                         controller.execute(
880                             subCompContext,
881                             (HttpServletRequest) pageContext.getRequest(),
882                             (HttpServletResponse) pageContext.getResponse(),
883                             pageContext.getServletContext());
884 
885                     } catch (Exception e) {
886                         throw new ServletException(e);
887                     }
888 
889                 }
890 
891                 // include requested component.
892                 if (flush) {
893                     pageContext.getOut().flush();
894                 }
895 
896                 doInclude(page, flush);
897 
898             } catch (IOException e) {
899                 String msg =
900                     "Can't insert page '" + page + "' : " + e.getMessage();
901                 log.error(msg, e);
902                 throw new JspException(msg);
903 
904             } catch (IllegalArgumentException e) {
905                 // Can't resolve page uri, should we ignore it?
906                 if (!(page == null && isErrorIgnored)) {
907                     String msg =
908                         "Can't insert page '"
909                             + page
910                             + "'. Check if it exists.\n"
911                             + e.getMessage();
912 
913                     log.error(msg, e);
914                     throw new JspException(msg,e);
915                 }
916 
917             } catch (ServletException e) {
918                 Throwable cause = e;
919                 if (e.getRootCause() != null) {
920                     cause = e.getRootCause();
921                 }
922 
923                 String msg =
924                     "ServletException in '" + page + "': " + cause.getMessage();
925 
926                 log.error(msg, e);
927                 throw new JspException(msg,e);
928 
929             } finally {
930                 // restore old context only if currentContext not null
931                 // (bug with Silverstream ?; related by Arvindra Sehmi 20010712)
932                 if (currentContext != null) {
933                     pageContext.setAttribute(
934                         ComponentConstants.COMPONENT_CONTEXT,
935                         currentContext,
936                         PageContext.REQUEST_SCOPE);
937                 }
938             }
939 
940             return EVAL_PAGE;
941         }
942 
943         /**
944          * Process an exception.
945          * Depending of debug attribute, print full exception trace or only
946          * its message in output page.
947          * @param ex Exception
948          * @param msg An additional message to show in console and to propagate if we can't output exception.
949          * @deprecated This method will be removed in a release after Struts 1.2.
950          */
951         protected void processException(Throwable ex, String msg)
952             throws JspException {
953 
954             try {
955                 if (msg == null) {
956                     msg = ex.getMessage();
957                 }
958 
959                 if (log.isDebugEnabled()) { // show full trace
960                     log.debug(msg, ex);
961                     pageContext.getOut().println(msg);
962                     ex.printStackTrace(
963                         new PrintWriter(pageContext.getOut(), true));
964                 } else { // show only message
965                     pageContext.getOut().println(msg);
966                 }
967 
968             } catch (IOException ioex) { // problems. Propagate original exception
969                 pageContext.setAttribute(
970                     ComponentConstants.EXCEPTION_KEY,
971                     ex,
972                     PageContext.REQUEST_SCOPE);
973                 throw new JspException(msg,ioex);
974             }
975         }
976     }
977 
978     /**
979      * Parse the list of roles and return <code>true</code> or <code>false</code> based on whether
980      * the user has that role or not.
981      * @param role Comma-delimited list of roles.
982      * @param request The request.
983      */
984     static public boolean userHasRole(
985         HttpServletRequest request,
986         String role) {
987         StringTokenizer st = new StringTokenizer(role, ",");
988         while (st.hasMoreTokens()) {
989             if (request.isUserInRole(st.nextToken())) {
990                 return true;
991             }
992         }
993 
994         return false;
995     }
996 
997     /////////////////////////////////////////////////////////////////////////////
998 
999     /**
1000      * Handle insert direct string.
1001      */
1002     protected class DirectStringHandler implements TagHandler {
1003         /** Object to print as a direct string */
1004         private Object value;
1005 
1006         /**
1007          * Constructor.
1008          */
1009         public DirectStringHandler(Object value) {
1010             this.value = value;
1011         }
1012 
1013         /**
1014          * Do nothing, there is no context for a direct string.
1015          */
1016         public int doStartTag() throws JspException {
1017             return SKIP_BODY;
1018         }
1019 
1020         /**
1021          * Add attribute to sub context.
1022          * Do nothing.
1023          */
1024         public void putAttribute(String name, Object value) {
1025         }
1026 
1027         /**
1028          * Print String in page output stream.
1029          */
1030         public int doEndTag() throws JspException {
1031             try {
1032                 if (flush) {
1033                     pageContext.getOut().flush();
1034                 }
1035 
1036                 pageContext.getOut().print(value);
1037 
1038             } catch (IOException ex) {
1039                 if (log.isDebugEnabled()) {
1040                     log.debug("Can't write string '" + value + "' : ", ex);
1041                 }
1042 
1043                 pageContext.setAttribute(
1044                     ComponentConstants.EXCEPTION_KEY,
1045                     ex,
1046                     PageContext.REQUEST_SCOPE);
1047 
1048                 throw new JspException(
1049                     "Can't write string '" + value + "' : " + ex.getMessage(), ex);
1050             }
1051 
1052             return EVAL_PAGE;
1053         }
1054     }
1055 }