Package org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation

Source Code of org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.JsfWindowContext

/*
* 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.extensions.cdi.jsf.impl.scope.conversation;

import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.Conversation;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.config.WindowContextConfig;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.config.ConversationConfig;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.event.CloseWindowContextEvent;
import org.apache.myfaces.extensions.cdi.core.impl.util.CodiUtils;
import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.ConversationFactory;
import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.ConversationKey;
import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.EditableConversation;
import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.EditableWindowContext;
import org.apache.myfaces.extensions.cdi.jsf.impl.util.JsfUtils;
import org.apache.myfaces.extensions.cdi.jsf.impl.util.RequestCache;

import javax.enterprise.inject.Typed;
import javax.enterprise.inject.spi.BeanManager;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import static org.apache.myfaces.extensions.cdi.core.impl.util.CodiUtils.isQualifierEqual;
import static org.apache.myfaces.extensions.cdi.jsf.impl.util.ConversationUtils.convertToScope;
import static org.apache.myfaces.extensions.cdi.jsf.impl.util.ExceptionUtils.*;

/**
* TODO
*
* @author Gerhard Petracek
*/
@Typed()
class JsfWindowContext implements EditableWindowContext
{
    private static final long serialVersionUID = 5272798129165017829L;

    private final String id;

    private final WindowContextConfig windowContextConfig;
    private final ConversationConfig conversationConfig;
    private final boolean projectStageDevelopment;

    //all implementations will be serializable
    private BeanManager beanManager;

    private ConcurrentHashMap<ConversationKey, EditableConversation> groupedConversations
            = new ConcurrentHashMap<ConversationKey, EditableConversation>();

    private ConcurrentHashMap<String, Object> attributes = new ConcurrentHashMap<String, Object>();

    private final TimeoutExpirationEvaluator expirationEvaluator;

    JsfWindowContext(String windowContextId,
                     WindowContextConfig windowContextConfig,
                     ConversationConfig conversationConfig,
                     boolean projectStageDevelopment,
                     BeanManager beanManager)
    {
        this.id = windowContextId;
        this.windowContextConfig = windowContextConfig;
        this.conversationConfig = conversationConfig;
        this.projectStageDevelopment = projectStageDevelopment;
        this.beanManager = beanManager;

        this.expirationEvaluator = new TimeoutExpirationEvaluator(
                this.windowContextConfig.getWindowContextTimeoutInMinutes());
    }

    /**
     * {@inheritDoc}
     */
    public String getId()
    {
        return this.id;
    }

    /**
     * {@inheritDoc}
     */
    public void closeConversations()
    {
        //don't force it because window-scoped beans shouldn't be affected
        closeConversations(false);
    }

    /**
     * {@inheritDoc}
     */
    public void close()
    {
        if(this.windowContextConfig.isCloseWindowContextEventEnabled())
        {
            this.beanManager.fireEvent(new CloseWindowContextEvent(this));
        }

        closeConversations(true);
        this.attributes.clear();
    }

    private synchronized void closeConversations(boolean forceEnd)
    {
        for (Map.Entry<ConversationKey, EditableConversation> conversationEntry : this.groupedConversations.entrySet())
        {
            closeAndRemoveConversation(conversationEntry.getKey(), conversationEntry.getValue(), forceEnd);
        }
        JsfUtils.resetConversationCache();
    }

    /**
     * {@inheritDoc}
     */
    public EditableConversation getConversation(Class conversationGroupKey, Annotation... qualifiers)
    {
        Class<? extends Annotation> scopeType = convertToScope(this.beanManager, conversationGroupKey, qualifiers);

        ConversationKey conversationKey =
                new DefaultConversationKey(scopeType, conversationGroupKey, qualifiers);

        EditableConversation conversation = RequestCache.getConversation(conversationKey);

        if(conversation == null)
        {
            conversation = getConversationForKey(conversationKey, false);

            //TODO
            if (conversation != null && !conversation.isActive())
            {
                closeAndRemoveConversation(conversationKey, conversation, true);
                conversation = null;
            }

            if (conversation == null)
            {
                conversation = createConversation(conversationGroupKey, qualifiers);
                this.groupedConversations.put(conversationKey, conversation);
            }

            RequestCache.setConversation(conversationKey, conversation);
        }
        return conversation;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isConversationActive(Class conversationGroupKey, Annotation... qualifiers)
    {
        Class<? extends Annotation> scopeType = convertToScope(this.beanManager, conversationGroupKey, qualifiers);

        ConversationKey conversationKey =
                new DefaultConversationKey(scopeType, conversationGroupKey, qualifiers);

        EditableConversation conversation = RequestCache.getConversation(conversationKey);

        if(conversation == null)
        {
            conversation = getConversationForKey(conversationKey, false);

            if (conversation == null)
            {
                return false;
            }
        }
        return conversation.getActiveState();
    }

    /**
     * {@inheritDoc}
     */
    public Conversation closeConversation(Class conversationGroupKey, Annotation... qualifiers)
    {
        Class<? extends Annotation> scopeType = convertToScope(this.beanManager, conversationGroupKey, qualifiers);

        ConversationKey conversationKey =
                new DefaultConversationKey(scopeType, conversationGroupKey, qualifiers);

        EditableConversation conversation = getConversationForKey(conversationKey, true);

        return closeAndRemoveConversation(conversationKey, conversation, true);
    }

    /**
     * {@inheritDoc}
     */
    public Set<Conversation> closeConversationGroup(Class conversationGroupKey)
    {
        Set<Conversation> removedConversations = new HashSet<Conversation>();
        for(Map.Entry<ConversationKey, EditableConversation> conversationEntry : this.groupedConversations.entrySet())
        {
            if(conversationGroupKey.isAssignableFrom(conversationEntry.getKey().getConversationGroup()))
            {
                removedConversations.add(
                        closeAndRemoveConversation(conversationEntry.getKey(), conversationEntry.getValue(), true));
            }
        }
        return removedConversations;
    }

    private EditableConversation closeAndRemoveConversation(ConversationKey conversationKey,
                                                            EditableConversation conversation,
                                                            boolean forceEnd)
    {
        logInformationAboutConversations("before JsfWindowContext#endAndRemoveConversation");

        try
        {
            if (forceEnd)
            {
                conversation.close();
                return this.groupedConversations.remove(conversationKey);
            }
            else
            {
                conversation.deactivate();

                if(!conversation.isActive())
                {
                    return this.groupedConversations.remove(conversationKey);
                }
            }
        }
        finally
        {
            logInformationAboutConversations("after JsfWindowContext#endAndRemoveConversation");
        }

        return null;
    }

    /**
     * {@inheritDoc}
     */
    public EditableConversation createConversation(Class conversationGroupKey, Annotation... qualifiers)
    {
        Class<? extends Annotation> scopeType = convertToScope(this.beanManager, conversationGroupKey, qualifiers);

        ConversationKey conversationKey =
                new DefaultConversationKey(scopeType, conversationGroupKey, qualifiers);

        ConversationFactory conversationFactory = CodiUtils.getContextualReferenceByClass(ConversationFactory.class);
        return conversationFactory.createConversation(conversationKey, this.conversationConfig);
    }

    /**
     * {@inheritDoc}
     */
    public Map<ConversationKey /*conversation group*/, EditableConversation> getConversations()
    {
        return Collections.unmodifiableMap(this.groupedConversations);
    }

    /**
     * {@inheritDoc}
     */
    public WindowContextConfig getConfig()
    {
        return this.windowContextConfig;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isActive()
    {
        return !this.expirationEvaluator.isExpired();
    }

    /**
     * {@inheritDoc}
     */
    public Date getLastAccess()
    {
        return this.expirationEvaluator.getLastAccess();
    }

    /**
     * {@inheritDoc}
     */
    public void touch()
    {
        this.expirationEvaluator.touch();
    }

    /**
     * {@inheritDoc}
     */
    public void removeInactiveConversations()
    {
        Iterator<EditableConversation> conversations = this.groupedConversations.values().iterator();

        EditableConversation conversation;
        while (conversations.hasNext())
        {
            conversation = conversations.next();

            if (!conversation.getActiveState())
            {
                conversations.remove();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean setAttribute(String name, Object value)
    {
        return setAttribute(name, value, true);
    }

    /**
     * {@inheritDoc}
     */
    public boolean setAttribute(String name, Object value, boolean forceOverride)
    {
        if(value == null || (!forceOverride && containsAttribute(name)))
        {
            return false;
        }
        this.attributes.put(name, value);
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsAttribute(String name)
    {
        return this.attributes.containsKey(name);
    }

    /**
     * {@inheritDoc}
     */
    public <T> T getAttribute(String name, Class<T> targetType)
    {
        //noinspection unchecked
        return (T)this.attributes.get(name);
    }

    private EditableConversation getConversationForKey(ConversationKey conversationKey, boolean forceNewConversation)
    {
        EditableConversation editableConversation = this.groupedConversations.get(conversationKey);

        if(editableConversation != null)
        {
            return editableConversation;
        }

        if(!forceNewConversation)
        {
            return null;
        }

        if(conversationKey.getQualifiers() != null)
        {
            /*
             * we have to manually recalculate the conversation keys due to the restrictions of annotations.
             * we don't do that per default because in most use-cases you don't need to create manual qualifiers.
             * that means most use-cases will have a better performance and only very few will have an overhead as soon
             * as a conversation gets closed manually.
             */
            editableConversation = getConversationForDynamicKey(conversationKey);
        }

        if(editableConversation != null)
        {
            return editableConversation;
        }

        throw conversationNotFoundException(conversationKey.toString());
    }

    private EditableConversation getConversationForDynamicKey(ConversationKey conversationKey)
    {
        for(Map.Entry<ConversationKey, EditableConversation> conversationEntry : this.groupedConversations.entrySet())
        {
            if(isSameConversationType(conversationEntry.getKey(), conversationKey))
            {
                if(compareAnnotations(conversationEntry.getKey().getQualifiers(), conversationKey.getQualifiers()))
                {
                    return conversationEntry.getValue();
                }
            }

        }

        return null;
    }

    private boolean isSameConversationType(ConversationKey currentConversationKey, ConversationKey conversationKey)
    {
        return currentConversationKey.getConversationGroup().equals(conversationKey.getConversationGroup()) &&
                currentConversationKey.getScope().equals(conversationKey.getScope());
    }

    private boolean compareAnnotations(Set<Annotation> source, Set<Annotation> target)
    {
        Set<Annotation> sourceAnnotations = new HashSet<Annotation>(source);
        Set<Annotation> targetAnnotations = new HashSet<Annotation>(target);

        Iterator<Annotation> sourceAnnotationIterator = sourceAnnotations.iterator();

        Annotation sourceAnnotation;
        Annotation targetAnnotation;

        outer:
        while(sourceAnnotationIterator.hasNext())
        {
            sourceAnnotation = sourceAnnotationIterator.next();
           
            Iterator<Annotation> targetAnnotationIterator = targetAnnotations.iterator();
            while (targetAnnotationIterator.hasNext())
            {
                targetAnnotation = targetAnnotationIterator.next();

                if(isQualifierEqual(sourceAnnotation, targetAnnotation))
                {
                    sourceAnnotationIterator.remove();
                    targetAnnotationIterator.remove();

                    continue outer;
                }
            }
        }

        return sourceAnnotations.isEmpty() && targetAnnotations.isEmpty();
    }

    private void logInformationAboutConversations(String label)
    {
        if(!this.projectStageDevelopment)
        {
            return;
        }

        Logger logger = Logger.getLogger(JsfWindowContext.class.getName());
        logger.info(label);
        logger.info("\n*** conversations - start ***");
        for(Map.Entry<ConversationKey, EditableConversation> conversationEntry : this.groupedConversations.entrySet())
        {
            if(conversationEntry.getValue() instanceof DefaultConversation)
            {
                logger.info(conversationEntry.getValue().toString());
            }
        }
        logger.info("\n\n*** conversations - end ***");
        logger.info("***************************");
    }
}
TOP

Related Classes of org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.JsfWindowContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.