Package org.jboss.seam.faces.context

Source Code of org.jboss.seam.faces.context.RenderScopedContext

/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.seam.faces.context;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.enterprise.context.ContextNotActiveException;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.BeanManager;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.inject.Named;

import org.jboss.seam.faces.util.BeanManagerUtils;
import org.jboss.seam.solder.beanManager.BeanManagerLocator;

/**
* This class provides lifecycle management for the {@link RenderContext}
*
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
* @author Brian Leathem
*/
@RequestScoped
public class RenderScopedContext implements Context, PhaseListener, Serializable {
    // TODO probably need a way to clean up old contexts - e.g: after a certain
    // expiry, the context is probably dead, and to prevent leaks if sessions
    // live for a long time, it would be important to clean these up
    private static final long serialVersionUID = -1580689204988513798L;

    private static final String SESSION_KEY_PREFIX = RenderScopedContext.class.getName() + ".context";
    private final static String COMPONENT_MAP_NAME = RenderScopedContext.class.getName() + ".componentInstanceMap";
    private final static String CREATIONAL_MAP_NAME = RenderScopedContext.class.getName() + ".creationalInstanceMap";
    public static final String RENDER_SCOPE_URL_KEY = RenderScopedContext.class.getName() + ".url.key";

    String requestParameterName = "fid";

    RenderContext currentContext = null;

    @Produces
    @Named
    @RequestScoped
    public RenderContext getContextInstance() {
        if (currentContext == null) {
            initializeCurrentContext();
        }
        return currentContext;
    }

    private RenderContext getCurrentRenderContext() {
        BeanManager manager = new BeanManagerLocator().getBeanManager();
        return BeanManagerUtils.getContextualInstance(manager, RenderContext.class);
    }

    private void assertActive() {
        if (!isActive()) {
            throw new ContextNotActiveException(
                    "Seam context with scope annotation @RenderScoped is not active with respect to the current thread. "
                            + "This is probably caused by attempting to access the Flash before it was created or after it was destroyed.");
        }
    }

    private void initializeCurrentContext() {
        Integer currentId = getCurrentId();

        if ((currentId != null) && savedContextExists(currentId)) {
            // getRenderContextForCurrentIdAndReferrer
            RenderContext context = getRenderContextMap().get(currentId);
            currentContext = context;
        }

        if (currentContext == null) {
            RenderContextImpl context = new RenderContextImpl();
            context.setId(getNextRenderContextId());
            getRenderContextMap().put(context.getId(), context);
            currentContext = context;
        }
    }

    private int getNextRenderContextId() {
        Map<Integer, RenderContext> renderContextMap = getRenderContextMap();
        int id = 0;

        while (renderContextMap.containsKey(id)) {
            id++;
        }
        return id;
    }

    private boolean savedContextExists(final int id) {
        return getRenderContextMap().get(id) instanceof RenderContext;
    }

    private Integer getCurrentId() {
        if (countRenderContexts() == 1) {
            return getRenderContextMap().keySet().iterator().next();
        }
        Map<String, String> requestParameterMap = FacesContext.getCurrentInstance().getExternalContext()
                .getRequestParameterMap();
        String currentId = requestParameterMap.get(requestParameterName);
        Integer result = null;
        try {
            if (currentId != null) {
                result = Integer.valueOf(currentId);
            }
        } catch (NumberFormatException e) {
            // ignored!
        }
        return result;
    }

    /**
     * Destroy the current context since Render Response has completed.
     */
    @SuppressWarnings({"unchecked", "rawtypes", "unused"})
    public void afterPhase(final PhaseEvent event) {
        if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
            RenderContext contextInstance = getContextInstance();
            if (contextInstance != null) {
                Integer id = contextInstance.getId();
                RenderContext removed = getRenderContextMap().remove(id);

                Map<Contextual<?>, Object> componentInstanceMap = getComponentInstanceMap();
                Map<Contextual<?>, CreationalContext<?>> creationalContextMap = getCreationalContextMap();

                if ((componentInstanceMap != null) && (creationalContextMap != null)) {
                    for (Entry<Contextual<?>, Object> componentEntry : componentInstanceMap.entrySet()) {
                        Contextual contextual = componentEntry.getKey();
                        Object instance = componentEntry.getValue();
                        CreationalContext creational = creationalContextMap.get(contextual);

                        contextual.destroy(instance, creational);
                    }
                }
            }
        }
    }

    public void beforePhase(final PhaseEvent arg0) {
        /* intentionally empty */
    }

    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }

    /*
     * Context Methods
     */
    @SuppressWarnings("unchecked")
    public <T> T get(final Contextual<T> component) {
        assertActive();
        return (T) getComponentInstanceMap().get(component);
    }

    @SuppressWarnings("unchecked")
    public <T> T get(final Contextual<T> component, final CreationalContext<T> creationalContext) {
        assertActive();

        T instance = get(component);

        if (instance == null) {
            Map<Contextual<?>, CreationalContext<?>> creationalContextMap = getCreationalContextMap();
            Map<Contextual<?>, Object> componentInstanceMap = getComponentInstanceMap();

            synchronized (componentInstanceMap) {
                instance = (T) componentInstanceMap.get(component);
                if (instance == null) {
                    instance = component.create(creationalContext);

                    if (instance != null) {
                        componentInstanceMap.put(component, instance);
                        creationalContextMap.put(component, creationalContext);
                    }
                }
            }
        }

        return instance;
    }

    public boolean isActive() {
        return FacesContext.getCurrentInstance() != null;
    }

    public Class<? extends Annotation> getScope() {
        return RenderScoped.class;
    }

    /*
     * Helpers for manipulating the Component/Context maps.
     */
    @SuppressWarnings("unchecked")
    private Map<Contextual<?>, Object> getComponentInstanceMap() {
        ConcurrentHashMap<Contextual<?>, Object> map = (ConcurrentHashMap<Contextual<?>, Object>) getCurrentRenderContext()
                .get(COMPONENT_MAP_NAME);

        if (map == null) {
            map = new ConcurrentHashMap<Contextual<?>, Object>();
            getCurrentRenderContext().put(COMPONENT_MAP_NAME, map);
        }

        return map;
    }

    @SuppressWarnings("unchecked")
    private Map<Contextual<?>, CreationalContext<?>> getCreationalContextMap() {
        Map<Contextual<?>, CreationalContext<?>> map = (ConcurrentHashMap<Contextual<?>, CreationalContext<?>>) getCurrentRenderContext()
                .get(CREATIONAL_MAP_NAME);

        if (map == null) {
            map = new ConcurrentHashMap<Contextual<?>, CreationalContext<?>>();
            getCurrentRenderContext().put(CREATIONAL_MAP_NAME, map);
        }

        return map;
    }

    @SuppressWarnings("unchecked")
    private synchronized Map<Integer, RenderContext> getRenderContextMap() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        Map<String, Object> sessionMap = externalContext.getSessionMap();
        Map<Integer, RenderContext> renderContextMap;
        if (sessionMap.containsKey(SESSION_KEY_PREFIX)) {
            renderContextMap = (Map<Integer, RenderContext>) sessionMap.get(SESSION_KEY_PREFIX);
        } else {
            renderContextMap = new ConcurrentHashMap<Integer, RenderContext>();
            sessionMap.put(SESSION_KEY_PREFIX, renderContextMap);
        }
        return renderContextMap;
    }

    public int countRenderContexts() {
        return getRenderContextMap().size();
    }

    /**
     * Get the name of the request parameter to contain the current {@link RenderContext} id.
     */
    public String getRequestParameterName() {
        return requestParameterName;
    }
}
TOP

Related Classes of org.jboss.seam.faces.context.RenderScopedContext

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.