dev@javaserverfaces.java.net

Retroactive review: ExternalContext / Streamlined PartialTraversal Strategy

From: Roger Kitain <Roger.Kitain_at_Sun.COM>
Date: Fri, 28 Nov 2008 22:37:47 -0500

At the suggestion of the Portlet Bridge team:
  - added setResponseHeader/addResponseHeader to ExternalContext
UIViewRoot: Tie in Partial Traversal *pluggable)
PartialTraversalImpl: fix renderAll

All automated tests run.

SECTION: Modified Files
----------------------------
M jsf-api/src/javax/faces/context/ExternalContext.java
M jsf-api/src/javax/faces/component/UIViewRoot.java
M jsf-ri/test/com/sun/faces/config/StoreServletContext.java
M jsf-ri/src/com/sun/faces/context/ExternalContextImpl.java
M jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java
M jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java
M jsf-ri/src/com/sun/faces/config/InitFacesContext.java
M lib/jsf-extensions-test-time.jar

SECTION: Diffs
----------------------------
Index: jsf-api/src/javax/faces/context/ExternalContext.java
===================================================================
--- jsf-api/src/javax/faces/context/ExternalContext.java (revision 5943)
+++ jsf-api/src/javax/faces/context/ExternalContext.java (working copy)
@@ -1437,5 +1437,28 @@
     public abstract void redirect(String url)
         throws IOException;
 
+ /**
+ * <p class="changed_added_2_0">Set the response header with the given name and value.</p>
+ *
+ * <p><em>Servlet:</em>This must be performed by calling the
+ * <code>javax.servlet.http.HttpServletResponse</code> <code>setHeader</code>
+ * method.</p>
+ *
+ * @param name The name of the response header.
+ * @param value The value of the response header.
+ */
+ public abstract void setResponseHeader(String name, String value);
 
+ /**
+ * <p class="changed_added_2_0">Add the given name and value to the response header.</p>
+ *
+ * <p><em>Servlet:</em>This must be performed by calling the
+ * <code>javax.servlet.http.HttpServletResponse</code> <code>addHeader</code>
+ * method.</p>
+ *
+ * @param name The name of the response header.
+ * @param value The value of the response header.
+ */
+ public abstract void addResponseHeader(String name, String value);
+

Index: jsf-api/src/javax/faces/component/UIViewRoot.java
===================================================================
--- jsf-api/src/javax/faces/component/UIViewRoot.java (revision 5943)
+++ jsf-api/src/javax/faces/component/UIViewRoot.java (working copy)
@@ -947,21 +947,11 @@
         notifyBefore(context, PhaseId.RENDER_RESPONSE);
 
         if (!skipPhase) {
- if (context.getPartialViewContext().isAjaxRequest()) {
- PartialTraversal traversal = context.getApplication().getPartialTraversal();
- if (traversal != null) {
- traversal.traverse(context, PhaseId.RENDER_RESPONSE, this);
- } else {
- if (LOGGER.isLoggable(Level.SEVERE)) {
- LOGGER.log(Level.SEVERE,
- "severe.encodeBegin.traversal_not_defined", "null");
- }
- }
- } else {
+ if (!context.getPartialViewContext().isAjaxRequest()) {
                 super.encodeBegin(context);
- }
             }
- }
+ }
+ }
 
     /**
      * <p class="changed_added_2_0">If {_at_link
@@ -985,12 +975,12 @@
                 if (LOGGER.isLoggable(Level.SEVERE)) {
                     LOGGER.log(Level.SEVERE,
                            "severe.encodeChildren.traversal_not_defined", "null");
- }
+ }
             }
         } else {
- super.encodeChildren(context);
+ super.encodeChildren(context);
+ }
     }
- }
 
     /**
      * <p class="changed_added_2_0">If {_at_link
@@ -1009,17 +999,7 @@
      */
     @Override
     public void encodeEnd(FacesContext context) throws IOException {
- if (context.getPartialViewContext().isAjaxRequest()) {
- PartialTraversal traversal = context.getApplication().getPartialTraversal();
- if (traversal != null) {
- traversal.traverse(context, PhaseId.RENDER_RESPONSE, this);
- } else {
- if (LOGGER.isLoggable(Level.SEVERE)) {
- LOGGER.log(Level.SEVERE,
- "severe.encodeEnd.traversal_not_defined", "null");
- }
- }
- } else {
+ if (!context.getPartialViewContext().isAjaxRequest()) {
             super.encodeEnd(context);
         }
         notifyAfter(context, PhaseId.RENDER_RESPONSE);
@@ -1040,8 +1020,7 @@
         FacesContext context = FacesContext.getCurrentInstance();
 
         PartialViewContext partialViewContext = context.getPartialViewContext();
- if (partialViewContext.isAjaxRequest() &&
- !partialViewContext.isRenderAll()) {
+ if (partialViewContext.isAjaxRequest()) {
             value = true;
         }
         return value;

Index: jsf-ri/test/com/sun/faces/config/StoreServletContext.java
===================================================================
--- jsf-ri/test/com/sun/faces/config/StoreServletContext.java (revision 5943)
+++ jsf-ri/test/com/sun/faces/config/StoreServletContext.java (working copy)
@@ -165,6 +165,12 @@
         public void setResponseCharacterEncoding(String responseCharacterEncoding) {
         }
 
+ public void setResponseHeader(String name, String value) {
+ }
+
+ public void addResponseHeader(String name, String value) {
+ }
+
         public String getRequestContextPath() {
             return null;
         }

Index: jsf-ri/src/com/sun/faces/context/ExternalContextImpl.java
===================================================================
--- jsf-ri/src/com/sun/faces/context/ExternalContextImpl.java (revision 5943)
+++ jsf-ri/src/com/sun/faces/context/ExternalContextImpl.java (working copy)
@@ -719,7 +719,30 @@
         
     }
 
+ /**
+ * @see ExternalContext#setResponseHeader(String, String)
+ * @param name
+ * @param value
+ */
+ @Override
+ public void setResponseHeader(String name, String value) {
 
+ ((HttpServletResponse) response).setHeader(name, value);
+
+ }
+
+ /**
+ * @see ExternalContext#addResponseHeader(String, String)
+ * @param name
+ * @param value
+ */
+ @Override
+ public void addResponseHeader(String name, String value) {
+
+ ((HttpServletResponse) response).addHeader(name, value);
+
+ }
+
     // ----------------------------------------------------------- Inner Classes

Index: jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java
===================================================================
--- jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java (revision 5943)
+++ jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java (working copy)
@@ -76,7 +76,7 @@
     private OnOffResponseWrapper onOffResponse = null;
     private Boolean ajaxRequest;
     private Boolean partialRequest;
- private Boolean renderAll;
+ private Boolean renderAll = null;
 
     // ----------------------------------------------------------- Constructors
 
@@ -170,12 +170,10 @@
     public boolean isRenderAll() {
 
         assertNotReleased();
- if (renderAll == null) {
- String render = FacesContext.getCurrentInstance().
- getExternalContext().getRequestParameterMap()
- .get(PARTIAL_RENDER_PARAM_NAME);
- renderAll = (ALL_PARTIAL_PHASE_CLIENT_IDS.equals(render));
- }
+ String render = FacesContext.getCurrentInstance().
+ getExternalContext().getRequestParameterMap()
+ .get(PARTIAL_RENDER_PARAM_NAME);
+ renderAll = (ALL_PARTIAL_PHASE_CLIENT_IDS.equals(render));
 
         return renderAll;

Index: jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java (revision 5943)
+++ jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java (working copy)
@@ -51,6 +51,7 @@
 import javax.faces.application.PartialTraversal;
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.PartialViewContext;
 import javax.faces.context.ResponseWriter;
@@ -80,9 +81,6 @@
 
     // ------------------------------------------------------ Instance Variables
 
- private boolean renderedBegin = false;
- private boolean renderedChildren = false;
- private boolean renderedEnd = false;
 
     private static final String RENDER_ALL_MARKER = "javax.faces.ViewRoot";
     private static final String ORIGINAL_WRITER = "javax.faces.originalWriter";
@@ -127,68 +125,42 @@
         } else if (phaseId == PhaseId.RENDER_RESPONSE) {
 
             try {
- if (!renderedBegin) {
- partialViewContext.enableResponseWriting(true);
- ResponseWriter writer = partialViewContext.getPartialResponseWriter();
- ResponseWriter orig = context.getResponseWriter();
- context.getAttributes().put(ORIGINAL_WRITER, orig);
- context.setResponseWriter(writer);
+ partialViewContext.enableResponseWriting(true);
+ ResponseWriter writer = partialViewContext.getPartialResponseWriter();
+ ResponseWriter orig = context.getResponseWriter();
+ context.getAttributes().put(ORIGINAL_WRITER, orig);
+ context.setResponseWriter(writer);
 
- // PENDING PORTLETS???
+ ExternalContext exContext = context.getExternalContext();
+ if (exContext.getResponse() instanceof HttpServletResponse) {
+ exContext.setResponseContentType("text/xml");
+ exContext.setResponseHeader("Cache-Control", "no-cache");
+ writer.startElement("partial-response", viewRoot);
+ writer.startElement("components", viewRoot);
+ }
 
- if (context.getExternalContext().getResponse() instanceof HttpServletResponse) {
- HttpServletResponse servletResponse = (HttpServletResponse)
- context.getExternalContext().getResponse();
- // this can be ExternalContext.setResponseContentType
- servletResponse.setContentType("text/xml");
- servletResponse.setHeader("Cache-Control", "no-cache");
- writer.startElement("partial-response", viewRoot);
- writer.startElement("components", viewRoot);
- renderedBegin = true;
- }
+ if (partialViewContext.isRenderAll()) {
+ renderAll(context, viewRoot);
+ writer.endElement("components");
+ renderState(context, viewRoot);
+ writer.endElement("partial-response");
+ return;
+ }
 
- if (partialViewContext.isRenderAll()) {
- // If this is a "render all via ajax" request,
- // make sure to wrap the entire page in a <render> elemnt
- // with the special id of VIEW_ROOT_ID. This is how the client
- // JavaScript knows how to replace the entire document with
- // this response.
- writer.startElement("render", viewRoot);
- writer.writeAttribute("id", RENDER_ALL_MARKER, "id");
- writer.startElement("markup", viewRoot);
- writer.write("<![CDATA[");
- renderedBegin = true;
- }
- } else if (!renderedChildren) {
- // Skip this processing if "none" is specified in the render list,
- // or there were no render phase client ids.
- if (renderPhaseClientIds == null || renderPhaseClientIds.isEmpty() ||
- partialViewContext.isRenderNone()) {
- } else {
- processComponents(viewRoot, phaseId, renderPhaseClientIds, context);
- }
- renderedChildren = true;
- } else if (!renderedEnd) {
- ResponseWriter writer = context.getResponseWriter();
- if (partialViewContext.isRenderAll()) {
- writer.write("]]>");
- writer.endElement("markup");
- writer.endElement("render");
- }
+ // Skip this processing if "none" is specified in the render list,
+ // or there were no render phase client ids.
+ if (renderPhaseClientIds == null || renderPhaseClientIds.isEmpty() ||
+ partialViewContext.isRenderNone()) {
+ } else {
+ processComponents(viewRoot, phaseId, renderPhaseClientIds, context);
+ }
 
- writer.endElement("components");
+ writer.endElement("components");
 
- // Get the view state and write it to the response..
- writer.startElement("state", viewRoot);
- String state = context.getApplication().getStateManager().getViewState(context);
- writer.write("<![CDATA[" + state + "]]>");
- writer.endElement("state");
- writer.endElement("partial-response");
+ renderState(context, viewRoot);
+
+ writer.endElement("partial-response");
          
- renderedBegin = false;
- renderedChildren = false;
- renderedEnd = false;
- }
             } catch (IOException ex) {
                 this.cleanupAfterView(context);
             } catch (RuntimeException ex) {
@@ -254,16 +226,45 @@
         }
     }
 
+ private void renderAll(FacesContext context, UIViewRoot viewRoot) throws IOException {
+ // If this is a "render all via ajax" request,
+ // make sure to wrap the entire page in a <render> elemnt
+ // with the special id of VIEW_ROOT_ID. This is how the client
+ // JavaScript knows how to replace the entire document with
+ // this response.
+ ResponseWriter writer = context.getResponseWriter();
+ writer.startElement("render", viewRoot);
+ writer.writeAttribute("id", RENDER_ALL_MARKER, "id");
+
+ writer.startElement("markup", viewRoot);
+ writer.write("<![CDATA[");
+
+ Iterator<UIComponent> itr = viewRoot.getFacetsAndChildren();
+ while (itr.hasNext()) {
+ UIComponent kid = (UIComponent)itr.next();
+ kid.encodeAll(context);
+ }
+
+ writer.write("]]>");
+ writer.endElement("markup");
+ writer.endElement("render");
+ }
+
+ private void renderState(FacesContext context, UIViewRoot viewRoot) throws IOException {
+ // Get the view state and write it to the response..
+ ResponseWriter writer = context.getResponseWriter();
+ writer.startElement("state", viewRoot);
+ String state = context.getApplication().getStateManager().getViewState(context);
+ writer.write("<![CDATA[" + state + "]]>");
+ writer.endElement("state");
+ }
+
+
     private void cleanupAfterView(FacesContext context) {
- renderedBegin = false;
- renderedChildren = false;
- renderedEnd = false;
         ResponseWriter orig = (ResponseWriter) context.getAttributes().
             get(ORIGINAL_WRITER);
         assert(null != orig);
         // move aside the PartialResponseWriter
         context.setResponseWriter(orig);
     }
-
-
 }

Index: jsf-ri/src/com/sun/faces/config/InitFacesContext.java
===================================================================
--- jsf-ri/src/com/sun/faces/config/InitFacesContext.java (revision 5943)
+++ jsf-ri/src/com/sun/faces/config/InitFacesContext.java (working copy)
@@ -410,6 +410,14 @@
         public void setResponseCharacterEncoding(String responseCharacterEncoding) {
         }
 
+ @Override
+ public void setResponseHeader(String name, String value) {
+ }
+
+ @Override
+ public void addResponseHeader(String name, String value) {
+ }
+
     } // END ServletContextAdapter
 
 }