After hitting my head against the wall that is PageContext.pushBody() 
and it's near-uselessness, I have finally hacked my Tomcat 4.0.1 and 
added one measly method to the servlet API.

And boy is my life getting better fast.

The issues are twofold:

1) pushBody() makes a BodyContent for you, pushes it, and returns it. 
This does nothing for folks who want to put some other sort of Writer in 
place, like say a PipedJspWriter to be fed from an XSLT Thread, or whatever.

2) even if pushBody() did what you want, it's pointless to invoke it 
from a Tag, since the JSP compiler won't set the "out" variable used to 
send static content etc.

So I have humbly - humbly! - added pushWriter(JspWriter) to the API and 
altered tomcat's TagBeginGenerator and TagEndGenerator to say

        out = pageContext.getOut()

when a BodyTag *doesn't* return EVAL_BODY_BUFFERED, and voila I finally 
have what I've been needing all this time. Now I can stream between Tags 
and take another, more general, and simpler crack at taglibs/io. And 
static HTML content just works, and Tags don't have to conspire with 
each other or mess with global state. And more, but that's for another post.

I don't know the JSP standards process, but I'm hoping whoever is in 
charge will take this modification and the reasoning behind it under 
serious consideration.

The attached patches are against jakarta-servletapi-4 as downloaded from 
the current CVS, and for jakarta-tomcat-4.0.1-src (the CVS for 
tomcat-4.0 seems to be older, and I didn't find a more current one).

Oh, the tomcat patch also includes a fix for TagCache that is more 
definite about finding setters for Tag attributes. So you can use 
"class=" now and get more predictable behavior for attributes in 
general. Apologies for mixing them.
diff -c -r jakarta-servletapi-4-orig/src/share/javax/servlet/jsp/PageContext.java 
jakarta-servletapi-4/src/share/javax/servlet/jsp/PageContext.java
*** jakarta-servletapi-4-orig/src/share/javax/servlet/jsp/PageContext.java      Fri 
Jul 13 16:57:18 2001
--- jakarta-servletapi-4/src/share/javax/servlet/jsp/PageContext.java   Sat Feb  2 
13:25:29 2002
***************
*** 109,115 ****
   *
   * <p>
   * The following methods enable the <B>management of nested</B> JspWriter streams to
!  * implement Tag Extensions: <code>pushBody()</code> and <code>popBody()</code>
   *
   * <p><B>Methods Intended for JSP authors</B>
   * <p>
--- 109,115 ----
   *
   * <p>
   * The following methods enable the <B>management of nested</B> JspWriter streams to
!  * implement Tag Extensions: <code>pushBody()</code>, <code>pushWriter()</code>, and 
<code>popBody()</code>
   *
   * <p><B>Methods Intended for JSP authors</B>
   * <p>
***************
*** 577,584 ****
           
  
      /**
       * Return the previous JspWriter "out" saved by the matching
!      * pushBody(), and update the value of the "out" attribute in
       * the page scope attribute namespace of the PageConxtext
       *
       * @return the saved JspWriter.
--- 577,596 ----
           
  
      /**
+      * Push a given JspWriter, save the current "out" JspWriter,
+      * and update the value of the "out" attribute in the page scope
+      * attribute namespace of the PageContext
+      *
+      * @param w the jspwriter to use
+      */
+ 
+     public void pushWriter(JspWriter w) {
+     }
+          
+ 
+     /**
       * Return the previous JspWriter "out" saved by the matching
!      * pushBody() or pushWriter(), and update the value of the "out" attribute in
       * the page scope attribute namespace of the PageConxtext
       *
       * @return the saved JspWriter.
diff -c -r 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/compiler/TagBeginGenerator.java
 
jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/compiler/TagBeginGenerator.java
*** 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/compiler/TagBeginGenerator.java
        Mon Nov 12 18:02:50 2001
--- 
jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/compiler/TagBeginGenerator.java
     Fri Feb  1 18:31:53 2002
***************
*** 377,382 ****
--- 377,388 ----
                writer.popIndent();
                writer.println("}");
  
+             // a Tag might have pushed something
+               writer.println("else");
+               writer.pushIndent();
+               writer.println("out = pageContext.getOut();");
+               writer.popIndent();
+ 
                writer.println(thVarName+".doInitBody();");
            }
  
diff -c -r 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/compiler/TagCache.java 
jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/compiler/TagCache.java
*** 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/compiler/TagCache.java 
Mon Nov 12 18:02:50 2001
--- jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/compiler/TagCache.java     
 Fri Feb  1 18:32:33 2002
***************
*** 109,114 ****
--- 109,118 ----
          return (Class) propertyEditorMaps.get(attrName);
      }
  
+     String setCap(String s) {
+         return "set" + Character.toUpperCase(s.charAt(0)) + s.substring(1);
+     }
+ 
      void setTagHandlerClass(Class tagHandlerClass) 
          throws JasperException
      {
***************
*** 121,129 ****
                  /* 
                     FIXME: should probably be checking for things like
                            pageContext, bodyContent, and parent here -akv
-                 */
                  if (pd[i].getWriteMethod() != null)
                      addSetterMethod(pd[i].getName(), pd[i].getWriteMethod());
                  if (pd[i].getPropertyEditorClass() != null)
                      addPropertyEditor(pd[i].getName(), 
pd[i].getPropertyEditorClass());
              }
--- 125,140 ----
                  /* 
                     FIXME: should probably be checking for things like
                            pageContext, bodyContent, and parent here -akv
                  if (pd[i].getWriteMethod() != null)
                      addSetterMethod(pd[i].getName(), pd[i].getWriteMethod());
+ 
+                  * the right way - check for setters directly, ignore non-setters 
+-bnl
+                  */
+                 try {
+                     Method m = tagHandlerClass.getMethod(setCap(pd[i].getName()), 
+new Class[] {String.class});
+                     addSetterMethod(pd[i].getName(), m);
+                 }
+                 catch (NoSuchMethodException e) {}
                  if (pd[i].getPropertyEditorClass() != null)
                      addPropertyEditor(pd[i].getName(), 
pd[i].getPropertyEditorClass());
              }
diff -c -r 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/compiler/TagEndGenerator.java
 jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/compiler/TagEndGenerator.java
*** 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/compiler/TagEndGenerator.java
  Mon Nov 12 18:02:50 2001
--- 
jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/compiler/TagEndGenerator.java  
     Fri Feb  1 18:31:05 2002
***************
*** 167,172 ****
--- 167,173 ----
        writer.pushIndent(); writer.println("return;"); writer.popIndent();
  
        writer.popIndent(); // try
+     writer.println("out = pageContext.getOut();"); // doEndTag might have popped
  
          /** FIXME: REMOVE BEGIN */
          //          writer.println("} catch (Throwable t) {");
diff -c -r 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java
 jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java
*** 
jakarta-tomcat-4.0.1-orig/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java
   Mon Nov 12 18:02:50 2001
--- 
jakarta-tomcat-4.0.1/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java   
     Fri Feb  1 18:09:00 2002
***************
*** 422,427 ****
--- 422,432 ----
          return (BodyContent) out;
      }
  
+     public void pushWriter(JspWriter w) {
+         writerStack.push(out);
+         out = w;
+     }
+ 
      public JspWriter popBody() {
          out = (JspWriter) writerStack.pop();
          return out;

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to