All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.faces.CurrentThreadToServletContext Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 * 
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 * 
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 * 
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.

 */

package javax.faces;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

// ----------------------------------------------------------- Inner Classes
final class CurrentThreadToServletContext {
    ConcurrentMap applicationMap = new ConcurrentHashMap();
    private AtomicBoolean logNullFacesContext = new AtomicBoolean(false);
    private AtomicBoolean logNonNullFacesContext = new AtomicBoolean(false);
    // Bug 20458755: This instance provides a method to look up the current FacesContext
    // that bypasses the additional check for the InitFacesContext introduced
    // by the fix for 20458755
    private final ServletContextFacesContextFactory servletContextFacesContextFactory;
    
    private static final Logger LOGGER;
    
    static {
        LOGGER = Logger.getLogger("javax.faces", "javax.faces.LogStrings");
    }

    CurrentThreadToServletContext() {
        servletContextFacesContextFactory = new ServletContextFacesContextFactory();
    }
    
    // ------------------------------------------------------ Public Methods
    Object getFallbackFactory(FactoryFinderInstance brokenFactoryManager, String factoryName) {
        Object result = null;
        ClassLoader cl = getClassLoader();        
        for (Map.Entry cur : applicationMap.entrySet()) {
            if (cur.getKey().getClassLoader().equals(cl) && !cur.getValue().equals(brokenFactoryManager)) {
                result = cur.getValue().getFactory(factoryName);
                if (null != result) {
                    break;
                }
            }
        }
        return result;
    }

    FactoryFinderInstance getApplicationFactoryManager() {
        ClassLoader cl = getClassLoader();
        FactoryFinderInstance result = getApplicationFactoryManager(cl, true);
        return result;
    }
    
    FactoryFinderInstance getApplicationFactoryManager(boolean create) {
        ClassLoader cl = getClassLoader();
        FactoryFinderInstance result = getApplicationFactoryManager(cl, create);
        return result;
    }
    
    private FactoryFinderInstance getApplicationFactoryManager(ClassLoader cl, boolean create) {
        FacesContext facesContext = servletContextFacesContextFactory.getFacesContextWithoutServletContextLookup();
        boolean isSpecialInitializationCase = detectSpecialInitializationCase(facesContext);
        FactoryManagerCacheKey key = new FactoryManagerCacheKey(facesContext, cl, applicationMap);
        FactoryFinderInstance result = applicationMap.get(key);
        FactoryFinderInstance toCopy = null;
        if (result == null && create) {
            boolean createNewFactoryManagerInstance = false;
            if (isSpecialInitializationCase) {
                // We need to obtain a reference to the correct
                // FactoryFinderInstance.  Iterate through the data structure
                // containing all FactoryFinderInstance instances for this VM.
                FactoryManagerCacheKey curKey;
                boolean classLoadersMatchButContextsDoNotMatch = false;
                boolean foundNoMatchInApplicationMap = true;
                for (Map.Entry cur : applicationMap.entrySet()) {
                    curKey = cur.getKey();
                    // If the current FactoryFinderInstance is for a
                    // the same ClassLoader as the current ClassLoader...
                    if (curKey.getClassLoader().equals(cl)) {
                        foundNoMatchInApplicationMap = false;
                        // Check the other descriminator for the
                        // key: the context.
                        // If the context objects of the keys are
                        // both non-null and non-equal, then *do*
                        // create a new FactoryFinderInstance instance.
                        if ((null != key.getContext() && null != curKey.getContext()) && (!key.getContext().equals(curKey.getContext()))) {
                            classLoadersMatchButContextsDoNotMatch = true;
                            toCopy = cur.getValue();
                        } else {
                            // Otherwise, use this FactoryFinderInstance
                            // instance.
                            result = cur.getValue();
                        }
                        break;
                    }
                }
                // We must create a new FactoryFinderInstance if there was no matchingKey
                // at all found in the applicationMap, or a matchingKey was found
                // and the matchingKey is safe to use in this web app
                createNewFactoryManagerInstance = foundNoMatchInApplicationMap || (null == result && classLoadersMatchButContextsDoNotMatch);
            } else {
                createNewFactoryManagerInstance = true;
            }
            if (createNewFactoryManagerInstance) {
                FactoryFinderInstance newResult;
                if (null != toCopy) {
                    newResult = new FactoryFinderInstance(toCopy);
                } else {
                    newResult = new FactoryFinderInstance();
                }
                result = applicationMap.putIfAbsent(key, newResult);
                result = (null != result) ? result : newResult;
            }
        }
        return result;
    }
    
    /*
     * Uses the FactoryManagerCacheKey system to find the ServletContext 
     * associated with the current ClassLoader, if any.
     */
    Object getServletContextForCurrentClassLoader() {
        Object result;
        FactoryManagerCacheKey key = new FactoryManagerCacheKey(null, getClassLoader(), applicationMap);
        result = key.getContext();
        
        return result;
    }

    /**
     * This method is used to detect the following special initialization case.
     * IF no FactoryFinderInstance can be found for key,
    AND this call to getApplicationFactoryFinderInstance() *does* have a currentKeyrent FacesContext
    BUT a previous call to getApplicationFactoryFinderInstance *did not* have a currentKeyrent FacesContext
     *
     * @param facesContext the currentKeyrent FacesContext for this request
     * @return true if the currentKeyrent execution falls into the special initialization case.
     */
    private boolean detectSpecialInitializationCase(FacesContext facesContext) {
        boolean result = false;
        if (null == facesContext) {
            logNullFacesContext.compareAndSet(false, true);
        } else {
            logNonNullFacesContext.compareAndSet(false, true);
        }
        result = logNullFacesContext.get() && logNonNullFacesContext.get();
        return result;
    }

    void removeApplicationFactoryManager() {
        ClassLoader cl = getClassLoader();
        FactoryFinderInstance fm = this.getApplicationFactoryManager(cl, false);
        if (null != fm) {
            fm.clearInjectionProvider();
        }
        FacesContext facesContext = servletContextFacesContextFactory.getFacesContextWithoutServletContextLookup();
        boolean isSpecialInitializationCase = detectSpecialInitializationCase(facesContext);
        FactoryManagerCacheKey key = new FactoryManagerCacheKey(facesContext, cl, applicationMap);
        applicationMap.remove(key);
        if (isSpecialInitializationCase) {
            logNullFacesContext.set(false);
            logNonNullFacesContext.set(false);
        }
    }

    void resetSpecialInitializationCaseFlags() {
        logNullFacesContext.set(false);
        logNonNullFacesContext.set(false);
    }
    
    /**
     * 

Identify and return the class loader that is associated with the * calling web application.

* * @throws FacesException if the web application class loader * cannot be identified */ private ClassLoader getClassLoader() throws FacesException { // J2EE 1.3 (and later) containers are required to make the // web application class loader visible through the context // class loader of the current thread. ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) { throw new FacesException("getContextClassLoader"); } return (cl); } private static final class FactoryManagerCacheKey { // The ClassLoader that is active the first time this key // is created. At startup time, this is assumed to be the // web app ClassLoader private ClassLoader cl; // I marker that disambiguates the case when multiple // web apps have the same web app ClassLoader but different // ServletContext instances. private Long marker; // The ServletContext corresponding to this marker/ClassLoader pair. private Object context; private static final String MARKER_KEY = FactoryFinder.class.getName() + "." + FactoryManagerCacheKey.class.getSimpleName(); private static final String INIT_TIME_CL_KEY = MARKER_KEY + ".InitTimeCLKey"; // FactoryManagerCacheKey(FacesContext facesContext, ClassLoader cl, Map factoryMap) { ExternalContext extContext = (null != facesContext) ? facesContext.getExternalContext() : null; Object servletContext = (null != extContext) ? extContext.getContext() : null; if (null == facesContext || null == extContext || null == servletContext) { initFromFactoryMap(cl, factoryMap); } else { initFromAppMap(extContext, cl); } } private void initFromFactoryMap(ClassLoader cl, Map factoryMap) { // We don't have a FacesContext. // Our only recourse is to inspect the keys of the // factoryMap and see if any of them has a classloader // equal to our argument cl. Set keys = factoryMap.keySet(); FactoryManagerCacheKey matchingKey = null; if (keys.isEmpty()) { this.cl = cl; this.marker = new Long(System.currentTimeMillis()); } else { // For each entry in the factoryMap's keySet... for (FactoryManagerCacheKey currentKey : keys) { assert(null != currentKey.cl); ClassLoader matchingCL = findMatchConsideringParentClassLoader(cl, currentKey.cl); // If there is a match... if (null != matchingCL) { // If the match was found on a previous iteration... if (null != matchingKey) { LOGGER.log(Level.WARNING, "Multiple JSF Applications found on same ClassLoader. Unable to safely determine which FactoryManager instance to use. Defaulting to first match."); break; } matchingKey = currentKey; this.cl = matchingCL; } } if (null != matchingKey) { this.marker = matchingKey.marker; this.context = matchingKey.context; } } } private ClassLoader findMatchConsideringParentClassLoader(ClassLoader argumentCL, ClassLoader currentKeyCL) { ClassLoader curCL = argumentCL; // For each ClassLoader in the hierarchy starting // with the argument ClassLoader... while (null != curCL) { // if the ClassLoader at this level in the hierarchy // is equal to the argument ClassLoader, consider it a matchingKey. if (curCL.equals(currentKeyCL)) { return curCL; } else { // If it's not a matchingKey, try the parent in the ClassLoader // hierarchy. curCL = curCL.getParent(); } } return null; } private void initFromAppMap(ExternalContext extContext, ClassLoader cl) { Map appMap = extContext.getApplicationMap(); Long val = (Long) appMap.get(MARKER_KEY); if (null == val) { this.marker = new Long(System.currentTimeMillis()); appMap.put(MARKER_KEY, marker); // If we needed to create a marker, assume that the // argument CL is safe to treat as the web app // ClassLoader. This assumption allows us // to bypass the ClassLoader resolution algorithm // in resolveToFirstTimeUsedClassLoader() in all cases // except when the TCCL has been replaced. appMap.put(INIT_TIME_CL_KEY, new Integer(System.identityHashCode(cl))); } else { this.marker = val; } this.cl = resolveToFirstTimeUsedClassLoader(cl, extContext); this.context = extContext.getContext(); } /* * Resolve the argument ClassLoader to be the ClassLoader that * was passed in to the ctor the first time a FactoryManagerCacheKey * was created for this web app. */ private ClassLoader resolveToFirstTimeUsedClassLoader(ClassLoader toResolve, ExternalContext extContext) { ClassLoader curCL = toResolve; ClassLoader resolved = null; Map appMap = extContext.getApplicationMap(); // See if the argument curCL already is the web app class loader Integer webAppCLHashCode = (Integer) appMap.get(INIT_TIME_CL_KEY); boolean found = false; if (null != webAppCLHashCode) { int toResolveHashCode = System.identityHashCode(curCL); while (!found && null != curCL) { found = (toResolveHashCode == webAppCLHashCode); if (!found) { curCL = curCL.getParent(); toResolveHashCode = System.identityHashCode(curCL); } } } resolved = found ? curCL : toResolve; return resolved; } // ClassLoader getClassLoader() { return cl; } Object getContext() { return context; } private FactoryManagerCacheKey() {} @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final FactoryManagerCacheKey other = (FactoryManagerCacheKey) obj; if (this.cl != other.cl && (this.cl == null || !this.cl.equals(other.cl))) { return false; } if (this.marker != other.marker && (this.marker == null || !this.marker.equals(other.marker))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 97 * hash + (this.cl != null ? this.cl.hashCode() : 0); hash = 97 * hash + (this.marker != null ? this.marker.hashCode() : 0); return hash; } } } // END FactoryCache




© 2015 - 2024 Weber Informatics LLC | Privacy Policy