Hi Andy
Here I have to mention something
Oh, interesting. This does seem extremely important. We've got two types of viewIds:
- Raw: deriveViewId() logic has not yet been applied
- Derived: deriveViewId() has been applied
ViewHandler.getViewDeclarationLanguage() needs to be specific about what type of viewId is expected. Based on the above code snippets, it looks like Mojarra's implementation expects raw viewIds. MyFaces expects derived viewIds. However, as you said, for the most part, Mojarra is passing derived viewIds into ViewHandler.getViewDeclarationLanguage(). This means that Mojarra is repeatedly re-deriving viewIds on each ViewHandler.getViewDeclarationLanguage() call. Since there can be many calls to this method per-request, and since checking for the physical existence of a view isn't always cheap, this seems bad.
Perhaps the spec needs to be updated to make it clear that ViewHandler.getViewDeclarationLanguage() operates on derived viewIds?
Right: ViewHandler.deriveViewId().
In this case, MyFaces "derive" the physical viewId before call getViewDeclarationLanguage
from RestoreViewPhase. In theory, we should call from RestoreViewPhase algorithm a method
exposed by ViewHandler.
Getting back to the question of how to check whether a particular view exists... I agree that at a minimum in the Facelets case we need to be consistent about always including the ResourceResolver in this decision. The new existence check method on ViewDeclarationLanguageFactory() that you proposed would definitely help. Actually, something like this would be tremendously helpful for us here (ADF Faces), since at the moment we have logic scattered across ResourceResolver + ExternalContext. This split approach is particularly awkward since ExternalContext.getResource() is used more generically than ResourceResolver - ie. ExternalContext.getResource() may be called for arbitrary resource retrieval, whereas we are particularly interested in view resolving.
I wanted to mention an alternate to the ViewDeclarationLanguageFactory approach, though I am not sure whether it is an improvement. In our case, we wouldn't mind using the ResourceResolver generically across VDLs, ie. we wouldn't mind seeing ResourceResolver promoted to a first class/VDL-agnostic API. Our ResourceResolver implementation is used to serve up resources from the class path as well as from remote repositories (eg. a database). This ability could be useful not just for Facelets, but for arbitrary VDLs. It would be nice if we could implement this behavior one time in a standard/portable way rather than requiring a new solution for each VDL.
If we had access to an application-level (VDL-independent) ResourceResolver, the JSF implementations could use this to check for the existence of views when deriving view ids (and elsewhere) without having to go through the ViewDeclarationLanguageFactory.
I don't think it would be especially hard to make the ResourceResolver more general-purpose. We would likely want to add a new version of this class outside of the Facelets packaging and possibly re-parent the existing Facelets ResourceResolver to the new API. Or, at least, we would want to provide the ability to transparently adopt the old Facelets ResourceResolver to the new generic ResourceResolver.
Another small change that might be helpful... in order to answer the question of whether or not a resource exists, we currently need to literally cough up an URL. In our case, we might be able to optimize if we just had to test for existence as opposed to return a reference to the resource. Perhaps we could consider adding exists() method to the generic ResourceResolver. By default this would just do "resolveUrl() != null", but this could be optimized in other implementations.
Of course, if we generalize the ResourceResolver in this way and call this from ViewHandler.deriveViewId(), this does introduce a new assumption: that ViewDeclarationLanguages will also use the ResourceResolver for loading views (like Facelets does). One case where this isn't necessarily true is the JSP ViewDeclarationLanguage, since the JSP engine itself is responsible for loading the view. FWIW, in our particular case, our JSP engine actually does contain resource resolving logic that matches our ResourceResolver implementation. As such, we would prefer to use the ResourceResolver to check for view existence even in the JSP case, though I imagine our requirements are a bit unusual in this area.
Thoughts?