/* * 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.ConversationSubGroup; 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.ContextualInstanceInfo; import org.apache.deltaspike.core.util.context.ContextualStorage; import javax.enterprise.context.spi.Contextual; import javax.enterprise.inject.Typed; import javax.enterprise.inject.spi.BeanManager; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; 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; 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 protected ContextualStorage getContextualStorage(Contextual<?> contextual, boolean createIfNotExist) { ConversationKey conversationKey = ConversationUtils.convertToConversationKey(contextual, this.beanManager); return this.conversationBeanHolder.getContextualStorage(this.beanManager, conversationKey, createIfNotExist); } @Override protected List<ContextualStorage> getActiveContextualStorages() { List<ContextualStorage> result = new ArrayList<ContextualStorage>(); result.addAll(this.conversationBeanHolder.getStorageMap().values()); return result; } @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>(); ConversationSubGroup conversationSubGroup = conversationGroup.getAnnotation(ConversationSubGroup.class); Set<Class<?>> subGroups = null; if (conversationSubGroup != null) { conversationGroup = ConversationUtils.getDeclaredConversationGroup(conversationGroup); subGroups = new HashSet<Class<?>>(conversationSubGroup.subGroup().length); Collections.addAll(subGroups, conversationSubGroup.subGroup()); } Map<ConversationKey, ContextualStorage> storageMap = this.conversationBeanHolder.getStorageMap(); for (Map.Entry<ConversationKey, ContextualStorage> entry : storageMap.entrySet()) { if (entry.getKey().getConversationGroup().equals(conversationGroup)) { if (subGroups == null) { AbstractContext.destroyAllActive(entry.getValue()); result.add(entry.getValue()); storageMap.remove(entry.getKey()); //ok due to ConcurrentHashMap } else { tryToDestroySubGroup(subGroups, entry); if (entry.getValue().getStorage().isEmpty()) { storageMap.remove(entry.getKey()); //ok due to ConcurrentHashMap } } } } return result; } private void tryToDestroySubGroup(Set<Class<?>> subGroups, Map.Entry<ConversationKey, ContextualStorage> entry) { ContextualStorage storage = entry.getValue(); for (Map.Entry<Object, ContextualInstanceInfo<?>> storageEntry : storage.getStorage().entrySet()) { for (Class<?> subGroup : subGroups) { Class classOfEntry = storageEntry.getValue().getContextualInstance().getClass(); if (subGroup.equals(classOfEntry) || (subGroup.isInterface() && subGroup.isAssignableFrom(classOfEntry))) { Contextual bean = storage.getBean(storageEntry.getKey()); AbstractContext.destroyBean(bean, storageEntry.getValue()); storage.getStorage().remove(storageEntry.getKey()); //ok due to ConcurrentHashMap break; } } } } @Override public void closeConversations() { this.conversationBeanHolder.destroyBeans(); } }