jsr344-experts@javaserverfaces-spec-public.java.net

[jsr344-experts] Re: [949-WindowId] Best place to specify creating the windowId?

From: Leonardo Uribe <lu4242_at_gmail.com>
Date: Mon, 27 Feb 2012 14:59:46 -0500

Hi

2012/2/23 Edward Burns <edward.burns_at_oracle.com>:
>>>>>> On Sun, 19 Feb 2012 21:09:20 -0500, Leonardo Uribe <lu4242_at_gmail.com> said:
>
> LU> The problem here is we want to fix Flash scope with windowId
> LU> concept, and that initialization code occur before any phase
> LU> listener. The only way to fix it correctly is inserting
> LU> initialization code before flash scope init. This is one reason why
> LU> windowId should be include at spec level.
>
> I see.  I interpret your above text as a core requirement of the feature
> and have added this text to the "Invariants" section of the proposal
> [1].
>
> * The windowId must be the anchor to which the Flash is hitched.
>
> Leonardo, have I accurately understood and applied your meaning?
>

Yes, but only when windowId is enabled, when it is disabled, the
current strategy using cookies should apply.

> LU> Yes, it is relevant. Gerhard agrees with me in this point. I think the
> LU> post-phase code is also necessary.
>
> We have a rich tradition of not adding hooks to the spec until we have
> at least one solid use case for them.  Just trust that if one surfaces,
> we can correctly address it.
>

Ok, it has sense.

>>>>>> On Tue, 21 Feb 2012 10:45:50 +0100, Werner Punz <werner.punz_at_gmail.com> said:
>
> EB> It certainly can't be called without first obtaining the jsf.js, which
> EB> can't have been obtained without first making a request to the JSF
> EB> runtime, which we are now in the process of making allocate and return a
> EB> windowId upon first request.  Please help me understand why simply
> EB> looking in the most recently returned <partial-response> element,
> EB> per-session of course, is insufficient.
>
> WP> The problem is
>
> WP> a) the window id can be stored within a url or a form and
>
> In the case of Ajax, I have specified that there is now an
>
> <update id="javax.faces.WindowId<SEP><UNIQUE_PER_VIEW_NUMBER">
>  <![CDATA[...]]>
> </update>
>
> Now, I know it can be within a URL, but I need someone to explain how
> that works.
>
> WP> b) the combination of this with Portlets and/or subscopes which handle
> WP> their own windowIds.
>
> From issue 220, the ViewState update will now have this
>
> <update
> id="<VIEW_ROOT_CONTAINER_CLIENT_ID><SEP>javax.faces.ViewState<SEP><UNIQUE_PER_VIEW_NUMBER>">
>  <![CDATA[...]]>
> </update>
>
> This must work even for portlets.
>
> WP> In the proposal we have the function the function
> WP> jsf.util.getWindowId(node) instead of a simple jsf.util.getWindowId(). With
> WP> node being any arbitrary element under the current ViewRoot.
>
> WP> *However second (new) proposal*:
>
> this is getting too confusing.  There are too many proposals and I don't
> know which one is current.
>
> Here is the commit log from what I'm calling the first draft of the
> proposal.  It is in revision 9732.  It's inspired from the various
> incarnations of proposals I've found on several different Apache wikis.
>
> Please let's take the code base of the RI trunk as the starting point
> for how to complete this feature.
>
> http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-949
>
> This is the first draft of the specification of the WindowId feature.
>
> Leonardo, Werner, and Gerhard, please look for "ACTION" in this email
> because I really need your input in those areas.
>
> SECTION: Modified Files
> ----------------------------
>
> M       jsf-api/src/main/java/javax/faces/webapp/FacesServlet.java
>
> - Modifiy the spec for service() to require a call to
>  Lifecycle.attachWindow() before Lifecycle.execute().
>
> M       jsf-api/src/main/java/javax/faces/lifecycle/Lifecycle.java
>
> - Add attachWindow() method.  Gerhard Patracek and Leonardo Uribe are
>  very keen on making sure the windowId solution is plugable.  Because
>  this method is responsible for making sure the ClientWindow is created
>  and installed in the ExternalContext, I assert that the plugability
>  story is to decorate the Lifecycle instance and override this method.
>
>  To make this easier, I've added the following class:
>
> A       jsf-api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java
>
> - Make it easier to decorate the lifecycle, through a combination of the
>  existing LifecycleFactory and this new LifecycleWrapper class.
>
> M       jsf-api/src/main/java/javax/faces/lifecycle/package.html
>
> - First change to this package in 2.2.
>
> A       jsf-api/src/main/java/javax/faces/lifecycle/ClientWindow.java
>
> - In WINDOW_ID_MODE_PARAM_NAME, I only have "field" and "none".  I'd
>  like to have "script" and "url" but I don't understand them well
>  enough to specify it.
>
> ACTION: => Can someone please explain how these modes are supposed to work?
>

Ok, "field" mode works as described on:

http://myfaces.apache.org/orchestra/myfaces-orchestra-core/multiwindow.html

See: Embedding a window-id in a hidden field

Just store it in a hidden field, and if no windowId, generate one from
server side. In theory,
if the windowId is found on the hidden field, it takes priority over
any other strategy to
derive the windowId.

"url" mode works as described on:

See: Embedding a window-id in the URL

If no windowId, generate one from server side. Then, just append the
query param to generated
links (in orchestra there is a wrapper over HttpServletResponse.encodeURL() ).
This strategy is implemented in MyFaces Orchestra (conversationContext url query
param).

See:

http://svn.apache.org/repos/asf/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/requestParameterProvider/RequestParameterResponseWrapper.java

http://svn.apache.org/repos/asf/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/requestParameterProvider/RequestParameterProviderManager.java

http://svn.apache.org/repos/asf/myfaces/orchestra/trunk/core20/src/main/java/org/apache/myfaces/orchestra/urlParamNav/UrlParameterViewHandler.java

It is still pending how to hook the generated urls to include this param.
In the wiki this is mentioned as #encodeXYZ . The idea is ExternalContext
implementation uses Window object to hook the proper methods. I was
thinking on hook encodeXXXURL methods instead do Orchestra hack.

"client" mode is the one derived from CODI, which also uses an url query param,
but uses the script to generate the unique id from the client side. Maybe Mark
Struberg or Gerhard knows better than me how this mode should work.

> M       jsf-api/src/main/java/javax/faces/render/ResponseStateManager.java
>
> - Declare WINDOW_ID_PARAM
>
> - Update spec for writeState(FacesContext, Object) to call for writing
>  of ClientWindow.
>
> M       jsf-api/src/main/resources/jsf.js
>
> - Update jsf.ajax.response() to cover <update id="javax.faces.WindowId:0" />
>
> - Add jsf.getWindowId(form)
>
> ACTION: I'm aware that Werner is working on this and I want him to look
> at what I've done here and suggest how I can improve it.
>
> M       jsf-api/src/main/java/javax/faces/context/ExternalContext.java
> M       jsf-api/src/main/java/javax/faces/context/ExternalContextWrapper.java
>
> - add getSessionId().
>
> - Add property for ClientWindow.-
>
> A       jsf-ri/src/main/java/com/sun/faces/lifecycle/ClientWindowImpl.java
> M       jsf-ri/src/main/java/com/sun/faces/context/ExternalContextImpl.java
> M       jsf-ri/src/main/java/com/sun/faces/context/PartialViewContextImpl.java
> M       jsf-ri/src/main/java/com/sun/faces/renderkit/StateHelper.java
> M       jsf-ri/src/main/java/com/sun/faces/renderkit/ClientSideStateHelper.java
> M       jsf-ri/src/main/java/com/sun/faces/renderkit/ServerSideStateHelper.java
> M       jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleImpl.java
> M       jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleFactoryImpl.java
> M       jsf-ri/src/main/java/com/sun/faces/config/WebConfiguration.java
> M       jsf-ri/src/main/java/com/sun/faces/util/Util.java
> M       build.xml
> M       jsf-test/build.xml
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces/test
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces/test/i_spec_949_war
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces/test/i_spec_949_war/UserBean.java
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/resources
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/main.xhtml
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF/beans.xml
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF/web.xml
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/pom.xml
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces/test
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces/test/i_spec_949_htmlunit
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces/test/i_spec_949_htmlunit/IssueSpec949TestCase.java
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/resources
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/pom.xml
> A       jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/build.xml
>
> SECTION: Diffs
> ----------------------------
>
> Index: jsf-ri/src/main/java/com/sun/faces/context/ExternalContextImpl.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/context/ExternalContextImpl.java (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/context/ExternalContextImpl.java (working copy)
> @@ -82,6 +82,7 @@
>  import com.sun.faces.context.flash.ELFlash;
>  import javax.faces.FactoryFinder;
>  import javax.faces.context.FlashFactory;
> +import javax.faces.lifecycle.ClientWindow;
>
>  /**
>  * <p>This implementation of {_at_link ExternalContext} is specific to the
> @@ -94,6 +95,7 @@
>     private ServletContext servletContext = null;
>     private ServletRequest request = null;
>     private ServletResponse response = null;
> +    private ClientWindow clientWindow = null;
>
>     private Map<String,Object> applicationMap = null;
>     private Map<String,Object> sessionMap = null;
> @@ -157,6 +159,17 @@
>         return (((HttpServletRequest) request).getSession(create));
>     }
>
> +    @Override
> +    public String getSessionId(boolean create) {
> +        HttpSession session = null;
> +        String id = null;
> +
> +        session = (HttpSession)getSession(create);
> +        if (null != session) {
> +            id = session.getId();
> +        }
> +        return id;
> +    }
>
>     /**
>      * @see javax.faces.context.ExternalContext#getContext()
> @@ -189,8 +202,7 @@
>     public Object getRequest() {
>         return this.request;
>     }
> -
> -
> +
>     /**
>      * @see ExternalContext#setRequest(Object)
>      */
> @@ -232,7 +244,16 @@
>         }
>     }
>
> +    @Override
> +    public ClientWindow getClientWindow() {
> +        return clientWindow;
> +    }
>
> +    @Override
> +    public void setClientWindow(ClientWindow window) {
> +        this.clientWindow = window;
> +    }
> +
>     /**
>      * @see ExternalContext#setResponseCharacterEncoding(String)
>      */
> Index: jsf-ri/src/main/java/com/sun/faces/context/PartialViewContextImpl.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/context/PartialViewContextImpl.java      (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/context/PartialViewContextImpl.java      (working copy)
> @@ -67,7 +67,7 @@
>  import com.sun.faces.component.visit.PartialVisitContext;
>  import com.sun.faces.util.FacesLogger;
>  import com.sun.faces.util.Util;
> -import javax.faces.component.UINamingContainer;
> +import javax.faces.lifecycle.ClientWindow;
>
>  public class PartialViewContextImpl extends PartialViewContext {
>
> @@ -419,6 +419,14 @@
>             String state = context.getApplication().getStateManager().getViewState(context);
>             writer.write(state);
>             writer.endUpdate();
> +
> +            ClientWindow window = context.getExternalContext().getClientWindow();
> +            if (null != window) {
> +                String windowIdId = Util.getWindowIdId(context);
> +                writer.startUpdate(windowIdId);
> +                writer.write(window.getId());
> +                writer.endUpdate();
> +            }
>         }
>
>     }
> Index: jsf-ri/src/main/java/com/sun/faces/renderkit/StateHelper.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/renderkit/StateHelper.java       (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/renderkit/StateHelper.java       (working copy)
> @@ -41,6 +41,7 @@
>  package com.sun.faces.renderkit;
>
>
> +import javax.faces.lifecycle.ClientWindow;
>  import com.sun.faces.RIConstants;
>  import java.io.IOException;
>
> @@ -52,6 +53,7 @@
>  import com.sun.faces.spi.SerializationProviderFactory;
>  import com.sun.faces.spi.SerializationProvider;
>  import com.sun.faces.config.WebConfiguration;
> +import com.sun.faces.util.Util;
>  import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.CompressViewState;
>  import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.AutoCompleteOffOnViewState;
>
> @@ -74,11 +76,22 @@
>
>     /**
>      * <p>
> +     * The first portion of the window id field.
> +     * </p>
> +     *
> +     */
> +    protected static final char[] WINDOW_ID_FIELD_START =
> +          ("<input type=\"hidden\" name=\""
> +           + ResponseStateManager.WINDOW_ID_PARAM
> +           + "\" id=\"").toCharArray();
> +
> +    /**
> +     * <p>
>      * The second portion of the hidden state field.
>      * </p>
>      *
>      */
> -    protected static final char[] STATE_FIELD_MIDDLE =
> +    protected static final char[] FIELD_MIDDLE =
>           ("\" value=\"").toCharArray();
>
>     /**
> @@ -86,7 +99,7 @@
>      * The end of the hidden state field.
>      * </p>
>      */
> -    protected static final char[] STATE_FIELD_END =
> +    protected static final char[] FIELD_END =
>           "\" />".toCharArray();
>
>     /**
> @@ -134,19 +147,25 @@
>     protected char[] stateFieldStart;
>
>     /**
> +     * This will be used the by the different <code>StateHelper</code> implementations
> +     * when writing the start of the windowId field.
> +     */
> +    protected char[] windowIdFieldStart;
> +
> +    /**
>      * This will be used by the different <code>StateHelper</code> implementations
> -     * when writing the middle of the state field.
> +     * when writing the middle of the state or viewId fields.
>      */
>
> -    protected char[] stateFieldMiddle;
> +    protected char[] fieldMiddle;
>
>
>     /**
>      * This will be used the by the different <code>StateHelper</code> implementations
> -     * when writing the end of the state field.  This value of this field is
> +     * when writing the end of the state or viewId field.  This value of this field is
>      * determined by the value of the {_at_link com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter#AutoCompleteOffOnViewState}<code>
>      */
> -    protected char[] stateFieldEnd;
> +    protected char[] fieldEnd;
>
>
>     // ------------------------------------------------------------ Constructors
> @@ -163,10 +182,11 @@
>         webConfig = WebConfiguration.getInstance(ctx.getExternalContext());
>         compressViewState = webConfig.isOptionEnabled(CompressViewState);
>         stateFieldStart = STATE_FIELD_START;
> -        stateFieldMiddle = STATE_FIELD_MIDDLE;
> -        stateFieldEnd = (webConfig.isOptionEnabled(AutoCompleteOffOnViewState)
> +        windowIdFieldStart = WINDOW_ID_FIELD_START;
> +        fieldMiddle = FIELD_MIDDLE;
> +        fieldEnd = (webConfig.isOptionEnabled(AutoCompleteOffOnViewState)
>                            ? STATE_FIELD_AUTOCOMPLETE_END
> -                           : STATE_FIELD_END);
> +                           : FIELD_END);
>
>
>         if (serialProvider == null) {
> @@ -278,5 +298,19 @@
>         }
>
>     }
> +
> +    protected void writeWindowIdField(FacesContext context,
> +                                      ResponseWriter writer)
> +    throws IOException {
> +        ClientWindow window = context.getExternalContext().getClientWindow();
> +        if (null != window) {
> +            writer.write(windowIdFieldStart);
> +            writer.write(Util.getWindowIdId(context));
> +            writer.write(fieldMiddle);
> +            writer.write(window.getId());
> +            writer.write(fieldEnd);
> +        }
> +
> +    }
>
>  }
> Index: jsf-ri/src/main/java/com/sun/faces/renderkit/ClientSideStateHelper.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/renderkit/ClientSideStateHelper.java     (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/renderkit/ClientSideStateHelper.java     (working copy)
> @@ -171,9 +171,10 @@
>             writer.write(stateFieldStart);
>             String viewStateId = Util.getViewStateId(ctx);
>             writer.write(viewStateId);
> -            writer.write(stateFieldMiddle);
> +            writer.write(fieldMiddle);
>             doWriteState(state, writer);
> -            writer.write(stateFieldEnd);
> +            writer.write(fieldEnd);
> +            writeWindowIdField(ctx, writer);
>             writeRenderKitIdField(ctx, writer);
>         }
>
> Index: jsf-ri/src/main/java/com/sun/faces/renderkit/ServerSideStateHelper.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/renderkit/ServerSideStateHelper.java     (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/renderkit/ServerSideStateHelper.java     (working copy)
> @@ -234,9 +234,10 @@
>                  writer.write(stateFieldStart);
>                  String viewStateId = Util.getViewStateId(ctx);
>                  writer.write(viewStateId);
> -                 writer.write(stateFieldMiddle);
> +                 writer.write(fieldMiddle);
>                  writer.write(id);
> -                 writer.write(stateFieldEnd);
> +                 writer.write(fieldEnd);
> +                 writeWindowIdField(ctx, writer);
>                  writeRenderKitIdField(ctx, writer);
>              }
>         }
> Index: jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleImpl.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleImpl.java     (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleImpl.java     (working copy)
> @@ -40,6 +40,7 @@
>
>  package com.sun.faces.lifecycle;
>
> +import com.sun.faces.config.WebConfiguration;
>  import java.util.List;
>  import java.util.concurrent.CopyOnWriteArrayList;
>  import java.util.logging.Level;
> @@ -52,6 +53,8 @@
>
>  import com.sun.faces.util.FacesLogger;
>  import com.sun.faces.util.MessageUtils;
> +import javax.faces.context.ExternalContext;
> +import javax.faces.lifecycle.ClientWindow;
>
>
>  /**
> @@ -89,12 +92,49 @@
>     // List for registered PhaseListeners
>     private List<PhaseListener> listeners =
>           new CopyOnWriteArrayList<PhaseListener>();
> +    private boolean isWindowIdEnabled = false;
> +
> +    public LifecycleImpl() {
> +
> +    }
>
> +    public LifecycleImpl(ExternalContext extContext) {
> +        WebConfiguration config = WebConfiguration.getInstance(extContext);
> +        String optionValue = config.getOptionValue(WebConfiguration.WebContextInitParameter.WindowIdMode);
> +        isWindowIdEnabled = (null != optionValue) && !optionValue.equals(WebConfiguration.WebContextInitParameter.WindowIdMode.getDefaultValue());
> +
>
> +    }
>
>     // ------------------------------------------------------- Lifecycle Methods
>
> +    @Override
> +    public void attachWindow(FacesContext context) {
> +        if (!isWindowIdEnabled) {
> +            return;
> +        }
> +        if (context == null) {
> +            throw new NullPointerException
> +                (MessageUtils.getExceptionMessageString
> +                 (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "context"));
> +        }
>
> +        ExternalContext extContext = context.getExternalContext();
> +        ClientWindow myWindow = extContext.getClientWindow();
> +        if (null == myWindow) {
> +            myWindow = new ClientWindowImpl();
> +            myWindow.decode(context);
> +            extContext.setClientWindow(myWindow);
> +
> +        }
> +
> +
> +        // If you need to do the "send down the HTML" trick, be sure to
> +        // mark responseComplete true after doing so.  That way
> +        // the remaining lifecycle methods will not execute.
> +
> +    }
> +
>     // Execute the phases up to but not including Render Response
>     public void execute(FacesContext context) throws FacesException {
>
> Index: jsf-ri/src/main/java/com/sun/faces/lifecycle/ClientWindowImpl.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/lifecycle/ClientWindowImpl.java  (revision 0)
> +++ jsf-ri/src/main/java/com/sun/faces/lifecycle/ClientWindowImpl.java  (revision 0)
> @@ -0,0 +1,90 @@
> +/*
> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> + *
> + * Copyright (c) 1997-2012 Oracle and/or its affiliates. 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_1_1.html
> + * or packager/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 packager/legal/LICENSE.txt.
> + *
> + * GPL Classpath Exception:
> + * Oracle designates this particular file as subject to the "Classpath"
> + * exception as provided by Oracle in the GPL Version 2 section of the License
> + * file that accompanied this code.
> + *
> + * Modifications:
> + * If applicable, add the following below the License Header, with the fields
> + * enclosed by brackets [] replaced by your own identifying information:
> + * "Portions Copyright [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 com.sun.faces.lifecycle;
> +
> +import java.util.Map;
> +import javax.faces.component.UINamingContainer;
> +import javax.faces.context.ExternalContext;
> +import javax.faces.context.FacesContext;
> +import javax.faces.lifecycle.ClientWindow;
> +import javax.faces.render.ResponseStateManager;
> +
> +public class ClientWindowImpl extends ClientWindow {
> +
> +    String id;
> +
> +    public ClientWindowImpl() {
> +    }
> +
> +    @Override
> +    public void decode(FacesContext context) {
> +        Map<String, String> requestParamMap = context.getExternalContext().getRequestParameterMap();
> +        id = requestParamMap.get(ResponseStateManager.WINDOW_ID_PARAM);
> +        if (null == id) {
> +            id = calculateWindowId(context);
> +        }
> +    }
> +
> +    private String calculateWindowId(FacesContext context) {
> +        final String windowIdCounterKey = "com.sun.faces.lifecycle.WindowIdCounterKey";
> +        ExternalContext extContext = context.getExternalContext();
> +        Map<String, Object> sessionAttrs = extContext.getSessionMap();
> +        Integer counter = (Integer) sessionAttrs.get(windowIdCounterKey);
> +        if (null == counter) {
> +            counter = new Integer(0);
> +        }
> +        char sep = UINamingContainer.getSeparatorChar(context);
> +        id = extContext.getSessionId(true) + sep +
> +                + counter;
> +
> +        sessionAttrs.put(windowIdCounterKey, ++counter);
> +
> +        return id;
> +    }
> +
> +    @Override
> +    public String getId() {
> +        return id;
> +    }
> +
> +
> +
> +}
> Index: jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleFactoryImpl.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleFactoryImpl.java      (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleFactoryImpl.java      (working copy)
> @@ -53,6 +53,8 @@
>  import java.util.concurrent.ConcurrentHashMap;
>  import java.util.logging.Level;
>  import java.util.logging.Logger;
> +import javax.faces.context.ExternalContext;
> +import javax.faces.context.FacesContext;
>
>  /**
>  * <B>LifecycleFactoryImpl</B> is the stock implementation of Lifecycle
> @@ -76,10 +78,11 @@
>     public LifecycleFactoryImpl() {
>         super();
>         lifecycleMap = new ConcurrentHashMap<String,Lifecycle>();
> +        ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
>
>         // We must have an implementation under this key.
>         lifecycleMap.put(LifecycleFactory.DEFAULT_LIFECYCLE,
> -                         new LifecycleImpl());
> +                         new LifecycleImpl(extContext));
>         if (LOGGER.isLoggable(Level.FINE)) {
>             LOGGER.fine("Created Default Lifecycle");
>         }
> Index: jsf-ri/src/main/java/com/sun/faces/config/WebConfiguration.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/config/WebConfiguration.java     (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/config/WebConfiguration.java     (working copy)
> @@ -71,6 +71,7 @@
>  import javax.faces.FactoryFinder;
>  import javax.faces.component.UIInput;
>  import javax.faces.event.PhaseListener;
> +import javax.faces.lifecycle.ClientWindow;
>  import javax.faces.lifecycle.Lifecycle;
>  import javax.faces.lifecycle.LifecycleFactory;
>  import javax.faces.validator.BeanValidator;
> @@ -959,7 +960,12 @@
>         FaceletsProcessingFileExtensionProcessAs(
>                 "",
>                 ""
> -        );
> +        ),
> +        WindowIdMode(
> +              ClientWindow.WINDOW_ID_MODE_PARAM_NAME,
> +              "none"
> +        ),
> +;
>
>
>
> Index: jsf-ri/src/main/java/com/sun/faces/util/Util.java
> ===================================================================
> --- jsf-ri/src/main/java/com/sun/faces/util/Util.java   (revision 9730)
> +++ jsf-ri/src/main/java/com/sun/faces/util/Util.java   (working copy)
> @@ -953,10 +953,26 @@
>         result = root.getContainerClientId(context) + sep +
>                 ResponseStateManager.VIEW_STATE_PARAM + sep +
>                 + counter;
> -        contextAttrs.put(viewStateCounterKey, counter++);
> +        contextAttrs.put(viewStateCounterKey, ++counter);
>
>         return result;
>     }
>
> +    public static String getWindowIdId(FacesContext context) {
> +        String result = null;
> +        final String windowIdIdCounterKey = "com.sun.faces.util.WindowIdCounterKey";
> +        Map<Object, Object> contextAttrs = context.getAttributes();
> +        Integer counter = (Integer) contextAttrs.get(windowIdIdCounterKey);
> +        if (null == counter) {
> +            counter = new Integer(0);
> +        }
> +
> +        char sep = UINamingContainer.getSeparatorChar(context);
> +        result = ResponseStateManager.WINDOW_ID_PARAM + sep +
> +                + counter;
> +        contextAttrs.put(windowIdIdCounterKey, ++counter);
> +
> +        return result;
> +    }
>
>  } // end of class Util
> Index: build.xml
> ===================================================================
> --- build.xml   (revision 9730)
> +++ build.xml   (working copy)
> @@ -134,7 +134,7 @@
>     </target>
>
>     <target name="test" description="Run API, Impl, and Demo automated tests">
> -        <call.modules target="test"/>
> +<!--        <call.modules target="test"/> -->
>         <subant target="test" inheritAll="false" failonerror="true">
>           <filelist dir="${regression.test.dir}">
>               <file name="build.xml"/>
> Index: jsf-test/build.xml
> ===================================================================
> --- jsf-test/build.xml  (revision 9730)
> +++ jsf-test/build.xml  (working copy)
> @@ -110,7 +110,8 @@
>                     JAVASERVERFACES_SPEC_PUBLIC-479,
>                     JAVASERVERFACES_SPEC_PUBLIC-220,
>                     JAVASERVERFACES_SPEC_PUBLIC-594,
> -                    JAVASERVERFACES_SPEC_PUBLIC-1071" />
> +                    JAVASERVERFACES_SPEC_PUBLIC-1071,
> +                    JAVASERVERFACES_SPEC_PUBLIC-949" />
>
>     <target name="clean" depends="define.applications"
>             description="">
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces/test/i_spec_949_war/UserBean.java
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces/test/i_spec_949_war/UserBean.java       (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/java/com/sun/faces/test/i_spec_949_war/UserBean.java       (revision 0)
> @@ -0,0 +1,92 @@
> +package com.sun.faces.test.i_spec_949_war;
> +
> +import java.io.Serializable;
> +import java.util.Date;
> +import javax.enterprise.context.SessionScoped;
> +import javax.faces.application.FacesMessage;
> +import javax.faces.component.UIComponent;
> +import javax.faces.context.FacesContext;
> +import javax.faces.validator.ValidatorException;
> +import javax.inject.Named;
> +
> +_at_Named
> +_at_SessionScoped
> +public class UserBean implements Serializable {
> +
> +    protected String firstName = "Duke";
> +    protected String lastName = "Java";
> +    protected Date dob;
> +    protected String sex = "Unknown";
> +    protected String email;
> +    protected String serviceLevel = "medium";
> +
> +    public UserBean() {}
> +
> +    public String getFirstName() {
> +        return firstName;
> +    }
> +
> +    public void setFirstName(String firstName) {
> +        this.firstName = firstName;
> +    }
> +
> +    public String getLastName() {
> +        return lastName;
> +    }
> +
> +    public void setLastName(String lastName) {
> +        this.lastName = lastName;
> +    }
> +
> +    public Date getDob() {
> +        return dob;
> +    }
> +
> +    public void setDob(Date dob) {
> +        this.dob = dob;
> +    }
> +
> +    public String getSex() {
> +        return sex;
> +    }
> +
> +    public void setSex(String sex) {
> +        this.sex = sex;
> +    }
> +
> +    public String getEmail() {
> +        return email;
> +    }
> +
> +    public void setEmail(String email) {
> +        this.email = email;
> +    }
> +
> +    public String getServiceLevel() {
> +        return serviceLevel;
> +    }
> +
> +    public void setServiceLevel(String serviceLevel) {
> +        this.serviceLevel = serviceLevel;
> +    }
> +
> +    public void validateEmail(FacesContext context, UIComponent toValidate,
> +            Object value) throws ValidatorException {
> +        String emailStr = (String) value;
> +        if (-1 == emailStr.indexOf("@")) {
> +            FacesMessage message = new FacesMessage("Invalid email address");
> +            throw new ValidatorException(message);
> +        }
> +    }
> +
> +    public String addConfirmedUser() {
> +        // This method would call a database or other service and add the
> +        // confirmed user information.
> +        // For now, we just place an informative message in request scope
> +        FacesMessage doneMessage =
> +                new FacesMessage("Successfully added new user");
> +        FacesContext.getCurrentInstance().addMessage(null, doneMessage);
> +        return "done";
> +    }
> +}
> +
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/main.xhtml
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/main.xhtml  (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/main.xhtml  (revision 0)
> @@ -0,0 +1,43 @@
> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> +<html xmlns="http://www.w3.org/1999/xhtml"
> +      xmlns:h="http://java.sun.com/jsf/html"
> +      xmlns:f="http://java.sun.com/jsf/core">
> +<h:head>
> +  <title>A Simple JavaServer Faces 2.0 View</title>
> +</h:head>
> +<h:body>
> +    <script type="text/javascript">
> +        //<![CDATA[
> +        var windowId = "";
> +        var callGetWindowId = function callGetWindowId() {
> +            windowId = jsf.getWindowId(document.forms[0]);
> +            var echoWindowId = document.getElementById("echoWindowId");
> +            echoWindowId.innerHTML = "<b>" + windowId + "</b>";
> +            return true;
> +        }
> +        //]]>
> +
> +    </script>
> +
> +
> +  <h:form prependId="false">
> +      First name: <h:inputText id="firstName" value="#{userBean.firstName}" /> Last name: #{userBean.lastName}
> +      <p><h:commandButton id="submitAjax" value="submitAjax" onclick="callGetWindowId()">
> +              <f:ajax execute="@form" render="echoPanel" />
> +          </h:commandButton>
> +
> +    </p>
> +      <p><h:commandButton id="submitNonAjax" value="submitNonAjax" /> </p>
> +
> +
> +    <h:panelGroup id="echoPanel">
> +
> +        |#{userBean.firstName}|
> +
> +    </h:panelGroup>
> +
> +      <p>|WindowId: <span id="echoWindowId" />|</p>
> +
> +  </h:form>
> +</h:body>
> +</html>
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF/beans.xml
> ===================================================================
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF/web.xml
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF/web.xml     (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/src/main/webapp/WEB-INF/web.xml     (revision 0)
> @@ -0,0 +1,37 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
> +    <display-name>mojarra-regression-test</display-name>
> +    <description>A simple regression test to make it easier to get your bug fixed. The only reason we need a web.xml is to set the PROJECT_STAGE to Develoment.  If you have a web.xml, then you need to map the FacesServlet.</description>
> +    <context-param>
> +        <description>
> +            Tell the runtime where we are in the project development
> +            lifecycle.  Valid values are:
> +            Development, UnitTest, SystemTest, or Production.
> +            The runtime will display helpful hints to correct common mistakes
> +            when the value is Development.
> +        </description>
> +        <param-name>javax.faces.PROJECT_STAGE</param-name>
> +        <param-value>Development</param-value>
> +    </context-param>
> +    <context-param>
> +        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
> +        <param-value>client</param-value>
> +    </context-param>
> +    <!-- Faces Servlet -->
> +    <context-param>
> +        <param-name>javax.faces.WINDOW_ID_MODE</param-name>
> +        <param-value>field</param-value>
> +    </context-param>
> +    <servlet>
> +        <servlet-name>Faces Servlet</servlet-name>
> +        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
> +        <load-on-startup>1</load-on-startup>
> +    </servlet>
> +    <servlet-mapping>
> +        <servlet-name>Faces Servlet</servlet-name>
> +        <url-pattern>/faces/*</url-pattern>
> +    </servlet-mapping>
> +    <welcome-file-list>
> +        <welcome-file>faces/main.xhtml</welcome-file>
> +    </welcome-file-list>
> +</web-app>
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/pom.xml
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/pom.xml     (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_war/pom.xml     (revision 0)
> @@ -0,0 +1,46 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
> +    <modelVersion>4.0.0</modelVersion>
> +
> +    <groupId>com.sun.faces</groupId>
> +    <artifactId>i_spec_949_war</artifactId>
> +    <version>1.0-SNAPSHOT</version>
> +    <packaging>war</packaging>
> +    <name>${project.artifactId}</name>
> +    <description>A simple project with war packaging that depends on JSF 2.1 and
> +        javaee 6, in that order.</description>
> +    <url>http://jsf-spec.java.net/</url>
> +    <build>
> +        <finalName>${project.artifactId}</finalName>
> +        <plugins>
> +            <plugin>
> +                <artifactId>maven-compiler-plugin</artifactId>
> +                <configuration>
> +                    <source>1.6</source>
> +                    <target>1.6</target>
> +                </configuration>
> +            </plugin>
> +            <plugin>
> +                <artifactId>maven-war-plugin</artifactId>
> +                <configuration>
> +                  <failOnMissingWebXml>false</failOnMissingWebXml>
> +                </configuration>
> +            </plugin>
> +
> +        </plugins>
> +    </build>
> +    <dependencies>
> +        <dependency>
> +            <groupId>javax.faces</groupId>
> +            <artifactId>javax.faces-api</artifactId>
> +            <version>2.2-SNAPSHOT</version>
> +            <scope>provided</scope>
> +        </dependency>
> +        <dependency>
> +            <groupId>javax</groupId>
> +            <artifactId>javaee-api</artifactId>
> +            <version>6.0</version>
> +            <scope>provided</scope>
> +        </dependency>
> +    </dependencies>
> +</project>
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces/test/i_spec_949_htmlunit/IssueSpec949TestCase.java
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces/test/i_spec_949_htmlunit/IssueSpec949TestCase.java (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/src/main/java/com/sun/faces/test/i_spec_949_htmlunit/IssueSpec949TestCase.java (revision 0)
> @@ -0,0 +1,114 @@
> +/*
> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> + *
> + * Copyright (c) 1997-2011 Oracle and/or its affiliates. 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_1_1.html
> + * or packager/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 packager/legal/LICENSE.txt.
> + *
> + * GPL Classpath Exception:
> + * Oracle designates this particular file as subject to the "Classpath"
> + * exception as provided by Oracle in the GPL Version 2 section of the License
> + * file that accompanied this code.
> + *
> + * Modifications:
> + * If applicable, add the following below the License Header, with the fields
> + * enclosed by brackets [] replaced by your own identifying information:
> + * "Portions Copyright [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 com.sun.faces.test.i_spec_949_htmlunit;
> +
> +import com.gargoylesoftware.htmlunit.BrowserVersion;
> +import com.gargoylesoftware.htmlunit.WebClient;
> +import com.gargoylesoftware.htmlunit.html.HtmlPage;
> +
> +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
> +import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
> +import com.sun.faces.htmlunit.HtmlUnitFacesTestCase;
> +import junit.framework.Test;
> +import junit.framework.TestSuite;
> +
> +
> +public class IssueSpec949TestCase extends HtmlUnitFacesTestCase {
> +
> +    public IssueSpec949TestCase(String name) {
> +        super(name);
> +    }
> +
> +
> +    /**
> +     * Return the tests included in this test suite.
> +     */
> +    public static Test suite() {
> +        return (new TestSuite(IssueSpec949TestCase.class));
> +    }
> +
> +
> +    // ------------------------------------------------------------ Test Methods
> +
> +    public void testWindowId() throws Exception {
> +        String windowId1, windowId2, window1Session, window2Session;
> +        windowId1 = doTestAndReturnWindowId(client, "window0");
> +        windowId2 = doTestAndReturnWindowId(client, "window1");
> +        assertNotSame(windowId1, windowId2);
> +        window1Session = windowId1.substring(0, windowId1.indexOf(':'));
> +        window2Session = windowId2.substring(0, windowId2.indexOf(':'));
> +        assertEquals(window1Session, window2Session);
> +
> +    }
> +
> +    public String doTestAndReturnWindowId(WebClient yourClient, String windowName) throws Exception {
> +        String windowId = null;
> +
> +        HtmlPage page = (HtmlPage) yourClient.openWindow(getURL("/"), windowName).getEnclosedPage();
> +        HtmlTextInput textField = (HtmlTextInput) page.getElementById("firstName");
> +        textField.setValueAttribute("ajaxFirstName");
> +
> +        HtmlSubmitInput button = (HtmlSubmitInput) page.getElementById("submitAjax");
> +        page = button.click();
> +        Thread.sleep(2000);
> +        String pageText = page.asText();
> +        assertTrue(pageText.contains("|ajaxFirstName|"));
> +
> +        final String windowIdLabel = "WindowId: ";
> +        int windowIdLabelIndex = pageText.indexOf(windowIdLabel);
> +        windowId = pageText.substring(windowIdLabelIndex + windowIdLabel.length());
> +
> +
> +        textField = (HtmlTextInput) page.getElementById("firstName");
> +        textField.setValueAttribute("nonAjaxFirstName");
> +
> +        button = (HtmlSubmitInput) page.getElementById("submitNonAjax");
> +        page = button.click();
> +        Thread.sleep(2000);
> +        pageText = page.asText();
> +        assertTrue(pageText.contains("|nonAjaxFirstName|"));
> +
> +        return windowId;
> +    }
> +
> +
> +
> +}
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/pom.xml
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/pom.xml        (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/i_spec_949_htmlunit/pom.xml        (revision 0)
> @@ -0,0 +1,97 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> +
> +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> +
> +    Copyright (c) 1997-2011 Oracle and/or its affiliates. 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_1_1.html
> +    or packager/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 packager/legal/LICENSE.txt.
> +
> +    GPL Classpath Exception:
> +    Oracle designates this particular file as subject to the "Classpath"
> +    exception as provided by Oracle in the GPL Version 2 section of the License
> +    file that accompanied this code.
> +
> +    Modifications:
> +    If applicable, add the following below the License Header, with the fields
> +    enclosed by brackets [] replaced by your own identifying information:
> +    "Portions Copyright [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.
> +
> +--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
> +   <modelVersion>4.0.0</modelVersion>
> +   <groupId>com.sun.faces</groupId>
> +   <artifactId>i_spec_949_htmlunit</artifactId>
> +   <packaging>jar</packaging>
> +   <name>i_spec_949_htmlunit</name>
> +   <version>1.0-SNAPSHOT</version>
> +
> +   <dependencies>
> +
> +      <dependency>
> +       <artifactId>htmlunit</artifactId>
> +       <groupId>net.sourceforge.htmlunit</groupId>
> +       <version>2.4</version>
> +         <scope>provided</scope>
> +      </dependency>
> +      <dependency>
> +         <groupId>junit</groupId>
> +         <artifactId>junit</artifactId>
> +         <version>3.8.1</version>
> +         <scope>provided</scope>
> +      </dependency>
> +      <dependency>
> +       <groupId>com.sun.faces.extensions</groupId>
> +       <artifactId>jsf-extensions-test-time</artifactId>
> +       <version>2.0</version>
> +       <scope>provided</scope>
> +      </dependency>
> +
> +   </dependencies>
> +
> +   <build>
> +      <plugins>
> +         <plugin>
> +            <groupId>org.apache.maven.plugins</groupId>
> +            <artifactId>maven-compiler-plugin</artifactId>
> +            <version>2.0.2</version>
> +            <configuration>
> +               <source>1.6</source>
> +               <target>1.6</target>
> +            </configuration>
> +         </plugin>
> +      </plugins>
> +      <finalName>i_jsf_xxxx_htmlunit</finalName>
> +   </build>
> +
> +   <repositories>
> +     <repository>
> +       <id>java.net</id>
> +       <name>java.net</name>
> +       <url>http://download.java.net/maven/2</url>
> +       <layout>default</layout>
> +     </repository>
> +   </repositories>
> +
> +</project>
> Index: jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/build.xml
> ===================================================================
> --- jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/build.xml  (revision 0)
> +++ jsf-test/JAVASERVERFACES_SPEC_PUBLIC-949/build.xml  (revision 0)
> @@ -0,0 +1,89 @@
> +<?xml version='1.0' encoding='UTF-8'?>
> +<!--
> +
> +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> +
> +    Copyright (c) 1997-2011 Oracle and/or its affiliates. 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_1_1.html
> +    or packager/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 packager/legal/LICENSE.txt.
> +
> +    GPL Classpath Exception:
> +    Oracle designates this particular file as subject to the "Classpath"
> +    exception as provided by Oracle in the GPL Version 2 section of the License
> +    file that accompanied this code.
> +
> +    Modifications:
> +    If applicable, add the following below the License Header, with the fields
> +    enclosed by brackets [] replaced by your own identifying information:
> +    "Portions Copyright [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.
> +
> +-->
> +<!-- ************ JSF build file ************************************** -->
> +<project name="JAVASERVERFACES-i_spec_949" default="test" basedir=".">
> +
> +    <property file="../../build.properties"/>
> +    <path id="i_spec_949.classpath">
> +        <path refid="html.classpath" />
> +        <pathelement location="${basedir}/i_spec_949_htmlunit/target/classes"/>
> +    </path>
> +
> +    <import file="${jsf.build.home}/common/ant/common.xml"/>
> +
> +    <target name="build">
> +        <jsf.mvn dir="${basedir}/i_spec_949_war" goals="install" />
> +        <jsf.mvn dir="${basedir}/i_spec_949_htmlunit" goals="install" />
> +    </target>
> +
> +    <target name="clean">
> +        <jsf.mvn dir="${basedir}/i_spec_949_htmlunit" goals="clean" />
> +        <jsf.mvn dir="${basedir}/i_spec_949_war" goals="clean" />
> +    </target>
> +
> +    <target name="install">
> +        <deploy.artifact
> +              artifact="${basedir}/i_spec_949_war/target/i_spec_949_war.war"
> +              appName="i_spec_949_war"/>
> +    </target>
> +
> +    <target name="remove">
> +        <undeploy.artifact
> +              artifact="${basedir}/i_spec_949_war/target/i_spec_949_war.war"
> +              appName="i_spec_949_war"/>
> +    </target>
> +
> +    <target name="test" depends="define.scenario.aware.port">
> +
> +        <jsf.junit context-path="/i_spec_949_war"
> +                 classpath-refid="i_spec_949.classpath"
> +                 test-results-dir="${regression.test.results.dir}">
> +            <tests>
> +                <fileset dir="${basedir}/i_spec_949_htmlunit/target/classes"
> +                     includes="com/sun/faces/test/i_spec_949_htmlunit/IssueSpec949TestCase.class"/>
> +            </tests>
> +        </jsf.junit>
> +
> +    </target>
> +
> +</project>
> Index: jsf-api/src/main/java/javax/faces/lifecycle/Lifecycle.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/lifecycle/Lifecycle.java  (revision 9730)
> +++ jsf-api/src/main/java/javax/faces/lifecycle/Lifecycle.java  (working copy)
> @@ -46,7 +46,7 @@
>
>
>  /**
> - * <p><strong>Lifecycle</strong> manages the
> + * <p><strong class="changed_modified_2_2">Lifecycle</strong> manages the
>  * processing of the entire lifecycle of a particular JavaServer Faces
>  * request.  It is responsible for executing all of the phases that have
>  * been defined by the JavaServer Faces Specification, in the specified
> @@ -97,6 +97,19 @@
>      *  is <code>null</code>
>      */
>     public abstract void execute(FacesContext context) throws FacesException;
> +
> +
> +    /**
> +     * <p class="changed_added_2_2">Create or restore the window to be
> +     * used to display the {_at_link javax.faces.component.UIViewRoot} for
> +     * this run through the lifecycle.</p>
> +     *
> +     *
> +     * @since 2.2
> +     */
> +
> +    public void attachWindow(FacesContext context) {
> +    }
>
>
>     /**
> Index: jsf-api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java   (revision 0)
> +++ jsf-api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java   (revision 0)
> @@ -0,0 +1,100 @@
> +/*
> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> + *
> + * Copyright (c) 1997-2012 Oracle and/or its affiliates. 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_1_1.html
> + * or packager/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 packager/legal/LICENSE.txt.
> + *
> + * GPL Classpath Exception:
> + * Oracle designates this particular file as subject to the "Classpath"
> + * exception as provided by Oracle in the GPL Version 2 section of the License
> + * file that accompanied this code.
> + *
> + * Modifications:
> + * If applicable, add the following below the License Header, with the fields
> + * enclosed by brackets [] replaced by your own identifying information:
> + * "Portions Copyright [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.lifecycle;
> +
> +import javax.faces.FacesException;
> +import javax.faces.FacesWrapper;
> +import javax.faces.context.FacesContext;
> +import javax.faces.event.PhaseListener;
> +
> +/**
> + * <p class="changed_added_2_2">Provides a simple implementation of
> + * {_at_link Lifecycle} that can be subclassed by developers wishing to
> + * provide specialized behavior to an existing {_at_link Lifecycle}
> + * instance.  The default implementation of all methods is to call
> + * through to the wrapped {_at_link Lifecycle}.</p>
> +
> + * <div class="changed_added_2_2">
> +
> + * <p>Usage: extend this class and override getWrapped() to return the
> + * instance we are wrapping.</p>
> +
> + * </div>
> +
> + * @since 2.2
> + */
> +
> +public abstract class LifecycleWrapper extends Lifecycle implements FacesWrapper<Lifecycle> {
> +
> +    public abstract Lifecycle getWrapped();
> +
> +    @Override
> +    public void attachWindow(FacesContext context) {
> +        getWrapped().attachWindow(context);
> +    }
> +
> +    @Override
> +    public void addPhaseListener(PhaseListener listener) {
> +        getWrapped().addPhaseListener(listener);
> +    }
> +
> +    @Override
> +    public void execute(FacesContext context) throws FacesException {
> +        getWrapped().execute(context);
> +    }
> +
> +    @Override
> +    public PhaseListener[] getPhaseListeners() {
> +        return getWrapped().getPhaseListeners();
> +    }
> +
> +    @Override
> +    public void removePhaseListener(PhaseListener listener) {
> +        getWrapped().removePhaseListener(listener);
> +    }
> +
> +    @Override
> +    public void render(FacesContext context) throws FacesException {
> +        getWrapped().render(context);
> +    }
> +
> +
> +}
> Index: jsf-api/src/main/java/javax/faces/lifecycle/ClientWindow.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/lifecycle/ClientWindow.java       (revision 0)
> +++ jsf-api/src/main/java/javax/faces/lifecycle/ClientWindow.java       (revision 0)
> @@ -0,0 +1,106 @@
> +/*
> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> + *
> + * Copyright (c) 1997-2012 Oracle and/or its affiliates. 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_1_1.html
> + * or packager/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 packager/legal/LICENSE.txt.
> + *
> + * GPL Classpath Exception:
> + * Oracle designates this particular file as subject to the "Classpath"
> + * exception as provided by Oracle in the GPL Version 2 section of the License
> + * file that accompanied this code.
> + *
> + * Modifications:
> + * If applicable, add the following below the License Header, with the fields
> + * enclosed by brackets [] replaced by your own identifying information:
> + * "Portions Copyright [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.lifecycle;
> +
> +import javax.faces.context.FacesContext;
> +
> +/**
> + * <p class="changed_added_2_2">This class represents a client window,
> + * which may be a browser tab, browser window, browser pop-up, portlet,
> + * or anything else that can display a {_at_link
> + * javax.faces.component.UIComponent} hierarchy rooted at a {_at_link
> + * javax.faces.component.UIViewRoot}.</p>
> + *
> + * <div class="changed_added_2_2">
> +
> + * <p>Lifetime</p>
> +
> + * <p>The lifetime of a <code>ClientWindow</code> starts on the first
> + * request made by a particular client window (or tab, or pop-up, etc)
> + * to the JSF runtime and persists as long as that window remains open.
> + * A client window is always associated with exactly one
> + * <code>UIViewRoot</code> instance at a time, but may display many
> + * different <code>UIViewRoot</code>s during its lifetime.</p>
> +
> + * <p>The generation of <code>ClientWindow</code> is controlled by the
> + * value of the <code>context-param</code> named by the value of {_at_link
> + * #WINDOW_ID_MODE_PARAM_NAME}.  If this <code>context-param</code> is
> + * not specified, or its value is "none", no <code>ClientWindow</code>
> + * instances will be generated, and the entire feature is effectively
> + * disabled.  For all other valid values of {_at_link
> + * #WINDOW_ID_MODE_PARAM_NAME}, the <code>ClientWindow</code> instance
> + * is associated with the incoming request during the {_at_link
> + * Lifecycle#attachWindow} method.  If the feature is enabled, this
> + * method will cause a new instance of <code>ClientWindow</code> to be
> + * created, assigned an id, and passed to {_at_link
> + * javax.faces.context.ExternalContext#setClientWindow}.</p>
> +
> + * <p>The <code>ClientWindow</code> is stored the response as specified
> + * in </p>
> +
> + * </div>
> + *
> + * @since 2.2
> + *
> + */
> +
> +public abstract class ClientWindow {
> +
> +    /**
> +     * <p class="changed_added_2_2">The context-param that controls the operation
> +     * of the <code>ClientWindow</code> feature.  Valid values are "none" and
> +     * "field", without the quotes.  If not specified, "none" is assumed.</p>
> +     *
> +     * @since 2.2
> +     */
> +    public static final String WINDOW_ID_MODE_PARAM_NAME =
> +          "javax.faces.WINDOW_ID_MODE";
> +
> +    /**
> +     *
> +     * @return
> +     */
> +
> +    public abstract String getId();
> +
> +    public abstract void decode(FacesContext context);
> +
> +}
> Index: jsf-api/src/main/java/javax/faces/lifecycle/package.html
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/lifecycle/package.html    (revision 9730)
> +++ jsf-api/src/main/java/javax/faces/lifecycle/package.html    (working copy)
> @@ -45,7 +45,7 @@
>  <title>Package Description for "javax.faces.lifecycle"</title>
>  </head>
>  <body bgcolor="white">
> -    <p><span class="changed_modified_2_0">Classes</span> and interfaces defining lifecycle management for the
> +    <p><span class="changed_modified_2_0 changed_modified_2_2">Classes</span> and interfaces defining lifecycle management for the
>  JavaServer Faces implementation.  The main class in this package is
>  {_at_link javax.faces.lifecycle.Lifecycle}.  <code>Lifecycle</code> is the
>  gateway to executing the request processing lifecycle.
> Index: jsf-api/src/main/java/javax/faces/webapp/FacesServlet.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/webapp/FacesServlet.java  (revision 9730)
> +++ jsf-api/src/main/java/javax/faces/webapp/FacesServlet.java  (working copy)
> @@ -506,8 +506,9 @@
>
>
>     /**
> -     * <p class="changed_modified_2_0">Process an incoming request, and create the
> -     * corresponding response according to the following
> +     * <p class="changed_modified_2_0"><span
> +     * class="changed_modified_2_2">Process</span> an incoming request,
> +     * and create the corresponding response according to the following
>      * specification.</p>
>      *
>      * <div class="changed_modified_2_0">
> @@ -550,9 +551,11 @@
>      * javax.faces.application.ResourceHandler#isResourceRequest}.  If
>      * this returns <code>true</code> call {_at_link
>      * javax.faces.application.ResourceHandler#handleResourceRequest}.
> -     * If this returns <code>false</code>, call {_at_link
> -     * javax.faces.lifecycle.Lifecycle#execute} followed by {_at_link
> -     * javax.faces.lifecycle.Lifecycle#render}.  If a {_at_link
> +     * If this returns <code>false</code>, <span
> +     * class="changed_added_2_2">call {_at_link
> +     * javax.faces.lifecycle.Lifecycle#attachWindow} followed by </span>
> +     * {_at_link javax.faces.lifecycle.Lifecycle#execute} followed by
> +     * {_at_link javax.faces.lifecycle.Lifecycle#render}.  If a {_at_link
>      * javax.faces.FacesException} is thrown in either case, extract the
>      * cause from the <code>FacesException</code>.  If the cause is
>      * <code>null</code> extract the message from the
> @@ -633,6 +636,7 @@
>             if (handler.isResourceRequest(context)) {
>                 handler.handleResourceRequest(context);
>             } else {
> +                lifecycle.attachWindow(context);
>                 lifecycle.execute(context);
>                 lifecycle.render(context);
>             }
> Index: jsf-api/src/main/java/javax/faces/render/ResponseStateManager.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/render/ResponseStateManager.java  (revision 9730)
> +++ jsf-api/src/main/java/javax/faces/render/ResponseStateManager.java  (working copy)
> @@ -103,6 +103,14 @@
>     public static final String VIEW_STATE_PARAM = "javax.faces.ViewState";
>
>     /**
> +     * <p class="changed_added_2_2">The name of the request parameter that
> +     * refers to the encoded WindowId.</p>
> +     *
> +     */
> +
> +    public static final String WINDOW_ID_PARAM = "javax.faces.WindowId";
> +
> +    /**
>      * <p class="changed_added_2_2">The value of this constant is taken
>      * to be the name of a request parameter whose value is inspected
>      * to verify the safety of an incoming non-postback request with respect
> @@ -116,7 +124,7 @@
>             "javax.faces.Token";
>
>     /**
> -     * <p><span class=" class="changed_modified_2_2"">Take</span> the argument
> +     * <p><span class="changed_modified_2_2"">Take</span> the argument
>      * <code>state</code> and write it into the
>      * output using the current {_at_link ResponseWriter}, which must be
>      * correctly positioned already.</p>
> @@ -164,6 +172,14 @@
>      * an instance of <code>SerializedView</code> and
>      * stores the state as the treeStructure, and passes it to {_at_link
>      * #writeState(javax.faces.context.FacesContext,javax.faces.application.StateManager.SerializedView)}.</p>
> +     *
> +     * <p class="changed_added_2_2">The {_at_link javax.faces.lifecycle.ClientWindow}
> +     * must be written using these
> +     * steps.  Call {_at_link javax.faces.context.ExternalContext#getClientWindow}.
> +     * If the result is <code>null</code>, take no further action regarding
> +     * the <code>ClientWindow</code>.  If the result is non-<code>null</code>,
> +     * write a hidden field whose name is {_at_link #WINDOW_ID_PARAM} and whose
> +     * id </p>
>      *
>      *
>      * @since 1.2
> Index: jsf-api/src/main/java/javax/faces/context/ExternalContext.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/context/ExternalContext.java      (revision 9730)
> +++ jsf-api/src/main/java/javax/faces/context/ExternalContext.java      (working copy)
> @@ -56,6 +56,7 @@
>  import java.net.URL;
>  import java.security.Principal;
>  import java.util.*;
> +import javax.faces.lifecycle.ClientWindow;
>
>
>  /**
> @@ -1338,6 +1339,37 @@
>      *  created if there is no session associated with the current request
>      */
>     public abstract Object getSession(boolean create);
> +
> +    /**
> +     * <p class="changed_added_2_2">Return the id of the current session
> +     * or the empty string if no session has been created and the
> +     * <code>create</code> parameter is <code>false</code>.</p>
> +     *
> +     * <div class="changed_added_2_2">
> +     *
> +     * <p><em>Servlet:</em> If <code>create</code> is true, obtain
> +     * a reference to the <code>HttpSession</code> for the current request
> +     * (creating the session if necessary) and return its id.  If
> +     * <code>create</code> is <code>false</code>, obtain a reference to the
> +     * current session, if one exists, and return its id.  If no session exists,
> +     * return the empty string.</p>
> +     *
> +     * </div>
> +     *
> +     * @since 2.2
> +     *
> +     * @param create Flag indicating whether or not a new session should be
> +     *  created if there is no session associated with the current request
> +     */
> +    public String getSessionId(boolean create) {
> +        String result = "";
> +        if (defaultExternalContext != null) {
> +            result = defaultExternalContext.getSessionId(create);
> +        } else {
> +            throw new UnsupportedOperationException();
> +        }
> +        return result;
> +    }
>
>     /**
>      * <p class="changed_added_2_1">Returns the maximum time interval, in seconds, that
> @@ -1419,6 +1451,24 @@
>      *
>      */
>     public abstract Principal getUserPrincipal();
> +
> +
> +    /**
> +     * <p class="changed_added_2_2">Return the {_at_link ClientWindow} set in a preceding
> +     * call to {_at_link #setClientWindow}, or <code>null</code> if no such call has
> +     * been made.</p>
> +     *
> +     * @since 2.2
> +     *
> +     */
> +    public ClientWindow getClientWindow() {
> +        if (defaultExternalContext != null) {
> +            return defaultExternalContext.getClientWindow();
> +        } else {
> +            throw new UnsupportedOperationException();
> +        }
> +
> +    }
>
>
>     /**
> @@ -1799,6 +1849,23 @@
>         }
>
>     }
> +
> +    /**
> +     * <p class="changed_added_2_2">Associate this instance with a {_at_link ClientWindow}.</p>
> +     *
> +     * @param window the window with which this instance is associated.
> +     *
> +     * @since 2.2
> +     */
> +
> +    public void setClientWindow(ClientWindow window) {
> +        if (defaultExternalContext != null) {
> +            defaultExternalContext.setClientWindow(window);
> +        } else {
> +            throw new UnsupportedOperationException();
> +        }
> +
> +    }
>
>     /**
>      * <p class="changed_added_2_0">Flushes the buffered response content to the
> Index: jsf-api/src/main/java/javax/faces/context/ExternalContextWrapper.java
> ===================================================================
> --- jsf-api/src/main/java/javax/faces/context/ExternalContextWrapper.java       (revision 9730)
> +++ jsf-api/src/main/java/javax/faces/context/ExternalContextWrapper.java       (working copy)
> @@ -51,6 +51,7 @@
>  import java.security.Principal;
>
>  import javax.faces.FacesWrapper;
> +import javax.faces.lifecycle.ClientWindow;
>
>  /**
>  * <p class="changed_added_2_0"><span class="changed_modified_2_2">Provides</span>
> @@ -418,6 +419,20 @@
>     }
>
>     /**
> +     * <p class="changed_added_2_2">The default behavior of this method is to
> +     * call {_at_link ExternalContext#getSessionId(boolean)}
> +     * on the wrapped {_at_link ExternalContext} object.</p>
> +     *
> +     * @since 2.2
> +     *
> +     * @see javax.faces.context.ExternalContext#getSessionId(boolean)
> +     */
> +    @Override
> +    public String getSessionId(boolean create) {
> +        return getWrapped().getSessionId(create);
> +    }
> +
> +    /**
>      * <p>The default behavior of this method is to
>      * call {_at_link ExternalContext#getSessionMap()}
>      * on the wrapped {_at_link ExternalContext} object.</p>
> @@ -451,7 +466,24 @@
>     public void setSessionMaxInactiveInterval(int interval) {
>         getWrapped().setSessionMaxInactiveInterval(interval);
>     }
> +
> +    /**
> +     * <p class="changed_added_2_2">The default behavior of this method is to
> +     * call {_at_link ExternalContext#setClientWindow}
> +     * on the wrapped {_at_link ExternalContext} object.</p>
> +     *
> +     * @since 2.2
> +     *
> +     * @param window the window associated with this request.
> +     */
>
> +    @Override
> +    public void setClientWindow(ClientWindow window) {
> +        getWrapped().setClientWindow(window);
> +    }
> +
> +
> +
>     /**
>      * <p>The default behavior of this method is to
>      * call {_at_link ExternalContext#getUserPrincipal}
> @@ -464,6 +496,20 @@
>     }
>
>     /**
> +     * <p class="changed_added_2_2">The default behavior of this method is to
> +     * call {_at_link ExternalContext#getClientWindow}
> +     * on the wrapped {_at_link ExternalContext} object.</p>
> +     *
> +     * @since 2.2
> +     *
> +     * @see javax.faces.context.ExternalContext#getClientWindow()
> +     */
> +    @Override
> +    public ClientWindow getClientWindow() {
> +        return getWrapped().getClientWindow();
> +    }
> +
> +    /**
>      * <p>The default behavior of this method is to
>      * call {_at_link ExternalContext#isUserInRole(String)}
>      * on the wrapped {_at_link ExternalContext} object.</p>
> Index: jsf-api/src/main/resources/jsf.js
> ===================================================================
> --- jsf-api/src/main/resources/jsf.js   (revision 9730)
> +++ jsf-api/src/main/resources/jsf.js   (working copy)
> @@ -804,13 +804,15 @@
>          * @ignore
>          */
>         var doUpdate = function doUpdate(element, context, partialResponseId) {
> -            var id, content, markup, state;
> -            var stateForm;
> +            var id, content, markup, state, windowId;
> +            var stateForm, windowIdForm;
>             var scripts = []; // temp holding value for array of script nodes
>
>             id = element.getAttribute('id');
>             var viewStateRegex = new RegExp("javax.faces.ViewState" +
>                                             jsf.separatorchar + ".*$");
> +            var windowIdRegex = new RegExp("javax.faces.WindowId" +
> +                                            jsf.separatorchar + ".*$");
>             if (id.match(viewStateRegex)) {
>
>                 state = element.firstChild;
> @@ -857,6 +859,52 @@
>                     }
>                 }
>                 return;
> +            } else if (id.match(windowIdRegex)) {
> +
> +                windowId = element.firstChild;
> +
> +                // Now set the windowId from the server into the DOM
> +                // but only for the form that submitted the request.
> +
> +                windowIdForm = document.getElementById(context.formid);
> +                if (!windowIdForm || !windowIdForm.elements) {
> +                    // if the form went away for some reason, or it lacks elements
> +                    // we're going to just return silently.
> +                    return;
> +                }
> +                var field = windowIdForm.elements["javax.faces.WindowId"];
> +                if (typeof field == 'undefined') {
> +                    field = document.createElement("input");
> +                    field.type = "hidden";
> +                    field.name = "javax.faces.WindowId";
> +                    windowIdForm.appendChild(field);
> +                }
> +                field.value = windowId.nodeValue;
> +
> +                // Now set the windowId from the server into the DOM
> +                // for any form that is a render target.
> +
> +                if (typeof context.render !== 'undefined' && context.render !== null) {
> +                    var temp = context.render.split(' ');
> +                    for (var i = 0; i < temp.length; i++) {
> +                        if (temp.hasOwnProperty(i)) {
> +                            // See if the element is a form and
> +                            // the form is not the one that caused the submission..
> +                            var f = document.forms[temp[i]];
> +                            if (typeof f !== 'undefined' && f !== null && f.id !== context.formid) {
> +                                field = f.elements["javax.faces.WindowId"];
> +                                if (typeof field === 'undefined') {
> +                                    field = document.createElement("input");
> +                                    field.type = "hidden";
> +                                    field.name = "javax.faces.WindowId";
> +                                    f.appendChild(field);
> +                                }
> +                                field.value = windowId.nodeValue;
> +                            }
> +                        }
> +                    }
> +                }
> +                return;
>             }
>
>             // join the CDATA sections in the markup
> @@ -1913,7 +1961,8 @@
>
>             },
>             /**
> -             * <p>Receive an Ajax response from the server.
> +             * <p><span class="changed_modified_2_2">Receive</span> an Ajax response
> +             * from the server.
>              * <p><b>Usage:</b></p>
>              * <pre><code>
>              * jsf.ajax.response(request, context);
> @@ -1948,15 +1997,57 @@
>              * &lt;/update&gt;</code></pre>
>              * Update the entire DOM replacing the appropriate <code>head</code> and/or
>              * <code>body</code> sections with the content from the response.</li>
> -             * <li>If an <code>update</code> element is found in the response with the identifier
> +
> +             * <li class="changed_modified_2_2">If an
> +             * <code>update</code> element is found in the response with
> +             * an identifier containing
>              * <code>javax.faces.ViewState</code>:
> -             * <pre><code>&lt;update id="javax.faces.ViewState"&gt;
> +
> +             * <pre><code>&lt;update id="&lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt;&lt;SEP&gt;javax.faces.ViewState&lt;SEP&gt;&lt;UNIQUE_PER_VIEW_NUMBER&gt;"&gt;
>              *    &lt;![CDATA[...]]&gt;
>              * &lt;/update&gt;</code></pre>
> -             * locate and update the submitting form's <code>javax.faces.ViewState</code> value
> -             * with the <code>CDATA</code> contents from the response.  Locate and update the
> -             * <code>javax.faces.ViewState</code> value for all forms specified in the
> -             * <code>render</code> target list.</li>
> +
> +             * locate and update the submitting form's
> +             * <code>javax.faces.ViewState</code> value with the
> +             * <code>CDATA</code> contents from the response.
> +             * &lt;SEP&gt: is the currently configured
> +             * <code>UINamingContainer.getSeparatorChar()</code>.
> +             * &lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt; is the return from
> +             * <code>UIViewRoot.getContainerClientId()</code> on the
> +             * view from whence this state originated.
> +             * &lt;UNIQUE_PER_VIEW_NUMBER&gt; is a number that must be
> +             * unique within this view, but must not be included in the
> +             * view state.  This requirement is simply to satisfy XML
> +             * correctness in parity with what is done in the
> +             * corresponding non-partial JSF view.  Locate and update
> +             * the <code>javax.faces.ViewState</code> value for all
> +             * forms specified in the <code>render</code> target
> +             * list.</li>
> +
> +             * <li class="changed_added_2_2">If an
> +             * <code>update</code> element is found in the response with
> +             * an identifier containing
> +             * <code>javax.faces.WindowId</code>:
> +
> +             * <pre><code>&lt;update id="javax.faces.WindowId&lt;SEP&gt;&lt;UNIQUE_PER_VIEW_NUMBER&gt;"&gt;
> +             *    &lt;![CDATA[...]]&gt;
> +             * &lt;/update&gt;</code></pre>
> +
> +             * locate and update the submitting form's
> +             * <code>javax.faces.WindowId</code> value with the
> +             * <code>CDATA</code> contents from the response.
> +             * &lt;SEP&gt: is the currently configured
> +             * <code>UINamingContainer.getSeparatorChar()</code>.
> +             * &lt;UNIQUE_PER_VIEW_NUMBER&gt; is a number that must be
> +             * unique within this view, but must not be included in the
> +             * view state.  This requirement is simply to satisfy XML
> +             * correctness in parity with what is done in the
> +             * corresponding non-partial JSF view.  Locate and update
> +             * the <code>javax.faces.WindowId</code> value for all
> +             * forms specified in the <code>render</code> target
> +             * list.</li>
> +
> +
>              * <li>If an <code>update</code> element is found in the response with the identifier
>              * <code>javax.faces.ViewHead</code>:
>              * <pre><code>&lt;update id="javax.faces.ViewHead"&gt;
> @@ -2285,6 +2376,28 @@
>     };
>
>     /**
> +     * <p class="changed_added_2_2">Return the windowId of the window
> +     * in which the argument form is rendered.</p>
> +
> +     * @param form The <code>form</code> element whose contained
> +     * <code>input</code> controls will be collected and encoded.
> +     * Only successful controls will be collected and encoded in
> +     * accordance with: <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2">
> +     * Section 17.13.2 of the HTML Specification</a>.
> +     *
> +     * @returns String The windowId of the current window, or null
> +     *  if the windowId cannot be determined.
> +     * @function jsf.getViewState
> +     */
> +    jsf.getWindowId = function(form) {
> +        var field = form.elements["javax.faces.WindowId"];
> +        if (!(typeof field == 'undefined')) {
> +            return field.value;
> +        }
> +    }
> +
> +
> +    /**
>      * The namespace for JavaServer Faces JavaScript utilities.
>      * @name jsf.util
>      * @namespace
> @@ -2332,7 +2445,7 @@
>
>     /**
>      * <p class="changed_added_2_2">The result of calling
> -     * <code>UINamingContainer.getNamingContainerSeparatorChar().</p>
> +     * <code>UINamingContainer.getNamingContainerSeparatorChar().</code></p>
>      */
>     jsf.separatorchar = '#{facesContext.namingContainerSeparatorChar}';
>
>
> --
> | edward.burns_at_oracle.com | office: +1 407 458 0017
> | homepage:               | http://ridingthecrest.com/