You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2008/11/04 15:12:39 UTC

svn commit: r711257 - /myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/FlowCallComponentHandler.java

Author: skitching
Date: Tue Nov  4 06:12:38 2008
New Revision: 711257

URL: http://svn.apache.org/viewvc?rev=711257&view=rev
Log:
Prevent text content within the of:flowCall tag from being added as transient child elements to the component.

Modified:
    myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/FlowCallComponentHandler.java

Modified: myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/FlowCallComponentHandler.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/FlowCallComponentHandler.java?rev=711257&r1=711256&r2=711257&view=diff
==============================================================================
--- myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/FlowCallComponentHandler.java (original)
+++ myfaces/orchestra/trunk/flow/src/main/java/org/apache/myfaces/orchestra/flow/components/FlowCallComponentHandler.java Tue Nov  4 06:12:38 2008
@@ -19,8 +19,11 @@
 
 package org.apache.myfaces.orchestra.flow.components;
 
+import java.io.IOException;
 import java.util.Iterator;
 
+import javax.el.ELException;
+import javax.faces.FacesException;
 import javax.faces.component.UIComponent;
 
 import com.sun.facelets.FaceletContext;
@@ -31,9 +34,14 @@
 /**
  * Facelets component-handler which creates a FlowCallComponent instance.
  * <p>
- * Note that a facelets ComponentHandler is invoked only when the component is first created;
- * later re-renders of the same view do not invoke ComponentHandlers for components that 
- * already exist.
+ * Note that a facelets ComponentHandler is a subclass of TagHandler. The methods in TagHandler
+ * are "tag oriented", ie focused on handling a tree of tags. The methods in a ComponentHandler
+ * are "higher level", ie the callbacks are focused on component creation and configuration.
+ * <p>
+ * Facelets first parses the input into a syntax tree (of Facelets Instruction nodes) and caches
+ * it (for later use). It then walks the tree, invoking the appropriate tag or component handler.
+ * Each ComponentHandler has access to the list of nodes nested within it via the "nextHandler"
+ * member.
  */
 public class FlowCallComponentHandler extends ComponentHandler
 {
@@ -43,26 +51,33 @@
     }
 
     /**
-     * When Facelets encounters the start tag for this component, it will create the
-     * component and assign any attributes. It then calls this method.
+     * When Facelets encounters the start tag for this component, it will create the component and assign any
+     * attributes. It then calls this method.
+     * <p>
+     * Here we ask the nodes nested within this element to return their text. Then the nested text is passed
+     * to the new component. This has the same effect as a JSP tag overriding "doAfterBody", but is pull-style
+     * rather than waiting for a callback to occur. Note, however that the body of this element *has* already
+     * been parsed into instruction nodes; there appears to be no way to stop Facelets doing this.
      * <p>
-     * Here we do a kind of "pull parsing" of the input, fetching the nested text. Then
-     * the nested text is passed to the new component. This has the same effect as a
-     * JSP tag overriding "doAfterBody", but is pull-style rather than waiting for a
-     * callback to occur.
+     * Note that even though we process the body text explicitly here, facelets will try to process the nested
+     * Instruction nodes after this method has returned. Therefore the applyNextHandler method is overridden
+     * to prevent that.
      */
     protected void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent)
     {
         StringBuffer content = new StringBuffer();
 
-        // Method findNextByType will repeatedly call the facelets parser ("compiler") to get
-        // "nodes" from the input. If the "handler" for that node is of the specified type then
-        // the handler is returned. I'm not sure what happens for nodes whose handler is not of
-        // the specified type, but in this case we don't expect anything other than Text nodes
-        // nested within an of:flowCall tag.
+        // Method findNextByType will scan the list of child "nodes" for the "StartElementInstruction" node
+        // that triggered the call to this method. We actually expect just one node (of type Instruction)
+        // which implements the TextHandler interface. It will internally have broken down the XML content
+        // of the flowCall element into separate nodes for the xml elements, attributes and body-text.
+        // However we don't need to know that; just calling getText on that top-level child will cause
+        // it to append together the text representations of all the child elements and return the complete
+        // string.
         //
-        // The iterator stops (hasNext is false) when the end-tag for this of:flowCall tag
-        // is encountered.
+        // The loop is just in case there are multiple child Instruction objects for some reason; this is
+        // not expected. The iterator always stops (hasNext is false) when there are no more child nodes
+        // for this flowCall element.
         content.append("<flowCall>\n");
         Iterator iter = findNextByType(TextHandler.class);
         while (iter.hasNext())
@@ -79,4 +94,29 @@
 
         ((FlowCallComponent) c).setBody(content.toString());
     }
+    
+    protected void onComponentPopulated(FaceletContext ctx, UIComponent c, UIComponent parent)
+    {
+        // do nothing
+    }
+
+    protected void applyNextHandler(FaceletContext ctx, UIComponent c) 
+            throws IOException, FacesException, ELException
+    {
+        // Do nothing.
+        //
+        // This method is called by the Facelets framework immediately after onComponentCreated
+        // is called.
+        //
+        // The normal behaviour is to call this.nextHandler.apply(ctx, c) in order to iterate over
+        // the child instructions of this element and process them. But we don't want this as out
+        // onComponentCreated method has already extracted all of the data we wanted. Without
+        // this override, transient text children would be added to component "c".
+        //
+        // It would be better if we could tell Facelets to not create Instruction nodes for the
+        // nested content of this element at all; then it would not be necessary to override
+        // this method as there *would* be no nested Instruction nodes. But I haven't figured
+        // out how to do that. Facelets is of course driven by a normal XML parser that will
+        // always break down the input into SAX events anyway... 
+    }
 }