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

org.apache.myfaces.webapp.AbstractFacesInitializer Maven / Gradle / Ivy

Go to download

The private implementation classes of the Apache MyFaces Core JSF-2.0 Implementation

There is a newer version: 4.1.0-RC2
Show newest version
/*
 * 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.webapp;

import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
import org.apache.myfaces.config.FacesConfigValidator;
import org.apache.myfaces.config.FacesConfigurator;
import org.apache.myfaces.config.ManagedBeanBuilder;
import org.apache.myfaces.config.RuntimeConfig;
import org.apache.myfaces.config.element.ManagedBean;
import org.apache.myfaces.context.ReleaseableExternalContext;
import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
import org.apache.myfaces.shared.context.ExceptionHandlerImpl;
import org.apache.myfaces.shared.util.StateUtils;
import org.apache.myfaces.shared.util.WebConfigParamUtils;
import org.apache.myfaces.spi.WebConfigProvider;
import org.apache.myfaces.spi.WebConfigProviderFactory;
import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;

import javax.el.ExpressionFactory;
import javax.faces.application.Application;
import javax.faces.application.ProjectStage;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PostConstructApplicationEvent;
import javax.faces.event.PreDestroyApplicationEvent;
import javax.faces.event.SystemEvent;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Performs common initialization tasks.
 */
public abstract class AbstractFacesInitializer implements FacesInitializer {
    /**
     * The logger instance for this class.
     */
    //private static final Log log = LogFactory.getLog(AbstractFacesInitializer.class);
    private static final Logger log = Logger.getLogger(AbstractFacesInitializer.class.getName());
    
    /**
     * If the servlet mapping for the FacesServlet is added dynamically, Boolean.TRUE 
     * is stored under this key in the ServletContext.
     * ATTENTION: this constant is duplicate in MyFacesContainerInitializer.
     */
    private static final String FACES_SERVLET_ADDED_ATTRIBUTE = "org.apache.myfaces.DYNAMICALLY_ADDED_FACES_SERVLET";

    /**
     * This parameter specifies the ExpressionFactory implementation to use.
     */
    @JSFWebConfigParam(since="1.2.7")
    protected static final String EXPRESSION_FACTORY = "org.apache.myfaces.EXPRESSION_FACTORY";
    
    /**
     * If this param is set to true, the check for faces servlet mapping is not done 
     */
    @JSFWebConfigParam(since="2.0.3", defaultValue="false")
    protected static final String INITIALIZE_ALWAYS_STANDALONE = "org.apache.myfaces.INITIALIZE_ALWAYS_STANDALONE";

    /**
     * Performs all necessary initialization tasks like configuring this JSF
     * application.
     */
    public void initFaces(ServletContext servletContext) {
        try {
            if (log.isLoggable(Level.FINEST)) {
                log.finest("Initializing MyFaces");
            }

            // Some parts of the following configuration tasks have been implemented 
            // by using an ExternalContext. However, that's no problem as long as no 
            // one tries to call methods depending on either the ServletRequest or 
            // the ServletResponse.
            // JSF 2.0: FacesInitializer now has some new methods to
            // use proper startup FacesContext and ExternalContext instances.
            FacesContext facesContext = FacesContext.getCurrentInstance();
            ExternalContext externalContext = facesContext.getExternalContext();

            // Parse and validate the web.xml configuration file
            
            if (!WebConfigParamUtils.getBooleanInitParameter(externalContext, INITIALIZE_ALWAYS_STANDALONE, false))
            {
                WebConfigProvider webConfigProvider = WebConfigProviderFactory.getWebConfigProviderFactory(
                        facesContext.getExternalContext()).getWebConfigProvider(facesContext.getExternalContext());

                if (webConfigProvider.getFacesServletMappings(facesContext.getExternalContext()).isEmpty()) {
                    // check if the FacesServlet has been added dynamically
                    // in a Servlet 3.0 environment by MyFacesContainerInitializer
                    Boolean mappingAdded = (Boolean) servletContext.getAttribute(FACES_SERVLET_ADDED_ATTRIBUTE);
                    if (mappingAdded == null || !mappingAdded)
                    {
                        if (log.isLoggable(Level.WARNING))
                        {
                            log.warning("No mappings of FacesServlet found. Abort initializing MyFaces.");
                        }
                        return;
                    }
                }
            }

            initContainerIntegration(servletContext, externalContext);

            String useEncryption = servletContext.getInitParameter(StateUtils.USE_ENCRYPTION);
            if (!"false".equals(useEncryption)) { // the default value is true
                StateUtils.initSecret(servletContext);
            }

            if (log.isLoggable(Level.INFO)) {
                log.info("ServletContext '" + servletContext.getRealPath("/") + "' initialized.");
            }
            
            // initialize eager managed beans
            _createEagerBeans(facesContext);

            _dispatchApplicationEvent(servletContext, PostConstructApplicationEvent.class);
            
            // print out a very prominent log message if the project stage is != Production
            if (!facesContext.isProjectStage(ProjectStage.Production))
            {
                ProjectStage projectStage = facesContext.getApplication().getProjectStage();
                StringBuilder message = new StringBuilder("\n\n");
                message.append("*******************************************************************\n");
                message.append("*** WARNING: Apache MyFaces-2 is running in ");
                message.append(projectStage.name().toUpperCase());        
                message.append(" mode.");
                int length = projectStage.name().length();
                for (int i = 0; i < 11 - length; i++)
                {
                    message.append(" ");
                }
                message.append("   ***\n");
                message.append("***                                         ");
                for (int i = 0; i < length; i++)
                {
                    message.append("^");
                }
                for (int i = 0; i < 20 - length; i++)
                {
                    message.append(" ");
                }
                message.append("***\n");
                message.append("*** Do NOT deploy to your live server(s) without changing this. ***\n");
                message.append("*** See Application#getProjectStage() for more information.     ***\n");
                message.append("*******************************************************************\n");
                log.log(Level.WARNING, message.toString());
            }

        } catch (Exception ex) {
            log.log(Level.SEVERE, "An error occured while initializing MyFaces: "
                      + ex.getMessage(), ex);
        }
    }
    
    /**
     * Checks for application scoped managed-beans with eager=true,
     * creates them and stores them in the application map.
     * @param facesContext
     */
    private void _createEagerBeans(FacesContext facesContext)
    {
        ExternalContext externalContext = facesContext.getExternalContext();
        RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
        List eagerBeans = new ArrayList();
        
        // check all registered managed-beans
        for (ManagedBean bean : runtimeConfig.getManagedBeans().values())
        {
            String eager = bean.getEager();
            if (eager != null && "true".equals(eager))
            {
                // eager beans are only allowed for application scope
                if (ManagedBeanBuilder.APPLICATION.equals(bean.getManagedBeanScope()))
                {
                    // add to eager beans
                    eagerBeans.add(bean);
                }
                else
                {
                    // log warning and continue (the bean will be lazy loaded)
                    log.log(Level.WARNING, "The managed-bean with name "
                            + bean.getManagedBeanName()
                            + " must be application scoped to support eager=true.");
                }
            }
        }
        
        // check if there are any eager beans
        if (!eagerBeans.isEmpty())
        {
            ManagedBeanBuilder managedBeanBuilder = new ManagedBeanBuilder();
            Map applicationMap = externalContext.getApplicationMap();
            
            for (ManagedBean bean : eagerBeans)
            {
                // check application scope for bean instance
                if (applicationMap.containsKey(bean.getManagedBeanName()))
                {
                    // do not build bean, because it already exists
                    // (e.g. @ManagedProperty from previous managed bean already created it)
                    continue;
                }

                // create instance
                Object beanInstance = managedBeanBuilder.buildManagedBean(facesContext, bean);
                
                // put in application scope
                applicationMap.put(bean.getManagedBeanName(), beanInstance);
            }
        }
    }

    /**
     * Eventually we can use our plugin infrastructure for this as well
     * it would be a cleaner interception point than the base class
     * but for now this position is valid as well
     * 

* Note we add it for now here because the application factory object * leaves no possibility to have a destroy interceptor * and applications are per web application singletons * Note if this does not work out * move the event handler into the application factory * * @param servletContext the servlet context to be passed down * @param eventClass the class to be passed down into the dispatching * code */ private void _dispatchApplicationEvent(ServletContext servletContext, Class eventClass) { FacesContext facesContext = FacesContext.getCurrentInstance(); Application application = facesContext.getApplication(); application.publishEvent(facesContext, eventClass, Application.class, application); } /** * Cleans up all remaining resources (well, theoretically). */ public void destroyFaces(ServletContext servletContext) { FacesContext facesContext = FacesContext.getCurrentInstance(); if (!WebConfigParamUtils.getBooleanInitParameter(facesContext.getExternalContext(), INITIALIZE_ALWAYS_STANDALONE, false)) { //We need to check if the current application was initialized by myfaces WebConfigProvider webConfigProvider = WebConfigProviderFactory.getWebConfigProviderFactory( facesContext.getExternalContext()).getWebConfigProvider(facesContext.getExternalContext()); if (webConfigProvider.getFacesServletMappings(facesContext.getExternalContext()).isEmpty()) { // check if the FacesServlet has been added dynamically // in a Servlet 3.0 environment by MyFacesContainerInitializer Boolean mappingAdded = (Boolean) servletContext.getAttribute(FACES_SERVLET_ADDED_ATTRIBUTE); if (mappingAdded == null || !mappingAdded) { if (log.isLoggable(Level.WARNING)) { log.warning("No mappings of FacesServlet found. Abort destroy MyFaces."); } return; } } } _dispatchApplicationEvent(servletContext, PreDestroyApplicationEvent.class); // clear the cache of MetaRulesetImpl in order to prevent a memory leak MetaRulesetImpl.clearMetadataTargetCache(); // TODO is it possible to make a real cleanup? } /** * Configures this JSF application. It's required that every * FacesInitializer (i.e. every subclass) calls this method during * initialization. * * @param servletContext the current ServletContext * @param externalContext the current ExternalContext * @param expressionFactory the ExpressionFactory to use * @return the current runtime configuration */ protected RuntimeConfig buildConfiguration(ServletContext servletContext, ExternalContext externalContext, ExpressionFactory expressionFactory) { RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext); runtimeConfig.setExpressionFactory(expressionFactory); // And configure everything new FacesConfigurator(externalContext).configure(); validateFacesConfig(servletContext, externalContext); return runtimeConfig; } protected void validateFacesConfig(ServletContext servletContext, ExternalContext externalContext) { String validate = servletContext.getInitParameter(FacesConfigValidator.VALIDATE_CONTEXT_PARAM); if ("true".equals(validate) && log.isLoggable(Level.WARNING)) { // the default value is false List warnings = FacesConfigValidator.validate( externalContext, servletContext.getRealPath("/")); for (String warning : warnings) { log.warning(warning); } } } /** * Try to load user-definied ExpressionFactory. Returns null, * if no custom ExpressionFactory was specified. * * @param externalContext the current ExternalContext * @return User-specified ExpressionFactory, or * null, if no no custom implementation was specified */ protected static ExpressionFactory getUserDefinedExpressionFactory(ExternalContext externalContext) { String expressionFactoryClassName = WebConfigParamUtils.getStringInitParameter(externalContext, EXPRESSION_FACTORY); if (expressionFactoryClassName != null && expressionFactoryClassName.trim().length() > 0) { if (log.isLoggable(Level.FINE)) { log.fine("Attempting to load the ExpressionFactory implementation " + "you've specified: '" + expressionFactoryClassName + "'."); } return loadExpressionFactory(expressionFactoryClassName); } return null; } /** * Loads and instantiates the given ExpressionFactory implementation. * * @param expressionFactoryClassName the class name of the ExpressionFactory implementation * @return the newly created ExpressionFactory implementation, or * null, if an error occurred */ protected static ExpressionFactory loadExpressionFactory(String expressionFactoryClassName) { try { Class expressionFactoryClass = Class.forName(expressionFactoryClassName); return (ExpressionFactory) expressionFactoryClass.newInstance(); } catch (Exception ex) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "An error occured while instantiating a new ExpressionFactory. " + "Attempted to load class '" + expressionFactoryClassName + "'.", ex); } } return null; } public FacesContext initStartupFacesContext(ServletContext servletContext) { // We cannot use FacesContextFactory, because it is necessary to initialize // before Application and RenderKit factories, so we should use different object. return _createFacesContext(servletContext, true); } public void destroyStartupFacesContext(FacesContext facesContext) { _releaseFacesContext(facesContext); } public FacesContext initShutdownFacesContext(ServletContext servletContext) { return _createFacesContext(servletContext, false); } public void destroyShutdownFacesContext(FacesContext facesContext) { _releaseFacesContext(facesContext); } private FacesContext _createFacesContext(ServletContext servletContext, boolean startup) { ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, startup); ExceptionHandler exceptionHandler = new ExceptionHandlerImpl(); FacesContext facesContext = new StartupFacesContextImpl(externalContext, (ReleaseableExternalContext) externalContext, exceptionHandler, startup); // If getViewRoot() is called during application startup or shutdown, // it should return a new UIViewRoot with its locale set to Locale.getDefault(). UIViewRoot startupViewRoot = new UIViewRoot(); startupViewRoot.setLocale(Locale.getDefault()); facesContext.setViewRoot(startupViewRoot); return facesContext; } private void _releaseFacesContext(FacesContext facesContext) { // make sure that the facesContext gets released. // This is important in an OSGi environment if (facesContext != null) { facesContext.release(); } } /** * Performs initialization tasks depending on the current environment. * * @param servletContext the current ServletContext * @param externalContext the current ExternalContext */ protected abstract void initContainerIntegration( ServletContext servletContext, ExternalContext externalContext); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy