Hi folks,
I've been using Orchestra for a few months now and in doing so I've been
questioning some major implementation decisions, to be more specific I
really want to discuss if it's really necessary to bind beans to a
certain conversation (and therefore also a certein persistence
context!). Let me give you some examples:
Example 1)
I've developed some views for a search dialog that I wanted to use in at
least two different conversations. Everything worked fine for the first
conversation. The following code listing should give you an idea of the
problem.
///
view.xhtml
<h:inputText value="#{conversationBean.value}" />
spring-bean-config.xml
<bean id="conversationBean" class="..." scope="conversation.manual"
orchestra:conversationName="conversationA" />
\\\
Maybe some of you have realized my problem by now: The bean somehow
depends on the conversation and as the view depends on the bean I can't
use it with a different conversation (or at least I'm missing a major
feature of Orchestra). :-f
I've solved this issue by creating some Facelets components so that I'm
able to pass the conversation bean as parameter. However, I had to
duplicate navigation rules, etc, i.e. now I've got the following structure:
///
viewA.xhtml
<my:view bean="#{conversationABean}" />
viewB.xhtml
<my:view bean="#{conversationBBean}" />
view.xhtml
<h:inputText value="#{bean.value}" />
spring-bean-config.xml
<bean id="conversationABean" class="..." scope="conversation.manual"
orchestra:conversationName="conversationA" />
<bean id="conversationBBean" class="..." scope="conversation.manual"
orchestra:conversationName="conversationB" />
\\\
Example 2)
In a different part of the same application I've created a view that
should serve for three different usecases. Basically the view doesn't
change for these usecases at all, but the logic of the backing bean
does. My first approach was to determine the specific page bean at
runtime in the action method that navigates to this view. This action
method was supposed to register the specific page bean under a common
name. So somehow it can be said that I wanted to use "polymorphic beans".
///
public String action() {
Conversation conversation = getCurrentConversation();
switch (criterium) {
case CASE_A:
conversation.setAttribute("commonBean", specificBeanA);
break;
case CASE_B:
conversation.setAttribute("commonBean", specificBeanB);
break;
case CASE_C:
conversation.setAttribute("commonBean", specificBeanC);
break;
default:
throw new IllegalStateException(); // shouldn't occur anway
}
return outcome;
}
view.xhtml
<h:commandButton action="#{commonBean.save}" />
\\\
However, that wouldn't work for two reasons:
- Orchestra only knows how to resolve Spring beans as the bean
definition determines the conversation being used (well, Orchestra
doesn't know how to resolve anything, actually it's the
EL-/VariableResolver of Spring that does this job in this case). It's
only possible to resolve such variables if the view knows which
conversation it should access (i.e. if one would develop a custom
ELResolver that knows how to resolve expressions like
#{conversation.conversationA.commonBean} - *cough* problem of the first
example *cough*).
- Orchestra wouldn't create a persistence context for that bean as the
persistence interceptor only gets attached to Spring beans. (No, I'm not
telling you to modify the setAttribute method so that advices will be
attached. I'm rather telling you to use conversation listeners instead
for persistence support, just like Web Flow does).
I was able to work around this issue by introducing an additional
indirection, i.e. I'm resolving that bean with the expression
#{pageAccessor['commonBean']}, but that's just not intuitional.
However, please don't get me wrong. I don't want to hear anything about
certain workarounds that I could have used in these cases as I think
that these usecases aren't exceptional enough to justify workarounds. Of
course, the current approach has got its advantages too (e.g. switching
arbitrarily between different conversations as there is no hierarchical
structure), but at least I haven't needed this feature yet.
Summarizing it can be stated that I'd propose you to rewrite
conversation handling for the next major release and I'd be willing to
contribute. Note that I don't want to drop support for these "named
conversations", but I think that this usecase is not the default one for
conversations.
regards,
Bernhard Huemer