[ 
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.

Reply via email to