Home » geronimo-2.2-source-release » org.apache.geronimo.myfaces.deployment » [javadoc | source]

    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.geronimo.myfaces.deployment;
   19   
   20   import java.io.IOException;
   21   import java.net.MalformedURLException;
   22   import java.net.URL;
   23   import java.util.ArrayList;
   24   import java.util.Collection;
   25   import java.util.HashMap;
   26   import java.util.List;
   27   import java.util.Map;
   28   import java.util.StringTokenizer;
   29   import java.util.jar.JarFile;
   30   
   31   import javax.faces.webapp.FacesServlet;
   32   
   33   import org.slf4j.Logger;
   34   import org.slf4j.LoggerFactory;
   35   import org.apache.geronimo.common.DeploymentException;
   36   import org.apache.geronimo.deployment.ModuleIDBuilder;
   37   import org.apache.geronimo.deployment.service.EnvironmentBuilder;
   38   import org.apache.geronimo.deployment.util.DeploymentUtil;
   39   import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
   40   import org.apache.geronimo.gbean.AbstractName;
   41   import org.apache.geronimo.gbean.AbstractNameQuery;
   42   import org.apache.geronimo.gbean.GBeanData;
   43   import org.apache.geronimo.gbean.GBeanInfo;
   44   import org.apache.geronimo.gbean.GBeanInfoBuilder;
   45   import org.apache.geronimo.j2ee.annotation.Holder;
   46   import org.apache.geronimo.j2ee.deployment.EARContext;
   47   import org.apache.geronimo.j2ee.deployment.Module;
   48   import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
   49   import org.apache.geronimo.j2ee.deployment.NamingBuilder;
   50   import org.apache.geronimo.j2ee.deployment.WebModule;
   51   import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
   52   import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
   53   import org.apache.geronimo.kernel.Naming;
   54   import org.apache.geronimo.kernel.config.Configuration;
   55   import org.apache.geronimo.kernel.config.ConfigurationStore;
   56   import org.apache.geronimo.kernel.repository.Environment;
   57   import org.apache.geronimo.myfaces.LifecycleProviderGBean;
   58   import org.apache.geronimo.schema.SchemaConversionUtils;
   59   import org.apache.geronimo.xbeans.javaee.FacesConfigDocument;
   60   import org.apache.geronimo.xbeans.javaee.FacesConfigManagedBeanType;
   61   import org.apache.geronimo.xbeans.javaee.FacesConfigType;
   62   import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType;
   63   import org.apache.geronimo.xbeans.javaee.ParamValueType;
   64   import org.apache.geronimo.xbeans.javaee.ServletType;
   65   import org.apache.geronimo.xbeans.javaee.WebAppType;
   66   import org.apache.geronimo.xbeans.javaee.ListenerType;
   67   import org.apache.myfaces.webapp.StartupServletContextListener;
   68   import org.apache.xbean.finder.ClassFinder;
   69   import org.apache.xmlbeans.XmlCursor;
   70   import org.apache.xmlbeans.XmlException;
   71   import org.apache.xmlbeans.XmlObject;
   72   
   73   /**
   74    * @version $Rev $Date
   75    */
   76   public class MyFacesModuleBuilderExtension implements ModuleBuilderExtension {
   77   
   78       private static final Logger log = LoggerFactory.getLogger(MyFacesModuleBuilderExtension.class);
   79   
   80       private final Environment defaultEnvironment;
   81       private final AbstractNameQuery providerFactoryNameQuery;
   82       private final NamingBuilder namingBuilders;
   83       private static final String CONTEXT_LISTENER_NAME = StartupServletContextListener.class.getName();
   84       private static final String FACES_SERVLET_NAME = FacesServlet.class.getName();
   85       private static final String SCHEMA_LOCATION_URL = "http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd";
   86       private static final String VERSION = "1.2";
   87   
   88   
   89       public MyFacesModuleBuilderExtension(Environment defaultEnvironment, AbstractNameQuery providerFactoryNameQuery, NamingBuilder namingBuilders) {
   90           this.defaultEnvironment = defaultEnvironment;
   91           this.providerFactoryNameQuery = providerFactoryNameQuery;
   92           this.namingBuilders = namingBuilders;
   93       }
   94   
   95       public void createModule(Module module, Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
   96           if (!(module instanceof WebModule)) {
   97               //not a web module, nothing to do
   98               return;
   99           }
  100           WebModule webModule = (WebModule) module;
  101           WebAppType webApp = (WebAppType) webModule.getSpecDD();
  102           if (!hasFacesServlet(webApp)) {
  103               return;
  104           }
  105   
  106           EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
  107       }
  108   
  109       public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repository) throws DeploymentException {
  110       }
  111   
  112       public void initContext(EARContext earContext, Module module, ClassLoader cl) throws DeploymentException {
  113       }
  114   
  115       public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repository) throws DeploymentException {
  116           if (!(module instanceof WebModule)) {
  117               //not a web module, nothing to do
  118               return;
  119           }
  120           WebModule webModule = (WebModule) module;
  121           WebAppType webApp = (WebAppType) webModule.getSpecDD();
  122           if (!hasFacesServlet(webApp)) {
  123               return;
  124           }
  125   
  126           EARContext moduleContext = module.getEarContext();
  127           Map sharedContext = module.getSharedContext();
  128           //add the ServletContextListener to the web app context
  129           GBeanData webAppData = (GBeanData) sharedContext.get(WebModule.WEB_APP_DATA);
  130           //jetty specific support
  131           Object value = webAppData.getAttribute("listenerClassNames");
  132           if (value instanceof Collection && !((Collection) value).contains(CONTEXT_LISTENER_NAME)) {
  133               ((Collection<String>) value).add(CONTEXT_LISTENER_NAME);
  134           } else {
  135               //try to add listener to the web app xml
  136               ListenerType listenerType = webApp.addNewListener();
  137               FullyQualifiedClassType className = listenerType.addNewListenerClass();
  138               className.setStringValue(CONTEXT_LISTENER_NAME);
  139           }
  140           AbstractName moduleName = moduleContext.getModuleName();
  141           Map<NamingBuilder.Key, Object> buildingContext = new HashMap<NamingBuilder.Key, Object>();
  142           buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, moduleName);
  143   
  144           //use the same jndi context as the web app
  145           Map compContext = NamingBuilder.JNDI_KEY.get(module.getSharedContext());
  146           buildingContext.put(NamingBuilder.JNDI_KEY, compContext);
  147   
  148           //use the same holder object as the web app.
  149           Holder holder = NamingBuilder.INJECTION_KEY.get(sharedContext);
  150           buildingContext.put(NamingBuilder.INJECTION_KEY, holder);
  151   
  152           XmlObject jettyWebApp = webModule.getVendorDD();
  153   
  154           Configuration earConfiguration = earContext.getConfiguration();
  155   
  156           ClassFinder classFinder = createMyFacesClassFinder(webApp, webModule);
  157           webModule.setClassFinder(classFinder);
  158   
  159           namingBuilders.buildNaming(webApp, jettyWebApp, webModule, buildingContext);
  160   
  161           AbstractName providerName = moduleContext.getNaming().createChildName(moduleName, "jsf-lifecycle", "jsf");
  162           GBeanData providerData = new GBeanData(providerName, LifecycleProviderGBean.GBEAN_INFO);
  163           providerData.setAttribute("holder", holder);
  164           providerData.setAttribute("componentContext", compContext);
  165           providerData.setReferencePattern("LifecycleProviderFactory", providerFactoryNameQuery);
  166           try {
  167               moduleContext.addGBean(providerData);
  168           } catch (GBeanAlreadyExistsException e) {
  169               throw new DeploymentException("Duplicate jsf config gbean in web module", e);
  170           }
  171   
  172           //make the web app start second after the injection machinery
  173           webAppData.addDependency(providerName);
  174   
  175       }
  176   
  177       private boolean hasFacesServlet(WebAppType webApp) {
  178           for (ServletType servlet : webApp.getServletArray()) {
  179               if (servlet.isSetServletClass() && FACES_SERVLET_NAME.equals(servlet.getServletClass().getStringValue().trim())) {
  180                   return true;
  181               }
  182           }
  183           return false;
  184       }
  185   
  186   
  187       protected ClassFinder createMyFacesClassFinder(WebAppType webApp, WebModule webModule) throws DeploymentException {
  188   
  189           List<Class> classes = getFacesClasses(webApp, webModule);
  190           return new ClassFinder(classes);
  191       }
  192   
  193   
  194       /**
  195        * getFacesConfigFileURL()
  196        * <p/>
  197        * <p>Locations to search for the MyFaces configuration file(s):
  198        * <ol>
  199        * <li>META-INF/faces-config.xml
  200        * <li>WEB-INF/faces-config.xml
  201        * <li>javax.faces.CONFIG_FILES -- Context initialization param of Comma separated
  202        * list of URIs of (additional) faces config files
  203        * </ol>
  204        * <p/>
  205        * <p><strong>Notes:</strong>
  206        * <ul>
  207        * </ul>
  208        *
  209        * @param webApp    spec DD for module
  210        * @param webModule module being deployed
  211        * @return list of all managed bean classes from all faces-config xml files.
  212        * @throws org.apache.geronimo.common.DeploymentException
  213        *          if a faces-config.xml file is located but cannot be parsed.
  214        */
  215       private List<Class> getFacesClasses(WebAppType webApp, WebModule webModule) throws DeploymentException {
  216           log.debug("getFacesClasses( " + webApp.toString() + "," + '\n' +
  217                              (webModule != null ? webModule.getName() : null) + " ): Entry");
  218   
  219           // Get the classloader from the module's EARContext
  220           ClassLoader classLoader = webModule.getEarContext().getClassLoader();
  221   
  222           // 1. META-INF/faces-config.xml
  223           List<Class> classes = new ArrayList<Class>();
  224           try {
  225               URL url = DeploymentUtil.createJarURL(webModule.getModuleFile(), "META-INF/faces-config.xml");
  226               parseConfigFile(url, classLoader, classes);
  227           } catch (MalformedURLException mfe) {
  228               throw new DeploymentException("Could not locate META-INF/faces-config.xml" + mfe.getMessage(), mfe);
  229           }
  230   
  231           // 2. WEB-INF/faces-config.xml
  232           try {
  233               URL url = DeploymentUtil.createJarURL(webModule.getModuleFile(), "WEB-INF/faces-config.xml");
  234               parseConfigFile(url, classLoader, classes);
  235           } catch (MalformedURLException mfe) {
  236               throw new DeploymentException("Could not locate WEB-INF/faces-config.xml" + mfe.getMessage(), mfe);
  237           }
  238   
  239           // 3. javax.faces.CONFIG_FILES
  240           ParamValueType[] paramValues = webApp.getContextParamArray();
  241           for (ParamValueType paramValue : paramValues) {
  242               if (paramValue.getParamName().getStringValue().trim().equals("javax.faces.CONFIG_FILES")) {
  243                   String configFiles = paramValue.getParamValue().getStringValue().trim();
  244                   StringTokenizer st = new StringTokenizer(configFiles, ",", false);
  245                   while (st.hasMoreTokens()) {
  246                       String configfile = st.nextToken().trim();
  247                       if (!configfile.equals("")) {
  248                           if (configfile.startsWith("/")) {
  249                               configfile = configfile.substring(1);
  250                           }
  251                           try {
  252                               URL url = DeploymentUtil.createJarURL(webModule.getModuleFile(), configfile);
  253                               parseConfigFile(url, classLoader, classes);
  254                           } catch (MalformedURLException mfe) {
  255                               throw new DeploymentException("Could not locate config file " + configfile + ", " + mfe.getMessage(), mfe);
  256                           }
  257                       }
  258                   }
  259                   break;
  260               }
  261           }
  262   
  263           log.debug("getFacesClasses() Exit: " + classes.size() + " " + classes.toString());
  264           return classes;
  265       }
  266   
  267       private void parseConfigFile(URL url, ClassLoader classLoader, List<Class> classes) throws DeploymentException {
  268           log.debug("parseConfigFile( " + url.toString() + " ): Entry");
  269   
  270           try {
  271               XmlObject xml = XmlBeansUtil.parse(url, null);
  272               FacesConfigDocument fcd = convertToFacesConfigSchema(xml);
  273               FacesConfigType facesConfig = fcd.getFacesConfig();
  274   
  275               // Get all the managed beans from the faces configuration file
  276               FacesConfigManagedBeanType[] managedBeans = facesConfig.getManagedBeanArray();
  277               for (FacesConfigManagedBeanType managedBean : managedBeans) {
  278                   FullyQualifiedClassType cls = managedBean.getManagedBeanClass();
  279                   String className = cls.getStringValue().trim();
  280                   Class<?> clas;
  281                   try {
  282                       clas = classLoader.loadClass(className);
  283                       classes.add(clas);
  284                   }
  285                   catch (ClassNotFoundException e) {
  286                       log.warn("MyFacesModuleBuilderExtension: Could not load managed bean class: " + className  + " mentioned in faces-config.xml file at " + url.toString());
  287                   }
  288               }
  289           }
  290           catch (XmlException xmle) {
  291               throw new DeploymentException("Could not parse alleged faces-config.xml at " + url.toString(), xmle);
  292           }
  293           catch (IOException ioe) {
  294               //config file does not exist
  295           }
  296   
  297           log.debug("parseConfigFile(): Exit");
  298       }
  299   
  300       protected static FacesConfigDocument convertToFacesConfigSchema(XmlObject xmlObject) throws XmlException {
  301           log.debug("convertToFacesConfigSchema( " + xmlObject.toString() + " ): Entry");
  302           XmlCursor cursor = xmlObject.newCursor();
  303           try {
  304               cursor.toStartDoc();
  305               cursor.toFirstChild();
  306               if (SchemaConversionUtils.JAVAEE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) {
  307                   //do nothing
  308               } else if (SchemaConversionUtils.J2EE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) {
  309                   SchemaConversionUtils.convertSchemaVersion(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, SCHEMA_LOCATION_URL, VERSION);
  310               } else {
  311               // otherwise assume DTD
  312                   SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, SCHEMA_LOCATION_URL, VERSION);
  313               }
  314           }
  315           finally {
  316               cursor.dispose();
  317           }
  318           XmlObject result = xmlObject.changeType(FacesConfigDocument.type);
  319           if (result != null) {
  320               XmlBeansUtil.validateDD(result);
  321               log.debug("convertToFacesConfigSchema(): Exit 2" );
  322               return(FacesConfigDocument) result;
  323           }
  324           XmlBeansUtil.validateDD(xmlObject);
  325           log.debug("convertToFacesConfigSchema(): Exit 3" );
  326           return(FacesConfigDocument) xmlObject;
  327       }
  328   
  329       public static final GBeanInfo GBEAN_INFO;
  330   
  331       static {
  332           GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(MyFacesModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
  333           infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
  334           infoBuilder.addAttribute("providerFactoryNameQuery", AbstractNameQuery.class, true, true);
  335           infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
  336   
  337           infoBuilder.setConstructor(new String[]{
  338                   "defaultEnvironment",
  339                   "providerFactoryNameQuery",
  340                   "NamingBuilders"});
  341           GBEAN_INFO = infoBuilder.getBeanInfo();
  342       }
  343   
  344       public static GBeanInfo getGBeanInfo() {
  345           return GBEAN_INFO;
  346       }
  347   
  348   
  349   }

Home » geronimo-2.2-source-release » org.apache.geronimo.myfaces.deployment » [javadoc | source]