Pete and I had a chat on this a few days ago, and here's the summary
on how we decided to go, and what I've implemented in the patch at
https://jira.jboss.org/jira/browse/JBSEAM-3645
Seam doesn't have any notion of choosing components based on request
specifics, so rather than having the Manager and StatusMessages
component subclasses install themselves based on class dependencies,
we'll have the base classes unwrap themselves as the
view-layer-dependent subclasses per-request, by asking the subclasses
if they want to participate in the request. The subclasses register
with the parent class at startup. See the above issue for more
details.
Also, the WicketRedirectFilter will co-exist with, rather than
replace, the jsf RedirectFilter, and each will turn on/off based on
whether the requests is specific to that view layer.
As an aside, I do think that it would be worth, in the long run,
having a mechanism to choose components to instantiate by annotating a
component method that would let the context ask the component whether
it wishes to be used. Right now, if you need to contextually choose a
component to install from a set of components, you have to have a
@Factory or an @Unwrap which knows about all the possible
implementations, which isn't always possible or even desired. The
mechanism I used in the above patch is slightly contorted. What I'd
like to be able to do is:
@In StatusMessages statusMessages;
...
@Name("facesMessages")
public class FacesMessages extends StatusMessages {
@RoleSelector("statusMessages")
public boolean shouldIbeInstalled() {
return FacesContext.getCurrentInstance() != null;
}
...
}
@Name("wicketMessages")
public class WicketMessages extends StatusMessages {
@RoleSelector("statusMessages")
public boolean shouldIbeInstalled() {
return Application.exists(); //ask wicket's threadlocal-aware code
}
...
}
and then have Component.getInstance() do the work for me, throwing an
exception if two components simultaneously volunteer for a role, or
perhaps provide a precedence mechanism for resolution of conflicts a
la @Install.
-Clint
On Thu, Oct 23, 2008 at 5:57 PM, Clint Popetz <cpopetz(a)gmail.com> wrote:
On Fri, Oct 17, 2008 at 1:59 PM, Clint Popetz
<cpopetz(a)gmail.com> wrote:
> * Fixes to make it possible for jsf, wicket, and other web tier components
> (i.e. struts, using ContextFilter) to co-exist in the same deployment, which
Per Pete's suggestion, I'm starting a discussion on how to do this.
There are four classes that currently prevent this from working:
* WicketRedirectFilter and WicketExceptionFilter
These exist mainly to turn off those two filters for wicket requests.
I suggest that these can be deleted, and wicket users can just do:
<web:redirect-filter url-pattern="*.seam"/>
<web:exception-filter url-pattern="*.seam"/>
so that the filters are only enabled for faces-specific requests.
That violates DRY, because they have to change that if they change
web.xml's mapping of the faces servlet. But I know of no good way
from a filter to figure out at runtime how the faces servlet is
mapped.
* WicketStatusMessages and WicketManager
These are more difficult. The hack I did, which works, is to have
each extend the faces variants of these classes, and to have each
short-circuit the direct super class behavior when
org.apache.wicket.Application..exists() returns true, i.e. when wicket
has decided it owns the request. But that's ugly, and wouldn't be
sustainable as more view layer options are added.
FacesManager really shouldn't subclass Manager, in my opinion. It
overrides hardly any methods, and the ones it does override only exist
in the base class for the benefit of other code which could directly
call FacesManager, because it is already faces-aware. I made a stab
at seeing what it would take to refactor this to make Manager a
view-layer-agnostic component. It's possible, and not even that hard,
but the main problem are redirects. Currently a lot of code tells the
conversation (or conversation entry) to redirect(), and they both
store a jsf view id and then ask the manager to redirect to that id.
Since there is only one manager, that manager has to be faces aware.
We could instead have conversation subclasses for each view
technology, i.e. FacesConversation, and FacesConversationEntry, and
create the right one with factories, and have each know how to
redirect, or know which component (FacesManager) to ask to redirect.
But then we come to the question of "should conversations themselves
be view-agnostic," e.g. should it be possible to move from a
wicket-based page to a jsf based page while maintaining the same
conversation. I think so. But that would mean a fair amount of work,
because it means having conversations have two components, a
view-agnostic part and a view-centric part, with each delegating to
the other.
At this point, I feel like I might be treading into deep waters, and
so I'm interested in whether this type of work, to make the core of
seam less dependent on JSF, is a direction you'd like to see the
source go. I don't think it can be done without breaking a fair
amount of code, and who knows how much code has EL expressions that
reference these components, i.e. to do conversation-switching from
JSF. (Ironically, untyped EL expressions breaking due to refactoring
is the main reason I'm switching from JSF to wicket :)
Thanks for listening, and interested in your thoughts.
-Clint