You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by "Leonardo Uribe (JIRA)" <de...@myfaces.apache.org> on 2010/11/17 22:15:14 UTC

[jira] Commented: (MYFACES-2945) Make a way to get the FacesConfig from a provider

    [ https://issues.apache.org/jira/browse/MYFACES-2945?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12933164#action_12933164 ] 

Leonardo Uribe commented on MYFACES-2945:
-----------------------------------------

Hi

Here we have different problems to handle, so below there is a list of them:

1. commons-discovery package might not work correctly in OSGi environment: OSGi does not provide a Thread Context Class  Loader (TCCL) by default, but as explained before (MYFACES-2944), the container must provide a TCCL to make JSF work in OSGi. In theory, if the TCCL interface is correct, this should not be a problem, but anyway it could be good to provide an interface that can be configured using an application scope key to locate SPI interfaces. Right now we are using commons-discovery for LifecycleProvider and others Providers under org.apache.myfaces.spi interface, but we have a  different code on FacesConfigurator, following JSF 2.0 spec section 11.2.6.1 FactoryFinder. Before solve this one we must  unify the code that load SPI interfaces from /META-INF/services in one way or another (use commons discovery or a custom code).

2. How to prevent parse faces-config.xml files more times than necessary?. I think this is the objective why it is required an interface to handle this issue, right? From the server container point of view, it could be good to parse all stuff (faces-config.xml, META-INF/services and JSF annotations) just once and save it, so if the web application is undeployed and deployed again, the initialization time will be faster.

In this issue I suppose we are only interested in (2) but in some way it is related to (1). To understand clearly which options do we have, it is necessary to take into account JSF 2.0 spec section 11, specially section 11.2.6.1 and 11.4. The relevant points are resumed below (the idea is be very detailed on this part, otherwise it is easy to get lost):

1.2.6.1 FactoryFinder

"... For a given factory class name, a corresponding implementation class is searched for based on the following algorithm. Items are listed in order of decreasing search precedence ...", that means the if there is configuration on the first items on the list, that one takes precedence over the later ones.

"...
1. If a default JavaServer Faces configuration file (/WEB-INF/faces-config.xml) is bundled into the web application, and it contains a factory entry of the given factory class name, that factory class is used.
2. If the JavaServer Faces configuration resource(s) named by the javax.faces.CONFIG_FILES ServletContext init parameter (if any) contain any factory entries of the given factory class name, those factories are used, with the last one taking precedence.
3. If there are any META-INF/faces-config.xml resources bundled any JAR files in the web ServletContext's resource paths, the factory entries of the given factory class name in those files are used, with the last one taking precedence.
4. If a META-INF/services/{factory-class-name} resource is visible to the web application class loader for the calling application (typically as a result of being present in the manifest of a JAR file), its first line is read and assumed to be the name of the factory implementation class to use.
5. If none of the above steps yield a match, the JavaServer Faces implementation specific class is used.
..."

11.4 Application Startup Behavior

".. At application startup time, before any requests are processed, the JSF implementation must process zero or more application configuration resources, located according as follows:

Make a list of all of the application configuration resources found using the following algorithm:

- Search for all resources that match either "META-INF/faces-config.xml" or end with ".facesconfig.xml" directly in the "META-INF" directory. Each resource that matches that expression must be considered an application configuration resource.

- Check for the existence of a context initialization parameter named javax.faces.CONFIG_FILES. If it exists, treat it as a comma-delimited list of context relative resource paths (starting with a "/"), and add each of the specfied resources to the list.

Let this list be known as applicationConfigurationResources for discussion. Also, check for the existence of a web application configuration resource named "/WEB-INF/faces-config.xml", and refer to this as applicationFacesConfig for discussion, but do not put it in the list. When parsing the application configuration resources, the implementation must ensure that applicationConfigurationResources are parsed before applicationFacesConfig..."

11.5.1 Requirements for scanning of classes for annotations

"...
- If the <faces-config> element in the WEB-INF/faces-config.xml file contains metadata-complete attribute whose value is "true", the implementation must not perform annotation scanning on any classes except for those classes provided by the implementation itself. Otherwise, continue as follows.
- If the runtime discovers a conflict between an entry in the Application Configuration Resources and an annotation, the entry in the Application Configuration Resources takes precedence.
- All classes in WEB-INF/classes must be scanned.
- For every jar in the application's WEB-INF/lib directory, if the jar contains a "META-INF/faces-config.xml" file or a file that matches the regular expression ".*\.faces-config.xml" (even an empty one), all classes in that jar must be scanned. ..."

Based on the previous documentation, the ordering to load JSF configuration is this:

- Look JSF standard faces-config.xml file (in myfaces case META-INF/standard-faces-config.xml).
- Look JSF Factory class configuration under META-INF/services/{factory-class-name}.
- Look JSF annotation on the classpath (jars and WEB-INF/classes). (org.apache.myfaces.spi.AnnotationProvider delegates how JSF annotations are scanned).
- Look for META-INF/faces-config.xml and META-INF/*.faces-config.xml resources on classpath (org.apache.myfaces.spi.FacesConfigResourceProvider delegates how these config files are found if it is necessary to the server container, for example if it use a custom way to load resources like JBoss AS 6 (jndi://...) ). This resources are 
added as applicationConfigurationResources.
- Look for resources under javax.faces.CONFIG_FILES. This resources are added as applicationConfigurationResources.
- Sort all applicationConfigurationResources using rules on JSF 2.0 section 11.4.7
- Look for /WEB-INF/faces-config.xml file. 

And finally the configuration information are feed in this way (from lower to upper priority)

- META-INF/standard-faces-config.xml
- META-INF/services/{factory-class-name}
- Annotations if and only if /WEB-INF/faces-config.xml <metadata-complete> is set to true.
- Sorted ApplicationConfigurationResources.
- /WEB-INF/faces-config.xml

I hope with the previous explanation, it becomes clear the steps required to create the configuration information. These steps are done by FacesConfigurator.

Now, if the problem is "cache" configuration information there are two possible options:

1. Cache the final information of all previous process. That means if in a project a dependency is changed, of a relate file is, all previous algorithm must be done again.
2. Cache each configuration bundle separately. That means if a dependency is added to the project on the server, we only need to parse the additional files and all final configuration will be calculated each time the web application is deployed, but in this case it will be a lot faster than parse all files over and over.

The option (1) (note this is the one proposed here) looks the most easy one, but I checked the current algorithm and I notice it requires some major changes. The first problem is the "container" used to "sum" all information is not:

org.apache.myfaces.config.impl.digester.elements.FacesConfig

It is

org.apache.myfaces.config.impl.digester.FacesConfigDispenser<FacesConfig>

The first step is change FacesConfigDispenser from interface to abstract class. But one problem is FacesConfigurator does not implement the algorithm exactly as the theorical algorithm exposed here says. So we need to fix that. After that, we need to "hide" all methods on FacesConfigDispenser that start with "feed" word, because it is a detail that we don't want to expose in a SPI interface. All previous points can be done, but it will take some time to complete them.

The option (2) is in theory more flexible, but requires to think more about how the interface should looks like, and do a similar work to the one exposed before. Anyway, do those changes will take more time than I expected.

Suggestions are welcome.

> Make a way to get the FacesConfig from a provider
> -------------------------------------------------
>
>                 Key: MYFACES-2945
>                 URL: https://issues.apache.org/jira/browse/MYFACES-2945
>             Project: MyFaces Core
>          Issue Type: Improvement
>          Components: General
>    Affects Versions: 2.0.2
>            Reporter: Ivan
>            Assignee: Leonardo Uribe
>
> Currently, MyFaces startup listener will parse the all the faces configuration files and sort them on each startup time, and it will be better to do it once in the deployment time, and get those data structure instances from a provider. One possible way is to make those FacesConfig class serializable.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.