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