[
https://issues.apache.org/jira/browse/MYFACES-2730?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12882004#action_12882004
]
Leonardo Uribe commented on MYFACES-2730:
-----------------------------------------
I review again all the problem and finally I notice the missing arguments.
The lines that cause the problem are these (see AbstractFacesInitializer class):
private void dispatchInitDestroyEvent(ServletContext servletContext, Class
eventClass) {
ApplicationFactory appFac = (ApplicationFactory)
FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
FacesContext fc = null;
fc = FacesContext.getCurrentInstance();
if (fc == null) {
LifecycleFactory lifeFac = (LifecycleFactory)
FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
FacesContextFactory facFac = (FacesContextFactory)
FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
fc = facFac.getFacesContext(servletContext,
new _SystemEventServletRequest(),
new _SystemEventServletResponse(),
lifeFac.getLifecycle(getLifecycleId(servletContext)));
}
// in order to allow FacesContext.getViewRoot calls during
startup/shutdown listeners,
// we need to initialize a new ViewRoot with locale set to
Locale.getDefault().
UIViewRoot root = new UIViewRoot();
root.setLocale(Locale.getDefault());
fc.setViewRoot(root);
appFac.getApplication().publishEvent(fc, eventClass, Application.class,
appFac.getApplication());
}
In order to propagate init and destroy events we try to lookup the
FacesContextFactory instance and create a FacesContext object just for that
purpose. With the changes proposed, that lookup just dissapear, because it is
replaced by StartupFacesContext.
Myfaces orchestra and trinidad installs its own FacesContext wrapper, and in
those methods, initialization stuff happen. See for example trinidad
(FacesContextFactoryImpl):
public FacesContext getFacesContext(
Object context,
Object request,
Object response,
Lifecycle lifecycle)
{
return new CacheRenderKit(_factory.getFacesContext(context, request,
response, lifecycle));
}
static public class CacheRenderKit extends FacesContext
{
@SuppressWarnings("unchecked")
public CacheRenderKit(FacesContext base)
{
_base = base;
ExternalContext baseExternal = base.getExternalContext();
GlobalConfiguratorImpl config = GlobalConfiguratorImpl.getInstance();
//This should be done only if beginRequest was not called on the
configurator
//before we retrieve the FacesContext. If this is the case then we'll
need to handle
//cleanup on the release of the FacesContext. Otherwise the endRequest
should be
//called by whatever did he origional beginRequest.
if(!GlobalConfiguratorImpl.isRequestStarted(baseExternal))
{
Map<String, Object> requestMap = baseExternal.getRequestMap();
requestMap.put(_CONFIG_IN_CONTEXT, Boolean.TRUE);
}
_external = new OverrideDispatch(config.getExternalContext(baseExternal));
setCurrentInstance(this);
}
Now look this stack trace from MYFACES-2520.
at
org.apache.myfaces.context.servlet.ServletExternalContextImpl.getRequestContentType(ServletExternalContextImpl.java:322)
at
org.apache.myfaces.trinidad.util.ExternalContextUtils.getContentType(ExternalContextUtils.java:341)
at
org.apache.myfaces.trinidadinternal.share.util.MultipartFormHandler.isMultipartRequest(MultipartFormHandler.java:57)
at
org.apache.myfaces.trinidadinternal.config.upload.FileUploadConfiguratorImpl.beginRequest(FileUploadConfiguratorImpl.java:109)
at
org.apache.myfaces.trinidadinternal.config.GlobalConfiguratorImpl._startConfiguratorServiceRequest(GlobalConfiguratorImpl.java:532)
at
org.apache.myfaces.trinidadinternal.config.GlobalConfiguratorImpl.beginRequest(GlobalConfiguratorImpl.java:211)
at
org.apache.myfaces.trinidadinternal.config.GlobalConfiguratorImpl.getExternalContext(GlobalConfiguratorImpl.java:327)
at
org.apache.myfaces.trinidadinternal.context.FacesContextFactoryImpl$CacheRenderKit.<init>(FacesContextFactoryImpl.java:90)
at
org.apache.myfaces.trinidadinternal.context.FacesContextFactoryImpl.getFacesContext(FacesContextFactoryImpl.java:68)
I was supposing this error was because there was a lookup for RenderKitFactory,
but after checking the code, the conclusion is that's not true.
So, which factories should not be called during initialization, because they
are susceptible to have code that require request/response objects?
FacesContextFactory
ExternalContextFactory (added on jsf 2.0)
PartialViewContextFactory (added on jsf 2.0)
VisitContextFactory (added on jsf 2.0)
All other factories are safe, because from its constructors or its methods
there is no way to get request or response object without go through
FacesContext.getCurrentInstance(). Fortunately, with the fix proposed those
factories will not be lookup during setup or shutdown time. Since we are not
using FacesContextFactory to create FacesContext instances, there is just no
chance that we could call methods that requires request/response objects during
initialization, so there will not be compatibility problems with old jsf
libraries, because we will not call susceptible methods from those locations.
So, with the recently found evidence we can conclude the following (see
proposed solution MYFACES-2730-4.patch):
- It is not necessary to use dummy methods on StartupFacesContextImpl and
StartupServletExternalContextImpl, because there is no jsf 1.1 or jsf 1.2 code
that requires dummy request/response objects. The reason about why there is no
susceptible code is FacesContext is not set on setup/shutdown, and there is no
way to access to request or response object. In jsf 1.1 or jsf 1.2, the common
workaroud was use custom wrappers but located on the filter used (see trinidad
filter for example), and initialize on the first request.
- All methods that are not related to request/response objects are required to
be implemented. The list of methods to be implement is this:
StartupFacesContextImpl
public ExceptionHandler getExceptionHandler()
public void setExceptionHandler(ExceptionHandler exceptionHandler)
public final ExternalContext getExternalContext()
public Application getApplication()
public final RenderKit getRenderKit()
public final void setViewRoot(final UIViewRoot viewRoot) //For event processing
public final UIViewRoot getViewRoot() //For event processing
public final ELContext getELContext()
public Map<Object, Object> getAttributes()
public boolean isProcessingEvents() //For event processing
public void setProcessingEvents(boolean processingEvents) //For event processing
public void release()
StartupServletExternalContextImpl
public Map<String, Object> getApplicationMap()
public String getMimeType(String file)
public Object getContext()
public String getContextName()
public String getInitParameter(final String s)
public Map<String, String> getInitParameterMap()
public URL getResource(final String path) throws MalformedURLException
public InputStream getResourceAsStream(final String path)
public Set<String> getResourcePaths(final String path)
public void log(final String message)
public void log(final String message, final Throwable exception)
public String getRealPath(String path)
public void release()
The remaining methods could throw
UnsupportedOperationException/IllegalStateException.
I'm happy with the latest solution, because it is supported with all evidence
and does not have any hidden problems. If no objections I'll commit this patch
soon.
> FacesContext not available on application startup
> -------------------------------------------------
>
> Key: MYFACES-2730
> URL: https://issues.apache.org/jira/browse/MYFACES-2730
> Project: MyFaces Core
> Issue Type: Bug
> Components: JSR-127, JSR-252, JSR-314
> Affects Versions: 1.1.8, 1.2.9, 2.0.0
> Reporter: Nick Belaevski
> Assignee: Leonardo Uribe
> Fix For: 2.0.2-SNAPSHOT
>
> Attachments: MYFACES-2730-1.patch, MYFACES-2730-2.patch,
> MYFACES-2730-3.patch, MYFACES-2730-4.patch, MYFACES-2730-revert.patch
>
>
> If custom ResourceHandler calls FacesContext.getCurrentInstance() in
> constructor to read init parameters, null value is returned. This affects
> latest MyFaces 2.0.0-SNAPSHOT. Mojarra 2.0 provides InitFacesContext in this
> case.
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.