You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2007/11/23 19:11:46 UTC

svn commit: r597709 - in /myfaces/core/trunk_1.2.x/impl/src: main/java/org/apache/myfaces/config/ main/java/org/apache/myfaces/config/impl/digester/elements/ main/java/org/apache/myfaces/util/ main/java/org/apache/myfaces/webapp/ test/java/org/apache/m...

Author: matzew
Date: Fri Nov 23 10:11:45 2007
New Revision: 597709

URL: http://svn.apache.org/viewvc?rev=597709&view=rev
Log:
MYFACES-1693 - Make JSP 2.1 optional

Big thanks to Bernhard Huemer for making this patch

Added:
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/util/ContainerUtils.java
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp20FacesInitializer.java
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp21FacesInitializer.java
    myfaces/core/trunk_1.2.x/impl/src/test/java/org/apache/myfaces/webapp/Jsp21FacesInitializerTest.java
Removed:
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/DefaultFacesInitializer.java
    myfaces/core/trunk_1.2.x/impl/src/test/java/org/apache/myfaces/webapp/DefaultFacesInitializerTest.java
Modified:
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/ManagedBeanBuilder.java
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/ManagedProperty.java
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServlet.java
    myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java

Modified: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/ManagedBeanBuilder.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/ManagedBeanBuilder.java?rev=597709&r1=597708&r2=597709&view=diff
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/ManagedBeanBuilder.java (original)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/ManagedBeanBuilder.java Fri Nov 23 10:11:45 2007
@@ -32,7 +32,6 @@
 import javax.faces.application.Application;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
-import javax.faces.webapp.UIComponentTag;
 import javax.naming.NamingException;
 
 import org.apache.commons.beanutils.PropertyUtils;
@@ -47,6 +46,7 @@
 import org.apache.myfaces.config.element.MapEntries;
 import org.apache.myfaces.config.element.MapEntry;
 import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.util.ContainerUtils;
 
 
 /**
@@ -498,7 +498,7 @@
             MapEntry entry = (MapEntry) iterator.next();
             Object key = entry.getKey();
 
-            if (UIComponentTag.isValueReference((String) key))
+            if (ContainerUtils.isValueReference((String) key))
             {
                 valueExpression = expFactory.createValueExpression(elContext, (String) key, Object.class);
                 key = valueExpression.getValue(elContext);
@@ -511,7 +511,7 @@
             else
             {
                 Object value = entry.getValue();
-                if (UIComponentTag.isValueReference((String) value))
+                if (ContainerUtils.isValueReference((String) value))
                 {
                     valueExpression = expFactory.createValueExpression(elContext, (String) value, Object.class);
                     value = valueExpression.getValue(elContext);
@@ -539,7 +539,7 @@
             else
             {
                 Object value = entry.getValue();
-                if (UIComponentTag.isValueReference((String) value))
+                if (ContainerUtils.isValueReference((String) value))
                 {
                     ValueExpression valueExpression = expFactory.createValueExpression(elContext, (String) value, Object.class);
                     value = valueExpression.getValue(elContext);

Modified: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/ManagedProperty.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/ManagedProperty.java?rev=597709&r1=597708&r2=597709&view=diff
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/ManagedProperty.java (original)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/ManagedProperty.java Fri Nov 23 10:11:45 2007
@@ -17,9 +17,9 @@
 
 import javax.faces.context.FacesContext;
 import javax.faces.el.ValueBinding;
-import javax.faces.webapp.UIComponentTag;
 
 import org.apache.myfaces.config.impl.digester.elements.ListEntries;
+import org.apache.myfaces.util.ContainerUtils;
 
 
 /**
@@ -144,7 +144,7 @@
 
     public boolean isValueReference()
     {
-        return UIComponentTag.isValueReference(_value);
+        return ContainerUtils.isValueReference(_value);
     }
 
 

Added: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/util/ContainerUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/util/ContainerUtils.java?rev=597709&view=auto
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/util/ContainerUtils.java (added)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/util/ContainerUtils.java Fri Nov 23 10:11:45 2007
@@ -0,0 +1,77 @@
+/*
+ * 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.util;
+
+/**
+ * Utilities for determining the current container and for the unified
+ * expression language.
+ * 
+ */
+public class ContainerUtils
+{
+    /**
+     * Determines whether we're running in a Servlet 2.5/JSP 2.1 environment.
+     * 
+     * @return <code>true</code> if we're running in a JSP 2.1 environment,
+     *         <code>false</code> otherwise
+     */
+    public static boolean isJsp21()
+    {
+        try 
+        {
+            // simply check if the class JspApplicationContext is available
+            Class.forName("javax.servlet.jsp.JspApplicationContext");
+            return true;
+        } 
+        catch (ClassNotFoundException ex) 
+        {
+            ; // expected exception in a JSP 2.0 (or less) environment
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Return true if the specified string contains an EL expression.
+     * 
+     * <p>
+     * <strong>NOTICE</strong> This method is just a copy of
+     * {@link UIComponentTag#isValueReference(String)}, but it's required
+     * because the class UIComponentTag depends on a JSP 2.1 container 
+     * (for example, it indirectly implements the interface JspIdConsumer)
+     * and therefore internal classes shouldn't access this class. That's
+     * also the reason why this method is inside the class ContainerUtils,
+     * because it allows MyFaces to be independent of a JSP 2.1 container.
+     * </p>
+     */
+    public static boolean isValueReference(String value) 
+    {
+        if (value == null) {
+            throw new NullPointerException("value");
+        }
+
+        int start = value.indexOf("#{");
+        if (start < 0) {
+            return false;
+        }
+
+        int end = value.lastIndexOf('}');
+        return (end >=0 && start < end);
+    }
+}

Added: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java?rev=597709&view=auto
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java (added)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java Fri Nov 23 10:11:45 2007
@@ -0,0 +1,162 @@
+/*
+ * 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 java.util.List;
+
+import javax.el.ExpressionFactory;
+import javax.faces.context.ExternalContext;
+import javax.servlet.ServletContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.application.ApplicationImpl;
+import org.apache.myfaces.config.FacesConfigValidator;
+import org.apache.myfaces.config.FacesConfigurator;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.context.servlet.ServletExternalContextImpl;
+import org.apache.myfaces.shared_impl.util.StateUtils;
+import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
+
+/**
+ * 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);
+
+    /**
+     * Performs all necessary initialization tasks like configuring this JSF
+     * application.
+     */
+    public void initFaces(ServletContext servletContext)
+    {
+        try {
+            if (log.isTraceEnabled()) {
+                log.trace("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.
+            ExternalContext externalContext = new ServletExternalContextImpl(
+                    servletContext, null, null);
+
+            // Parse and validate the web.xml configuration file
+            WebXml webXml = WebXml.getWebXml(externalContext);
+            if (webXml == null) {
+                if (log.isWarnEnabled()) {
+                    log.warn("Couldn't find the web.xml configuration file. "
+                            + "Abort initializing MyFaces.");
+                }
+
+                return;
+            } else if (webXml.getFacesServletMappings().isEmpty()) {
+                if (log.isWarnEnabled()) {
+                    log.warn("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.isInfoEnabled()) {
+                log.info("ServletContext '" + servletContext.getRealPath("/") + "' initialized.");
+            }
+        } catch (Exception ex) {
+            log.error("An error occured while initializing MyFaces: "
+                    + ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * Cleans up all remaining resources (well, theoretically).
+     * 
+     */
+    public void destroyFaces(ServletContext servletContext)
+    {
+        // 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);
+        
+        ApplicationImpl.setInitializingRuntimeConfig(runtimeConfig);
+        
+        // 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.isWarnEnabled()) { // the default value is false
+            List<String> warnings = FacesConfigValidator.validate(
+                    externalContext, servletContext.getRealPath("/"));
+            
+            for (String warning : warnings) {
+                log.warn(warning);
+            }
+        }
+    }
+
+    /**
+     * 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);
+
+}

Added: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp20FacesInitializer.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp20FacesInitializer.java?rev=597709&view=auto
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp20FacesInitializer.java (added)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp20FacesInitializer.java Fri Nov 23 10:11:45 2007
@@ -0,0 +1,208 @@
+/*
+ * 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 javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.servlet.ServletContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Initializes MyFaces in a JSP 2.0 (or less) environment.
+ *
+ */
+public class Jsp20FacesInitializer extends AbstractFacesInitializer
+{
+    /**
+     * The logger instance for this class.
+     */
+    private static final Log log = LogFactory.getLog(Jsp20FacesInitializer.class);
+    
+    /**
+     * This parameter specifies the ExpressionFactory implementation to use.
+     */
+    private static final String EXPRESSION_FACTORY = "org.apache.myfaces.EXPRESSION_FACTORY";
+    
+    /**
+     * The ExpressionFactory implementation of the EL-RI.
+     */
+    private static final String EL_RI_EXPRESSION_FACTORY_IMPL = "com.sun.el.ExpressionFactoryImpl";
+    
+    /**
+     * Jasper's ExpressionFactory implementation.
+     */
+    private static final String JASPER_EL_EXPRESSION_FACTORY_IMPL = "org.apache.el.ExpressionFactoryImpl";
+    
+    /**
+     * All known ExpressionFactory implementations.
+     */
+    private static final String[] KNOWN_EXPRESSION_FACTORIES = 
+        new String[] { EL_RI_EXPRESSION_FACTORY_IMPL, JASPER_EL_EXPRESSION_FACTORY_IMPL };
+
+    
+    @Override
+    protected void initContainerIntegration(
+            ServletContext servletContext, ExternalContext externalContext)
+    {
+        if (log.isInfoEnabled()) {
+            log.info("This application isn't running in a JSP 2.1 container."); 
+        }
+        
+        // It's possible to run MyFaces in a JSP 2.0 Container, but the user has to provide
+        // the ExpressionFactory implementation to use as there is no JspApplicationContext
+        // we could ask for. Having said that, though, the user only has to provide it, if
+        // there is no known ExpressionFactory available (i.e. if neither 
+        // "com.sun.el.ExpressionFactoryImpl" nor "org.apache.el.ExpressionFactoryImpl"
+        // are available).
+        ExpressionFactory expressionFactory = null;
+        
+        String expressionFactoryClassName = externalContext.getInitParameter(EXPRESSION_FACTORY);
+        if (expressionFactoryClassName != null
+                && expressionFactoryClassName.trim().length() > 0) {
+            if (log.isDebugEnabled()) {
+                log.debug("Attempting to load the ExpressionFactory implementation " 
+                        + "you've specified: '" + expressionFactoryClassName + "'.");
+            }
+            
+            expressionFactory = loadExpressionFactory(expressionFactoryClassName);
+        }
+        
+        if (expressionFactory == null) {
+            if (log.isInfoEnabled()) {
+                log.info("Either you haven't specified the ExpressionFactory implementation, or an " 
+                        + "error occured while instantiating the implementation you've specified. "
+                        + "However, attempting to load a known implementation.");
+            }
+            
+            expressionFactory = findExpressionFactory(KNOWN_EXPRESSION_FACTORIES);
+            if (expressionFactory == null) { // if we still haven't got a valid implementation
+                if (log.isErrorEnabled()) {
+                    log.error("No valid ExpressionFactory implementation is available "
+                            + "but that's required as this application isn't running in a JSP 2.1 container.");
+                }
+                
+                // use a dummy implementation that reports the error again
+                expressionFactory = new ErrorExpressionFactory();
+            }
+        }
+        
+        if (log.isDebugEnabled()) {
+            log.debug("The following ExpressionFactory implementation will " 
+                    + "be used: '" + expressionFactory + "'.");
+        }
+        
+        buildConfiguration(servletContext, externalContext, expressionFactory);
+    }
+    
+    /**
+     * Loads and instantiates the given ExpressionFactory implementation.
+     * 
+     * @param expressionFactoryClassName
+     *            the class name of the ExpressionFactory implementation
+     * 
+     * @return the newly created ExpressionFactory implementation, or
+     *         <code>null</code>, if an error occurred
+     */
+    private static ExpressionFactory loadExpressionFactory(String expressionFactoryClassName) 
+    {
+       try {
+           Class<?> expressionFactoryClass = Class.forName(expressionFactoryClassName);
+           return (ExpressionFactory) expressionFactoryClass.newInstance();
+       } catch (Exception ex) {
+           if (log.isDebugEnabled()) {
+               log.debug("An error occured while instantiating a new ExpressionFactory. " 
+                   + "Attempted to load class '" + expressionFactoryClassName + "'.", ex);
+           }
+       }
+       
+       return null;
+    }
+    
+    /**
+     * Attempts to find a valid ExpressionFactory implementation. Each of the
+     * given "ExpressionFactory implementation candidates" will be tried to
+     * instantiate. If an attempt succeeded, the ExpressionFactory implementation
+     * will be returned (i.e. the first valid ExpressionFactory implementation
+     * will be returned) and if no attempt succeeds, <code>null</code> will be
+     * returned.
+     * 
+     * @param expressionFactoryClassNames
+     *            "ExpresionFactory implementation candidates"
+     * 
+     * @return the newly created ExpressionFactory implementation, or
+     *         <code>null</code>, if there is no valid implementation
+     */
+    private static ExpressionFactory findExpressionFactory(String[] expressionFactoryClassNames) 
+    {
+        for (String expressionFactoryClassName : expressionFactoryClassNames) {
+            ExpressionFactory expressionFactory = 
+                loadExpressionFactory(expressionFactoryClassName);
+            if (expressionFactory != null) {
+                return expressionFactory;
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Dummy implementation informing the user that there is no valid
+     * ExpressionFactory implementation available. This class makes it easier
+     * for the user to understand why the application crashes. Otherwise he
+     * would have to deal with NullPointerExceptions.
+     * 
+     */
+    private class ErrorExpressionFactory extends ExpressionFactory
+    {
+
+        public Object coerceToType(Object obj, Class<?> targetType)
+        {
+            throw new FacesException("No valid ExpressionFactory implementation is available "
+                            + "but that's required as this application isn't running in a JSP 2.1 container.");
+        }
+
+        public MethodExpression createMethodExpression(ELContext context,
+                String expression, Class<?> expectedReturnType, Class<?>[] expectedParamTypes)
+        {
+            throw new FacesException("No valid ExpressionFactory implementation is available "
+                            + "but that's required as this application isn't running in a JSP 2.1 container.");
+        }
+
+        public ValueExpression createValueExpression(Object instance, Class<?> expectedType)
+        {
+            throw new FacesException("No valid ExpressionFactory implementation is available "
+                            + "but that's required as this application isn't running in a JSP 2.1 container.");
+        }
+
+        public ValueExpression createValueExpression(
+                ELContext context, String expression, Class<?> expectedType)
+        {
+            throw new FacesException("No valid ExpressionFactory implementation is available "
+                            + "but that's required as this application isn't running in a JSP 2.1 container.");
+        }
+
+    }
+
+}

Added: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp21FacesInitializer.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp21FacesInitializer.java?rev=597709&view=auto
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp21FacesInitializer.java (added)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/Jsp21FacesInitializer.java Fri Nov 23 10:11:45 2007
@@ -0,0 +1,129 @@
+/*
+ * 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 java.util.Iterator;
+
+import javax.faces.FactoryFinder;
+import javax.faces.context.ExternalContext;
+import javax.faces.event.PhaseListener;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.JspApplicationContext;
+import javax.servlet.jsp.JspFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.el.ResolverForJSPInitializer;
+import org.apache.myfaces.el.unified.ELResolverBuilder;
+import org.apache.myfaces.el.unified.ResolverBuilderForJSP;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
+
+/**
+ * Initializes MyFaces in a JSP 2.1 environment.
+ *
+ */
+public class Jsp21FacesInitializer extends AbstractFacesInitializer
+{
+    /**
+     * The logger instance for this class.
+     */
+    private static final Log log = LogFactory.getLog(Jsp21FacesInitializer.class);
+    
+    /**
+     * Cached instance of the JspFactory to use.
+     */
+    private JspFactory jspFactory;
+    
+    @Override
+    protected void initContainerIntegration(
+            ServletContext servletContext, ExternalContext externalContext)
+    {
+        JspApplicationContext appCtx = 
+            getJspFactory().getJspApplicationContext(servletContext);
+        appCtx.addELContextListener(new FacesELContextListener());
+        
+        RuntimeConfig runtimeConfig = 
+            buildConfiguration(servletContext, externalContext, appCtx.getExpressionFactory());
+        
+        // configure the el resolver for jsp
+        configureResolverForJSP(appCtx, runtimeConfig);
+    }
+    
+    protected JspFactory getJspFactory()
+    {
+        if (jspFactory == null) {
+            // TODO: this Class.forName will be removed when Tomcat fixes a bug
+            // also, we should then be able to remove jasper.jar from the deployment
+            try {
+                Class.forName("org.apache.jasper.compiler.JspRuntimeContext");
+            } catch (ClassNotFoundException e) {
+                ; // ignore
+            } catch (Exception ex) {
+                log.debug("An unexpected exception occured "
+                        + "while loading the JspRuntimeContext.", ex);
+            }
+
+            jspFactory = JspFactory.getDefaultFactory();
+        }
+
+        return jspFactory;
+    }
+
+    /**
+     * Sets the JspFactory to use. Currently, this method just simplifies
+     * testing.
+     * 
+     * @param jspFactory
+     *            the JspFactory to use
+     */
+    protected void setJspFactory(JspFactory jspFactory)
+    {
+        this.jspFactory = jspFactory;
+    }
+
+    /**
+     * Register a phase listener to every lifecycle. This listener will lazy fill the el resolver for jsp as soon as the
+     * first lifecycle is executed. This is necessarry to allow a faces application further setup after MyFaces has been
+     * initialized. When the first request is processed no further configuation of the el resolvers is allowed.
+     * 
+     * @param appCtx
+     * @param runtimeConfig
+     */
+    private void configureResolverForJSP(JspApplicationContext appCtx, RuntimeConfig runtimeConfig)
+    {
+        FacesCompositeELResolver facesCompositeELResolver = new FacesCompositeELResolver(Scope.JSP);
+        appCtx.addELResolver(facesCompositeELResolver);
+        PhaseListener resolverForJSPInitializer = new ResolverForJSPInitializer(
+                createResolverBuilderForJSP(runtimeConfig), facesCompositeELResolver);
+
+        LifecycleFactory factory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        for (Iterator<String> iter = factory.getLifecycleIds(); iter.hasNext();)
+        {
+            factory.getLifecycle(iter.next()).addPhaseListener(resolverForJSPInitializer);
+        }
+    }
+    
+    protected ELResolverBuilder createResolverBuilderForJSP(RuntimeConfig runtimeConfig)
+    {
+        return new ResolverBuilderForJSP(runtimeConfig);
+    }
+}

Modified: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServlet.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServlet.java?rev=597709&r1=597708&r2=597709&view=diff
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServlet.java (original)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServlet.java Fri Nov 23 10:11:45 2007
@@ -18,6 +18,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.myfaces.shared_impl.webapp.webxml.DelegatedFacesServlet;
+import org.apache.myfaces.util.ContainerUtils;
 
 import javax.faces.webapp.FacesServlet;
 import javax.servlet.*;
@@ -42,8 +43,16 @@
     {
         if (_facesInitializer == null)
         {
-            _facesInitializer = new DefaultFacesInitializer();
+            if (ContainerUtils.isJsp21()) 
+            {
+                _facesInitializer = new Jsp21FacesInitializer();
+            } 
+            else 
+            {
+                _facesInitializer = new Jsp20FacesInitializer();
+            }
         }
+        
         return _facesInitializer;
     }
     

Modified: myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java?rev=597709&r1=597708&r2=597709&view=diff
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java (original)
+++ myfaces/core/trunk_1.2.x/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java Fri Nov 23 10:11:45 2007
@@ -23,6 +23,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.myfaces.config.ManagedBeanBuilder;
+import org.apache.myfaces.util.ContainerUtils;
 
 import javax.faces.FactoryFinder;
 import javax.servlet.ServletContext;
@@ -67,8 +68,16 @@
     {
         if (_facesInitializer == null)
         {
-            _facesInitializer = new DefaultFacesInitializer();
+            if (ContainerUtils.isJsp21()) 
+            {
+                _facesInitializer = new Jsp21FacesInitializer();
+            } 
+            else 
+            {
+                _facesInitializer = new Jsp20FacesInitializer();
+            }
         }
+        
         return _facesInitializer;
     }
 

Added: myfaces/core/trunk_1.2.x/impl/src/test/java/org/apache/myfaces/webapp/Jsp21FacesInitializerTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk_1.2.x/impl/src/test/java/org/apache/myfaces/webapp/Jsp21FacesInitializerTest.java?rev=597709&view=auto
==============================================================================
--- myfaces/core/trunk_1.2.x/impl/src/test/java/org/apache/myfaces/webapp/Jsp21FacesInitializerTest.java (added)
+++ myfaces/core/trunk_1.2.x/impl/src/test/java/org/apache/myfaces/webapp/Jsp21FacesInitializerTest.java Fri Nov 23 10:11:45 2007
@@ -0,0 +1,100 @@
+/*
+ * 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 junit.framework.TestCase;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.el.DefaultPropertyResolver;
+import org.apache.myfaces.el.VariableResolverImpl;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
+import static org.easymock.EasyMock.*;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+
+import javax.el.ExpressionFactory;
+import javax.faces.webapp.FacesServlet;
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.JspApplicationContext;
+import javax.servlet.jsp.JspFactory;
+
+/**
+ * @author Mathias Broekelmann (latest modification by $Author: baranda $)
+ * @version $Revision: 532019 $ $Date: 2007-04-24 19:34:36 +0200 (Di, 24 Apr 2007) $
+ */
+public class Jsp21FacesInitializerTest extends TestCase
+{
+
+    /**
+     * Test method for {@link org.apache.myfaces.webapp.DefaultFacesInitializer#initFaces(javax.servlet.ServletContext)}.
+     * @throws Exception 
+     */
+    public void testInitFaces() throws Exception
+    {
+        Jsp21FacesInitializer initializer = new Jsp21FacesInitializer();
+        IMocksControl control = EasyMock.createControl();
+        
+        JspFactory jspFactory = control.createMock(JspFactory.class);
+        initializer.setJspFactory(jspFactory);
+        
+        RuntimeConfig runtimeConfig = control.createMock(RuntimeConfig.class);
+        
+        ServletContext context = control.createMock(ServletContext.class);
+        ExpressionFactory expressionFactory = control.createMock(ExpressionFactory.class);
+        runtimeConfig.setExpressionFactory(expressionFactory);
+        runtimeConfig.setPropertyResolverChainHead(isA(DefaultPropertyResolver.class));
+        runtimeConfig.setVariableResolverChainHead(isA(VariableResolverImpl.class));
+        
+        expect(context.getAttribute(eq(RuntimeConfig.class.getName()))).andReturn(runtimeConfig).anyTimes();
+        
+        expect(context.getInitParameter(eq(FacesServlet.CONFIG_FILES_ATTR))).andReturn(null);
+        expect(context.getResourceAsStream(eq("/WEB-INF/faces-config.xml"))).andReturn(null);
+        expect(context.getInitParameter(eq(FacesServlet.LIFECYCLE_ID_ATTR))).andReturn(null);
+
+        // TODO: add myfaces specific tests
+        expect(context.getResource(isA(String.class))).andReturn(null);
+        expect(context.getResourceAsStream(isA(String.class))).andReturn(null);
+        expect(context.getInitParameter(isA(String.class))).andReturn(null).anyTimes();
+        expect(context.getAttribute(isA(String.class))).andReturn(null).anyTimes();
+        context.setAttribute(isA(String.class), anyObject());
+        expectLastCall().anyTimes();
+        expect(context.getRealPath(isA(String.class))).andAnswer(new IAnswer<String>() {
+            public String answer() throws Throwable
+            {
+                return (String) org.easymock.EasyMock.getCurrentArguments()[0];
+            }
+        });
+        
+        JspApplicationContext jspAppCtx = control.createMock(JspApplicationContext.class);
+        expect(jspAppCtx.getExpressionFactory()).andReturn(expressionFactory);
+        jspAppCtx.addELContextListener(isA(FacesELContextListener.class));
+        expect(jspFactory.getJspApplicationContext(eq(context))).andReturn(jspAppCtx);
+        jspAppCtx.addELResolver(isA(FacesCompositeELResolver.class));
+
+        control.replay();
+        initializer.initFaces(context);
+
+        // In MYFACES-1222: The Jsp21FacesInitializer isn't practicable anymore.
+        // The ServletContext-Mock won't return its WebXml instance, so Jsp21FacesInitializer will stop initializing.
+        // This is why the next line is commented:
+        
+        //control.verify();
+    }
+
+}