Updated Branches:
  refs/heads/master 4e33427a1 -> db3605e8e

DELTASPIKE-488 @GroupedConversationScoped (first draft)


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/fca5cbd5
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/fca5cbd5
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/fca5cbd5

Branch: refs/heads/master
Commit: fca5cbd5c43d769210a9decd94d5e7087a990679
Parents: 4e33427
Author: gpetracek <gpetra...@apache.org>
Authored: Thu Jan 2 23:16:26 2014 +0100
Committer: gpetracek <gpetra...@apache.org>
Committed: Fri Jan 3 00:10:54 2014 +0100

----------------------------------------------------------------------
 .../core/api/scope/ConversationGroup.java       |  46 ++++++
 .../core/api/scope/GroupedConversation.java     |  26 +++
 .../api/scope/GroupedConversationScoped.java    |  39 +++++
 .../GroupedConversationManager.java             |  48 ++++++
 .../core/util/context/AbstractContext.java      |   3 +-
 .../util/context/ContextualInstanceInfo.java    |   2 +
 .../core/impl/scope/AbstractBeanHolder.java     |  93 +++++++++++
 .../impl/scope/DeltaSpikeContextExtension.java  |  81 ++++++++++
 .../conversation/ConversationBeanHolder.java    |  28 ++++
 .../scope/conversation/ConversationKey.java     | 161 +++++++++++++++++++
 .../GroupedConversationArtifactProducer.java    |  52 ++++++
 .../GroupedConversationContext.java             | 152 +++++++++++++++++
 .../InjectableGroupedConversation.java          |  50 ++++++
 .../InjectableGroupedConversationManager.java   |  67 ++++++++
 .../window/DeltaSpikeContextExtension.java      |  63 --------
 .../scope/window/InjectableWindowContext.java   |   1 +
 .../impl/scope/window/WindowBeanHolder.java     |  91 +----------
 .../impl/scope/window/WindowContextImpl.java    |   2 +-
 .../scope/window/WindowContextProducer.java     |   3 +-
 .../core/impl/util/ConversationUtils.java       |  77 +++++++++
 .../javax.enterprise.inject.spi.Extension       |   2 +-
 21 files changed, 932 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ConversationGroup.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ConversationGroup.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ConversationGroup.java
new file mode 100644
index 0000000..1274392
--- /dev/null
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/ConversationGroup.java
@@ -0,0 +1,46 @@
+/*
+ * 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.deltaspike.core.api.scope;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target( { PARAMETER, FIELD, METHOD, CONSTRUCTOR, TYPE } )
+@Retention(RUNTIME)
+@Documented
+
+@Qualifier
+public @interface ConversationGroup
+{
+    /**
+     * Class or interface which should be used as type-safe key for 
identifying the conversation-group.
+     *
+     * @return class or interface which should be used as key
+     */
+    Class<?> value();
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversation.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversation.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversation.java
new file mode 100644
index 0000000..6d8231b
--- /dev/null
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversation.java
@@ -0,0 +1,26 @@
+/*
+ * 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.deltaspike.core.api.scope;
+
+import java.io.Serializable;
+
+public interface GroupedConversation extends Serializable
+{
+    void close();
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversationScoped.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversationScoped.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversationScoped.java
new file mode 100644
index 0000000..5db9768
--- /dev/null
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/scope/GroupedConversationScoped.java
@@ -0,0 +1,39 @@
+/*
+ * 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.deltaspike.core.api.scope;
+
+import javax.enterprise.context.NormalScope;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target( { METHOD,TYPE,FIELD } )
+@Retention(RUNTIME)
+@Inherited
+@Documented
+@NormalScope(passivating = true)
+public @interface GroupedConversationScoped
+{
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/scope/conversation/GroupedConversationManager.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/scope/conversation/GroupedConversationManager.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/scope/conversation/GroupedConversationManager.java
new file mode 100644
index 0000000..dfa0a49
--- /dev/null
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/scope/conversation/GroupedConversationManager.java
@@ -0,0 +1,48 @@
+/*
+ * 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.deltaspike.core.spi.scope.conversation;
+
+import org.apache.deltaspike.core.util.context.ContextualStorage;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+public interface GroupedConversationManager extends Serializable
+{
+    /**
+     * @param conversationGroup group of the conversation in question
+     * @param qualifiers        optional qualifiers for the conversation
+     * @return the removed conversation - null otherwise
+     */
+    ContextualStorage closeConversation(Class<?> conversationGroup, 
Annotation... qualifiers);
+
+    /**
+     * destroys all conversation of a group independent of the qualifiers
+     *
+     * @param conversationGroup group of the conversation in question
+     * @return the removed storages - null otherwise
+     */
+    Set<ContextualStorage> closeConversationGroup(Class<?> conversationGroup);
+
+    /**
+     * invalidate all conversations immediately (within the current window)
+     */
+    void closeConversations();
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/AbstractContext.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/AbstractContext.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/AbstractContext.java
index 7be712c..11546ec 100644
--- 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/AbstractContext.java
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/AbstractContext.java
@@ -160,7 +160,7 @@ public abstract class AbstractContext implements Context
      * This is a static method to allow various holder objects to cleanup
      * properly in &#064;PreDestroy.
      */
-    public static void destroyAllActive(ContextualStorage storage)
+    public static Map<Object, ContextualInstanceInfo<?>> 
destroyAllActive(ContextualStorage storage)
     {
         //drop all entries in the storage before starting with destroying the 
original entries
         Map<Object, ContextualInstanceInfo<?>> contextMap =
@@ -174,6 +174,7 @@ public abstract class AbstractContext implements Context
             ContextualInstanceInfo<?> contextualInstanceInfo = 
entry.getValue();
             bean.destroy(contextualInstanceInfo.getContextualInstance(), 
contextualInstanceInfo.getCreationalContext());
         }
+        return contextMap;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/ContextualInstanceInfo.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/ContextualInstanceInfo.java
 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/ContextualInstanceInfo.java
index b970cc0..3e26522 100644
--- 
a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/ContextualInstanceInfo.java
+++ 
b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/context/ContextualInstanceInfo.java
@@ -28,6 +28,8 @@ import java.io.Serializable;
  */
 public class ContextualInstanceInfo<T> implements Serializable
 {
+    private static final long serialVersionUID = 6384932199958645324L;
+
     /**
      * The actual Contextual Instance in the context
      */

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/AbstractBeanHolder.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/AbstractBeanHolder.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/AbstractBeanHolder.java
new file mode 100644
index 0000000..3648dd6
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/AbstractBeanHolder.java
@@ -0,0 +1,93 @@
+/*
+ * 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.deltaspike.core.impl.scope;
+
+import org.apache.deltaspike.core.util.context.AbstractContext;
+import org.apache.deltaspike.core.util.context.ContextualStorage;
+
+import javax.annotation.PreDestroy;
+import javax.enterprise.inject.spi.BeanManager;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class AbstractBeanHolder<K> implements Serializable
+{
+    private Map<K, ContextualStorage> storageMap = new ConcurrentHashMap<K, 
ContextualStorage>();
+
+    private final boolean useConcurrentStorage;
+    private final boolean usePassivationCapableStorage;
+
+    protected AbstractBeanHolder()
+    {
+        this(true, true);
+    }
+
+    protected AbstractBeanHolder(boolean useConcurrentStorage, boolean 
usePassivationCapableStorage)
+    {
+        this.useConcurrentStorage = useConcurrentStorage;
+        this.usePassivationCapableStorage = usePassivationCapableStorage;
+    }
+
+    public ContextualStorage getContextualStorage(BeanManager beanManager, K 
key, boolean createIfNotExist)
+    {
+        ContextualStorage contextualStorage = storageMap.get(key);
+
+        if (contextualStorage == null && createIfNotExist)
+        {
+            contextualStorage = createContextualStorage(beanManager, key);
+        }
+
+        return contextualStorage;
+    }
+
+    protected synchronized ContextualStorage 
createContextualStorage(BeanManager beanManager, K key)
+    {
+        ContextualStorage contextualStorage = storageMap.get(key);
+        if (contextualStorage == null)
+        {
+            contextualStorage = new ContextualStorage(beanManager, 
useConcurrentStorage, usePassivationCapableStorage);
+            storageMap.put(key, contextualStorage);
+        }
+        return contextualStorage;
+    }
+
+    public Map<K, ContextualStorage> getStorageMap()
+    {
+        return storageMap;
+    }
+
+    public Map<K, ContextualStorage> forceNewStorage()
+    {
+        Map<K, ContextualStorage> oldStorageMap = storageMap;
+        storageMap = new ConcurrentHashMap<K, ContextualStorage>();
+        return oldStorageMap;
+    }
+
+    @PreDestroy
+    public void destroyBeans()
+    {
+        Map<K, ContextualStorage> oldWindowContextStorages = forceNewStorage();
+
+        for (ContextualStorage contextualStorage : 
oldWindowContextStorages.values())
+        {
+            AbstractContext.destroyAllActive(contextualStorage);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java
new file mode 100644
index 0000000..2e74c0f
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/DeltaSpikeContextExtension.java
@@ -0,0 +1,81 @@
+/*
+ * 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.deltaspike.core.impl.scope;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AfterDeploymentValidation;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Extension;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import 
org.apache.deltaspike.core.impl.scope.conversation.ConversationBeanHolder;
+import 
org.apache.deltaspike.core.impl.scope.conversation.GroupedConversationContext;
+import org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder;
+import org.apache.deltaspike.core.impl.scope.window.WindowContextImpl;
+import org.apache.deltaspike.core.impl.scope.window.WindowIdHolder;
+
+/**
+ * Handle all DeltaSpike WindowContext and ConversationContext
+ * related features.
+ */
+public class DeltaSpikeContextExtension implements Extension
+{
+    private WindowContextImpl windowContext;
+
+    private GroupedConversationContext conversationContext;
+
+    public void registerDeltaSpikeContexts(@Observes AfterBeanDiscovery 
afterBeanDiscovery, BeanManager beanManager)
+    {
+        windowContext = new WindowContextImpl(beanManager);
+        conversationContext = new GroupedConversationContext(beanManager, 
windowContext);
+        afterBeanDiscovery.addContext(windowContext);
+        afterBeanDiscovery.addContext(conversationContext);
+    }
+
+    /**
+     * We can only initialize our contexts in AfterDeploymentValidation because
+     * getBeans must not be invoked earlier than this phase to reduce 
randomness
+     * caused by Beans no being fully registered yet.
+     */
+    public void initializeDeltaSpikeContexts(@Observes 
AfterDeploymentValidation adv, BeanManager beanManager)
+    {
+        WindowBeanHolder windowBeanHolder =
+            BeanProvider.getContextualReference(beanManager, 
WindowBeanHolder.class, false);
+
+        WindowIdHolder windowIdHolder =
+            BeanProvider.getContextualReference(beanManager, 
WindowIdHolder.class, false);
+
+        windowContext.init(windowBeanHolder, windowIdHolder);
+
+        ConversationBeanHolder conversationBeanHolder =
+            BeanProvider.getContextualReference(beanManager, 
ConversationBeanHolder.class, false);
+        conversationContext.init(conversationBeanHolder);
+    }
+
+    public WindowContextImpl getWindowContext()
+    {
+        return windowContext;
+    }
+
+    public GroupedConversationContext getConversationContext()
+    {
+        return conversationContext;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationBeanHolder.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationBeanHolder.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationBeanHolder.java
new file mode 100644
index 0000000..5caf2fa
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationBeanHolder.java
@@ -0,0 +1,28 @@
+/*
+ * 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.deltaspike.core.impl.scope.conversation;
+
+import org.apache.deltaspike.core.api.scope.WindowScoped;
+import org.apache.deltaspike.core.impl.scope.AbstractBeanHolder;
+
+@WindowScoped
+public class ConversationBeanHolder extends AbstractBeanHolder<ConversationKey>
+{
+    private static final long serialVersionUID = 6313493410718133308L;
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationKey.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationKey.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationKey.java
new file mode 100644
index 0000000..378322b
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/ConversationKey.java
@@ -0,0 +1,161 @@
+/*
+ * 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.deltaspike.core.impl.scope.conversation;
+
+import org.apache.deltaspike.core.api.scope.ConversationGroup;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
+import javax.inject.Named;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ConversationKey implements Serializable
+{
+    private static final long serialVersionUID = 6565204223928766263L;
+
+    private final Class<?> groupKey;
+
+    //HashSet due to Serializable warning in checkstyle rules
+    private HashSet<Annotation> qualifiers;
+
+    public ConversationKey(Class<?> groupKey, Annotation... qualifiers)
+    {
+        this.groupKey = groupKey;
+
+        //TODO maybe we have to add a real qualifier instead
+        Class<? extends Annotation> annotationType;
+        for (Annotation qualifier : qualifiers)
+        {
+            annotationType = qualifier.annotationType();
+
+            if (Any.class.isAssignableFrom(annotationType) ||
+                    Default.class.isAssignableFrom(annotationType) ||
+                    Named.class.isAssignableFrom(annotationType) ||
+                    ConversationGroup.class.isAssignableFrom(annotationType))
+            {
+                //won't be used for this key!
+                continue;
+            }
+
+            if (this.qualifiers == null)
+            {
+                this.qualifiers = new HashSet<Annotation>();
+            }
+            this.qualifiers.add(qualifier);
+        }
+    }
+
+    public Class<?> getConversationGroup()
+    {
+        return groupKey;
+    }
+
+    public Set<Annotation> getQualifiers()
+    {
+        if (qualifiers == null)
+        {
+            return Collections.emptySet();
+        }
+        return Collections.unmodifiableSet(this.qualifiers);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        if (!(o instanceof ConversationKey))
+        {
+            return false;
+        }
+
+        ConversationKey that = (ConversationKey) o;
+
+        if (!groupKey.equals(that.groupKey))
+        {
+            return false;
+        }
+        if (qualifiers == null && that.qualifiers == null)
+        {
+            return true;
+        }
+        if (qualifiers != null && that.qualifiers == null)
+        {
+            return false;
+        }
+
+        if (!that.qualifiers.equals(qualifiers))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int result = groupKey.hashCode();
+        result = 31 * result + (qualifiers != null ? qualifiers.hashCode() : 
0);
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder result = new StringBuilder("conversation-key\n");
+
+        result.append("\n");
+        result.append("\tgroup:\t\t");
+        result.append(this.groupKey.getName());
+
+        result.append("\n");
+        result.append("\tqualifiers:\t");
+
+        if (qualifiers != null)
+        {
+            for (Annotation qualifier : this.qualifiers)
+            {
+                result.append(qualifier.annotationType().getName());
+                result.append(" ");
+            }
+        }
+        else
+        {
+            result.append("---");
+        }
+
+        return result.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationArtifactProducer.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationArtifactProducer.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationArtifactProducer.java
new file mode 100644
index 0000000..fe387c7
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationArtifactProducer.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.deltaspike.core.impl.scope.conversation;
+
+import org.apache.deltaspike.core.api.scope.GroupedConversation;
+import org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension;
+import org.apache.deltaspike.core.impl.util.ConversationUtils;
+import 
org.apache.deltaspike.core.spi.scope.conversation.GroupedConversationManager;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.inject.Inject;
+
+@ApplicationScoped
+public class GroupedConversationArtifactProducer
+{
+    @Inject
+    private DeltaSpikeContextExtension deltaSpikeContextExtension;
+
+    @Produces
+    @Dependent
+    public GroupedConversationManager getGroupedConversationManager()
+    {
+        return new 
InjectableGroupedConversationManager(deltaSpikeContextExtension.getConversationContext());
+    }
+
+    @Produces
+    @Dependent
+    public GroupedConversation getGroupedConversation(InjectionPoint 
injectionPoint)
+    {
+        ConversationKey conversationKey = 
ConversationUtils.convertToConversationKey(injectionPoint.getBean());
+        return new InjectableGroupedConversation(conversationKey, 
getGroupedConversationManager());
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationContext.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationContext.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationContext.java
new file mode 100644
index 0000000..0724ae4
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/GroupedConversationContext.java
@@ -0,0 +1,152 @@
+/*
+ * 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.deltaspike.core.impl.scope.conversation;
+
+import org.apache.deltaspike.core.api.scope.GroupedConversationScoped;
+import org.apache.deltaspike.core.impl.scope.window.WindowContextImpl;
+import org.apache.deltaspike.core.impl.util.ConversationUtils;
+import 
org.apache.deltaspike.core.spi.scope.conversation.GroupedConversationManager;
+import org.apache.deltaspike.core.util.context.AbstractContext;
+import org.apache.deltaspike.core.util.context.ContextualStorage;
+
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.Typed;
+import javax.enterprise.inject.spi.BeanManager;
+import java.lang.annotation.Annotation;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+@Typed()
+//TODO add RequestCache
+//TODO ConversationSubGroup
+public class GroupedConversationContext extends AbstractContext implements 
GroupedConversationManager
+{
+    private static final long serialVersionUID = -5463564406828391468L;
+
+    @Deprecated //TODO remove it once DELTASPIKE-489 is fixed
+    private static ThreadLocal<Contextual<?>> currentContextual = new 
ThreadLocal<Contextual<?>>();
+
+    private final BeanManager beanManager;
+
+    private final WindowContextImpl windowContext;
+
+    private ConversationBeanHolder conversationBeanHolder;
+
+    public GroupedConversationContext(BeanManager beanManager, 
WindowContextImpl windowContext)
+    {
+        super(beanManager);
+
+        this.beanManager = beanManager;
+        this.windowContext = windowContext;
+    }
+
+    public void init(ConversationBeanHolder conversationBeanHolder)
+    {
+        this.conversationBeanHolder = conversationBeanHolder;
+    }
+
+    @Override
+    public <T> T get(Contextual<T> bean)
+    {
+        try
+        {
+            currentContextual.set(bean);
+            return super.get(bean);
+        }
+        finally
+        {
+            currentContextual.set(null);
+            currentContextual.remove();
+        }
+    }
+
+    @Override
+    public <T> T get(Contextual<T> bean, CreationalContext<T> 
creationalContext)
+    {
+        try
+        {
+            currentContextual.set(bean);
+            return super.get(bean, creationalContext);
+        }
+        finally
+        {
+            currentContextual.set(null);
+            currentContextual.remove();
+        }
+    }
+
+    @Override
+    protected ContextualStorage getContextualStorage(boolean createIfNotExist)
+    {
+        ConversationKey conversationKey = 
ConversationUtils.convertToConversationKey(currentContextual.get());
+        return this.conversationBeanHolder.getContextualStorage(beanManager, 
conversationKey, createIfNotExist);
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope()
+    {
+        return GroupedConversationScoped.class;
+    }
+
+    @Override
+    public boolean isActive()
+    {
+        return this.windowContext.isActive(); //autom. active once a window is 
active
+    }
+
+    @Override
+    public ContextualStorage closeConversation(Class<?> conversationGroup, 
Annotation... qualifiers)
+    {
+        ConversationKey conversationKey = new 
ConversationKey(conversationGroup, qualifiers);
+        ContextualStorage contextualStorage = 
this.conversationBeanHolder.getStorageMap().remove(conversationKey);
+
+        if (contextualStorage != null)
+        {
+            AbstractContext.destroyAllActive(contextualStorage);
+        }
+
+        return contextualStorage;
+    }
+
+    @Override
+    public Set<ContextualStorage> closeConversationGroup(Class<?> 
conversationGroup)
+    {
+        Set<ContextualStorage> result = new HashSet<ContextualStorage>();
+
+        Map<ConversationKey, ContextualStorage> storageMap = 
this.conversationBeanHolder.getStorageMap();
+        for (Map.Entry<ConversationKey, ContextualStorage> entry : 
storageMap.entrySet())
+        {
+            if 
(entry.getKey().getConversationGroup().equals(conversationGroup))
+            {
+                AbstractContext.destroyAllActive(entry.getValue());
+                result.add(entry.getValue());
+                storageMap.remove(entry.getKey()); //ok due to 
ConcurrentHashMap
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void closeConversations()
+    {
+        this.conversationBeanHolder.destroyBeans();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversation.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversation.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversation.java
new file mode 100644
index 0000000..4805aa6
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversation.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.deltaspike.core.impl.scope.conversation;
+
+import org.apache.deltaspike.core.api.scope.GroupedConversation;
+import 
org.apache.deltaspike.core.spi.scope.conversation.GroupedConversationManager;
+
+import javax.enterprise.inject.Typed;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+@Typed()
+class InjectableGroupedConversation implements GroupedConversation
+{
+    private static final long serialVersionUID = -3909049219127821425L;
+
+    private final ConversationKey conversationKey;
+    private final GroupedConversationManager conversationManager;
+
+    InjectableGroupedConversation(ConversationKey conversationKey, 
GroupedConversationManager conversationManager)
+    {
+        this.conversationManager = conversationManager;
+        this.conversationKey = conversationKey;
+    }
+
+    @Override
+    public void close()
+    {
+        Set<Annotation> qualifiers = this.conversationKey.getQualifiers();
+
+        this.conversationManager.closeConversation(
+            this.conversationKey.getConversationGroup(), 
qualifiers.toArray(new Annotation[qualifiers.size()]));
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversationManager.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversationManager.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversationManager.java
new file mode 100644
index 0000000..f88d491
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/conversation/InjectableGroupedConversationManager.java
@@ -0,0 +1,67 @@
+/*
+ * 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.deltaspike.core.impl.scope.conversation;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension;
+import 
org.apache.deltaspike.core.spi.scope.conversation.GroupedConversationManager;
+import org.apache.deltaspike.core.util.context.ContextualStorage;
+
+import javax.enterprise.inject.Typed;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+@Typed()
+class InjectableGroupedConversationManager implements 
GroupedConversationManager
+{
+    private transient volatile GroupedConversationManager conversationManager;
+
+    public InjectableGroupedConversationManager(GroupedConversationManager 
conversationManager)
+    {
+        this.conversationManager = conversationManager;
+    }
+
+    private GroupedConversationManager getConversationManager()
+    {
+        if (this.conversationManager == null)
+        {
+            this.conversationManager =
+                
BeanProvider.getContextualReference(DeltaSpikeContextExtension.class).getConversationContext();
+        }
+        return conversationManager;
+    }
+
+    @Override
+    public ContextualStorage closeConversation(Class<?> conversationGroup, 
Annotation... qualifiers)
+    {
+        return getConversationManager().closeConversation(conversationGroup, 
qualifiers);
+    }
+
+    @Override
+    public Set<ContextualStorage> closeConversationGroup(Class<?> 
conversationGroup)
+    {
+        return 
getConversationManager().closeConversationGroup(conversationGroup);
+    }
+
+    @Override
+    public void closeConversations()
+    {
+        getConversationManager().closeConversations();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/DeltaSpikeContextExtension.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/DeltaSpikeContextExtension.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/DeltaSpikeContextExtension.java
deleted file mode 100644
index ad8186e..0000000
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/DeltaSpikeContextExtension.java
+++ /dev/null
@@ -1,63 +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.deltaspike.core.impl.scope.window;
-
-import javax.enterprise.event.Observes;
-import javax.enterprise.inject.spi.AfterBeanDiscovery;
-import javax.enterprise.inject.spi.AfterDeploymentValidation;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.enterprise.inject.spi.Extension;
-
-import org.apache.deltaspike.core.api.provider.BeanProvider;
-
-/**
- * Handle all DeltaSpike WindowContext and ConversationContext
- * related features.
- */
-public class DeltaSpikeContextExtension implements Extension
-{
-    private WindowContextImpl windowContext;
-
-    public void registerDeltaSpikeContexts(@Observes AfterBeanDiscovery 
afterBeanDiscovery, BeanManager beanManager)
-    {
-        windowContext = new WindowContextImpl(beanManager);
-        afterBeanDiscovery.addContext(windowContext);
-    }
-
-    /**
-     * We can only initialize our contexts in AfterDeploymentValidation because
-     * getBeans must not be invoked earlier than this phase to reduce 
randomness
-     * caused by Beans no being fully registered yet.
-     */
-    public void initializeDeltaSpikeContexts(@Observes 
AfterDeploymentValidation adv, BeanManager beanManager)
-    {
-        WindowBeanHolder windowBeanHolder
-            = BeanProvider.getContextualReference(beanManager, 
WindowBeanHolder.class, false);
-
-        WindowIdHolder windowIdHolder
-            = BeanProvider.getContextualReference(beanManager, 
WindowIdHolder.class, false);
-
-        windowContext.initWindowContext(windowBeanHolder, windowIdHolder);
-    }
-
-    public WindowContextImpl getWindowContext()
-    {
-        return windowContext;
-    }
-}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/InjectableWindowContext.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/InjectableWindowContext.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/InjectableWindowContext.java
index 4263c8e..f5f3945 100644
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/InjectableWindowContext.java
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/InjectableWindowContext.java
@@ -19,6 +19,7 @@
 package org.apache.deltaspike.core.impl.scope.window;
 
 import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension;
 import org.apache.deltaspike.core.spi.scope.window.WindowContext;
 
 import javax.enterprise.inject.Typed;

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
index a94966f..a83e0bd 100644
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
@@ -18,15 +18,9 @@
  */
 package org.apache.deltaspike.core.impl.scope.window;
 
-import javax.annotation.PreDestroy;
-import javax.enterprise.context.SessionScoped;
-import javax.enterprise.inject.spi.BeanManager;
-import java.io.Serializable;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import org.apache.deltaspike.core.impl.scope.AbstractBeanHolder;
 
-import org.apache.deltaspike.core.util.context.AbstractContext;
-import org.apache.deltaspike.core.util.context.ContextualStorage;
+import javax.enterprise.context.SessionScoped;
 
 /**
  * This holder will store the window Ids and it's beans for the current
@@ -34,86 +28,7 @@ import 
org.apache.deltaspike.core.util.context.ContextualStorage;
  * to treat async-supported and similar headache.
  */
 @SessionScoped
-public class WindowBeanHolder implements Serializable
+public class WindowBeanHolder extends AbstractBeanHolder<String>
 {
     private static final long serialVersionUID = 6313493410718133308L;
-
-    /**
-     * key: the windowId for the browser tab or window
-     * value: the {@link ContextualStorage} which holds all the
-     * {@link javax.enterprise.inject.spi.Bean}s.
-     */
-    private Map<String, ContextualStorage> storageMap = new 
ConcurrentHashMap<String, ContextualStorage>();
-
-    /**
-     * This method will return the ContextualStorage or create a new one
-     * if no one is yet assigned to the current windowId.
-     * @param beanManager we need the CDI {@link 
javax.enterprise.inject.spi.BeanManager} for serialisation.
-     * @param windowId the windowId for the current browser tab or window.
-     * @param createIfNotExist true if a new storage should get created (if it 
doesn't exist already), false otherwise
-     */
-    public ContextualStorage getContextualStorage(BeanManager beanManager, 
String windowId, boolean createIfNotExist)
-    {
-        ContextualStorage contextualStorage = storageMap.get(windowId);
-        if (contextualStorage == null && createIfNotExist)
-        {
-            contextualStorage = createContextualStorage(beanManager, windowId);
-        }
-
-        return contextualStorage;
-    }
-
-    private synchronized ContextualStorage createContextualStorage(BeanManager 
beanManager, String windowId)
-    {
-        ContextualStorage contextualStorage = storageMap.get(windowId);
-        if (contextualStorage == null)
-        {
-            contextualStorage = new ContextualStorage(beanManager, true, true);
-            storageMap.put(windowId, contextualStorage);
-        }
-        return contextualStorage;
-    }
-
-    public Map<String, ContextualStorage> getStorageMap()
-    {
-        return storageMap;
-    }
-
-    /**
-     *
-     * This method will replace the storageMap and with
-     * a new empty one.
-     * This method can be used to properly destroy the WindowBeanHolder beans
-     * without having to sync heavily. Any
-     * {@link javax.enterprise.inject.spi.Bean#destroy(Object, 
javax.enterprise.context.spi.CreationalContext)}
-     * should be performed on the returned old storage map.
-     * @return the old storageMap.
-     */
-    public Map<String, ContextualStorage> forceNewStorage()
-    {
-        Map<String, ContextualStorage> oldStorageMap = storageMap;
-        storageMap = new ConcurrentHashMap<String, ContextualStorage>();
-        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;WindowScoped beans.
-     */
-    @PreDestroy
-    public void destroyBeans()
-    {
-        // we replace the old windowBeanHolder beans with a new storage Map
-        // an afterwards destroy the old Beans without having to care about 
any syncs.
-        Map<String, ContextualStorage> oldWindowContextStorages = 
forceNewStorage();
-
-        for (ContextualStorage contextualStorage : 
oldWindowContextStorages.values())
-        {
-            AbstractContext.destroyAllActive(contextualStorage);
-        }
-
-    }
 }

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
index ce63708..10faa7b 100644
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
@@ -65,7 +65,7 @@ public class WindowContextImpl extends AbstractContext 
implements WindowContext
      * requestscoped windowIdHolder in a later phase because
      * getBeans is only allowed from AfterDeploymentValidation onwards.
      */
-    void initWindowContext(WindowBeanHolder windowBeanHolder, WindowIdHolder 
windowIdHolder)
+    public void init(WindowBeanHolder windowBeanHolder, WindowIdHolder 
windowIdHolder)
     {
         this.windowBeanHolder = windowBeanHolder;
         this.windowIdHolder = windowIdHolder;

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextProducer.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextProducer.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextProducer.java
index 2f1e686..46d8d31 100644
--- 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextProducer.java
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextProducer.java
@@ -23,13 +23,14 @@ import javax.enterprise.context.Dependent;
 import javax.enterprise.inject.Produces;
 import javax.inject.Inject;
 
+import org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension;
 import org.apache.deltaspike.core.spi.scope.window.WindowContext;
 
 /**
  * This producer provides access to the internally created
  * {@link WindowContext} implementation.
  * It simply wraps through to the instance used in the
- * {@link DeltaSpikeContextExtension}.
+ * {@link org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension}.
  */
 @ApplicationScoped
 public class WindowContextProducer

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/ConversationUtils.java
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/ConversationUtils.java
 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/ConversationUtils.java
new file mode 100644
index 0000000..08e4028
--- /dev/null
+++ 
b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/ConversationUtils.java
@@ -0,0 +1,77 @@
+/*
+ * 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.deltaspike.core.impl.util;
+
+import org.apache.deltaspike.core.api.scope.ConversationGroup;
+import org.apache.deltaspike.core.impl.scope.conversation.ConversationKey;
+
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.inject.Typed;
+import javax.enterprise.inject.spi.Bean;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+@Typed()
+public abstract class ConversationUtils
+{
+    private ConversationUtils()
+    {
+    }
+
+    public static ConversationKey convertToConversationKey(Contextual<?> 
contextual)
+    {
+        if (!(contextual instanceof Bean))
+        {
+            throw new IllegalArgumentException(
+                contextual.getClass().getName() + " is not of type " + 
Bean.class.getName());
+        }
+
+        Bean<?> bean = (Bean<?>) contextual;
+
+        //don't cache it (due to the support of different producers)
+        ConversationGroup conversationGroupAnnotation = 
findConversationGroupAnnotation(bean);
+
+        Class<?> conversationGroup;
+        if (conversationGroupAnnotation != null)
+        {
+            conversationGroup = conversationGroupAnnotation.value();
+        }
+        else
+        {
+            conversationGroup = bean.getBeanClass();
+        }
+
+        Set<Annotation> qualifiers = bean.getQualifiers();
+        return new ConversationKey(conversationGroup, qualifiers.toArray(new 
Annotation[qualifiers.size()]));
+    }
+
+    private static ConversationGroup findConversationGroupAnnotation(Bean<?> 
bean)
+    {
+        Set<Annotation> qualifiers = bean.getQualifiers();
+
+        for (Annotation qualifier : qualifiers)
+        {
+            if 
(ConversationGroup.class.isAssignableFrom(qualifier.annotationType()))
+            {
+                return (ConversationGroup) qualifier;
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/fca5cbd5/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
----------------------------------------------------------------------
diff --git 
a/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
 
b/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index 666a6b6..a943098 100644
--- 
a/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ 
b/deltaspike/core/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -22,4 +22,4 @@ org.apache.deltaspike.core.impl.message.MessageBundleExtension
 
org.apache.deltaspike.core.impl.exception.control.extension.ExceptionControlExtension
 org.apache.deltaspike.core.impl.config.ConfigurationExtension
 org.apache.deltaspike.core.impl.jmx.MBeanExtension
-org.apache.deltaspike.core.impl.scope.window.DeltaSpikeContextExtension
+org.apache.deltaspike.core.impl.scope.DeltaSpikeContextExtension

Reply via email to