myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lu4...@apache.org
Subject svn commit: r1766172 [1/2] - in /myfaces/core/branches/2.3.x: api/src/main/java/javax/faces/application/ api/src/main/java/javax/faces/context/ api/src/main/java/javax/faces/event/ api/src/main/java/javax/faces/push/ impl/src/main/java/org/apache/myfac...
Date Sat, 22 Oct 2016 03:15:34 GMT
Author: lu4242
Date: Sat Oct 22 03:15:34 2016
New Revision: 1766172

URL: http://svn.apache.org/viewvc?rev=1766172&view=rev
Log:
MYFACES-4069 Implement f:websocket and related api (not final, pending javascript)

Added:
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/event/WebsocketEvent.java
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/Push.java
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/PushContext.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/AbstractWebsocketComponent.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/EndpointImpl.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/HtmlBufferResponseWriterWrapper.java
      - copied, changed from r1743285, myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/HtmlBufferResponseWriterWrapper.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketComponentRenderer.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketConfigurator.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketFacesInit.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketInitRenderer.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketSessionClusterSerializedRestore.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/_WebsocketInit.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/CsrfSessionTokenFactory.java
      - copied, changed from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/CsrfSessionTokenFactory.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextCDIExtension.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextFactoryBean.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextImpl.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/RandomCsrfSessionTokenFactory.java
      - copied, changed from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/RandomCsrfSessionTokenFactory.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SecureRandomCsrfSessionTokenFactory.java
      - copied, changed from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SecureRandomCsrfSessionTokenFactory.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SessionIdGenerator.java
      - copied, changed from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SessionIdGenerator.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketApplicationBean.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketApplicationSessionHolder.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketChannel.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketChannelMetadata.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketChannelTokenBuilderBean.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketSessionBean.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/WebsocketViewBean.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/util/
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/util/Json.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/WebsocketHandler.java
    myfaces/core/branches/2.3.x/impl/src/main/resources/META-INF/licenses/omnifaces-LICENSE.txt
Modified:
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/application/ViewHandler.java
    myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/context/ExternalContext.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/util/CDIUtils.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextImpl.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java
    myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java
    myfaces/core/branches/2.3.x/impl/src/main/resources/META-INF/NOTICE.txt
    myfaces/core/branches/2.3.x/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension

Modified: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/application/ViewHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/application/ViewHandler.java?rev=1766172&r1=1766171&r2=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/application/ViewHandler.java (original)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/application/ViewHandler.java Sat Oct 22 03:15:34 2016
@@ -407,4 +407,26 @@ public abstract class ViewHandler
         Set<String> set = Collections.emptySet();
         return Collections.unmodifiableSet(set);
     }
+
+    /**
+     * Indicates the port used for websocket connections.
+     */
+    @JSFWebConfigParam(since = "2.3")
+    public static final java.lang.String WEBSOCKET_PORT = "javax.faces.WEBSOCKET_PORT";
+    
+    /**
+     * Return a JSF URL that represents a websocket connection for the passed channel and channelToken
+     * 
+     * @since 2.3
+     * @param context
+     * @param channel
+     * @param channelToken
+     * @return 
+     */
+    public String getWebsocketURL(FacesContext context, String channel, String channelToken)
+    {
+        String url = context.getExternalContext().getRequestContextPath() + 
+                "/javax.faces.push/"+channel+"?"+channelToken;
+        return url;
+    }
 }

Modified: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/context/ExternalContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/context/ExternalContext.java?rev=1766172&r1=1766171&r2=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/context/ExternalContext.java (original)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/context/ExternalContext.java Sat Oct 22 03:15:34 2016
@@ -805,4 +805,21 @@ public abstract class ExternalContext
         
         return ctx.getApplicationContextPath();
     }
+    
+    /**
+     * 
+     * @param url
+     * @return 
+     */
+    public String encodeWebsocketURL(String url)
+    {
+        ExternalContext ctx = _MyFacesExternalContextHelper.firstInstance.get();
+        
+        if (ctx == null)
+        {
+            throw new UnsupportedOperationException();
+        }
+        
+        return ctx.encodeWebsocketURL(url);
+    }
 }

Added: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/event/WebsocketEvent.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/event/WebsocketEvent.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/event/WebsocketEvent.java (added)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/event/WebsocketEvent.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.faces.event;
+
+import java.io.Serializable;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Objects;
+import javax.inject.Qualifier;
+import javax.websocket.CloseReason;
+
+/**
+ *
+ */
+public class WebsocketEvent implements Serializable
+{
+   
+    private String channel;
+    private Serializable user;
+    private CloseReason.CloseCode code;
+    
+    public WebsocketEvent(String channel, Serializable user, CloseReason.CloseCode code)
+    {
+        this.channel = channel;
+        this.user = user;
+        this.code = code;
+    }
+
+    public String getChannel()
+    {
+        return channel;
+    }
+
+    public Serializable getUser()
+    {
+        return user;
+    }
+
+    public CloseReason.CloseCode getCode()
+    {
+        return code;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 3;
+        hash = 23 * hash + Objects.hashCode(this.channel);
+        hash = 23 * hash + Objects.hashCode(this.user);
+        hash = 23 * hash + Objects.hashCode(this.code);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final WebsocketEvent other = (WebsocketEvent) obj;
+        if (!Objects.equals(this.channel, other.channel))
+        {
+            return false;
+        }
+        if (!Objects.equals(this.user, other.user))
+        {
+            return false;
+        }
+        if (!Objects.equals(this.code, other.code))
+        {
+            return false;
+        }
+        return true;
+    }
+    
+    @Override
+    public String toString()
+    {
+        return "WebsocketEvent{" + "channel=" + channel + ", user=" + user + ", code=" + code + '}';
+    }
+    
+    @Qualifier
+    @Target(ElementType.PARAMETER)
+    @Retention(RetentionPolicy.RUNTIME)
+    @Documented
+    public static @interface Opened 
+    {
+    }
+
+    @Qualifier
+    @Target(ElementType.PARAMETER)
+    @Retention(RetentionPolicy.RUNTIME)
+    @Documented
+    public static @interface Closed 
+    {
+    }
+}

Added: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/Push.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/Push.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/Push.java (added)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/Push.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.faces.push;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.enterprise.util.Nonbinding;
+import javax.inject.Qualifier;
+
+/**
+ *
+ */
+@Qualifier
+@Retention(value=RetentionPolicy.RUNTIME)
+@Target(value={ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
+public @interface Push
+{
+    public @Nonbinding String channel() default "";
+}

Added: myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/PushContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/PushContext.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/PushContext.java (added)
+++ myfaces/core/branches/2.3.x/api/src/main/java/javax/faces/push/PushContext.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package javax.faces.push;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+/**
+ *
+ */
+public interface PushContext extends Serializable
+{
+    
+    public static final String ENABLE_WEBSOCKET_ENDPOINT_PARAM_NAME = "javax.faces.ENABLE_WEBSOCKET_ENDPOINT";
+    
+    public static final String URI_PREFIX = "/javax.faces.push";
+    
+    public Set<Future<Void>> send(Object message);
+            
+    public <S extends Serializable> Set<Future<Void>> send(Object message, S user);  
+    
+    public <S extends Serializable> Map<S, Set<Future<Void>>> send(Object message, Collection<S> users);
+}

Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/util/CDIUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/util/CDIUtils.java?rev=1766172&r1=1766171&r2=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/util/CDIUtils.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/util/CDIUtils.java Sat Oct 22 03:15:34 2016
@@ -18,13 +18,19 @@
  */
 package org.apache.myfaces.cdi.util;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
+import java.util.Collections;
 import java.util.Set;
+import javax.enterprise.context.ContextNotActiveException;
+import javax.enterprise.context.SessionScoped;
+import javax.enterprise.context.spi.Context;
 
 import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.faces.context.ExternalContext;
+import javax.faces.view.ViewScoped;
 import org.apache.myfaces.webapp.AbstractFacesInitializer;
 
 /**
@@ -60,4 +66,104 @@ public class CDIUtils
         return dao;
 
     }
+    
+    /**
+     * {@inheritDoc}
+     *
+     * @see Beans#resolve(Class, Annotation...)
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Bean<T> resolve(BeanManager beanManager, Class<T> beanClass, Annotation... qualifiers)
+    {
+        Set<Bean<?>> beans = beanManager.getBeans(beanClass, qualifiers);
+
+        for (Bean<?> bean : beans)
+        {
+            if (bean.getBeanClass() == beanClass)
+            {
+                return (Bean<T>) beanManager.resolve(Collections.<Bean<?>>singleton(bean));
+            }
+        }
+
+        return (Bean<T>) beanManager.resolve(beans);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see Beans#getInstance(Class, boolean, Annotation...)
+     */
+    public static <T> T getInstance(BeanManager beanManager, Class<T> beanClass, 
+            boolean create, Annotation... qualifiers)
+    {
+        try
+        {
+            Bean<T> bean = resolve(beanManager, beanClass, qualifiers);
+            return (bean != null) ? getInstance(beanManager, bean, create) : null;
+        }
+        catch (ContextNotActiveException e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see Beans#getInstance(Bean, boolean)
+     */
+    public static <T> T getInstance(BeanManager beanManager, Bean<T> bean, boolean create)
+    {
+        Context context = beanManager.getContext(bean.getScope());
+
+        if (create)
+        {
+            return context.get(bean, beanManager.createCreationalContext(bean));
+        }
+        else
+        {
+            return context.get(bean);
+        }
+    }
+    
+    public static boolean isSessionScopeActive(BeanManager beanManager)
+    {
+        try 
+        {
+            Context ctx = beanManager.getContext(SessionScoped.class);
+            return ctx != null;
+        }
+        catch (ContextNotActiveException ex)
+        {
+            //No op
+        }
+        catch (Exception ex)
+        {
+            // Sometimes on startup time, since there is no active request context, trying to grab session scope
+            // throws NullPointerException.
+            //No op
+        }
+        return false;
+    }
+    
+    public static boolean isViewScopeActive(BeanManager beanManager)
+    {
+        try 
+        {
+            Context ctx = beanManager.getContext(ViewScoped.class);
+            return ctx != null;
+        }
+        catch (ContextNotActiveException ex)
+        {
+            //No op
+        }
+        catch (Exception ex)
+        {
+            // Sometimes on startup time, since there is no active request context, trying to grab session scope
+            // throws NullPointerException.
+            //No op
+        }
+        return false;
+    }
+        
 }
\ No newline at end of file

Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextImpl.java?rev=1766172&r1=1766171&r2=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextImpl.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextImpl.java Sat Oct 22 03:15:34 2016
@@ -125,7 +125,15 @@ public class ViewScopeContextImpl implem
     public boolean isActive()
     {
         FacesContext facesContext = FacesContext.getCurrentInstance();
-        return facesContext.getViewRoot() != null;
+        if (facesContext != null)
+        {
+            return facesContext.getViewRoot() != null;
+        }
+        else
+        {
+            // No FacesContext means no view scope active.
+            return false;
+        }
     }
 
     public <T> T get(Contextual<T> bean)

Modified: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java?rev=1766172&r1=1766171&r2=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java Sat Oct 22 03:15:34 2016
@@ -22,6 +22,8 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.security.Principal;
@@ -35,6 +37,7 @@ import java.util.logging.Logger;
 
 import javax.faces.FacesException;
 import javax.faces.FactoryFinder;
+import javax.faces.application.ViewHandler;
 import javax.faces.context.FacesContext;
 import javax.faces.context.Flash;
 import javax.faces.context.FlashFactory;
@@ -52,6 +55,7 @@ import javax.servlet.http.HttpServletRes
 import javax.servlet.http.HttpSession;
 
 import org.apache.myfaces.shared.context.flash.FlashImpl;
+import org.apache.myfaces.shared.util.WebConfigParamUtils;
 import org.apache.myfaces.util.EnumerationIterator;
 
 /**
@@ -386,6 +390,36 @@ public final class ServletExternalContex
     }
 
     @Override
+    public String encodeWebsocketURL(String baseUrl)
+    {
+        Integer port = WebConfigParamUtils.getIntegerInitParameter(
+                _currentFacesContext.getExternalContext(), ViewHandler.WEBSOCKET_PORT);
+        port = (port == 0) ? null : port;
+        if (port != null && 
+            !port.equals(_currentFacesContext.getExternalContext().getRequestServerPort()))
+        {
+            String scheme = _currentFacesContext.getExternalContext().getRequestScheme();
+            String serverName = _currentFacesContext.getExternalContext().getRequestServerName();
+            String url;
+            try
+            {
+                url = new URL(scheme, serverName, port, baseUrl).toExternalForm();
+                url = url.replaceFirst("http", "ws");
+                return ((HttpServletResponse) _servletResponse).encodeURL(url);
+            }
+            catch (MalformedURLException ex)
+            {
+                //If cannot build the url, return the base one unchanged
+                return baseUrl;
+            }
+        }
+        else
+        {
+            return baseUrl;
+        }
+    }
+
+    @Override
     public void dispatch(final String requestURI) throws IOException, FacesException
     {
         RequestDispatcher requestDispatcher = _servletRequest.getRequestDispatcher(requestURI);

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/AbstractWebsocketComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/AbstractWebsocketComponent.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/AbstractWebsocketComponent.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/AbstractWebsocketComponent.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push;
+
+import java.util.Collection;
+import java.util.Iterator;
+import javax.faces.component.UIOutput;
+import javax.faces.component.behavior.ClientBehaviorHolder;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
+
+/**
+ * This component hold f:websocket client behavior and other properties.
+ */
+@JSFComponent(
+        clazz = "org.apache.myfaces.push.WebsocketComponent",
+        family = "javax.faces.Output",
+        type = "org.apache.myfaces.WebsocketComponent",
+        defaultRendererType="org.apache.myfaces.WebsocketComponent")
+public abstract class AbstractWebsocketComponent extends UIOutput implements ClientBehaviorHolder
+{
+    
+    @JSFProperty
+    public abstract String getChannel();
+    
+    @JSFProperty
+    public abstract String getScope();
+    
+    @JSFProperty
+    public abstract String getUser();
+    
+    @JSFProperty
+    public abstract String getOnopen();
+    
+    @JSFProperty
+    public abstract String getOnmessage();
+    
+    @JSFProperty
+    public abstract String getOnclose();
+    
+    @JSFProperty(defaultValue = "true")
+    public abstract boolean isConnected();
+
+    /**
+     * Return the id used by the component used to render the markup at the end of body section.
+     * 
+     * @return 
+     */
+    @JSFProperty(tagExcluded = true)
+    public abstract String getInitComponentId();
+
+    @Override
+    public Collection<String> getEventNames()
+    {
+        return new Collection<String>(){
+
+            @Override
+            public int size()
+            {
+                return 0;
+            }
+
+            @Override
+            public boolean isEmpty()
+            {
+                return false;
+            }
+
+            @Override
+            public boolean contains(Object o)
+            {
+                return true;
+            }
+
+            @Override
+            public Iterator<String> iterator()
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public Object[] toArray()
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public <T> T[] toArray(T[] a)
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public boolean add(String e)
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public boolean remove(Object o)
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public boolean containsAll(Collection<?> c)
+            {
+                return true;
+            }
+
+            @Override
+            public boolean addAll(Collection<? extends String> c)
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public boolean removeAll(Collection<?> c)
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public boolean retainAll(Collection<?> c)
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public void clear()
+            {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+        };
+    }
+    
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/EndpointImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/EndpointImpl.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/EndpointImpl.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/EndpointImpl.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.push;
+
+import org.apache.myfaces.push.cdi.WebsocketApplicationSessionHolder;
+import java.io.IOException;
+import java.io.Serializable;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.CDI;
+import javax.enterprise.util.AnnotationLiteral;
+import javax.faces.event.WebsocketEvent;
+import javax.faces.event.WebsocketEvent.Closed;
+import javax.faces.event.WebsocketEvent.Opened;
+import javax.websocket.CloseReason;
+import javax.websocket.CloseReason.CloseCodes;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.Session;
+
+/**
+ *
+ */
+public class EndpointImpl extends Endpoint
+{
+
+    public static final String JAVAX_FACES_PUSH_PATH = "/javax.faces.push/{channel}";
+
+    public static final String PUSH_CHANNEL_PARAMETER = "channel";
+    
+    private static final AnnotationLiteral<Opened> OPENED = 
+            new AnnotationLiteral<Opened>() 
+            {
+                private static final long serialVersionUID = 2789324L;
+            };
+    private static final AnnotationLiteral<Closed> CLOSED = 
+            new AnnotationLiteral<Closed>() 
+            {
+                private static final long serialVersionUID = 38450203L;
+            };
+
+    @Override
+    public void onOpen(Session session, EndpointConfig config)
+    {
+        // Get the channel and the channel id
+        String channel = session.getPathParameters().get(PUSH_CHANNEL_PARAMETER);
+        String channelToken = session.getQueryString();
+
+        // Locate holder
+        // Note in this point there is no session scope because there is no HttpSession available,
+        // but on the handshake there is. So, everything below should use CDI application scoped
+        // beans only.
+
+        if (Boolean.TRUE.equals(session.getUserProperties().get(WebsocketConfigurator.WEBSOCKET_VALID)) &&
+                WebsocketApplicationSessionHolder.addOrUpdateSession(channelToken, session))
+        {
+            session.setMaxIdleTimeout((Long) config.getUserProperties().getOrDefault(
+                    WebsocketConfigurator.MAX_IDLE_TIMEOUT, 300000L));
+
+            Serializable user = (Serializable) session.getUserProperties().get(WebsocketConfigurator.WEBSOCKET_USER);
+
+            BeanManager beanManager = CDI.current().getBeanManager();
+            beanManager.fireEvent(new WebsocketEvent(channel, user, null), OPENED);
+            
+            session.getUserProperties().put(
+                    WebsocketSessionClusterSerializedRestore.WEBSOCKET_SESSION_SERIALIZED_RESTORE, 
+                    new WebsocketSessionClusterSerializedRestore(channelToken));
+        }
+        else
+        {
+            try
+            {
+                session.close(new CloseReason(CloseCodes.UNEXPECTED_CONDITION,
+                        "Websocket connection not registered in current session"));
+            }
+            catch (IOException ex)
+            {
+                onError(session, ex);
+            }
+        }
+    }
+
+    @Override
+    public void onClose(Session session, CloseReason closeReason)
+    {
+        // Get the channel and the channel id
+        String channel = session.getPathParameters().get(PUSH_CHANNEL_PARAMETER);
+        String channelToken = session.getQueryString();
+
+        Serializable user = (Serializable) session.getUserProperties().get(WebsocketConfigurator.WEBSOCKET_USER);
+
+        // In this point in some cases (close reason 1006) CDI does not work and you cannot lookup application
+        // scope beans, because the context could not be properly initialized. In that case we should try to
+        // propagate the event but if an error happens, just ensure the Session is properly disposed.
+        try
+        {
+            BeanManager beanManager = CDI.current().getBeanManager();
+            beanManager.fireEvent(
+                    new WebsocketEvent(channel, user, closeReason.getCloseCode()),  CLOSED);
+        }
+        catch(Exception e)
+        {
+            //No op because it is expected something could go wrong.
+        }
+        finally
+        {
+            WebsocketApplicationSessionHolder.removeSession(channelToken);
+        }
+    }
+
+    @Override
+    public void onError(Session session, Throwable ex)
+    {
+        if (session.isOpen())
+        {
+            session.getUserProperties().put(Throwable.class.getName(), ex);
+        }
+    }
+}
\ No newline at end of file

Copied: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/HtmlBufferResponseWriterWrapper.java (from r1743285, myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/HtmlBufferResponseWriterWrapper.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/HtmlBufferResponseWriterWrapper.java?p2=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/HtmlBufferResponseWriterWrapper.java&p1=myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/HtmlBufferResponseWriterWrapper.java&r1=1743285&r2=1766172&rev=1766172&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/HtmlBufferResponseWriterWrapper.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/HtmlBufferResponseWriterWrapper.java Sat Oct 22 03:15:34 2016
@@ -16,19 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.renderkit.html.util;
+package org.apache.myfaces.push;
 
-import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlResponseWriterImpl;
 
 import javax.faces.context.ResponseWriter;
 import java.io.*;
+import org.apache.myfaces.shared.renderkit.html.HtmlResponseWriterImpl;
 
 /**A buffer for content which should not directly be rendered to the page.
  *
  * @author Sylvain Vieujot (latest modification by $Author: grantsmith $)
  * @version $Revision: 169649 $ $Date: 2005-05-11 17:47:12 +0200 (Wed, 11 May 2005) $
  */
-public class HtmlBufferResponseWriterWrapper extends HtmlResponseWriterImpl {
+public class HtmlBufferResponseWriterWrapper extends HtmlResponseWriterImpl
+{
 
     /**
      * Buffer writer to write content to and buffer it.
@@ -58,7 +59,8 @@ public class HtmlBufferResponseWriterWra
 
     /**Create an instance of the HtmlBufferResponseWriterWrapper
      *
-     * @param initialWriter The writer the content should have originally gone to, this will only be used to copy settings.
+     * @param initialWriter The writer the content should have originally gone to, this will only be used 
+     *        to copy settings.
      * @return A properly initialized writer which stores the output in a buffer; writer is wrapped.
      */
     static public HtmlBufferResponseWriterWrapper getInstance(ResponseWriter initialWriter)
@@ -72,11 +74,13 @@ public class HtmlBufferResponseWriterWra
 
     /**Constructor for the HtmlBufferResponseWriterWrapper.
      *
-     * @param initialWriter The writer the content should have originally gone to, this will only be used to copy settings.
+     * @param initialWriter The writer the content should have originally gone to, this will only be used 
+     * to copy settings.
      * @param bufferWriter A buffer to store content to.
      * @param wrapperWriter A wrapper around the buffer.
      */
-    private HtmlBufferResponseWriterWrapper(ResponseWriter initialWriter, StringWriter bufferWriter, PrintWriter wrapperWriter)
+    private HtmlBufferResponseWriterWrapper(ResponseWriter initialWriter, StringWriter bufferWriter,
+            PrintWriter wrapperWriter)
     {
         super(wrapperWriter, (initialWriter == null) ? null : initialWriter.getContentType(),
                 (initialWriter == null) ? null : initialWriter.getCharacterEncoding());

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketComponentRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketComponentRenderer.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketComponentRenderer.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketComponentRenderer.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.push;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.faces.component.UIComponent;
+import javax.faces.component.behavior.ClientBehavior;
+import javax.faces.component.behavior.ClientBehaviorContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.event.ListenerFor;
+import javax.faces.event.PostAddToViewEvent;
+import javax.faces.render.Renderer;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFRenderer;
+import org.apache.myfaces.cdi.util.CDIUtils;
+import org.apache.myfaces.push.cdi.WebsocketApplicationBean;
+import org.apache.myfaces.push.cdi.WebsocketChannelMetadata;
+import org.apache.myfaces.push.cdi.WebsocketChannelTokenBuilderBean;
+import org.apache.myfaces.push.cdi.WebsocketSessionBean;
+import org.apache.myfaces.push.cdi.WebsocketViewBean;
+import org.apache.myfaces.shared.renderkit.html.HTML;
+
+/**
+ *
+ */
+@JSFRenderer(
+        renderKitId = "HTML_BASIC",
+        family = "javax.faces.Output",
+        type = "org.apache.myfaces.WebsocketComponent")
+@ListenerFor(systemEventClass = PostAddToViewEvent.class)
+public class WebsocketComponentRenderer extends Renderer implements ComponentSystemEventListener
+{
+
+    @Override
+    public void processEvent(ComponentSystemEvent event)
+    {
+        if (event instanceof PostAddToViewEvent)
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance();
+            WebsocketComponent component = (WebsocketComponent) event.getComponent();
+            WebsocketInit initComponent = (WebsocketInit) facesContext.getViewRoot().findComponent(
+                    component.getInitComponentId());
+            if (initComponent == null)
+            {
+                initComponent = (WebsocketInit) facesContext.getApplication().createComponent(facesContext,
+                        "org.apache.myfaces.WebsocketInit", "org.apache.myfaces.WebsocketInit");
+                initComponent.setId(component.getInitComponentId());
+                facesContext.getViewRoot().addComponentResource(facesContext,
+                        initComponent, "body");
+            }
+        }
+    }
+
+    private HtmlBufferResponseWriterWrapper getResponseWriter(FacesContext context)
+    {
+        return HtmlBufferResponseWriterWrapper.getInstance(context.getResponseWriter());
+    }
+
+    public void encodeBegin(FacesContext facesContext, UIComponent component) throws IOException
+    {
+        ResponseWriter writer = facesContext.getResponseWriter();
+
+        // Render the tag that will be embedded into the DOM tree that helps to detect if the message
+        // must be processed or not and if the connection must be closed.
+        writer.startElement(HTML.DIV_ELEM, component);
+        writer.writeAttribute(HTML.ID_ATTR, component.getClientId() ,null);
+        writer.writeAttribute(HTML.STYLE_ATTR, "display:none", null);
+        writer.endElement(HTML.DIV_ELEM);
+        
+        if (!facesContext.getPartialViewContext().isAjaxRequest())
+        {
+            facesContext.setResponseWriter(getResponseWriter(facesContext));
+        }
+    }
+
+    @Override
+    public void encodeEnd(FacesContext facesContext, UIComponent c) throws IOException
+    {
+        super.encodeEnd(facesContext, c); //check for NP
+
+        WebsocketComponent component = (WebsocketComponent) c;
+
+        WebsocketInit init = (WebsocketInit) facesContext.getViewRoot().findComponent(
+                component.getInitComponentId());
+
+        ResponseWriter writer = facesContext.getResponseWriter();
+
+        //Only the first time it is required a session id.
+        if (component.getValue() == null)
+        {
+            String channel = component.getChannel();
+
+            // TODO: use a single bean and entry point for this algorithm.
+            BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
+
+            WebsocketChannelTokenBuilderBean channelTokenBean = CDIUtils.lookup(
+                    beanManager,
+                    WebsocketChannelTokenBuilderBean.class);
+
+            // This bean is required because you always need to register the token, so it can be properly destroyed
+            WebsocketViewBean viewTokenBean = CDIUtils.lookup(
+                    beanManager,
+                    WebsocketViewBean.class);
+            WebsocketSessionBean sessionTokenBean = CDIUtils.lookup(
+                    beanManager, WebsocketSessionBean.class);
+
+            // Create channel token 
+            // TODO: Use ResponseStateManager to create the token
+            String scope = component.getScope() == null ? "application" : component.getScope();
+            WebsocketChannelMetadata metadata = new WebsocketChannelMetadata(
+                    channel, scope, component.getUser(), component.isConnected());
+
+            String channelToken = null;
+            // Force a new channelToken if "connected" property is set to false, because in that case websocket
+            // creation 
+            if (!component.isConnected())
+            {
+                channelToken = viewTokenBean.getChannelToken(metadata);
+            }
+            if (channelToken == null)
+            {
+                // No channel token found for that combination, create a new token for this view
+                channelToken = channelTokenBean.createChannelToken(facesContext, channel);
+                
+                // Register the channel into the bean that will manage the Session instance used to do the push
+                component.setValue(channelToken);
+                
+                // Register channel in view scope to chain discard view algorithm using @PreDestroy
+                viewTokenBean.registerToken(channelToken, metadata);
+                
+                // Register channel in session scope to allow validation on handshake ( WebsocketConfigurator )
+                sessionTokenBean.registerToken(channelToken, metadata);
+            }
+
+            // Ask these two scopes 
+            WebsocketApplicationBean appTokenBean = CDIUtils.getInstance(
+                    beanManager, WebsocketApplicationBean.class, false);
+
+            // Register token and metadata in the proper bean
+            if (scope.equals("view"))
+            {
+                viewTokenBean.registerWebsocketSession(channelToken, metadata);
+            }
+            else if (scope.equals("session"))
+            {
+                sessionTokenBean = (sessionTokenBean != null) ? sessionTokenBean : CDIUtils.lookup(
+                        CDIUtils.getBeanManager(facesContext.getExternalContext()),
+                        WebsocketSessionBean.class);
+
+                sessionTokenBean.registerWebsocketSession(channelToken, metadata);
+            }
+            else
+            {
+                //Default application
+                appTokenBean = (appTokenBean != null) ? appTokenBean : CDIUtils.lookup(
+                        CDIUtils.getBeanManager(facesContext.getExternalContext()),
+                        WebsocketApplicationBean.class);
+
+                appTokenBean.registerWebsocketSession(channelToken, metadata);
+            }
+        }
+
+        writer.startElement(HTML.SCRIPT_ELEM, component);
+        writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
+
+        StringBuilder sb = new StringBuilder(50);
+        sb.append("jsf.push.init(");
+        sb.append("'"+component.getClientId()+"'");
+        sb.append(",");
+        sb.append("'"+facesContext.getExternalContext().encodeWebsocketURL(
+                facesContext.getApplication().getViewHandler().getWebsocketURL(
+                        facesContext, component.getChannel(), (String) component.getValue()))+"'");
+        sb.append(",");
+        sb.append(component.getOnopen());
+        sb.append(",");
+        sb.append(component.getOnmessage());
+        sb.append(",");
+        sb.append(component.getOnclose());
+        sb.append(",");
+        sb.append(getBehaviorScripts(facesContext, component));
+        sb.append(",");
+        sb.append(component.isConnected());
+        sb.append(");");
+
+        writer.write(sb.toString());
+
+        writer.endElement(HTML.SCRIPT_ELEM);
+        
+        if (!facesContext.getPartialViewContext().isAjaxRequest())
+        {
+            HtmlBufferResponseWriterWrapper buffwriter = (HtmlBufferResponseWriterWrapper) 
+                    facesContext.getResponseWriter();
+            init.getWebsocketComponentMarkupList().add(writer.toString());
+            facesContext.setResponseWriter(buffwriter.getInitialWriter());
+        }
+    }
+    
+    private String getBehaviorScripts(FacesContext facesContext, WebsocketComponent component)
+    {
+        Map<String, List<ClientBehavior>> clientBehaviorsByEvent = component.getClientBehaviors();
+
+        if (clientBehaviorsByEvent.isEmpty())
+        {
+            return "{}";
+        }
+
+        String clientId = component.getClientId(facesContext);
+        StringBuilder scripts = new StringBuilder("{");
+
+        for (Entry<String, List<ClientBehavior>> entry : clientBehaviorsByEvent.entrySet())
+        {
+            String event = entry.getKey();
+            List<ClientBehavior> clientBehaviors = entry.getValue();
+            scripts.append(scripts.length() > 1 ? "," : "").append(event).append(":[");
+
+            for (int i = 0; i < clientBehaviors.size(); i++)
+            {
+                scripts.append(i > 0 ? "," : "").append("function(event){");
+                scripts.append(clientBehaviors.get(i).getScript(
+                        ClientBehaviorContext.createClientBehaviorContext(
+                                facesContext, component, event, clientId, null)));
+                scripts.append("}");
+            }
+
+            scripts.append("]");
+        }
+
+        return scripts.append("}").toString();
+    }
+        
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketConfigurator.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketConfigurator.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketConfigurator.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.push;
+
+import java.io.Serializable;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.CDI;
+import javax.faces.context.ExternalContext;
+import javax.websocket.HandshakeResponse;
+import javax.websocket.server.HandshakeRequest;
+import javax.websocket.server.ServerEndpointConfig;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.cdi.util.CDIUtils;
+import org.apache.myfaces.push.cdi.WebsocketSessionBean;
+import org.apache.myfaces.shared.util.WebConfigParamUtils;
+
+/**
+ *
+ */
+public class WebsocketConfigurator extends ServerEndpointConfig.Configurator
+{
+    @JSFWebConfigParam(defaultValue = "300000")
+    public static final String INIT_PARAM_WEBSOCKET_MAX_IDLE_TIMEOUT = "org.apache.myfaces.WEBSOCKET_MAX_IDLE_TIMEOUT";
+    
+    public static final String MAX_IDLE_TIMEOUT = "oam.websocket.maxIdleTimeout";
+    
+    public static final String WEBSOCKET_VALID = "oam.websocket.valid";
+    
+    public static final String WEBSOCKET_USER = "oam.websocket.user";
+    
+    private final Long maxIdleTimeout;
+    
+    public WebsocketConfigurator(ExternalContext context)
+    {
+        this.maxIdleTimeout = WebConfigParamUtils.getLongInitParameter(context, 
+                INIT_PARAM_WEBSOCKET_MAX_IDLE_TIMEOUT);
+    }
+
+    @Override
+    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
+    {
+        if (this.maxIdleTimeout != null)
+        {
+            sec.getUserProperties().put(MAX_IDLE_TIMEOUT, this.maxIdleTimeout);
+        }
+        
+        String channelToken = request.getQueryString();
+        if (channelToken == null)
+        {
+            String uri = request.getRequestURI().toString();
+            if (uri.indexOf('?') >= 0)
+            {
+                channelToken = uri.substring(uri.indexOf('?')+1);
+            }
+            else
+            {
+                channelToken = uri.substring(uri.lastIndexOf('/')+1);
+            }
+        }
+        
+        BeanManager beanManager = CDI.current().getBeanManager();
+        WebsocketSessionBean websocketSessionBean = CDIUtils.getInstance(
+                beanManager, WebsocketSessionBean.class, false);
+        
+        if (websocketSessionBean != null)
+        {
+            Serializable user = websocketSessionBean.getUserFromChannelToken(channelToken);
+            if (user != null)
+            {
+                sec.getUserProperties().put(WEBSOCKET_USER, user);
+            }
+
+            sec.getUserProperties().put(WEBSOCKET_VALID, websocketSessionBean.isTokenValid(channelToken));
+        }
+        else
+        {
+            // Cannot validate session, mark as invalid
+            sec.getUserProperties().put(WEBSOCKET_VALID, false);
+        }
+    }
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketFacesInit.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketFacesInit.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketFacesInit.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketFacesInit.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push;
+
+import org.apache.myfaces.push.cdi.WebsocketApplicationSessionHolder;
+import javax.faces.context.ExternalContext;
+
+/**
+ * Class to decouple websocket initialization steps and avoid load unwanted websocket API 
+ * into AbstractFacesInitializer
+ * 
+ */
+public class WebsocketFacesInit
+{
+    
+    public static void initWebsocketSessionLRUCache(ExternalContext context)
+    {
+        WebsocketApplicationSessionHolder.initWebsocketSessionLRUCache(context);
+        
+    }
+    
+    public static void clearWebsocketSessionLRUCache(ExternalContext context)
+    {
+        WebsocketApplicationSessionHolder.clearWebsocketSessionLRUCache();
+    }
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketInitRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketInitRenderer.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketInitRenderer.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketInitRenderer.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push;
+
+import java.io.IOException;
+import java.util.Iterator;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.Renderer;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFRenderer;
+
+/**
+ *
+ */
+@JSFRenderer(
+    renderKitId = "HTML_BASIC",
+    family = "javax.faces.Output",
+    type = "org.apache.myfaces.WebsocketInit")
+public class WebsocketInitRenderer extends Renderer
+{
+
+    @Override
+    public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException
+    {
+        super.encodeEnd(facesContext, component); //check for NP
+        WebsocketInit init = (WebsocketInit) component;
+  
+        ResponseWriter writer = facesContext.getResponseWriter();
+        // If two websocket share the same channel and scope, share init.
+        for (Iterator it = init.getWebsocketComponentMarkupList().iterator(); it.hasNext();)
+        {
+            String markup = (String) it.next();
+            writer.write(markup);
+        }
+    }
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketSessionClusterSerializedRestore.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketSessionClusterSerializedRestore.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketSessionClusterSerializedRestore.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/WebsocketSessionClusterSerializedRestore.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.myfaces.push.cdi.WebsocketApplicationSessionHolder;
+
+/**
+ * This class ensures the Session instance is properly registered into WebsocketApplicationSessionHolder in case
+ * of serialization/deserialization roundtrip.
+ * 
+ */
+public class WebsocketSessionClusterSerializedRestore implements Externalizable
+{
+    public final static String WEBSOCKET_SESSION_SERIALIZED_RESTORE = "oam.websocket.SR";
+    
+    private String channelToken;
+    
+    private boolean deserialized = false;
+
+    public WebsocketSessionClusterSerializedRestore()
+    {
+    }
+
+    public WebsocketSessionClusterSerializedRestore(String channelToken)
+    {
+        this.channelToken = channelToken;
+    }
+
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException
+    {
+        out.writeUTF(this.channelToken);
+        
+    }
+
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+    {
+        this.channelToken = in.readUTF();
+        this.deserialized = true;
+        WebsocketApplicationSessionHolder.getRestoredQueue().add(this.channelToken);
+    }
+
+    /**
+     * @return the channelToken
+     */
+    public String getChannelToken()
+    {
+        return channelToken;
+    }
+
+    /**
+     * @param channelToken the channelToken to set
+     */
+    public void setChannelToken(String channelToken)
+    {
+        this.channelToken = channelToken;
+    }
+
+    /**
+     * @return the deserialized
+     */
+    public boolean isDeserialized()
+    {
+        return deserialized;
+    }
+    
+}
\ No newline at end of file

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/_WebsocketInit.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/_WebsocketInit.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/_WebsocketInit.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/_WebsocketInit.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push;
+
+import java.util.List;
+import javax.faces.component.UIOutput;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
+
+/**
+ * This component is the one that render the initialization at the end of body section.
+ * 
+ * The idea is it works like a buffer that collects all markup generated by 
+ * WebsocketComponent and then render it at the end of body section. In that way it 
+ * is possible to preserve the context and ensure the script is called when the page
+ * is loaded.
+ */
+@JSFComponent(template=true,
+        clazz = "org.apache.myfaces.push.WebsocketInit",
+        family = "javax.faces.Output",
+        type = "org.apache.myfaces.WebsocketInit",
+        defaultRendererType="org.apache.myfaces.WebsocketInit")
+public abstract class _WebsocketInit extends UIOutput
+{
+    /**
+     * List that stores the rendered markup of previous WebsocketComponent instances.
+     */
+    private transient List<String> websocketComponentMarkupList = new java.util.ArrayList<String>();
+    
+    public List<String> getWebsocketComponentMarkupList()
+    {
+        return websocketComponentMarkupList;
+    }
+}
\ No newline at end of file

Copied: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/CsrfSessionTokenFactory.java (from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/CsrfSessionTokenFactory.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/CsrfSessionTokenFactory.java?p2=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/CsrfSessionTokenFactory.java&p1=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/CsrfSessionTokenFactory.java&r1=1757774&r2=1766172&rev=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/CsrfSessionTokenFactory.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/CsrfSessionTokenFactory.java Sat Oct 22 03:15:34 2016
@@ -16,14 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.application.viewstate;
+package org.apache.myfaces.push.cdi;
 
 import javax.faces.context.FacesContext;
 
 /**
  *
- * @since 2.2
- * @author Leonardo Uribe
  */
 abstract class CsrfSessionTokenFactory
 {

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextCDIExtension.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextCDIExtension.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextCDIExtension.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextCDIExtension.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push.cdi;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessProducer;
+import javax.enterprise.inject.spi.Producer;
+import javax.faces.push.Push;
+import javax.faces.push.PushContext;
+
+/**
+ *
+ */
+public class PushContextCDIExtension implements Extension
+{
+    private List<Producer<PushContext>> pushContextProducers = new ArrayList<Producer<PushContext>>();
+
+    public List<Producer<PushContext>> getPushContextProducers()
+    {
+        return pushContextProducers;
+    }
+
+    void beforeBeanDiscovery(
+        @Observes final BeforeBeanDiscovery event, BeanManager beanManager)
+    {
+        // Register FlowBuilderFactoryBean as a bean with CDI annotations, so the system
+        // can take it into account, and use it later when necessary.
+        AnnotatedType<PushContextFactoryBean> pushContextFactoryBean =
+                        beanManager.createAnnotatedType(PushContextFactoryBean.class);
+        event.addAnnotatedType(pushContextFactoryBean);
+        
+        AnnotatedType wcbean = beanManager.createAnnotatedType(WebsocketChannelTokenBuilderBean.class);
+        event.addAnnotatedType(wcbean);        
+        
+        AnnotatedType sessionhandlerbean = beanManager.createAnnotatedType(WebsocketSessionBean.class);
+        event.addAnnotatedType(sessionhandlerbean);
+
+        AnnotatedType viewTokenBean = beanManager.createAnnotatedType(WebsocketViewBean.class);
+        event.addAnnotatedType(viewTokenBean);
+
+        AnnotatedType apphandlerbean = beanManager.createAnnotatedType(WebsocketApplicationBean.class);
+        event.addAnnotatedType(apphandlerbean);
+    }
+
+    /**
+     * Stores any producer method that is annotated with @Push
+     */
+    <T> void findFlowDefinition(@Observes ProcessProducer<T, PushContext> processProducer)
+    {
+        if (processProducer.getAnnotatedMember().isAnnotationPresent(Push.class))
+        {
+            pushContextProducers.add(processProducer.getProducer());
+        }
+    }
+
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextFactoryBean.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextFactoryBean.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextFactoryBean.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextFactoryBean.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.push.cdi;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Disposes;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.faces.push.Push;
+import javax.faces.push.PushContext;
+import javax.inject.Named;
+
+/**
+ *
+ */
+@Named(PushContextFactoryBean.PUSH_CONTEXT_FACTORY_BEAN_NAME)
+@ApplicationScoped
+public class PushContextFactoryBean
+{
+
+    protected static final String PUSH_CONTEXT_FACTORY_BEAN_NAME
+            = "oam_PUSH_CONTEXT_FACTORY_BEAN_NAME";
+    
+    @Produces
+    @Push
+    public PushContext createPushContext(InjectionPoint ip)
+    {
+        Push push = ip.getAnnotated().getAnnotation(Push.class);
+        String channel = push.channel().isEmpty() ? ip.getMember().getName() : push.channel();
+        return new PushContextImpl(channel);
+    }
+    
+    public void close(@Disposes PushContext context) 
+    {
+    }
+}

Added: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextImpl.java?rev=1766172&view=auto
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextImpl.java (added)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/PushContextImpl.java Sat Oct 22 03:15:34 2016
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.push.cdi;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.CDI;
+import javax.faces.FacesException;
+import javax.faces.context.FacesContext;
+import javax.faces.push.PushContext;
+import org.apache.myfaces.cdi.util.CDIUtils;
+
+/**
+ *
+ */
+public class PushContextImpl implements PushContext
+{
+    
+    private final String channel;
+
+    public PushContextImpl(String channel)
+    {
+        this.channel = channel;
+    }
+
+    /**
+     * @return the channel
+     */
+    public String getChannel()
+    {
+        return channel;
+    }
+
+    @Override
+    public Set<Future<Void>> send(Object message)
+    {
+        //1. locate the channel and define the context
+        String channel = getChannel();
+        BeanManager beanManager = null;
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        if (facesContext != null)
+        {
+            beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
+        }
+        else
+        {
+            beanManager = CDI.current().getBeanManager();
+        }
+        
+        WebsocketApplicationBean appTokenBean = CDIUtils.getInstance(beanManager, 
+                WebsocketApplicationBean.class, false);
+        WebsocketViewBean viewTokenBean = null;
+        WebsocketSessionBean sessionTokenBean = null;
+        
+        if (CDIUtils.isSessionScopeActive(beanManager))
+        {
+            sessionTokenBean = CDIUtils.getInstance(beanManager, WebsocketSessionBean.class, false);
+            if (CDIUtils.isViewScopeActive(beanManager))
+            {
+                viewTokenBean = CDIUtils.getInstance(beanManager, WebsocketViewBean.class, false);
+            }
+        }
+        
+        if (appTokenBean == null)
+        {
+            // No base bean to push message
+            return Collections.emptySet();
+        }
+        
+        List<String> channelTokens = null;
+        String scope = "application";
+        
+        if (viewTokenBean != null && viewTokenBean.isChannelAvailable(channel))
+        {
+            // Use view scope for context
+            channelTokens = viewTokenBean.getChannelTokensFor(channel);
+            scope = "view";
+        }
+        else if (sessionTokenBean != null && sessionTokenBean.isChannelAvailable(getChannel()))
+        {
+            // Use session scope for context
+            channelTokens = sessionTokenBean.getChannelTokensFor(channel);
+            scope = "session";
+        }
+        else if (appTokenBean != null && appTokenBean.isChannelAvailable(getChannel()))
+        {
+            // Use application scope for context
+            channelTokens = appTokenBean.getChannelTokensFor(channel);
+            scope = "application";
+        }
+        else
+        {
+            throw new FacesException("CDI bean not found for push message");
+        }
+        
+        //2. send the message
+        
+        if (channelTokens != null && !channelTokens.isEmpty())
+        {
+            Set<Future<Void>> result = null;
+            for (String channelToken : channelTokens)
+            {
+                if (result == null)
+                {
+                    result = WebsocketApplicationSessionHolder.send(channelToken, message);
+                }
+                else
+                {
+                    result.addAll(WebsocketApplicationSessionHolder.send(channelToken, message));
+                }
+            }
+            return result;
+        }
+        
+        return Collections.emptySet();
+    }
+
+    @Override
+    public <S extends Serializable> Set<Future<Void>> send(Object message, S user)
+    {
+        return send(message, Collections.singleton(user)).get(user);
+    }
+
+    @Override
+    public <S extends Serializable> Map<S, Set<Future<Void>>> send(Object message, Collection<S> users)
+    {
+        //1. locate the channel and define the context
+        String channel = getChannel();
+        BeanManager beanManager = null;
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        if (facesContext != null)
+        {
+            beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
+        }
+        else
+        {
+            beanManager = CDI.current().getBeanManager();
+        }
+        
+        WebsocketApplicationBean appTokenBean = CDIUtils.getInstance(beanManager, 
+                WebsocketApplicationBean.class, false);
+        WebsocketViewBean viewTokenBean = null;
+        WebsocketSessionBean sessionTokenBean = null;
+        
+        if (CDIUtils.isSessionScopeActive(beanManager))
+        {
+            sessionTokenBean = CDIUtils.getInstance(beanManager, WebsocketSessionBean.class, false);
+            if (CDIUtils.isViewScopeActive(beanManager))
+            {
+                viewTokenBean = CDIUtils.getInstance(beanManager, WebsocketViewBean.class, false);
+            }
+        }
+        
+        if (appTokenBean == null)
+        {
+            // No base bean to push message
+            return Collections.emptyMap();
+        }
+        
+        String scope = "application";
+        Map<S, Set<Future<Void>>> result = new HashMap<S, Set<Future<Void>>>();
+        
+        if (viewTokenBean != null && viewTokenBean.isChannelAvailable(channel))
+        {
+            // Use view scope for context
+            scope = "view";
+            for (S user : users)
+            {
+                result.put(user, send(viewTokenBean.getChannelTokensFor(channel, user), message));
+            }
+        }
+        else if (sessionTokenBean != null && sessionTokenBean.isChannelAvailable(getChannel()))
+        {
+            // Use session scope for context
+            scope = "session";
+            for (S user : users)
+            {
+                result.put(user, send(sessionTokenBean.getChannelTokensFor(channel, user), message));
+            }
+        }
+        else if (appTokenBean != null && appTokenBean.isChannelAvailable(getChannel()))
+        {
+            // Use application scope for context
+            scope = "application";
+            for (S user : users)
+            {
+                result.put(user, send(appTokenBean.getChannelTokensFor(channel, user), message));
+            }
+        }
+        else
+        {
+            throw new FacesException("CDI bean not found for push message");
+        }
+        
+        //2. send the message
+        return result;
+    }
+    
+    private Set<Future<Void>> send(
+            List<String> channelTokens, Object message)
+    {
+        if (channelTokens != null && !channelTokens.isEmpty())
+        {
+            Set<Future<Void>> result = null;
+            for (String channelToken : channelTokens)
+            {
+                if (result == null)
+                {
+                    result = WebsocketApplicationSessionHolder.send(channelToken, message);
+                }
+                else
+                {
+                    result.addAll(WebsocketApplicationSessionHolder.send(channelToken, message));
+                }
+            }
+            return result;
+        }
+        return Collections.emptySet();
+    }
+}

Copied: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/RandomCsrfSessionTokenFactory.java (from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/RandomCsrfSessionTokenFactory.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/RandomCsrfSessionTokenFactory.java?p2=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/RandomCsrfSessionTokenFactory.java&p1=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/RandomCsrfSessionTokenFactory.java&r1=1757774&r2=1766172&rev=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/RandomCsrfSessionTokenFactory.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/RandomCsrfSessionTokenFactory.java Sat Oct 22 03:15:34 2016
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.application.viewstate;
+package org.apache.myfaces.push.cdi;
 
 import java.util.Map;
 import java.util.Random;
@@ -29,7 +29,6 @@ import org.apache.myfaces.shared.util.We
 
 /**
  * @since 2.2
- * @author Leonardo Uribe
  */
 class RandomCsrfSessionTokenFactory extends CsrfSessionTokenFactory
 {

Copied: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SecureRandomCsrfSessionTokenFactory.java (from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SecureRandomCsrfSessionTokenFactory.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SecureRandomCsrfSessionTokenFactory.java?p2=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SecureRandomCsrfSessionTokenFactory.java&p1=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SecureRandomCsrfSessionTokenFactory.java&r1=1757774&r2=1766172&rev=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SecureRandomCsrfSessionTokenFactory.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SecureRandomCsrfSessionTokenFactory.java Sat Oct 22 03:15:34 2016
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.application.viewstate;
+package org.apache.myfaces.push.cdi;
 
 import javax.faces.context.FacesContext;
 import org.apache.commons.codec.binary.Hex;
@@ -29,7 +29,6 @@ import org.apache.myfaces.shared.util.We
  * session token.
  * 
  * @since 2.2
- * @author Leonardo Uribe
  */
 class SecureRandomCsrfSessionTokenFactory extends CsrfSessionTokenFactory
 {

Copied: myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SessionIdGenerator.java (from r1757774, myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SessionIdGenerator.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SessionIdGenerator.java?p2=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SessionIdGenerator.java&p1=myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SessionIdGenerator.java&r1=1757774&r2=1766172&rev=1766172&view=diff
==============================================================================
--- myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/application/viewstate/SessionIdGenerator.java (original)
+++ myfaces/core/branches/2.3.x/impl/src/main/java/org/apache/myfaces/push/cdi/SessionIdGenerator.java Sat Oct 22 03:15:34 2016
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.application.viewstate;
+package org.apache.myfaces.push.cdi;
 
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;



Mime
View raw message