You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2021/03/05 17:17:12 UTC

[myfaces] branch master updated: refactored CDI contexts (flow still missing)

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/master by this push:
     new 8012a70  refactored CDI contexts (flow still missing)
8012a70 is described below

commit 8012a70d2135da47f25585a0d5f9e777c306e3c3
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Fri Mar 5 18:17:05 2021 +0100

    refactored CDI contexts (flow still missing)
---
 .../viewstate/SerializedViewCollection.java        | 604 ++++++++++-----------
 .../cdi/clientwindow/ClientWindowScopeContext.java | 452 ++++++---------
 .../ClientWindowScopeContextualStorageHolder.java  |  59 ++
 .../cdi/util/AbstractContextualStorageHolder.java  | 270 +++++++++
 .../apache/myfaces/cdi/util/ContextualStorage.java |  27 +-
 .../myfaces/cdi/view/ViewScopeBeanHolder.java      | 239 --------
 .../apache/myfaces/cdi/view/ViewScopeCDIMap.java   |  54 +-
 .../apache/myfaces/cdi/view/ViewScopeContext.java  | 535 ++++++++----------
 .../cdi/view/ViewScopeContextualStorage.java       |  18 -
 .../cdi/view/ViewScopeContextualStorageHolder.java |  59 ++
 .../myfaces/cdi/view/ViewScopeExtension.java       |   2 +-
 .../org/apache/myfaces/view/ViewScopeProxyMap.java | 453 ++++++++--------
 .../myfaces/webapp/MyFacesHttpSessionListener.java | 194 +++----
 13 files changed, 1426 insertions(+), 1540 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java b/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java
index bd049b4..8eababb 100644
--- a/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java
+++ b/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java
@@ -1,302 +1,302 @@
-/*
- * 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.application.viewstate;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Logger;
-import jakarta.faces.context.FacesContext;
-import java.util.function.Consumer;
-import org.apache.myfaces.cdi.view.ViewScopeContext;
-import org.apache.myfaces.config.MyfacesConfig;
-import org.apache.myfaces.util.lang.LRULinkedHashMap;
-
-/**
- *
- */
-class SerializedViewCollection implements Serializable
-{
-    private static final Logger log = Logger.getLogger(SerializedViewCollection.class.getName());
-
-    private static final Object[] EMPTY_STATES = new Object[]{null, null};
-
-    private static final long serialVersionUID = -3734849062185115847L;
-
-    private final List<SerializedViewKey> _keys = new ArrayList<>(MyfacesConfig.NUMBER_OF_VIEWS_IN_SESSION_DEFAULT);
-    private final Map<SerializedViewKey, Object> _serializedViews = new HashMap<>();
-
-    /**
-     * The viewScopeIds can be shared between multiple entries of the same
-     * view. To store it into session, the best is use two maps, one to 
-     * associate the view key with the view scope id and other to keep track 
-     * of the number of times the id is used. In that way it is possible to
-     * know when a view scope id has been discarded and destroy the view scope
-     * in the right time.
-     */
-    private HashMap<SerializedViewKey, String> _viewScopeIds = null;
-    private HashMap<String, Integer> _viewScopeIdCounts = null;
-
-    private final Map<SerializedViewKey, SerializedViewKey> _precedence = new HashMap<>();
-    private Map<String, SerializedViewKey> _lastWindowKeys = null;
-
-    public void put(FacesContext context, Object state, SerializedViewKey key, SerializedViewKey previousRestoredKey)
-    {
-        put(context, state, key, previousRestoredKey, null,
-                (oldViewScopeId) -> ViewScopeContext.destroyAllActive(context, oldViewScopeId));
-    }
-    
-    public synchronized void put(FacesContext context, Object state, 
-        SerializedViewKey key, SerializedViewKey previousRestoredKey, String viewScopeId)
-    {
-        put(context, state, key, previousRestoredKey, viewScopeId,
-            (oldViewScopeId) -> ViewScopeContext.destroyAllActive(context, oldViewScopeId));
-    }
-
-    public synchronized void put(FacesContext context, Object state, 
-        SerializedViewKey key, SerializedViewKey previousRestoredKey, String viewScopeId,
-        Consumer<String> destroyCallback)
-    {
-        if (state == null)
-        {
-            state = EMPTY_STATES;
-        }
-        else if (state instanceof Object[] &&
-            ((Object[])state).length == 2 &&
-            ((Object[])state)[0] == null &&
-            ((Object[])state)[1] == null)
-        {
-            // The generated state can be considered zero, set it as null
-            // into the map.
-            state = null;
-        }
-
-        if (_serializedViews.containsKey(key))
-        {
-            // Update the state, the viewScopeId does not change.
-            _serializedViews.put(key, state);
-            // Make sure the view is at the end of the discard queue
-            while (_keys.remove(key))
-            {
-                // do nothing
-            }
-            _keys.add(key);
-            return;
-        }
-
-        Integer maxCount = getNumberOfSequentialViewsInSession(context);
-        if (maxCount != null)
-        {
-            if (previousRestoredKey != null)
-            {
-                if (!_serializedViews.isEmpty())
-                {
-                    _precedence.put((SerializedViewKey) key, previousRestoredKey);
-                }
-                else
-                {
-                    // Note when the session is invalidated, _serializedViews map is empty,
-                    // but we could have a not null previousRestoredKey (the last one before
-                    // invalidate the session), so we need to check that condition before
-                    // set the precence. In that way, we ensure the precedence map will always
-                    // have valid keys.
-                    previousRestoredKey = null;
-                }
-            }
-        }
-        _serializedViews.put(key, state);
-        
-        if (viewScopeId != null)
-        {
-            if (_viewScopeIds == null)
-            {
-                _viewScopeIds = new HashMap<>();
-            }
-            _viewScopeIds.put(key, viewScopeId);
-            if (_viewScopeIdCounts == null)
-            {
-                _viewScopeIdCounts = new HashMap<>();
-            }
-            Integer vscount = _viewScopeIdCounts.get(viewScopeId);
-            vscount = (vscount == null) ? 1 : vscount + 1;
-            _viewScopeIdCounts.put(viewScopeId, vscount);
-        }
-
-        while (_keys.remove(key))
-        {
-            // do nothing
-        }
-        _keys.add(key);
-
-        if (previousRestoredKey != null && maxCount != null && maxCount > 0)
-        {
-            int count = 0;
-            SerializedViewKey previousKey = (SerializedViewKey) key;
-            do
-            {
-                previousKey = _precedence.get(previousKey);
-                count++;
-            }
-            while (previousKey != null && count < maxCount);
-
-            if (previousKey != null)
-            {
-                SerializedViewKey keyToRemove = (SerializedViewKey) previousKey;
-                // In theory it should be only one key but just to be sure
-                // do it in a loop, but in this case if cache old views is on,
-                // put on that map.
-                do
-                {
-                    while (_keys.remove(keyToRemove))
-                    {
-                        // do nothing
-                    }
-
-                    _serializedViews.remove(keyToRemove);
-                    
-                    if (_viewScopeIds != null)
-                    {
-                        String oldViewScopeId = _viewScopeIds.remove(keyToRemove);
-                        if (oldViewScopeId != null)
-                        {
-                            Integer vscount = _viewScopeIdCounts.get(oldViewScopeId);
-                            vscount = vscount - 1;
-                            if (vscount < 1)
-                            {
-                                _viewScopeIdCounts.remove(oldViewScopeId);
-                                destroyCallback.accept(oldViewScopeId);
-                            }
-                            else
-                            {
-                                _viewScopeIdCounts.put(oldViewScopeId, vscount);
-                            }
-                        }
-                    }
-
-                    keyToRemove = _precedence.remove(keyToRemove);
-                }
-                while (keyToRemove != null);
-            }
-        }
-        int views = getNumberOfViewsInSession(context);
-        while (_keys.size() > views)
-        {
-            key = _keys.remove(0);
-            if (maxCount != null && maxCount > 0)
-            {
-                SerializedViewKey keyToRemove = (SerializedViewKey) key;
-                // Note in this case the key to delete is the oldest one,
-                // so it could be at least one precedence, but to be safe
-                // do it with a loop.
-                do
-                {
-                    keyToRemove = _precedence.remove(keyToRemove);
-                }
-                while (keyToRemove != null);
-            }
-
-            _serializedViews.remove(key);
-            
-            if (_viewScopeIds != null)
-            {
-                String oldViewScopeId = _viewScopeIds.remove(key);
-                if (oldViewScopeId != null)
-                {
-                    Integer vscount = _viewScopeIdCounts.get(oldViewScopeId);
-                    vscount = vscount - 1;
-                    if (vscount < 1)
-                    {
-                        _viewScopeIdCounts.remove(oldViewScopeId);
-                        destroyCallback.accept(oldViewScopeId);
-                    }
-                    else
-                    {
-                        _viewScopeIdCounts.put(oldViewScopeId, vscount);
-                    }
-                }
-            }
-        }
-    }
-
-    protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
-    {
-        return MyfacesConfig.getCurrentInstance(context).getNumberOfSequentialViewsInSession();
-    }
-
-    /**
-     * Reads the amount (default = 20) of views to be stored in session.
-     * @see ServerSideStateCacheImpl#NUMBER_OF_VIEWS_IN_SESSION_PARAM
-     * @param context FacesContext for the current request, we are processing
-     * @return Number vf views stored in the session
-     */
-    protected int getNumberOfViewsInSession(FacesContext context)
-    {
-        return MyfacesConfig.getCurrentInstance(context).getNumberOfViewsInSession();
-    }
-
-    public synchronized void putLastWindowKey(FacesContext context, String id, SerializedViewKey key)
-    {
-        if (_lastWindowKeys == null)
-        {
-            Integer i = getNumberOfSequentialViewsInSession(context);
-            int j = getNumberOfViewsInSession(context);
-            if (i != null && i> 0)
-            {
-                _lastWindowKeys = new LRULinkedHashMap<>((j / i) + 1);
-            }
-            else
-            {
-                _lastWindowKeys = new LRULinkedHashMap(j + 1);
-            }
-        }
-        _lastWindowKeys.put(id, key);
-    }
-
-    public SerializedViewKey getLastWindowKey(FacesContext context, String id)
-    {
-        if (_lastWindowKeys != null)
-        {
-            return _lastWindowKeys.get(id);
-        }
-        return null;
-    }
-
-    public Object get(SerializedViewKey key)
-    {
-        Object value = _serializedViews.get(key);
-        if (value == null)
-        {
-            if (_serializedViews.containsKey(key))
-            {
-                return EMPTY_STATES;
-            }
-        }
-        else if (value instanceof Object[] &&
-            ((Object[])value).length == 2 &&
-            ((Object[])value)[0] == null &&
-            ((Object[])value)[1] == null)
-        {
-            // Remember inside the state map null is stored as an empty array.
-            return null;
-        }
-        return value;
-    }
-}
+/*
+ * 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.application.viewstate;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+import jakarta.faces.context.FacesContext;
+import java.util.function.Consumer;
+import org.apache.myfaces.cdi.view.ViewScopeContext;
+import org.apache.myfaces.config.MyfacesConfig;
+import org.apache.myfaces.util.lang.LRULinkedHashMap;
+
+/**
+ *
+ */
+class SerializedViewCollection implements Serializable
+{
+    private static final Logger log = Logger.getLogger(SerializedViewCollection.class.getName());
+
+    private static final Object[] EMPTY_STATES = new Object[]{null, null};
+
+    private static final long serialVersionUID = -3734849062185115847L;
+
+    private final List<SerializedViewKey> _keys = new ArrayList<>(MyfacesConfig.NUMBER_OF_VIEWS_IN_SESSION_DEFAULT);
+    private final Map<SerializedViewKey, Object> _serializedViews = new HashMap<>();
+
+    /**
+     * The viewScopeIds can be shared between multiple entries of the same
+     * view. To store it into session, the best is use two maps, one to 
+     * associate the view key with the view scope id and other to keep track 
+     * of the number of times the id is used. In that way it is possible to
+     * know when a view scope id has been discarded and destroy the view scope
+     * in the right time.
+     */
+    private HashMap<SerializedViewKey, String> _viewScopeIds = null;
+    private HashMap<String, Integer> _viewScopeIdCounts = null;
+
+    private final Map<SerializedViewKey, SerializedViewKey> _precedence = new HashMap<>();
+    private Map<String, SerializedViewKey> _lastWindowKeys = null;
+
+    public void put(FacesContext context, Object state, SerializedViewKey key, SerializedViewKey previousRestoredKey)
+    {
+        put(context, state, key, previousRestoredKey, null,
+                (oldViewScopeId) -> ViewScopeContext.destroyAll(context, oldViewScopeId));
+    }
+    
+    public synchronized void put(FacesContext context, Object state, 
+        SerializedViewKey key, SerializedViewKey previousRestoredKey, String viewScopeId)
+    {
+        put(context, state, key, previousRestoredKey, viewScopeId,
+            (oldViewScopeId) -> ViewScopeContext.destroyAll(context, oldViewScopeId));
+    }
+
+    public synchronized void put(FacesContext context, Object state, 
+        SerializedViewKey key, SerializedViewKey previousRestoredKey, String viewScopeId,
+        Consumer<String> destroyCallback)
+    {
+        if (state == null)
+        {
+            state = EMPTY_STATES;
+        }
+        else if (state instanceof Object[] &&
+            ((Object[])state).length == 2 &&
+            ((Object[])state)[0] == null &&
+            ((Object[])state)[1] == null)
+        {
+            // The generated state can be considered zero, set it as null
+            // into the map.
+            state = null;
+        }
+
+        if (_serializedViews.containsKey(key))
+        {
+            // Update the state, the viewScopeId does not change.
+            _serializedViews.put(key, state);
+            // Make sure the view is at the end of the discard queue
+            while (_keys.remove(key))
+            {
+                // do nothing
+            }
+            _keys.add(key);
+            return;
+        }
+
+        Integer maxCount = getNumberOfSequentialViewsInSession(context);
+        if (maxCount != null)
+        {
+            if (previousRestoredKey != null)
+            {
+                if (!_serializedViews.isEmpty())
+                {
+                    _precedence.put((SerializedViewKey) key, previousRestoredKey);
+                }
+                else
+                {
+                    // Note when the session is invalidated, _serializedViews map is empty,
+                    // but we could have a not null previousRestoredKey (the last one before
+                    // invalidate the session), so we need to check that condition before
+                    // set the precence. In that way, we ensure the precedence map will always
+                    // have valid keys.
+                    previousRestoredKey = null;
+                }
+            }
+        }
+        _serializedViews.put(key, state);
+        
+        if (viewScopeId != null)
+        {
+            if (_viewScopeIds == null)
+            {
+                _viewScopeIds = new HashMap<>();
+            }
+            _viewScopeIds.put(key, viewScopeId);
+            if (_viewScopeIdCounts == null)
+            {
+                _viewScopeIdCounts = new HashMap<>();
+            }
+            Integer vscount = _viewScopeIdCounts.get(viewScopeId);
+            vscount = (vscount == null) ? 1 : vscount + 1;
+            _viewScopeIdCounts.put(viewScopeId, vscount);
+        }
+
+        while (_keys.remove(key))
+        {
+            // do nothing
+        }
+        _keys.add(key);
+
+        if (previousRestoredKey != null && maxCount != null && maxCount > 0)
+        {
+            int count = 0;
+            SerializedViewKey previousKey = (SerializedViewKey) key;
+            do
+            {
+                previousKey = _precedence.get(previousKey);
+                count++;
+            }
+            while (previousKey != null && count < maxCount);
+
+            if (previousKey != null)
+            {
+                SerializedViewKey keyToRemove = (SerializedViewKey) previousKey;
+                // In theory it should be only one key but just to be sure
+                // do it in a loop, but in this case if cache old views is on,
+                // put on that map.
+                do
+                {
+                    while (_keys.remove(keyToRemove))
+                    {
+                        // do nothing
+                    }
+
+                    _serializedViews.remove(keyToRemove);
+                    
+                    if (_viewScopeIds != null)
+                    {
+                        String oldViewScopeId = _viewScopeIds.remove(keyToRemove);
+                        if (oldViewScopeId != null)
+                        {
+                            Integer vscount = _viewScopeIdCounts.get(oldViewScopeId);
+                            vscount = vscount - 1;
+                            if (vscount < 1)
+                            {
+                                _viewScopeIdCounts.remove(oldViewScopeId);
+                                destroyCallback.accept(oldViewScopeId);
+                            }
+                            else
+                            {
+                                _viewScopeIdCounts.put(oldViewScopeId, vscount);
+                            }
+                        }
+                    }
+
+                    keyToRemove = _precedence.remove(keyToRemove);
+                }
+                while (keyToRemove != null);
+            }
+        }
+        int views = getNumberOfViewsInSession(context);
+        while (_keys.size() > views)
+        {
+            key = _keys.remove(0);
+            if (maxCount != null && maxCount > 0)
+            {
+                SerializedViewKey keyToRemove = (SerializedViewKey) key;
+                // Note in this case the key to delete is the oldest one,
+                // so it could be at least one precedence, but to be safe
+                // do it with a loop.
+                do
+                {
+                    keyToRemove = _precedence.remove(keyToRemove);
+                }
+                while (keyToRemove != null);
+            }
+
+            _serializedViews.remove(key);
+            
+            if (_viewScopeIds != null)
+            {
+                String oldViewScopeId = _viewScopeIds.remove(key);
+                if (oldViewScopeId != null)
+                {
+                    Integer vscount = _viewScopeIdCounts.get(oldViewScopeId);
+                    vscount = vscount - 1;
+                    if (vscount < 1)
+                    {
+                        _viewScopeIdCounts.remove(oldViewScopeId);
+                        destroyCallback.accept(oldViewScopeId);
+                    }
+                    else
+                    {
+                        _viewScopeIdCounts.put(oldViewScopeId, vscount);
+                    }
+                }
+            }
+        }
+    }
+
+    protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
+    {
+        return MyfacesConfig.getCurrentInstance(context).getNumberOfSequentialViewsInSession();
+    }
+
+    /**
+     * Reads the amount (default = 20) of views to be stored in session.
+     * @see ServerSideStateCacheImpl#NUMBER_OF_VIEWS_IN_SESSION_PARAM
+     * @param context FacesContext for the current request, we are processing
+     * @return Number vf views stored in the session
+     */
+    protected int getNumberOfViewsInSession(FacesContext context)
+    {
+        return MyfacesConfig.getCurrentInstance(context).getNumberOfViewsInSession();
+    }
+
+    public synchronized void putLastWindowKey(FacesContext context, String id, SerializedViewKey key)
+    {
+        if (_lastWindowKeys == null)
+        {
+            Integer i = getNumberOfSequentialViewsInSession(context);
+            int j = getNumberOfViewsInSession(context);
+            if (i != null && i> 0)
+            {
+                _lastWindowKeys = new LRULinkedHashMap<>((j / i) + 1);
+            }
+            else
+            {
+                _lastWindowKeys = new LRULinkedHashMap(j + 1);
+            }
+        }
+        _lastWindowKeys.put(id, key);
+    }
+
+    public SerializedViewKey getLastWindowKey(FacesContext context, String id)
+    {
+        if (_lastWindowKeys != null)
+        {
+            return _lastWindowKeys.get(id);
+        }
+        return null;
+    }
+
+    public Object get(SerializedViewKey key)
+    {
+        Object value = _serializedViews.get(key);
+        if (value == null)
+        {
+            if (_serializedViews.containsKey(key))
+            {
+                return EMPTY_STATES;
+            }
+        }
+        else if (value instanceof Object[] &&
+            ((Object[])value).length == 2 &&
+            ((Object[])value)[0] == null &&
+            ((Object[])value)[1] == null)
+        {
+            // Remember inside the state map null is stored as an empty array.
+            return null;
+        }
+        return value;
+    }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContext.java b/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContext.java
index d4aa201..8bb9d15 100644
--- a/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContext.java
+++ b/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContext.java
@@ -1,287 +1,165 @@
-/*
- * 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.cdi.clientwindow;
-
-import java.lang.annotation.Annotation;
-import java.util.Map;
-import jakarta.enterprise.context.ContextNotActiveException;
-import jakarta.enterprise.context.spi.Context;
-import jakarta.enterprise.context.spi.Contextual;
-import jakarta.enterprise.context.spi.CreationalContext;
-import jakarta.enterprise.inject.Typed;
-import jakarta.enterprise.inject.spi.BeanManager;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.lifecycle.ClientWindowScoped;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
-import org.apache.myfaces.cdi.util.ContextualStorage;
-
-/**
- * Minimal implementation of ClientWindowScope.
- */
-@Typed()
-public class ClientWindowScopeContext implements Context
-{
-    public static final String CLIENT_WINDOW_SCOPE_MAP = "oam.CLIENT_WINDOW_SCOPE_MAP";
-
-    private BeanManager beanManager;
-    
-    public ClientWindowScopeContext(BeanManager beanManager)
-    {
-        this.beanManager = beanManager;
-    }
-
-    /**
-     * An implementation has to return the underlying storage which
-     * contains the items held in the Context.
-     *
-     * @param createIfNotExist whether a ContextualStorage shall get created if it doesn't yet exist.
-     * @param facesContext 
-     * 
-     * @return the underlying storage
-     */
-    protected ContextualStorage getContextualStorage(boolean createIfNotExist, FacesContext facesContext)
-    {
-        if (facesContext == null)
-        {
-            throw new ContextNotActiveException(this.getClass().getName() + ": no current active FacesContext");
-        }
-
-        Map<String, Object> sessionMap =
-                facesContext.getExternalContext().getSessionMap();
-        Map<String, ContextualStorage> contextualStorageMap =
-                (Map<String, ContextualStorage>) sessionMap.get(CLIENT_WINDOW_SCOPE_MAP);
-        if (contextualStorageMap == null)
-        {
-            if (!createIfNotExist)
-            {
-                return null;
-            }
-
-            contextualStorageMap = new ConcurrentHashMap<>();
-            sessionMap.put(CLIENT_WINDOW_SCOPE_MAP, contextualStorageMap);
-        }
-
-        String clientWindowId = getCurrentClientWindowId();
-        ContextualStorage contextualStorage = contextualStorageMap.get(clientWindowId);
-        if (contextualStorage == null)
-        {
-            if (!createIfNotExist)
-            {
-                return null;
-            }
-
-            contextualStorage = new ContextualStorage(beanManager, false);
-            contextualStorageMap.put(clientWindowId, contextualStorage);
-        }
-
-        return contextualStorage;
-    }
-
-    @Override
-    public Class<? extends Annotation> getScope()
-    {
-        return ClientWindowScoped.class;
-    }
-
-    @Override
-    public boolean isActive()
-    {
-        return isActive(FacesContext.getCurrentInstance());
-    }
-
-    public boolean isActive(FacesContext facesContext)
-    {
-        if (facesContext == null || facesContext.getExternalContext().getClientWindow() == null)
-        {
-            return false;
-        }
-
-        return true;
-    }
-    
-    protected String getCurrentClientWindowId()
-    {
-        return FacesContext.getCurrentInstance().getExternalContext().getClientWindow().getId();
-    }
-
-    @Override
-    public <T> T get(Contextual<T> bean)
-    {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-
-        checkActive(facesContext);
-
-        if (facesContext != null)
-        {
-            ContextualStorage storage = getContextualStorage(false, facesContext);
-            if (storage != null)
-            {
-                Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
-                ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
-
-                if (contextualInstanceInfo != null)
-                {
-                    return (T) contextualInstanceInfo.getContextualInstance();
-                }
-            }
-        }
-        else
-        {
-            throw new IllegalStateException("FacesContext cannot be found when resolving bean " + bean.toString());
-        }
-        return null;
-    }
-
-    @Override
-    public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext)
-    {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        
-        checkActive(facesContext);
-
-        ContextualStorage storage = getContextualStorage(true, facesContext);
-
-        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
-        ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
-
-        if (contextualInstanceInfo != null)
-        {
-            @SuppressWarnings("unchecked")
-            final T instance = (T) contextualInstanceInfo.getContextualInstance();
-
-            if (instance != null)
-            {
-                return instance;
-            }
-        }
-
-        return storage.createContextualInstance(bean, creationalContext);
-    }
-
-    /**
-     * Destroy the Contextual Instance of the given Bean.
-     * @param bean dictates which bean shall get cleaned up
-     * @return <code>true</code> if the bean was destroyed, <code>false</code> if there was no such bean.
-     */
-    public boolean destroy(Contextual bean)
-    {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        ContextualStorage storage = getContextualStorage(false, facesContext);
-        if (storage == null)
-        {
-            return false;
-        }
-        ContextualInstanceInfo<?> contextualInstanceInfo = storage.getStorage().get(storage.getBeanKey(bean));
-
-        if (contextualInstanceInfo == null)
-        {
-            return false;
-        }
-
-        bean.destroy(contextualInstanceInfo.getContextualInstance(), contextualInstanceInfo.getCreationalContext());
-        return true;
-    }
-
-    /**
-     * Make sure that the context is really active.
-     *
-     * @param facesContext the current {@link FacesContext}.
-     * @throws ContextNotActiveException if there is no active context for the current thread.
-     */
-    protected void checkActive(FacesContext facesContext)
-    {
-        if (!isActive(facesContext))
-        {
-            throw new ContextNotActiveException("CDI context with scope annotation @"
-                + getScope().getName() + " is not active with respect to the current thread");
-        }
-    }
-
-    public static void onSessionDestroyed(FacesContext facesContext)
-    {
-        destroyAllActive(facesContext);
-    }
-    
-    public static void destroyAllActive(FacesContext facesContext)
-    {
-        if (facesContext == null)
-        {
-            return;
-        }
-        
-        Map<String, Object> sessionMap =
-                facesContext.getExternalContext().getSessionMap();
-        Map<String, ContextualStorage> contextualStorageMap =
-                (Map<String, ContextualStorage>) sessionMap.get(CLIENT_WINDOW_SCOPE_MAP);
-        if (contextualStorageMap == null || contextualStorageMap.isEmpty())
-        {
-            return;
-        }
-
-        Iterator<String> iterator = contextualStorageMap.keySet().iterator();
-        while (iterator.hasNext())
-        {
-            String clientWindowId = iterator.next();
-            iterator.remove();
-
-            ContextualStorage contextualStorage = contextualStorageMap.get(clientWindowId);
-            destroyAllActive(facesContext, contextualStorage);
-        }
-    }
-    
-    public static void destroyAllActive(FacesContext facesContext, String clientWindowId)
-    {
-        if (facesContext == null)
-        {
-            return;
-        }
-        
-        Map<String, Object> sessionMap =
-                facesContext.getExternalContext().getSessionMap();
-        Map<String, ContextualStorage> contextualStorageMap =
-                (Map<String, ContextualStorage>) sessionMap.get(CLIENT_WINDOW_SCOPE_MAP);
-        if (contextualStorageMap == null || contextualStorageMap.isEmpty())
-        {
-            return;
-        }
-        
-        ContextualStorage contextualStorage = contextualStorageMap.remove(clientWindowId);
-        destroyAllActive(facesContext, contextualStorage);
-    }
-    
-    protected static void destroyAllActive(FacesContext facesContext, ContextualStorage contextualStorage)
-    {
-        if (contextualStorage == null)
-        {
-            return;
-        }
-        
-        Map<Object, ContextualInstanceInfo<?>> contextMap = contextualStorage.getStorage();
-        for (Map.Entry<Object, ContextualInstanceInfo<?>> entry : contextMap.entrySet())
-        {
-            Contextual bean = contextualStorage.getBean(entry.getKey());
-
-            ContextualInstanceInfo<?> contextualInstanceInfo = entry.getValue();
-            bean.destroy(contextualInstanceInfo.getContextualInstance(), 
-                contextualInstanceInfo.getCreationalContext());
-        }
-    }
-}
+/*
+ * 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.cdi.clientwindow;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import jakarta.enterprise.context.ContextNotActiveException;
+import jakarta.enterprise.context.spi.Context;
+import jakarta.enterprise.context.spi.Contextual;
+import jakarta.enterprise.context.spi.CreationalContext;
+import jakarta.enterprise.inject.Typed;
+import jakarta.enterprise.inject.spi.BeanManager;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.lifecycle.ClientWindowScoped;
+import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
+import org.apache.myfaces.cdi.util.ContextualStorage;
+import org.apache.myfaces.cdi.util.AbstractContextualStorageHolder;
+
+/**
+ * Minimal implementation of ClientWindowScope.
+ */
+@Typed()
+public class ClientWindowScopeContext implements Context
+{
+    private BeanManager beanManager;
+    
+    public ClientWindowScopeContext(BeanManager beanManager)
+    {
+        this.beanManager = beanManager;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope()
+    {
+        return ClientWindowScoped.class;
+    }
+
+    @Override
+    public boolean isActive()
+    {
+        return isActive(FacesContext.getCurrentInstance());
+    }
+
+    public boolean isActive(FacesContext facesContext)
+    {
+        if (facesContext == null || facesContext.getExternalContext().getClientWindow() == null)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public <T> T get(Contextual<T> bean)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+
+        checkActive(facesContext);
+
+        if (facesContext != null)
+        {
+            ContextualStorage storage = getContextManager(facesContext).getContextualStorage(
+                    getCurrentClientWindowId(facesContext), false);
+            if (storage != null)
+            {
+                Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
+                ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
+
+                if (contextualInstanceInfo != null)
+                {
+                    return (T) contextualInstanceInfo.getContextualInstance();
+                }
+            }
+        }
+        else
+        {
+            throw new IllegalStateException("FacesContext cannot be found when resolving bean " + bean.toString());
+        }
+        return null;
+    }
+
+    @Override
+    public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        
+        checkActive(facesContext);
+
+        ContextualStorage storage = getContextManager(facesContext).getContextualStorage(
+                getCurrentClientWindowId(facesContext), true);
+
+        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
+        ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
+
+        if (contextualInstanceInfo != null)
+        {
+            @SuppressWarnings("unchecked")
+            final T instance = (T) contextualInstanceInfo.getContextualInstance();
+
+            if (instance != null)
+            {
+                return instance;
+            }
+        }
+
+        return storage.createContextualInstance(bean, creationalContext);
+    }
+
+    protected void checkActive(FacesContext facesContext)
+    {
+        if (!isActive(facesContext))
+        {
+            throw new ContextNotActiveException("CDI context with scope annotation @"
+                + getScope().getName() + " is not active with respect to the current thread");
+        }
+    }
+
+    protected ClientWindowScopeContextualStorageHolder getContextManager(FacesContext context)
+    {
+        return AbstractContextualStorageHolder.getInstance(context, ClientWindowScopeContextualStorageHolder.class);
+    }
+
+    protected String getCurrentClientWindowId(FacesContext context)
+    {
+        return context.getExternalContext().getClientWindow().getId();
+    }
+
+
+    public static void destroyAll(FacesContext facesContext)
+    {
+        ClientWindowScopeContextualStorageHolder manager = AbstractContextualStorageHolder.getInstance(facesContext,
+                ClientWindowScopeContextualStorageHolder.class);
+        if (manager != null)
+        {
+            manager.destroyAll(facesContext);
+        }
+    }
+    
+    public static void destroyAll(FacesContext context, String clientWindowId)
+    {
+        ClientWindowScopeContextualStorageHolder manager = AbstractContextualStorageHolder.getInstance(context,
+                ClientWindowScopeContextualStorageHolder.class);
+        if (manager != null)
+        {
+            manager.destroyAll(context, clientWindowId);
+        }
+    }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContextualStorageHolder.java b/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContextualStorageHolder.java
new file mode 100644
index 0000000..a12a323
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/cdi/clientwindow/ClientWindowScopeContextualStorageHolder.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cdi.clientwindow;
+
+import jakarta.enterprise.context.SessionScoped;
+import jakarta.enterprise.context.spi.Contextual;
+import jakarta.faces.context.FacesContext;
+import java.io.Serializable;
+import java.util.Map;
+import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
+import org.apache.myfaces.cdi.util.ContextualStorage;
+import org.apache.myfaces.cdi.util.AbstractContextualStorageHolder;
+
+@SessionScoped
+public class ClientWindowScopeContextualStorageHolder
+        extends AbstractContextualStorageHolder<ContextualStorage>
+        implements Serializable
+{
+    @Override
+    public void destroyAll(ContextualStorage contextualStorage, FacesContext facesContext)
+    {
+        if (contextualStorage == null)
+        {
+            return;
+        }
+        
+        Map<Object, ContextualInstanceInfo<?>> contextMap = contextualStorage.getStorage();
+        for (Map.Entry<Object, ContextualInstanceInfo<?>> entry : contextMap.entrySet())
+        {
+            Contextual bean = contextualStorage.getBean(entry.getKey());
+
+            ContextualInstanceInfo<?> contextualInstanceInfo = entry.getValue();
+            bean.destroy(contextualInstanceInfo.getContextualInstance(), 
+                contextualInstanceInfo.getCreationalContext());
+        }
+    }
+
+    @Override
+    protected ContextualStorage newContextualStorage(String slotId)
+    {
+        return new ContextualStorage(beanManager, true);
+    }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/util/AbstractContextualStorageHolder.java b/impl/src/main/java/org/apache/myfaces/cdi/util/AbstractContextualStorageHolder.java
new file mode 100644
index 0000000..88a6155
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/cdi/util/AbstractContextualStorageHolder.java
@@ -0,0 +1,270 @@
+/*
+ * 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.cdi.util;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import jakarta.enterprise.context.spi.Contextual;
+import jakarta.enterprise.inject.spi.BeanManager;
+import jakarta.faces.context.ExceptionHandler;
+import jakarta.faces.context.ExternalContext;
+import jakarta.faces.context.FacesContext;
+import jakarta.inject.Inject;
+import jakarta.servlet.ServletContext;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.myfaces.cdi.JsfApplicationArtifactHolder;
+import org.apache.myfaces.context.ExceptionHandlerImpl;
+import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
+import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
+
+public abstract class AbstractContextualStorageHolder<T extends ContextualStorage> implements Serializable
+{
+    @Inject
+    protected JsfApplicationArtifactHolder applicationContextBean;
+    
+    @Inject
+    protected BeanManager beanManager;
+    
+    protected Map<String, T> storageMap;
+
+    public AbstractContextualStorageHolder()
+    {
+    }
+
+    @PostConstruct
+    public void init()
+    {
+        storageMap = new ConcurrentHashMap<>();
+        
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+
+        Object context = facesContext.getExternalContext().getContext();
+        if (context instanceof ServletContext)
+        {
+            JsfApplicationArtifactHolder appBean = CDIUtils.get(beanManager, JsfApplicationArtifactHolder.class);
+            if (appBean.getServletContext() != null)
+            {
+                appBean.setServletContext((ServletContext) context);
+            }
+        }
+    }
+
+    /**
+     *
+     * This method will replace the storageMap and with a new empty one.
+     * This method can be used to properly destroy the BeanHolder beans without having to sync heavily.
+     * Any {@link jakarta.enterprise.inject.spi.Bean#destroy(Object, jakarta.enterprise.context.spi.CreationalContext)}
+     * should be performed on the returned old storage map.
+     *
+     * @return the old storageMap.
+     */
+    public Map<String, T> forceNewStorage()
+    {
+        Map<String, T> oldStorageMap = storageMap;
+        storageMap = new ConcurrentHashMap<>();
+        return oldStorageMap;
+    }
+
+    public Map<String, T> getStorageMap()
+    {
+        return storageMap;
+    }
+    
+    public T getContextualStorage(String slotId)
+    {
+        return getContextualStorage(slotId, true);
+    }
+    
+    public T getContextualStorage(String slotId, boolean create)
+    {
+        if (storageMap == null)
+        {
+            if (!create)
+            {
+                return null;
+            }
+            
+            storageMap = new ConcurrentHashMap<>();
+        }
+
+        T storage = storageMap.get(slotId);
+        if (storage == null && create)
+        {
+            storage = newContextualStorage(slotId);
+            storageMap.put(slotId, storage);
+        }
+        return storage;
+    }
+
+    protected abstract T newContextualStorage(String slotId);
+    
+    @PreDestroy
+    public void preDestroy()
+    {
+        // After some testing done two things are clear:
+        // 1. jetty +  weld call @PreDestroy at the end of the request
+        // 2. use a HttpServletListener in tomcat + owb does not work, because
+        //    CDI listener is executed first.
+        // So we need a mixed approach using both a listener and @PreDestroy annotations.
+        // When the first one in being called replace the storages with a new map 
+        // and call PreDestroy, when the second one is called, it founds an empty map
+        // and the process stops. A hack to get ServletContext from CDI is required to
+        // provide a valid FacesContext instance.
+        Map<String, T> oldContextStorages = forceNewStorage();
+        if (!oldContextStorages.isEmpty())
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance();
+            if (facesContext == null && applicationContextBean.getServletContext() != null)
+            {
+                try
+                {
+                    ServletContext servletContext = applicationContextBean.getServletContext();
+                    ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
+                    ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
+                    facesContext = new StartupFacesContextImpl(externalContext, 
+                            externalContext, exceptionHandler, false);
+                    for (T contextualStorage : oldContextStorages.values())
+                    {
+                        destroyAll(contextualStorage, facesContext);
+                    }
+                }
+                finally
+                {
+                    facesContext.release();
+                }
+            }
+            else
+            {
+                for (T contextualStorage : oldContextStorages.values())
+                {
+                    destroyAll(contextualStorage, facesContext);
+                }
+            }
+        }
+    }
+
+    public void destroyAll(FacesContext facesContext)
+    {
+        if (storageMap == null || storageMap.isEmpty())
+        {
+            return;
+        }
+
+        // we replace the old BeanHolder beans with a new storage Map
+        // an afterwards destroy the old Beans without having to care about any syncs.
+        // This behavior also helps as a check to avoid destroy the same beans twice.
+        Map<String, T> oldContextStorages = forceNewStorage();
+
+        for (T contextualStorage : oldContextStorages.values())
+        {
+            destroyAll(contextualStorage, facesContext);
+        }
+    }
+
+    public void destroyAll(T contextualStorage, FacesContext facesContext)
+    {
+        if (facesContext == null)
+        {
+            facesContext = FacesContext.getCurrentInstance();
+        }
+        
+        boolean tempFacesContext = false;
+        if (facesContext == null && applicationContextBean.getServletContext() != null)
+        {
+            ServletContext servletContext = applicationContextBean.getServletContext();
+            ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
+            ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
+            facesContext = new StartupFacesContextImpl(externalContext, externalContext, exceptionHandler, false);
+            tempFacesContext = true;
+        }
+
+        try
+        {
+            Map<Object, ContextualInstanceInfo<?>> contextMap = contextualStorage.getStorage();
+
+            for (Map.Entry<Object, ContextualInstanceInfo<?>> entry : contextMap.entrySet())
+            {  
+                Contextual bean = contextualStorage.getBean(entry.getKey());
+
+                ContextualInstanceInfo<?> contextualInstanceInfo = entry.getValue();
+                bean.destroy(contextualInstanceInfo.getContextualInstance(), 
+                    contextualInstanceInfo.getCreationalContext());
+            }
+
+            contextMap.clear();
+
+            contextualStorage.deactivate();
+        }
+        finally
+        {
+            if (tempFacesContext)
+            {
+                facesContext.release();
+            }
+        }
+    }
+
+    public void destroyAll(FacesContext context, String slotId)
+    {
+        if (storageMap == null || storageMap.isEmpty())
+        {
+            return;
+        }
+
+        T contextualStorage = storageMap.remove(slotId);
+        destroyAll(contextualStorage, context);
+    }
+
+    public static <T extends AbstractContextualStorageHolder> T getInstance(FacesContext facesContext,
+            Class<T> contextManagerClass)
+    {
+        if (facesContext == null
+                || facesContext.getExternalContext() == null
+                || facesContext.getExternalContext().getSession(false) == null)
+        {
+            return null;
+        }
+
+        BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
+        if (beanManager == null)
+        {
+            return null;
+        }
+
+        if (!CDIUtils.isSessionScopeActive(beanManager))
+        {
+            return null;
+        }
+
+        T cached = (T) facesContext.getExternalContext().getSessionMap().get(contextManagerClass.getClass().getName());
+        if (cached == null)
+        {
+            cached = CDIUtils.getOptional(beanManager, contextManagerClass);
+            if (cached != null)
+            {
+                facesContext.getExternalContext().getSessionMap().put(contextManagerClass.getClass().getName(),
+                        cached);
+            }
+        }
+
+        return cached;
+    }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/util/ContextualStorage.java b/impl/src/main/java/org/apache/myfaces/cdi/util/ContextualStorage.java
index 1537733..6aac5e4 100644
--- a/impl/src/main/java/org/apache/myfaces/cdi/util/ContextualStorage.java
+++ b/impl/src/main/java/org/apache/myfaces/cdi/util/ContextualStorage.java
@@ -39,10 +39,16 @@ public class ContextualStorage implements Serializable
 {
     private static final long serialVersionUID = 1L;
 
-    protected final Map<Object, ContextualInstanceInfo<?>> contextualInstances;
-    protected final BeanManager beanManager;
-    protected final boolean concurrent;
+    protected Map<Object, ContextualInstanceInfo<?>> contextualInstances;
+    protected BeanManager beanManager;
+    protected boolean concurrent;
+    protected transient volatile boolean activated;
 
+    public ContextualStorage()
+    {
+        this.activated = true;
+    }
+    
     /**
      * @param beanManager is needed for serialisation
      * @param concurrent whether the ContextualStorage might get accessed concurrently by different threads
@@ -59,6 +65,7 @@ public class ContextualStorage implements Serializable
         {
             contextualInstances = new HashMap<>();
         }
+        this.activated = true;
     }
 
     /**
@@ -164,4 +171,18 @@ public class ContextualStorage implements Serializable
         return (Contextual<?>) beanKey;
     }
 
+    public boolean isActivated()
+    {
+        return activated;
+    }
+
+    public void activate()
+    {
+        activated = true;
+    }
+
+    public void deactivate()
+    {
+        activated = false;
+    }
 }
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeBeanHolder.java b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeBeanHolder.java
deleted file mode 100644
index 980b975..0000000
--- a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeBeanHolder.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * 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.cdi.view;
-
-import org.apache.myfaces.cdi.JsfApplicationArtifactHolder;
-import java.io.Serializable;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-import jakarta.annotation.PostConstruct;
-import jakarta.annotation.PreDestroy;
-import jakarta.enterprise.context.SessionScoped;
-import jakarta.enterprise.inject.spi.BeanManager;
-import jakarta.faces.context.ExceptionHandler;
-import jakarta.faces.context.ExternalContext;
-import jakarta.faces.context.FacesContext;
-import jakarta.inject.Inject;
-import jakarta.servlet.ServletContext;
-import org.apache.myfaces.cdi.util.CDIUtils;
-import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
-import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
-import org.apache.myfaces.context.ExceptionHandlerImpl;
-
-/**
- *
- * @author Leonardo Uribe
- */
-@SessionScoped
-public class ViewScopeBeanHolder implements Serializable
-{
-    /**
-     * key: the windowId for the browser tab or window
-     * value: the {@link ViewScopeContextualStorage} which holds all the
-     * {@link jakarta.enterprise.inject.spi.Bean}s.
-     */
-    private Map<String, ViewScopeContextualStorage> storageMap;
-    
-    private static final Random RANDOM_GENERATOR = new Random();
-
-    public static final String CREATED = ViewScopeBeanHolder.class.getName() + ".CREATED";
-    
-    @Inject
-    JsfApplicationArtifactHolder applicationContextBean;
-    
-    public ViewScopeBeanHolder()
-    {
-    }
-    
-    @PostConstruct
-    public void init()
-    {
-        storageMap = new ConcurrentHashMap<>();
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        facesContext.getExternalContext().getSessionMap().put(CREATED, true);
-
-        Object context = facesContext.getExternalContext().getContext();
-        if (context instanceof ServletContext)
-        {
-            BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
-            JsfApplicationArtifactHolder appBean = CDIUtils.get(beanManager, JsfApplicationArtifactHolder.class);
-            if (appBean.getServletContext() != null)
-            {
-                appBean.setServletContext((ServletContext) context);
-            }
-        }
-    }
-
-    /**
-     * This method will return the ViewScopeContextualStorage or create a new one
-     * if no one is yet assigned to the current windowId.
-     * 
-     * @param beanManager
-     * @param viewScopeId
-     * @return 
-     */
-    public ViewScopeContextualStorage getContextualStorage(BeanManager beanManager, String viewScopeId)
-    {
-        ViewScopeContextualStorage storage = storageMap.get(viewScopeId);
-        if (storage == null)
-        {
-            storage = new ViewScopeContextualStorage(beanManager);
-            storageMap.put(viewScopeId, storage);
-        }
-        return storage;
-    }
-
-    public Map<String, ViewScopeContextualStorage> getStorageMap()
-    {
-        return storageMap;
-    }
-
-    /**
-     *
-     * This method will replace the storageMap and with a new empty one.
-     * This method can be used to properly destroy the BeanHolder beans without having to sync heavily.
-     * Any {@link jakarta.enterprise.inject.spi.Bean#destroy(Object, jakarta.enterprise.context.spi.CreationalContext)}
-     * should be performed on the returned old storage map.
-     *
-     * @return the old storageMap.
-     */
-    public Map<String, ViewScopeContextualStorage> forceNewStorage()
-    {
-        Map<String, ViewScopeContextualStorage> oldStorageMap = storageMap;
-        storageMap = new ConcurrentHashMap<>();
-        return oldStorageMap;
-    }
-
-    /**
-     * This method properly destroys all current &#064;WindowScoped beans
-     * of the active session and also prepares the storage for new beans.
-     * It will automatically get called when the session context closes
-     * but can also get invoked manually, e.g. if a user likes to get rid
-     * of all it's &#064;ViewScoped beans.
-     */
-    //@PreDestroy
-    public void destroyBeans()
-    {
-        // we replace the old BeanHolder beans with a new storage Map
-        // an afterwards destroy the old Beans without having to care about any syncs.
-        // This behavior also helps as a check to avoid destroy the same beans twice.
-        Map<String, ViewScopeContextualStorage> oldContextStorages = forceNewStorage();
-
-        for (ViewScopeContextualStorage contextualStorage : oldContextStorages.values())
-        {
-            ViewScopeContext.destroyAllActive(contextualStorage);
-        }
-    }
-    
-    public void destroyBeans(String viewScopeId)
-    {
-        ViewScopeContextualStorage contextualStorage = storageMap.get(viewScopeId);
-        if (contextualStorage != null)
-        {
-            try
-            {
-                FacesContext facesContext = FacesContext.getCurrentInstance();
-                if (facesContext == null && applicationContextBean.getServletContext() != null)
-                {
-                    try
-                    {
-                        ServletContext servletContext = applicationContextBean.getServletContext();
-                        ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
-                        ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
-                        facesContext = new StartupFacesContextImpl(externalContext, 
-                                externalContext, exceptionHandler, false);
-                        ViewScopeContext.destroyAllActive(contextualStorage, facesContext);
-                    }
-                    finally
-                    {
-                        facesContext.release();
-                    }
-                }
-                else
-                {
-                    ViewScopeContext.destroyAllActive(contextualStorage, facesContext);
-                }
-            }
-            finally
-            {
-                //remove the viewScopeId to prevent memory leak
-                storageMap.remove(viewScopeId);
-            }
-        }
-    }
-    
-    @PreDestroy
-    public void destroyBeansOnPreDestroy()
-    {
-        // After some testing done two things are clear:
-        // 1. jetty +  weld call @PreDestroy at the end of the request
-        // 2. use a HttpServletListener in tomcat + owb does not work, because
-        //    CDI listener is executed first.
-        // So we need a mixed approach using both a listener and @PreDestroy annotations.
-        // When the first one in being called replace the storages with a new map 
-        // and call PreDestroy, when the second one is called, it founds an empty map
-        // and the process stops. A hack to get ServletContext from CDI is required to
-        // provide a valid FacesContext instance.
-        Map<String, ViewScopeContextualStorage> oldContextStorages = forceNewStorage();
-        if (!oldContextStorages.isEmpty())
-        {
-            FacesContext facesContext = FacesContext.getCurrentInstance();
-            if (facesContext == null && applicationContextBean.getServletContext() != null)
-            {
-                try
-                {
-                    ServletContext servletContext = applicationContextBean.getServletContext();
-                    ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
-                    ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
-                    facesContext = new StartupFacesContextImpl(externalContext, 
-                            externalContext, exceptionHandler, false);
-                    for (ViewScopeContextualStorage contextualStorage : oldContextStorages.values())
-                    {
-                        ViewScopeContext.destroyAllActive(contextualStorage, facesContext);
-                    }
-                }
-                finally
-                {
-                    facesContext.release();
-                }
-            }
-            else
-            {
-                for (ViewScopeContextualStorage contextualStorage : oldContextStorages.values())
-                {
-                    ViewScopeContext.destroyAllActive(contextualStorage);
-                }
-            }
-        }
-    }
-    
-    public String generateUniqueViewScopeId()
-    {
-        // To ensure uniqueness we just use a random generator and we check
-        // if the key is already used.
-        String key;
-        do 
-        {
-            key = Integer.toString(RANDOM_GENERATOR.nextInt());
-        } while (storageMap.containsKey(key));
-        return key;
-    }
-
-}
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeCDIMap.java b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeCDIMap.java
index 8107645..e3874f1 100644
--- a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeCDIMap.java
+++ b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeCDIMap.java
@@ -35,32 +35,19 @@ import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
  */
 public class ViewScopeCDIMap implements Map<String, Object>
 {
-    private String _viewScopeId;
-    
+    private String viewScopeId;
     private ViewScopeContextualStorage storage;
 
     public ViewScopeCDIMap(FacesContext facesContext)
     {
         BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
-
-        ViewScopeBeanHolder bean = CDIUtils.get(beanManager, ViewScopeBeanHolder.class);
-
-        // 1. get a new view scope id
-        _viewScopeId = bean.generateUniqueViewScopeId();
-
-        storage = bean.getContextualStorage(beanManager, _viewScopeId);
+        ViewScopeContextualStorageHolder bean = CDIUtils.get(beanManager, ViewScopeContextualStorageHolder.class);
+        viewScopeId = bean.generateUniqueViewScopeId();
     }
     
     public ViewScopeCDIMap(FacesContext facesContext, String viewScopeId)
     {
-        BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
-
-        ViewScopeBeanHolder bean = CDIUtils.get(beanManager, ViewScopeBeanHolder.class);
-
-        // 1. get a new view scope id
-        _viewScopeId = viewScopeId;
-
-        storage = bean.getContextualStorage(beanManager, _viewScopeId);
+        this.viewScopeId = viewScopeId;
     }
     
     private ViewScopeContextualStorage getStorage()
@@ -74,9 +61,9 @@ public class ViewScopeCDIMap implements Map<String, Object>
             FacesContext facesContext = FacesContext.getCurrentInstance();
             BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
 
-            ViewScopeBeanHolder bean = CDIUtils.get(beanManager, ViewScopeBeanHolder.class);
+            ViewScopeContextualStorageHolder bean = CDIUtils.get(beanManager, ViewScopeContextualStorageHolder.class);
             
-            storage = bean.getContextualStorage(beanManager, _viewScopeId);
+            storage = bean.getContextualStorage(viewScopeId);
         }
         return storage;
     }
@@ -93,9 +80,9 @@ public class ViewScopeCDIMap implements Map<String, Object>
     
     public String getViewScopeId()
     {
-        return _viewScopeId;
+        return viewScopeId;
     }
-    
+
     @Override
     public int size()
     {
@@ -172,34 +159,11 @@ public class ViewScopeCDIMap implements Map<String, Object>
     @Override
     public void clear()
     {
-        boolean destroyed = false;
         // If the scope was already destroyed through an invalidateSession(), the storage instance
         // that is holding this map could be obsolete, so we need to grab the right instance from
         // the bean holder.
         FacesContext facesContext = FacesContext.getCurrentInstance();
-        if (facesContext != null)
-        {
-            BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
-
-            if (beanManager != null)
-            {
-                ViewScopeBeanHolder bean = CDIUtils.get(beanManager, ViewScopeBeanHolder.class);
-                if (bean != null)
-                {
-                    ViewScopeContextualStorage st = bean.getContextualStorage(beanManager, _viewScopeId);
-                    if (st != null)
-                    {
-                        ViewScopeContext.destroyAllActive(st);
-                        storage = null;
-                        destroyed = true;
-                    }
-                }
-            }
-        }
-        if (!destroyed)
-        {
-            ViewScopeContext.destroyAllActive(storage);
-        }
+        ViewScopeContext.destroyAll(facesContext, viewScopeId);
     }
 
     @Override
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContext.java b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContext.java
index 12fc8d2..e5826eb 100644
--- a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContext.java
+++ b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContext.java
@@ -1,323 +1,214 @@
-/*
- * 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.cdi.view;
-
-import jakarta.enterprise.context.ContextNotActiveException;
-import jakarta.enterprise.inject.Typed;
-import jakarta.enterprise.inject.spi.BeanManager;
-
-import java.lang.annotation.Annotation;
-import java.util.Map;
-import jakarta.enterprise.context.spi.Context;
-import jakarta.enterprise.context.spi.Contextual;
-import jakarta.enterprise.context.spi.CreationalContext;
-import jakarta.enterprise.inject.spi.PassivationCapable;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.view.ViewScoped;
-
-import org.apache.myfaces.cdi.util.CDIUtils;
-import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
-import org.apache.myfaces.view.ViewScopeProxyMap;
-
-/**
- * CDI Context to handle &#064;{@link ViewScoped} beans.
- * 
- * @author Leonardo Uribe
- */
-@Typed()
-public class ViewScopeContext implements Context
-{
-
-    /**
-     * needed for serialisation and passivationId
-     */
-    private BeanManager beanManager;
-    
-    private boolean passivatingScope;
-
-    public ViewScopeContext(BeanManager beanManager)
-    {
-        this.beanManager = beanManager;
-        this.passivatingScope = beanManager.isPassivatingScope(getScope());
-    }
-
-    protected ViewScopeBeanHolder getOrCreateViewScopeBeanHolder()
-    {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        ViewScopeBeanHolder beanHolder = (ViewScopeBeanHolder) facesContext.getExternalContext().getSessionMap()
-                .get(ViewScopeBeanHolder.class.getName());
-        if (beanHolder == null)
-        {
-            beanHolder = CDIUtils.get(beanManager, ViewScopeBeanHolder.class);
-            facesContext.getExternalContext().getSessionMap().put(
-                    ViewScopeBeanHolder.class.getName(),
-                    beanHolder);
-        }
-
-        return beanHolder;
-    }
-
-    protected static ViewScopeBeanHolder getViewScopeBeanHolder(FacesContext facesContext)
-    {
-        return (ViewScopeBeanHolder) facesContext.getExternalContext().getSessionMap()
-                .get(ViewScopeBeanHolder.class.getName());
-    }
-
-    public String getCurrentViewScopeId(boolean create)
-    {        
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        ViewScopeProxyMap map = (ViewScopeProxyMap) facesContext.getViewRoot().getViewMap(create);
-        if (map != null)
-        {
-            String id = map.getViewScopeId();
-            if (id == null && create)
-            {
-                // Force create
-                map.forceCreateWrappedMap(facesContext);
-                id = map.getViewScopeId();
-            }
-            return id;
-        }
-        return null;
-    }
-
-    protected ViewScopeContextualStorage getContextualStorage(boolean createIfNotExist)
-    {
-        String viewScopeId = getCurrentViewScopeId(createIfNotExist);
-        if (createIfNotExist && viewScopeId == null)
-        {
-            throw new ContextNotActiveException(
-                this.getClass().getSimpleName() + ": no viewScopeId set for the current view yet!");
-        }
-        if (viewScopeId != null)
-        {
-            return getOrCreateViewScopeBeanHolder().getContextualStorage(beanManager, viewScopeId);
-        }
-        return null;
-    }
-
-    @Override
-    public Class<? extends Annotation> getScope()
-    {
-        return ViewScoped.class;
-    }
-
-    /**
-     * The WindowContext is active once a current windowId is set for the current Thread.
-     * @return
-     */
-    @Override
-    public boolean isActive()
-    {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        if (facesContext != null)
-        {
-            return facesContext.getViewRoot() != null;
-        }
-        else
-        {
-            // No FacesContext means no view scope active.
-            return false;
-        }
-    }
-
-    @Override
-    public <T> T get(Contextual<T> bean)
-    {
-        checkActive();
-
-        // force session creation if ViewScoped is used
-        FacesContext.getCurrentInstance().getExternalContext().getSession(true);
-        
-        ViewScopeContextualStorage storage = getContextualStorage(false);
-        if (storage == null)
-        {
-            return null;
-        }
-
-        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
-        ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
-        if (contextualInstanceInfo == null)
-        {
-            return null;
-        }
-
-        return (T) contextualInstanceInfo.getContextualInstance();
-    }
-
-    @Override
-    public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext)
-    {
-        checkActive();
-
-        if (passivatingScope && !(bean instanceof PassivationCapable))
-        {
-            throw new IllegalStateException(bean.toString() +
-                    " doesn't implement " + PassivationCapable.class.getName());
-        }
-
-        // force session creation if ViewScoped is used
-        FacesContext.getCurrentInstance().getExternalContext().getSession(true);
-        
-        ViewScopeContextualStorage storage = getContextualStorage(true);
-
-        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
-        ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
-
-        if (contextualInstanceInfo != null)
-        {
-            @SuppressWarnings("unchecked")
-            final T instance = (T) contextualInstanceInfo.getContextualInstance();
-            if (instance != null)
-            {
-                return instance;
-            }
-        }
-
-        return storage.createContextualInstance(bean, creationalContext);
-    }
-
-    /**
-     * Destroy the Contextual Instance of the given Bean.
-     * @param bean dictates which bean shall get cleaned up
-     * @return <code>true</code> if the bean was destroyed, <code>false</code> if there was no such bean.
-     */
-    public boolean destroy(Contextual bean)
-    {
-        ViewScopeContextualStorage storage = getContextualStorage(false);
-        if (storage == null)
-        {
-            return false;
-        }
-        
-        ContextualInstanceInfo<?> contextualInstanceInfo = storage.getStorage().get(storage.getBeanKey(bean));
-        if (contextualInstanceInfo == null)
-        {
-            return false;
-        }
-
-        bean.destroy(contextualInstanceInfo.getContextualInstance(), 
-            contextualInstanceInfo.getCreationalContext());
-
-        return true;
-    }
-
-    /**
-     * destroys all the Contextual Instances in the Storage returned by
-     * {@link #getContextualStorage(boolean)}.
-     */
-    public void destroyAllActive()
-    {
-        ViewScopeContextualStorage storage = getContextualStorage(false);
-        if (storage == null)
-        {
-            return;
-        }
-
-        destroyAllActive(storage);
-    }
-
-    
-    public static void destroyAllActive(FacesContext context, String viewScopeId)
-    {
-        if (isViewScopeBeanHolderCreated(context))
-        {
-            ViewScopeBeanHolder beanHolder = getViewScopeBeanHolder(context);
-            if (beanHolder != null)
-            {
-                beanHolder.destroyBeans(viewScopeId);
-            }
-        }
-    }
-
-    
-    public static void destroyAllActive(ViewScopeContextualStorage storage)
-    {
-        destroyAllActive(storage, FacesContext.getCurrentInstance());
-    }
-
-    public static void destroyAllActive(ViewScopeContextualStorage storage, FacesContext facesContext)
-    {
-        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
-
-        for (Map.Entry<Object, ContextualInstanceInfo<?>> entry : contextMap.entrySet())
-        {
-            if (!(entry.getKey() instanceof ViewScopeContextualKey))
-            {            
-                Contextual bean = storage.getBean(entry.getKey());
-
-                ContextualInstanceInfo<?> contextualInstanceInfo = entry.getValue();
-                bean.destroy(contextualInstanceInfo.getContextualInstance(), 
-                    contextualInstanceInfo.getCreationalContext());
-            }
-        }
-
-        contextMap.clear();
-        
-        storage.deactivate();
-    }
-    
-    /**
-     * Make sure that the Context is really active.
-     * @throws ContextNotActiveException if there is no active
-     *         Context for the current Thread.
-     */
-    protected void checkActive()
-    {
-        if (!isActive())
-        {
-            throw new ContextNotActiveException("CDI context with scope annotation @"
-                + getScope().getName() + " is not active with respect to the current thread");
-        }
-    }
-
-    private static boolean isViewScopeBeanHolderCreated(FacesContext facesContext)
-    {
-        if (facesContext.getExternalContext().getSession(false) == null)
-        {
-            return false;
-        }
-        
-        return facesContext.getExternalContext().
-            getSessionMap().containsKey(ViewScopeBeanHolder.CREATED);
-    }
-    
-    public static void onSessionDestroyed(FacesContext facesContext)
-    {
-        if (facesContext == null)
-        {
-            return;
-        }
-        
-        // In CDI case, the best way to deal with this is use a method 
-        // with @PreDestroy annotation on a session scope bean 
-        // ( ViewScopeBeanHolder.destroyBeans() ). There is no need
-        // to do anything else in this location, but it is advised
-        // in CDI the beans are destroyed at the end of the request,
-        // not when invalidateSession() is called.
-        if (isViewScopeBeanHolderCreated(facesContext))
-        {
-            ViewScopeBeanHolder beanHolder = getViewScopeBeanHolder(facesContext);
-            if (beanHolder != null)
-            {
-                beanHolder.destroyBeans();                
-            }
-        }
-    }
+/*
+ * 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.cdi.view;
+
+import jakarta.enterprise.context.ContextNotActiveException;
+import jakarta.enterprise.inject.Typed;
+import jakarta.enterprise.inject.spi.BeanManager;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import jakarta.enterprise.context.spi.Context;
+import jakarta.enterprise.context.spi.Contextual;
+import jakarta.enterprise.context.spi.CreationalContext;
+import jakarta.enterprise.inject.spi.PassivationCapable;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.view.ViewScoped;
+
+import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
+import org.apache.myfaces.cdi.util.AbstractContextualStorageHolder;
+import org.apache.myfaces.view.ViewScopeProxyMap;
+
+/**
+ * CDI Context to handle &#064;{@link ViewScoped} beans.
+ * 
+ * @author Leonardo Uribe
+ */
+@Typed()
+public class ViewScopeContext implements Context
+{
+
+    /**
+     * needed for serialisation and passivationId
+     */
+    private BeanManager beanManager;
+    
+    private boolean passivatingScope;
+
+    public ViewScopeContext(BeanManager beanManager)
+    {
+        this.beanManager = beanManager;
+        this.passivatingScope = beanManager.isPassivatingScope(getScope());
+    }
+
+    protected ViewScopeContextualStorageHolder getContextManager(FacesContext facesContext)
+    {
+        return AbstractContextualStorageHolder.getInstance(facesContext, ViewScopeContextualStorageHolder.class);
+    }
+
+    protected static ViewScopeContextualStorageHolder getViewScopeBeanHolder(FacesContext facesContext)
+    {
+        return (ViewScopeContextualStorageHolder) facesContext.getExternalContext().getSessionMap()
+                .get(ViewScopeContextualStorageHolder.class.getName());
+    }
+
+    public String getCurrentViewScopeId(boolean create)
+    {        
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        ViewScopeProxyMap map = (ViewScopeProxyMap) facesContext.getViewRoot().getViewMap(create);
+        if (map != null)
+        {
+            String id = map.getViewScopeId();
+            if (id == null && create)
+            {
+                // Force create
+                map.forceCreateWrappedMap(facesContext);
+                id = map.getViewScopeId();
+            }
+            return id;
+        }
+        return null;
+    }
+
+    protected ViewScopeContextualStorage getContextualStorage(FacesContext facesContext, boolean createIfNotExist)
+    {
+        String viewScopeId = getCurrentViewScopeId(createIfNotExist);
+        if (createIfNotExist && viewScopeId == null)
+        {
+            throw new ContextNotActiveException(
+                this.getClass().getSimpleName() + ": no viewScopeId set for the current view yet!");
+        }
+        if (viewScopeId != null)
+        {
+            return getContextManager(facesContext).getContextualStorage(viewScopeId, createIfNotExist);
+        }
+        return null;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope()
+    {
+        return ViewScoped.class;
+    }
+
+    @Override
+    public boolean isActive()
+    {
+        return isActive(FacesContext.getCurrentInstance());
+    }
+
+    public boolean isActive(FacesContext facesContext)
+    {
+        if (facesContext == null || facesContext.getViewRoot() == null)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public <T> T get(Contextual<T> bean)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        
+        checkActive(facesContext);
+
+        // force session creation if ViewScoped is used
+        facesContext.getExternalContext().getSession(true);
+        
+        ViewScopeContextualStorage storage = getContextualStorage(facesContext, false);
+        if (storage == null)
+        {
+            return null;
+        }
+
+        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
+        ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
+        if (contextualInstanceInfo == null)
+        {
+            return null;
+        }
+
+        return (T) contextualInstanceInfo.getContextualInstance();
+    }
+
+    @Override
+    public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        
+        checkActive(facesContext);
+
+        if (passivatingScope && !(bean instanceof PassivationCapable))
+        {
+            throw new IllegalStateException(bean.toString() +
+                    " doesn't implement " + PassivationCapable.class.getName());
+        }
+
+        // force session creation if ViewScoped is used
+        facesContext.getExternalContext().getSession(true);
+        
+        ViewScopeContextualStorage storage = getContextualStorage(facesContext, true);
+
+        Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
+        ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
+
+        if (contextualInstanceInfo != null)
+        {
+            @SuppressWarnings("unchecked")
+            final T instance = (T) contextualInstanceInfo.getContextualInstance();
+            if (instance != null)
+            {
+                return instance;
+            }
+        }
+
+        return storage.createContextualInstance(bean, creationalContext);
+    }
+
+    protected void checkActive(FacesContext facesContext)
+    {
+        if (!isActive(facesContext))
+        {
+            throw new ContextNotActiveException("CDI context with scope annotation @"
+                + getScope().getName() + " is not active with respect to the current thread");
+        }
+    }
+
+    public static void destroyAll(FacesContext facesContext)
+    {
+        ViewScopeContextualStorageHolder manager = AbstractContextualStorageHolder.getInstance(facesContext,
+                ViewScopeContextualStorageHolder.class);
+        if (manager != null)
+        {
+            manager.destroyAll(facesContext);
+        }
+    }
+
+    public static void destroyAll(FacesContext facesContext, String viewScopeId)
+    {
+        ViewScopeContextualStorageHolder manager = AbstractContextualStorageHolder.getInstance(facesContext,
+                ViewScopeContextualStorageHolder.class);
+        if (manager != null)
+        {
+            manager.destroyAll(facesContext, viewScopeId);
+        }
+    }
 }
\ No newline at end of file
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorage.java b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorage.java
index 636972f..d9c52e6 100644
--- a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorage.java
+++ b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorage.java
@@ -38,13 +38,10 @@ public class ViewScopeContextualStorage extends ContextualStorage
     
     private final Map<String, Object> nameBeanKeyMap;
 
-    private transient volatile boolean activated;
-
     public ViewScopeContextualStorage(BeanManager beanManager)
     {
         super(beanManager, false);
         this.nameBeanKeyMap = new HashMap<>();
-        this.activated = true;
     }
 
     public Map<String, Object> getNameBeanKeyMap()
@@ -68,19 +65,4 @@ public class ViewScopeContextualStorage extends ContextualStorage
 
         return instance;
     }
-
-    public boolean isActivated()
-    {
-        return activated;
-    }
-
-    public void activate()
-    {
-        activated = true;
-    }
-
-    public void deactivate()
-    {
-        activated = false;
-    }
 }
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorageHolder.java b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorageHolder.java
new file mode 100644
index 0000000..abe80b9
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeContextualStorageHolder.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cdi.view;
+
+import java.io.Serializable;
+import java.util.Random;
+import jakarta.enterprise.context.SessionScoped;
+import org.apache.myfaces.cdi.util.AbstractContextualStorageHolder;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+@SessionScoped
+public class ViewScopeContextualStorageHolder
+        extends AbstractContextualStorageHolder<ViewScopeContextualStorage>
+        implements Serializable
+{    
+    private static final Random RANDOM_GENERATOR = new Random();
+
+    public ViewScopeContextualStorageHolder()
+    {
+    }
+
+    public String generateUniqueViewScopeId()
+    {
+        // To ensure uniqueness we just use a random generator and we check
+        // if the key is already used.
+        String key;
+        do 
+        {
+            key = Integer.toString(RANDOM_GENERATOR.nextInt());
+        } while (storageMap.containsKey(key));
+        return key;
+    }
+
+    @Override
+    protected ViewScopeContextualStorage newContextualStorage(String slotId)
+    {
+        return new ViewScopeContextualStorage(beanManager);
+    }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeExtension.java b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeExtension.java
index 6b764bd..78e7ab5 100644
--- a/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeExtension.java
+++ b/impl/src/main/java/org/apache/myfaces/cdi/view/ViewScopeExtension.java
@@ -40,7 +40,7 @@ public class ViewScopeExtension implements Extension
         event.addScope(ViewScoped.class, true, true);
         // Register ViewScopeBeanHolder as a bean with CDI annotations, so the system
         // can take it into account, and use it later when necessary.
-        AnnotatedType bean = beanManager.createAnnotatedType(ViewScopeBeanHolder.class);
+        AnnotatedType bean = beanManager.createAnnotatedType(ViewScopeContextualStorageHolder.class);
         event.addAnnotatedType(bean, bean.getJavaClass().getName());
     }
     
diff --git a/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java b/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java
index 715491e..6ea0762 100644
--- a/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java
+++ b/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java
@@ -1,226 +1,227 @@
-/*
- * 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.view;
-
-import jakarta.enterprise.inject.spi.BeanManager;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import jakarta.faces.component.StateHolder;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.event.PreDestroyViewMapEvent;
-import org.apache.myfaces.cdi.util.CDIUtils;
-import org.apache.myfaces.cdi.view.ViewScopeBeanHolder;
-import org.apache.myfaces.cdi.view.ViewScopeCDIMap;
-import org.apache.myfaces.util.ExternalSpecifications;
-
-/**
- * This wrapper has these objectives:
- * 
- * - Isolate the part that needs to be saved with the view (viewScopeId) from
- *   the part that should remain into session (bean map). This class will be
- *   serialized when UIViewRoot.saveState() is called.
- * - Decouple the way how the view scope map is stored. For example, in 
- *   CDI view scope a session scope bean is used, and in default view scope
- *   the same session map is used but using a prefix.
- *
- * @author Leonardo Uribe
- */
-public class ViewScopeProxyMap extends HashMap<String, Object> implements StateHolder
-{
-    private String _viewScopeId;
-    
-    private transient Map<String, Object> _delegate;
-
-    public ViewScopeProxyMap()
-    {
-    }
-    
-    
-    public String getViewScopeId()
-    {
-        return _viewScopeId;
-    }
-    
-    public void forceCreateWrappedMap(FacesContext facesContext)
-    {
-        getWrapped();
-    }
-    
-    public Map<String, Object> getWrapped()
-    {
-        if (_delegate == null)
-        {
-            FacesContext facesContext = FacesContext.getCurrentInstance();
-            
-            if (facesContext != null)
-            {
-                // for unittests without CDI
-                if (!ExternalSpecifications.isCDIAvailable(facesContext.getExternalContext()))
-                {
-                    _delegate = new ViewScope();
-                    return _delegate;
-                }
-
-                if (_viewScopeId == null)
-                {
-                    BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
-                    ViewScopeBeanHolder beanHolder = CDIUtils.get(beanManager, ViewScopeBeanHolder.class);
-                    _viewScopeId = beanHolder.generateUniqueViewScopeId();
-                }
-                _delegate = new ViewScopeCDIMap(facesContext, _viewScopeId);
-            }
-            else
-            {
-                // In junit test cases, where there is no facesContext instance, it is enough to
-                // just get a blank instance.
-                _delegate = new ViewScope();
-            }
-        }
-        return _delegate;
-    }
-    
-    @Override
-    public int size()
-    {
-        return getWrapped().size();
-    }
-
-    @Override
-    public boolean isEmpty()
-    {
-        return getWrapped().isEmpty();
-    }
-
-    @Override
-    public boolean containsKey(Object key)
-    {
-        return getWrapped().containsKey(key);
-    }
-
-    @Override
-    public boolean containsValue(Object value)
-    {
-        return getWrapped().containsValue(value);
-    }
-
-    @Override
-    public Object get(Object key)
-    {
-        return getWrapped().get(key);
-    }
-
-    @Override
-    public Object put(String key, Object value)
-    {
-        return getWrapped().put(key, value);
-    }
-
-    @Override
-    public Object remove(Object key)
-    {
-        return getWrapped().remove(key);
-    }
-
-    @Override
-    public void putAll(Map<? extends String, ? extends Object> m)
-    {
-        getWrapped().putAll(m);
-    }
-
-    @Override
-    public void clear()
-    {
-        /*
-         * The returned Map must be implemented such that calling clear() on the Map causes
-         * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
-         * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
-         */
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        facesContext.getApplication().publishEvent(facesContext, 
-                PreDestroyViewMapEvent.class, facesContext.getViewRoot());
-
-        getWrapped().clear();
-    }
-
-    @Override
-    public Set<String> keySet()
-    {
-        return getWrapped().keySet();
-    }
-
-    @Override
-    public Collection<Object> values()
-    {
-        return getWrapped().values();
-    }
-
-    @Override
-    public Set<Entry<String, Object>> entrySet()
-    {
-        return getWrapped().entrySet();
-    }
-
-    @Override
-    public void restoreState(FacesContext context, Object state)
-    {
-        _viewScopeId = (String) state;
-    }
-
-    @Override
-    public Object saveState(FacesContext context)
-    {
-        return _viewScopeId;
-    }
-
-    @Override
-    public boolean isTransient()
-    {
-        return false;
-    }
-
-    @Override
-    public void setTransient(boolean newTransientValue)
-    {
-    }
-    
-    private static class ViewScope extends HashMap<String, Object>
-    {
-        
-        private static final long serialVersionUID = -1088293802269478164L;
-        
-        @Override
-        public void clear()
-        {
-            /*
-             * The returned Map must be implemented such that calling clear() on the Map causes
-             * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
-             * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
-             */
-            FacesContext facesContext = FacesContext.getCurrentInstance();
-            facesContext.getApplication().publishEvent(facesContext, 
-                    PreDestroyViewMapEvent.class, facesContext.getViewRoot());
-            
-            super.clear();
-        }
-        
-    }
-
-}
+/*
+ * 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.view;
+
+import jakarta.enterprise.inject.spi.BeanManager;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import jakarta.faces.component.StateHolder;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.PreDestroyViewMapEvent;
+import org.apache.myfaces.cdi.util.CDIUtils;
+import org.apache.myfaces.cdi.view.ViewScopeContextualStorageHolder;
+import org.apache.myfaces.cdi.view.ViewScopeCDIMap;
+import org.apache.myfaces.util.ExternalSpecifications;
+
+/**
+ * This wrapper has these objectives:
+ * 
+ * - Isolate the part that needs to be saved with the view (viewScopeId) from
+ *   the part that should remain into session (bean map). This class will be
+ *   serialized when UIViewRoot.saveState() is called.
+ * - Decouple the way how the view scope map is stored. For example, in 
+ *   CDI view scope a session scope bean is used, and in default view scope
+ *   the same session map is used but using a prefix.
+ *
+ * @author Leonardo Uribe
+ */
+public class ViewScopeProxyMap extends HashMap<String, Object> implements StateHolder
+{
+    private String _viewScopeId;
+    
+    private transient Map<String, Object> _delegate;
+
+    public ViewScopeProxyMap()
+    {
+    }
+    
+    
+    public String getViewScopeId()
+    {
+        return _viewScopeId;
+    }
+    
+    public void forceCreateWrappedMap(FacesContext facesContext)
+    {
+        getWrapped();
+    }
+    
+    public Map<String, Object> getWrapped()
+    {
+        if (_delegate == null)
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance();
+            
+            if (facesContext != null)
+            {
+                // for unittests without CDI
+                if (!ExternalSpecifications.isCDIAvailable(facesContext.getExternalContext()))
+                {
+                    _delegate = new ViewScope();
+                    return _delegate;
+                }
+
+                if (_viewScopeId == null)
+                {
+                    BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
+                    ViewScopeContextualStorageHolder beanHolder =
+                            CDIUtils.get(beanManager, ViewScopeContextualStorageHolder.class);
+                    _viewScopeId = beanHolder.generateUniqueViewScopeId();
+                }
+                _delegate = new ViewScopeCDIMap(facesContext, _viewScopeId);
+            }
+            else
+            {
+                // In junit test cases, where there is no facesContext instance, it is enough to
+                // just get a blank instance.
+                _delegate = new ViewScope();
+            }
+        }
+        return _delegate;
+    }
+    
+    @Override
+    public int size()
+    {
+        return getWrapped().size();
+    }
+
+    @Override
+    public boolean isEmpty()
+    {
+        return getWrapped().isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key)
+    {
+        return getWrapped().containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value)
+    {
+        return getWrapped().containsValue(value);
+    }
+
+    @Override
+    public Object get(Object key)
+    {
+        return getWrapped().get(key);
+    }
+
+    @Override
+    public Object put(String key, Object value)
+    {
+        return getWrapped().put(key, value);
+    }
+
+    @Override
+    public Object remove(Object key)
+    {
+        return getWrapped().remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends String, ? extends Object> m)
+    {
+        getWrapped().putAll(m);
+    }
+
+    @Override
+    public void clear()
+    {
+        /*
+         * The returned Map must be implemented such that calling clear() on the Map causes
+         * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
+         * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
+         */
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        facesContext.getApplication().publishEvent(facesContext, 
+                PreDestroyViewMapEvent.class, facesContext.getViewRoot());
+
+        getWrapped().clear();
+    }
+
+    @Override
+    public Set<String> keySet()
+    {
+        return getWrapped().keySet();
+    }
+
+    @Override
+    public Collection<Object> values()
+    {
+        return getWrapped().values();
+    }
+
+    @Override
+    public Set<Entry<String, Object>> entrySet()
+    {
+        return getWrapped().entrySet();
+    }
+
+    @Override
+    public void restoreState(FacesContext context, Object state)
+    {
+        _viewScopeId = (String) state;
+    }
+
+    @Override
+    public Object saveState(FacesContext context)
+    {
+        return _viewScopeId;
+    }
+
+    @Override
+    public boolean isTransient()
+    {
+        return false;
+    }
+
+    @Override
+    public void setTransient(boolean newTransientValue)
+    {
+    }
+    
+    private static class ViewScope extends HashMap<String, Object>
+    {
+        
+        private static final long serialVersionUID = -1088293802269478164L;
+        
+        @Override
+        public void clear()
+        {
+            /*
+             * The returned Map must be implemented such that calling clear() on the Map causes
+             * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
+             * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
+             */
+            FacesContext facesContext = FacesContext.getCurrentInstance();
+            facesContext.getApplication().publishEvent(facesContext, 
+                    PreDestroyViewMapEvent.class, facesContext.getViewRoot());
+            
+            super.clear();
+        }
+        
+    }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/webapp/MyFacesHttpSessionListener.java b/impl/src/main/java/org/apache/myfaces/webapp/MyFacesHttpSessionListener.java
index e1b7eba..2ece7d6 100644
--- a/impl/src/main/java/org/apache/myfaces/webapp/MyFacesHttpSessionListener.java
+++ b/impl/src/main/java/org/apache/myfaces/webapp/MyFacesHttpSessionListener.java
@@ -1,97 +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.webapp;
-
-import jakarta.faces.context.ExceptionHandler;
-import jakarta.faces.context.ExternalContext;
-import jakarta.faces.context.FacesContext;
-import jakarta.servlet.ServletContext;
-import jakarta.servlet.http.HttpSessionEvent;
-import jakarta.servlet.http.HttpSessionListener;
-import org.apache.myfaces.cdi.clientwindow.ClientWindowScopeContext;
-import org.apache.myfaces.cdi.view.ViewScopeContext;
-import org.apache.myfaces.context.ExceptionHandlerImpl;
-import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
-import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
-import org.apache.myfaces.spi.FacesFlowProvider;
-
-public class MyFacesHttpSessionListener implements HttpSessionListener
-{
-    public static final String APPLICATION_MAP_KEY = MyFacesHttpSessionListener.class.getName();
-
-    private FacesFlowProvider facesFlowProvider = null;
-
-    public void setFacesFlowProvider(FacesFlowProvider facesFlowProvider)
-    {
-        this.facesFlowProvider = facesFlowProvider;
-    }
-    
-    @Override
-    public void sessionCreated(HttpSessionEvent event)
-    {
-    }
-    
-    @Override
-    public void sessionDestroyed(HttpSessionEvent event)
-    {
-        // If we don't propagate this event, CDI will do for us but outside JSF control
-        // so when @PreDestroy methods are called there will not be an active FacesContext.
-        // The trick here is ensure clean the affected scopes to avoid duplicates.
-        // Remember cdi session scope is different from jsf session scope, because in
-        // jsf case the beans are stored under a session attribute, so it has the problem
-        // with attributeRemoved, but on cdi a wrapper is used instead, avoiding the problem.
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        if (facesContext != null)
-        {
-            if (facesFlowProvider != null)
-            {
-                facesFlowProvider.onSessionDestroyed();
-            }
-            ViewScopeContext.onSessionDestroyed(facesContext);
-            ClientWindowScopeContext.onSessionDestroyed(facesContext);
-        }
-        else
-        {
-            // In case no FacesContext is available, we are on session invalidation
-            // through timeout. In that case, create a dummy FacesContext for this one
-            // like the one used in startup or shutdown and invoke the destroy method.
-            try
-            {
-                ServletContext servletContext = event.getSession().getServletContext();
-                ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
-                ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
-                facesContext = new StartupFacesContextImpl(externalContext, externalContext, exceptionHandler, false);
-
-                if (facesFlowProvider != null)
-                {
-                    facesFlowProvider.onSessionDestroyed();
-                }
-                ViewScopeContext.onSessionDestroyed(facesContext);
-                ClientWindowScopeContext.onSessionDestroyed(facesContext);
-            }
-            finally
-            {
-                if (facesContext != null)
-                {
-                    facesContext.release();
-                }
-            }
-        }
-    }
-}
+/*
+ * 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.webapp;
+
+import jakarta.faces.context.ExceptionHandler;
+import jakarta.faces.context.ExternalContext;
+import jakarta.faces.context.FacesContext;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSessionEvent;
+import jakarta.servlet.http.HttpSessionListener;
+import org.apache.myfaces.cdi.clientwindow.ClientWindowScopeContext;
+import org.apache.myfaces.cdi.view.ViewScopeContext;
+import org.apache.myfaces.context.ExceptionHandlerImpl;
+import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
+import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
+import org.apache.myfaces.spi.FacesFlowProvider;
+
+public class MyFacesHttpSessionListener implements HttpSessionListener
+{
+    public static final String APPLICATION_MAP_KEY = MyFacesHttpSessionListener.class.getName();
+
+    private FacesFlowProvider facesFlowProvider = null;
+
+    public void setFacesFlowProvider(FacesFlowProvider facesFlowProvider)
+    {
+        this.facesFlowProvider = facesFlowProvider;
+    }
+    
+    @Override
+    public void sessionCreated(HttpSessionEvent event)
+    {
+    }
+    
+    @Override
+    public void sessionDestroyed(HttpSessionEvent event)
+    {
+        // If we don't propagate this event, CDI will do for us but outside JSF control
+        // so when @PreDestroy methods are called there will not be an active FacesContext.
+        // The trick here is ensure clean the affected scopes to avoid duplicates.
+        // Remember cdi session scope is different from jsf session scope, because in
+        // jsf case the beans are stored under a session attribute, so it has the problem
+        // with attributeRemoved, but on cdi a wrapper is used instead, avoiding the problem.
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        if (facesContext != null)
+        {
+            if (facesFlowProvider != null)
+            {
+                facesFlowProvider.onSessionDestroyed();
+            }
+            ViewScopeContext.destroyAll(facesContext);
+            ClientWindowScopeContext.destroyAll(facesContext);
+        }
+        else
+        {
+            // In case no FacesContext is available, we are on session invalidation
+            // through timeout. In that case, create a dummy FacesContext for this one
+            // like the one used in startup or shutdown and invoke the destroy method.
+            try
+            {
+                ServletContext servletContext = event.getSession().getServletContext();
+                ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
+                ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
+                facesContext = new StartupFacesContextImpl(externalContext, externalContext, exceptionHandler, false);
+
+                if (facesFlowProvider != null)
+                {
+                    facesFlowProvider.onSessionDestroyed();
+                }
+                ViewScopeContext.destroyAll(facesContext);
+                ClientWindowScopeContext.destroyAll(facesContext);
+            }
+            finally
+            {
+                if (facesContext != null)
+                {
+                    facesContext.release();
+                }
+            }
+        }
+    }
+}