dev@javaserverfaces.java.net

[Retroactive REVIEW] PartialResponseWriter

From: Roger Kitain <Roger.Kitain_at_Sun.COM>
Date: Mon, 15 Dec 2008 15:28:12 -0500

attached mail follows:



Author: rogerk
Date: 2008-12-15 20:22:04+0000
New Revision: 6114

Added:
   trunk/jsf-api/src/javax/faces/context/PartialResponseWriter.java
Modified:
   trunk/jsf-api/src/javax/faces/context/PartialViewContext.java
   trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java
   trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java

Log:
PartialResponseWriter

Added: trunk/jsf-api/src/javax/faces/context/PartialResponseWriter.java
Url: https://mojarra.dev.java.net/source/browse/mojarra/trunk/jsf-api/src/javax/faces/context/PartialResponseWriter.java?view=auto&rev=6114
==============================================================================
--- (empty file)
+++ trunk/jsf-api/src/javax/faces/context/PartialResponseWriter.java 2008-12-15 20:22:04+0000
@@ -0,0 +1,378 @@
+
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
+ * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.faces.context;
+
+import java.util.Map;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * <p class="changed_added_2_0"><strong>PartialResponseWriter</strong>
+ * decorates an existing <code>ResponseWriter</code> to support the
+ * generation of a partial response suitable for Ajax operations.
+ * In addition to the markup generation methods inherited from
+ * <code>javax.faces.context.ResponseWriter</code>, this class provides
+ * methods for constructing the standard partial response elements.</p>
+ *
+ * @since 2.0
+ */
+public class PartialResponseWriter extends ResponseWriterWrapper {
+ // True when we need to close a start tag
+ //
+ private boolean inChanges = false;
+
+ // True when we need to close a before insert tag
+ //
+ private boolean inInsertBefore = false;
+
+ // True when we need to close afer insert tag
+ //
+ private boolean inInsertAfter = false;
+
+ ResponseWriter writer;
+
+ /**
+ * <p class="changed_added_2_0">Reserved ID value to indicate
+ * entire ViewRoot.</p>
+ *
+ * @since 2.0
+ */
+ public static final String RENDER_ALL_MARKER = "javax.faces.ViewRoot";
+
+ /**
+ * <p class="changed_added_2_0">Reserved ID value to indicate
+ * serialized ViewState.</p>
+ *
+ * @since 2.0
+ */
+ public static final String VIEW_STATE_MARKER = "javax.faces.ViewState";
+
+ /**
+ * <p class="changed_added_2_0">Create a <code>PartialResponseWriter</code>.</p>
+ *
+ * @since 2.0
+ */
+ public PartialResponseWriter(ResponseWriter writer) {
+ this.writer = writer;
+ }
+
+ /**
+ * <p class="changed_added_2_0">Return the wrapped
+ *{_at_link ResponseWriter} instance.</p>
+ * @see ResponseWriterWrapper#getWrapped()
+ *
+ * @since 2.0
+ */
+ public ResponseWriter getWrapped() {
+ return writer;
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of a partial response.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startDocument() throws IOException {
+ writer.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ writer.startElement("partial-response", null);
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the end of a partial response.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void endDocument() throws IOException {
+ endChangesIfNecessary();
+ writer.endElement("partial-response");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of an insert operation
+ * where the contents will be inserted before the specified target node.</p>
+ *
+ * @param fragmentId ID of the node to be inserted
+ * @param targetId ID of the node insertion should occur before
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startInsertBefore(String targetId)
+ throws IOException {
+ startChangesIfNecessary();
+ inInsertBefore = true;
+ writer.startElement("insert", null);
+ writer.startElement("before", null);
+ writer.writeAttribute("id", targetId, null);
+ writer.write("<![CDATA[");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of an insert operation
+ * where the contents will be inserted after the specified target node.</p>
+ *
+ * @param fragmentId ID of the node to be inserted
+ * @param targetId ID of the node insertion should occur after
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startInsertAfter(String targetId)
+ throws IOException {
+ startChangesIfNecessary();
+ inInsertAfter = true;
+ writer.startElement("insert", null);
+ writer.startElement("after", null);
+ writer.writeAttribute("id", targetId, null);
+ writer.write("<![CDATA[");
+ }
+
+
+ /**
+ * <p class="changed_added_2_0">Write the end of an insert operation.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void endInsert() throws IOException {
+ writer.write("]]>");
+ if (inInsertBefore) {
+ writer.endElement("before");
+ inInsertBefore = false;
+ } else if (inInsertAfter) {
+ writer.endElement("after");
+ inInsertAfter = false;
+ }
+ writer.endElement("insert");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of an update operation.</p>
+ *
+ * @param targetId ID of the node to be updated
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startUpdate(String targetId) throws IOException {
+ startChangesIfNecessary();
+ writer.startElement("update", null);
+ writer.writeAttribute("id", targetId, null);
+ writer.write("<![CDATA[");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the end of an update operation.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void endUpdate() throws IOException {
+ writer.write("]]>");
+ writer.endElement("update");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write an attribute update operation.</p>
+ *
+ * @param targetId ID of the node to be updated
+ * @param attributes Map of attribute name/value pairs to be updated
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void updateAttributes(String targetId, Map<String,String> attributes)
+ throws IOException {
+ startChangesIfNecessary();
+ writer.startElement("attributes", null);
+ writer.writeAttribute("id", targetId, null);
+ for (String name: attributes.keySet()) {
+ writer.startElement("attribute", null);
+ writer.writeAttribute("name", name, null);
+ writer.writeAttribute("value", attributes.get(name), null);
+ writer.endElement("attribute");
+ }
+ writer.endElement("attributes");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write a delete operation.</p>
+ *
+ * @param targetId ID of the node to be deleted
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void delete(String targetId) throws IOException {
+ startChangesIfNecessary();
+ writer.startElement("delete", null);
+ writer.writeAttribute("id", targetId, null);
+ writer.endElement("delete");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write a redirect operation.</p>
+ *
+ * @param url URL to redirect to
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void redirect(String url) throws IOException {
+ endChangesIfNecessary();
+ writer.startElement("redirect", null);
+ writer.writeAttribute("url", url, null);
+ writer.endElement("recirect");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of an eval operation.</p>
+ *
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startEval() throws IOException {
+ startChangesIfNecessary();
+ writer.startElement("eval", null);
+ writer.write("<![CDATA[");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the end of an eval operation.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void endEval() throws IOException {
+ writer.write("]]>");
+ writer.endElement("eval");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of an extension operation.</p>
+ *
+ * @param attributes String name/value pairs for extension element attributes
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startExtension(Map<String,String> attributes) throws IOException {
+ endChangesIfNecessary();
+ writer.startElement("extension", null);
+ if (null != attributes) {
+ for (String name : attributes.keySet()) {
+ writer.writeAttribute(name, attributes.get(name), null);
+ }
+ }
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the end of an extension operation.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void endExtension() throws IOException {
+ writer.endElement("extension");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the start of an error.</p>
+ *
+ * @param errorName Descriptive string for the error
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void startError(String errorName) throws IOException {
+ endChangesIfNecessary();
+ writer.startElement("error", null);
+ writer.startElement("error-name", null);
+ writer.write(errorName);
+ writer.endElement("error-name");
+ writer.startElement("error-message", null);
+ writer.write("<![CDATA[");
+ }
+
+ /**
+ * <p class="changed_added_2_0">Write the end of an error.</p>
+ *
+ * @throws IOException if an input/output error occurs
+ *
+ * @since 2.0
+ */
+ public void endError() throws IOException {
+ writer.write("]]>");
+ writer.endElement("error-message");
+ writer.endElement("error");
+ }
+
+ private void startChangesIfNecessary() throws IOException {
+ if (!inChanges) {
+ writer.startElement("changes", null);
+ inChanges = true;
+ }
+ }
+
+ private void endChangesIfNecessary() throws IOException {
+ if (inChanges) {
+ writer.endElement("changes");
+ inChanges = false;
+ }
+ }
+
+
+}

Modified: trunk/jsf-api/src/javax/faces/context/PartialViewContext.java
Url: https://mojarra.dev.java.net/source/browse/mojarra/trunk/jsf-api/src/javax/faces/context/PartialViewContext.java?view=diff&rev=6114&p1=trunk/jsf-api/src/javax/faces/context/PartialViewContext.java&p2=trunk/jsf-api/src/javax/faces/context/PartialViewContext.java&r1=6113&r2=6114
==============================================================================
--- trunk/jsf-api/src/javax/faces/context/PartialViewContext.java (original)
+++ trunk/jsf-api/src/javax/faces/context/PartialViewContext.java 2008-12-15 20:22:04+0000
@@ -153,7 +153,7 @@
     public abstract Collection<String> getRenderIds();
 
     /**
- * <p class="changed_added_2_0">Return the {_at_link ResponseWriter}
+ * <p class="changed_added_2_0">Return the {_at_link ResponseWriter}
      * to which components should
      * direct their output for partial view rendering. Within a given
      * response, components can use either the ResponseStream or the
@@ -164,7 +164,7 @@
      *
      * @since 2.0
      */
- public abstract ResponseWriter getPartialResponseWriter();
+ public abstract PartialResponseWriter getPartialResponseWriter();
 
     /**
      * <p class="changed_added_2_0">

Modified: trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java
Url: https://mojarra.dev.java.net/source/browse/mojarra/trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java?view=diff&rev=6114&p1=trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java&p2=trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java&r1=6113&r2=6114
==============================================================================
--- trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java (original)
+++ trunk/jsf-ri/src/com/sun/faces/context/AjaxExceptionHandlerImpl.java 2008-12-15 20:22:04+0000
@@ -48,6 +48,7 @@
 import javax.faces.context.ExceptionHandler;
 import javax.faces.context.ExceptionHandlerWrapper;
 import javax.faces.context.FacesContext;
+import javax.faces.context.PartialResponseWriter;
 import javax.faces.context.PartialViewContext;
 import javax.faces.context.ResponseWriter;
 import javax.faces.event.AbortProcessingException;
@@ -183,21 +184,16 @@
 
      private void handlePartialResponseError(FacesContext context, Throwable t) {
          try {
- ResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
- writer.startElement("partial-response", context.getViewRoot());
- writer.startElement("error", context.getViewRoot());
- writer.startElement("error-name", context.getViewRoot());
- writer.write(t.getClass().toString());
- writer.endElement("error-name");
- writer.startElement("error-message", context.getViewRoot());
+ PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
+ writer.startDocument();
+ writer.startError(t.getClass().toString());
              if (t.getCause() != null) {
                  writer.write(t.getCause().getMessage());
              } else {
                  writer.write(t.getMessage());
              }
- writer.endElement("error-message");
- writer.endElement("error");
- writer.endElement("partial-response");
+ writer.endError();
+ writer.endDocument();
              context.responseComplete();
          } catch (IOException ioe) {
             if (LOGGER.isLoggable(Level.SEVERE)) {

Modified: trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java
Url: https://mojarra.dev.java.net/source/browse/mojarra/trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java?view=diff&rev=6114&p1=trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java&p2=trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java&r1=6113&r2=6114
==============================================================================
--- trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java (original)
+++ trunk/jsf-ri/src/com/sun/faces/context/PartialViewContextImpl.java 2008-12-15 20:22:04+0000
@@ -48,6 +48,7 @@
 import javax.faces.component.visit.VisitResult;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
+import javax.faces.context.PartialResponseWriter;
 import javax.faces.context.PartialViewContext;
 import javax.faces.context.ResponseWriter;
 import javax.faces.event.PhaseId;
@@ -79,7 +80,7 @@
     private boolean released;
 
     // BE SURE TO ADD NEW IVARS TO THE RELEASE METHOD
- private ResponseWriter partialResponseWriter = null;
+ private PartialResponseWriter partialResponseWriter = null;
     private Map<Object,Object> attributes;
     private Collection<String> executeIds;
     private Collection<String> renderIds;
@@ -88,9 +89,7 @@
     private Boolean partialRequest;
     private Boolean renderAll = null;
 
- private static final String RENDER_ALL_MARKER = "javax.faces.ViewRoot";
     private static final String ORIGINAL_WRITER = "javax.faces.originalWriter";
- private static final String VIEW_STATE_MARKER = "javax.faces.ViewState";
 
 
     // ----------------------------------------------------------- Constructors
@@ -261,7 +260,7 @@
             // partial response writer.
             //
             if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
- ResponseWriter writer = getPartialResponseWriter();
+ PartialResponseWriter writer = getPartialResponseWriter();
                 context.setResponseWriter(writer);
             }
 
@@ -273,7 +272,7 @@
                 //
                 OnOffResponseWrapper onOffResponse = new OnOffResponseWrapper(context);
                 onOffResponse.setEnabled(true);
- ResponseWriter writer = getPartialResponseWriter();
+ PartialResponseWriter writer = getPartialResponseWriter();
                 ResponseWriter orig = context.getResponseWriter();
                 context.getAttributes().put(ORIGINAL_WRITER, orig);
                 context.setResponseWriter(writer);
@@ -282,15 +281,13 @@
                 if (exContext.getResponse() instanceof HttpServletResponse) {
                     exContext.setResponseContentType("text/xml");
                     exContext.setResponseHeader("Cache-Control", "no-cache");
- writer.startElement("partial-response", viewRoot);
- writer.startElement("changes", viewRoot);
+ writer.startDocument();
                 }
 
                 if (isRenderAll()) {
                     renderAll(context, viewRoot);
                     renderState(context, viewRoot);
- writer.endElement("changes");
- writer.endElement("partial-response");
+ writer.endDocument();
                     return;
                 }
 
@@ -303,8 +300,7 @@
 
                 renderState(context, viewRoot);
 
- writer.endElement("changes");
- writer.endElement("partial-response");
+ writer.endDocument();
             } catch (IOException ex) {
                 this.cleanupAfterView(context);
             } catch (RuntimeException ex) {
@@ -319,7 +315,7 @@
      * @see javax.faces.context.PartialViewContext#getPartialResponseWriter()
      */
     @Override
- public ResponseWriter getPartialResponseWriter() {
+ public PartialResponseWriter getPartialResponseWriter() {
         assertNotReleased();
         if (partialResponseWriter == null) {
             partialResponseWriter = createPartialResponseWriter();
@@ -386,11 +382,8 @@
         // 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("update", viewRoot);
- writer.writeAttribute("id", RENDER_ALL_MARKER, "id");
-
- writer.write("<![CDATA[");
+ PartialResponseWriter writer = getPartialResponseWriter();
+ writer.startUpdate(PartialResponseWriter.RENDER_ALL_MARKER);
 
         Iterator<UIComponent> itr = viewRoot.getFacetsAndChildren();
         while (itr.hasNext()) {
@@ -398,21 +391,19 @@
             kid.encodeAll(context);
         }
 
- writer.write("]]>");
- writer.endElement("update");
+ writer.endUpdate();
     }
 
     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("update", viewRoot);
- writer.writeAttribute("id", VIEW_STATE_MARKER, "id");
+ PartialResponseWriter writer = getPartialResponseWriter();
+ writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
         String state = context.getApplication().getStateManager().getViewState(context);
- writer.write("<![CDATA[" + state + "]]>");
- writer.endElement("update");
+ writer.write(state);
+ writer.endUpdate();
     }
 
- private ResponseWriter createPartialResponseWriter() {
+ private PartialResponseWriter createPartialResponseWriter() {
 
         FacesContext ctx = FacesContext.getCurrentInstance();
         ExternalContext extContext = ctx.getExternalContext();
@@ -437,7 +428,13 @@
                 ctx.getRenderKit().createResponseWriter(out,
                 "text/xml", encoding);
         }
- return responseWriter;
+ if (responseWriter instanceof PartialResponseWriter) {
+ return (PartialResponseWriter) responseWriter;
+ }
+ else {
+ return new PartialResponseWriter(responseWriter);
+ }
+
     }
 
     private void cleanupAfterView(FacesContext context) {
@@ -484,17 +481,12 @@
                     comp.processUpdates(facesContext);
                 } else if (curPhase == PhaseId.RENDER_RESPONSE) {
 
- ResponseWriter writer = facesContext.getResponseWriter();
+ PartialResponseWriter writer = facesContext.getPartialViewContext().getPartialResponseWriter();
 
- writer.startElement("update", comp);
- writer.writeAttribute("id", comp.getClientId(facesContext), "id");
+ writer.startUpdate(comp.getClientId(facesContext));
                     try {
- writer.write("<![CDATA[");
-
                         // do the default behavior...
                         comp.encodeAll(facesContext);
-
- writer.write("]]>");
                     }
                     catch (Exception ce) {
                         if (LOGGER.isLoggable(Level.SEVERE)) {
@@ -506,7 +498,7 @@
                             ce);
                         }
                     }
- writer.endElement("update");
+ writer.endUpdate();
                 }
                 else {
                     throw new IllegalStateException("I18N: Unexpected " +

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe_at_mojarra.dev.java.net
For additional commands, e-mail: commits-help_at_mojarra.dev.java.net