Hi
Implementing Faces Flow feature for MyFaces, I have found some
observations that I would like to discuss. In fact, I have a list of things I
have seen in JSF 2.2 that we can improve, and that I hope to discuss
in this mailing list in the future.
The first problem we have and the reason why @FlowScoped does not
look like a full conversation scope (Hantsy's item 4) is there is no
clarification about the relationship between flows.
In few words, there are two cases:
- Two or more independent flows are running at the same time.
- Flow A call flow B, but when the flow A ends, since A was called from
B, B should end too.
Support these two concepts are very important because users want
to model everything as a flow, and this is esential to allow better flow
reusal. In MyFaces I did this:
- Take into account an ordered list of the active flows instead the
current flow only in the navigation step.
- If the flow is called using its flow name, it is considered and
independent flow.
- If the flow is called using a call flow node, it is considered a subflow, so
if the parent flow ends, the children ends too.
I don't know if you have seen these examples done by a colleague
at Irian, Michael Kurz:
https://github.com/jsflive/jsf22-examples
Take a look at the example named jsf22-flows. It is quite easy to modify
it and do some tests. Try enter into a flow, then to another without exit
from the first flow and if you use Mojarra you'll see how some links
are disabled.
Other typical use case is if the user wants to create a link to enter into
a flow, but the flow is already active. In theory, the flow must be
restarted, but sometimes you want to encode the link to just move
to the start page.
The other problem is about how FlowHandler.clientWindowTransition(...).
The way how flow navigation using GET is different between MyFaces
and Mojarra, even if both are compatible with the spec. In MyFaces, we
are using a NavigationCase wrapper to override fromOutcome and
toFlowDocumentId:
* Wrapper that helps overriding toFlowDocumentId and fromOutcome, to build
* correctly a navigation case that cause a flow action (enter into a flow
* or return from a flow).
*
* The idea is if is necessary to enter into a flow set fromOutcome as the
* flow id and toFlowDocumentId as the flow document id. If it is a return,
* set fromOutcome as the return node and toFlowDocumentId as
FlowHandler.NULL_FLOW
Later, this will be useful to keep track of the navigation and start/end the
flows properly in FlowHandler.clientWindowTransition(...) This is how I
understood this part:
/**
* There are two basic cases: Enter into a flow and return from a flow.
*
* - FlowHandler.TO_FLOW_DOCUMENT_ID_REQUEST_PARAM_NAME : value of
the toFlowDocumentId property
* of the navigation case when enter into a flow OR
FlowHandler.NULL_FLOW when return from a flow.
*
* - FlowHandler.FLOW_ID_REQUEST_PARAM_NAME : value of the
fromOutcome property of the navigation case.
* According to the intention it has multiple options:
*
* 1. It can be a flowId, which means enter into a flow.
* 2. It can be a flow call id, which means enter into a flow.
* 3. It can be a flow return id, which means return from a flow.
* - The javadoc of NavigationCase.getToFlowDocumentId() says this:
* "... If this navigation case represents a flow invocation, this
property is the documentId in
* which the flow whose id is given by the return from
getFromOutcome() is defined. Implementations
* must override this method to return the value defined in the
corresponding application
* configuration resources element. The base implementation
returns the empty string. ..."
*
* This is consistent with the previous interpretation, but we
need to include the case where
* toFlowDocumentId is FlowHandler.NULL_FLOW too, which is derived
implicitly. The key of the trick
* is override fromOutcome / toFlowDocumentId in the navigation
algorithm to indicate when the
* navigation case is entering into a flow or return from a flow.
In that way, it is possible
* to use ConfigurableNavigationHandler.getNavigationCase(...) to
know the "route" using the
* initial fromOutcome given in FLOW_ID_REQUEST_PARAM_NAME.
*
**/
In my opinion, the specification done for this feature is fine, but in
MyFaces land
we have had a hard time doing a proper implementation. I agree there are
things to improve, like everything, but there is nothing we cannot do in JSF 2.3
or later.
Some comments over the suggestions done by Hantsy:
HB>> Spring Web Flow provides extended persistence support in the whole flow,
HB>> so you never worry about the LazyInitializationException thrown
by Hibernate.
That's CDI responsibility. Nothing to do from JSF side.
HB>> Spring Web Flow supports events on enter and exit point in every node.
Use f:viewAction
HB>> Spring Web Flow supports Ajax, thus the page fragment can participate
HB>> into the flow.
Something we need to think. An use case or example is welcomed.
HB>> Spring Web Flow supports subflows in the main flow, and allow you share
HB>> the data state between flows directly, the
inbound-parameter/outbound-parameter in the
HB>> Faces Flow is very stupid and ugly.
Take a look at MyFaces, A @FlowScoped bean from a parent flow can be shared
by the child flow.
HB>> Spring Web Flow is designated to remove any backend beans, and use
HB>> flow to hold the data, and use stateless Spring bean to sync data
with database.
Take a look at MyFaces. Faces Flow support initializer/finalizer. @PreDestroy
for flow scope beans works.
HB>> @Begin and @End are provided to declare the boundaries of a
HB>> conversation, no need extra flow definition.
Isn't @PostConstruct and @PreDestroy works?
regards,
Leonardo Uribe
2013/12/19 Edward Burns <edward.burns_at_oracle.com>:
> Hello Volunteers,
>
> Neil Griffin brought this old blog entry to my attention today:
> <http://hantsy.blogspot.com/2013/08/jsf-22-flow.html>. I think it is a
> decent summary of the Faces Flows feature, but it ends with this text:
>
> H> Personally, the new Faces Flow is neither good nor bad, but I am
> H> bitterly disappointed with it. JSF EG declares it is inspired by ADF
> H> Task Flow and Spring Web Flow, but it seems they just copied ADF Task
> H> Flow and made it standardized.
>
> Now, if Faces Flows does not represent enough of Spring Web Flow, that
> is only a function of the participation of the EG members representing
> Spring Web Flow. Rossen, do you agree with Hantsy's impression that
> Faces Flows just copies ADF Task Flows and doesn't represent SWF? What
> does SWF have that Faces Flows could benefit from?
>
> H> 1. The elements of the flow definition are tedious and not clear as
> H> the Spring Web Flow.
>
> I'd like to understand how to make flows better here.
>
> H> 2 The command action, especially, h:commandButton and h:commandLink
> H> became difficult to understand, the action value could be an implicit
> H> outcome, a flow name, a method call id, a flow call id etc.
>
> Yes, it's true. I wanted to make it very easy to adopt flows in an
> existing app.
>
> H> 3. The Java based flow definition(@FlowDefinition and FlowBuilder) is
> H> every ugly, just converts the xml tag. It is not fluent APIs at all.
>
> I welcome improvements. Does anyone else feel the same way, that the
> API needs to be more fluent?
>
> H> 4. The @FlowScoped bean does not work as the Seam 2 conversation
> H> bean.
>
> I see this statement on the Seam website: "Active development of Seam 3
> has been halted by Red Hat." Therefore, I don't know how important it
> is to do anyting about Hantsy's item 4.
>
> Ed