/FileExtraction/Java_unseen/dlitz_resin/modules/resin/src/com/caucho/jsf/webapp/FacesServletImpl.java
/*
 * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.jsf.webapp;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.*;

import javax.faces.*;
import javax.faces.application.*;
import javax.faces.event.*;
import javax.faces.lifecycle.*;
import javax.faces.webapp.*;

import javax.servlet.*;

import com.caucho.config.*;
import com.caucho.jsf.application.*;
import com.caucho.jsf.cfg.*;
import com.caucho.jsf.dev.*;
import com.caucho.vfs.*;
import com.caucho.server.webapp.WebApp;
import com.caucho.server.dispatch.ServletMapping;

public class FacesServletImpl extends GenericServlet
{
  private static final Logger log
    = Logger.getLogger(FacesServletImpl.class.getName());

  private static final String FACES_SCHEMA
    = "com/caucho/jsf/cfg/jsf.rnc";

  private ConfigException _configException;

  private ArrayList<PhaseListener> _phaseListenerList
    = new ArrayList<PhaseListener>();

  public FacesServletImpl()
  {
  }

  public void init(ServletConfig config)
    throws ServletException
  {
    initFactory(FactoryFinder.APPLICATION_FACTORY,
                "com.caucho.jsf.application.ApplicationFactoryImpl");

    initFactory(FactoryFinder.LIFECYCLE_FACTORY,
                "com.caucho.jsf.lifecycle.LifecycleFactoryImpl");

    initFactory(FactoryFinder.RENDER_KIT_FACTORY,
                "com.caucho.jsf.render.RenderKitFactoryImpl");

    initFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
                "com.caucho.jsf.context.FacesContextFactoryImpl");
    
    ApplicationFactory appFactory = (ApplicationFactory)
      FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);

    Application app = appFactory.getApplication();

    if (app == null) {
      app = new ApplicationImpl();
      appFactory.setApplication(app);
    }

    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    try {
      Enumeration e = loader.getResources("META-INF/faces-config.xml");
      while (e != null && e.hasMoreElements()) {
        URL url = (URL) e.nextElement();
        initPath(app, Vfs.lookup(url.toString()));
      }
    } catch (IOException e) {
      throw ConfigException.create(e);
    }

    String path = config.getServletContext().getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
    
    String []paths = null;

    if (path != null)
      paths = path.split("\\s*,\\s*");

    for (int i = 0; paths != null && i < paths.length; i++)
      initPath(app, Vfs.lookup("./" + paths[i]));

    initPath(app, Vfs.lookup("WEB-INF/faces-config.xml"));

    if (app.getViewHandler() == null)
      app.setViewHandler(new JspViewHandler());

    JsfPropertyGroup jsfPropertyGroup = WebApp.getLocal().getJsf();

    if (app.getStateManager() == null) {
      SessionStateManager stateManager = new SessionStateManager();

      if (jsfPropertyGroup != null)
        stateManager.setStateSerializationMethod(
          jsfPropertyGroup.getStateSerializationMethod());

      app.setStateManager(stateManager);
    }

    LifecycleFactory lifecycleFactory = (LifecycleFactory)
      FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);

    PhaseListener developerAidListener = null;

    if (jsfPropertyGroup != null && jsfPropertyGroup.isEnableDeveloperAid()) {
      developerAidListener = new JsfDeveloperAid();

      //will use Servlet 3.0
      ServletMapping servletMapping = WebApp.getCurrent()
        .createServletMapping();

      servletMapping.addURLPattern("/caucho.jsf.developer.aid");
      servletMapping.setServletClass(JsfDeveloperAidServlet.class.getName());

      WebApp.getCurrent().addServletMapping(servletMapping);
    }

    Iterator iter = lifecycleFactory.getLifecycleIds();
    while (iter.hasNext()) {
      Lifecycle lifecycle
        = lifecycleFactory.getLifecycle((String) iter.next());

      if (developerAidListener != null)
        lifecycle.addPhaseListener(developerAidListener);
      
      for (PhaseListener listener : _phaseListenerList) {
        lifecycle.addPhaseListener(listener);
      }
    }

  }

  private static void initFactory(String factoryName, String defaultName)
  {
    Object factoryObj = null;
    String factory;
    
    try {
      factoryObj = FactoryFinder.getFactory(factoryName);
    } catch (FacesException e) {
    }


    if (factoryObj == null) {
      FactoryFinder.setFactory(factoryName, defaultName);

      factory = getServiceFactory(factoryName);

      if (factory != null && ! "".equals(factory))
        FactoryFinder.setFactory(factoryName, factory);
    }
  }

  private static String getServiceFactory(String factoryName)
  {
    try {
      ClassLoader loader = Thread.currentThread().getContextClassLoader();

      InputStream is = loader.getResourceAsStream("META-INF/services/" + factoryName);

      try {
        if (is != null) {
          BufferedReader reader = new BufferedReader(new InputStreamReader(is));
          String line = reader.readLine();

          if (line != null) {
            if (line.indexOf('#') >= 0)
              line = line.substring(0, line.indexOf('#'));

            return line.trim();
          }
        }
      } catch (Exception e) {
        log.log(Level.WARNING, e.toString(), e);
      } finally {
        is.close();
      }
    } catch (Exception e) {
    }
    
    return null;
  }
    
  private void initPath(Application app, Path facesPath)
    throws ServletException
  {
    if (facesPath.canRead() && ! facesPath.isDirectory()) {
      try {
        FacesConfig facesConfig = new FacesConfig();

        Config config = new Config();

        config.setEL(false);

        config.configure(facesConfig, facesPath, FACES_SCHEMA);

        if (app instanceof ApplicationImpl) {
          ApplicationImpl appImpl = (ApplicationImpl) app;

          // jsf/4409
          NavigationHandlerImpl navigationHandler
            = appImpl.getDefaultNavigationHandler();

          List<NavigationRule> navigationRules
            = facesConfig.getNavigationRules();

          for (NavigationRule navigationRule : navigationRules) {
            navigationHandler.addRule(navigationRule);
          }

          facesConfig.configure(appImpl);

          facesConfig.configurePhaseListeners(_phaseListenerList);

          for (ManagedBeanConfig bean : facesConfig.getManagedBeans()) {
            appImpl.addManagedBean(bean.getName(), bean);
          }

          ApplicationConfig appConfig = facesConfig.getApplication();

          if (appConfig != null) {
            appConfig.configure(appImpl);

            for (ResourceBundleConfig bundle
                   : appConfig.getResourceBundleList()) {
              appImpl.addResourceBundle(bundle.getVar(), bundle);
            }
          }
        }
      } catch (ConfigException e) {
        _configException = e;

        throw e;
      } catch (RuntimeException e) {
        throw e;
      } catch (Exception e) {
        throw new ServletException(e);
      }
    }
  }

  public void service(ServletRequest request,
                      ServletResponse response)
    throws IOException, ServletException
  {
    throw new UnsupportedOperationException();
  }

  public void destroy()
  {
  }
}
