This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

What do you want in Spring Web Flow 1.1?

Apr 20th, 2007, 01:18 PM

Spring Web Flow community,

Work on Spring Web Flow 1.1 is getting started. 1.1 is going to be a major new functionality release with significant product investment from both Interface21 and Ervacon. The major themes are integration, ease of use, and reusability.

Planned features include:

Conversational persistence contexts

The ability to have persistence contexts driven by your conversational boundaries, and automatically managed within those boundaries. The basic pattern here is you start a conversation to load some objects, resume the conversation to update those objects over a series of requests, and end the conversation to commit your updates in a single transaction.

Acegi Security integration

The ability to secure flow definitions using the Acegi Security System for Spring. Being able to authorize:
- Does the principal have the rights to launch this flow?
- Does the principal have the rights to enter this state of this flow?
- Does the principal have the rights to signal this event against the current state of this flow?

Unified Expression Language (EL) integration

Currently the Object Graph Navigation Language (OGNL) is the only ExpressionParser supported out of the box in Spring Web Flow. We're going to add support for the Unified Expression Language (EL) which is widely-used in the Java Server Faces community and an emerging standard (JSR-245).

Integrated Spring 2.0 custom scopes

The ability to use Spring 2.0's "custom scope" capability to scope Spring beans in Web Flow's conversation, flow, and flash scopes. This allows scoped beans to benefit from dependency injection easily and to be used naturally in a Java Server Faces environment where Spring 2 is used as the managed bean provider.

Enhanced support for Java-based flows

Out-of-the-box support for engineering executable Flow defnitions from non-XML sources, including plain Java-based metadata. This includes support for declarative @RequestHandler method binding (for "stateless" flows), as well as the possibility of defining flows fully using plain Java objects, with Flow and States as classes and transitions as methods. A strong aspect of Spring Web Flow's design is the core engine is independent of any flow definition medium such as XML. The JIRA issue tracking this enhancement in the roadmap contains a prototype by Rod Johnson himself on some of this work.

Support for flow composition and inheritance

The ability to compose flows using inheritance and composition, similiar to how a class can extend another class and contain associations with other types. We expect inheritance to improve reuse for flows that share common controller behaviors, and composition to allow master flows to embed other flows as part of a overall controller graph, similiar to how today's component-based frameworks can nest other components.

There are other planned features as well, but these are some of the biggies. The full roadmap is here. Keep in mind this is subject to change and evolve as we get further along and receive more feedback.

What do you want to see in your Web Flow 1.1? I'm particularly interested in those who have been using Spring Web Flow for sometime and understand what it brings to the table and its potential. What new features would you stand to benefit from the most? They don't necessarily have to be on this list or the roadmap yet.

Ease of use is one of my major goals for 1.1. I want try and see how we can make SWF even easier and more natural to use. This also ties in with a number of big items Keith mentions above.

Any remarks or suggestions you might have from your experience using SWF are welcome:

Are there areas where SWF is too verbose in it's configuration or in the flow definitions (e.g. 'form handling view states')?
Should certain things be more intuitive?
Where does SWF violate the DRY (Don't Repeat Yourself) principle?
Can SWF benefit from convention over configuration (E.g. I have been thinking about something like a SWF SimpleFlowController that uses a continuation repo and loads flow defs from /WEB-INF/flows/**/*-flow.xml)
How can we make testing flows easier?

Erwin

Comment

I'd like to be able to 'import' a flow def into another flow. currently, only <beans> can be imported. We have an extension of DocumentLoader that imports a <flow> for the purpose of applying <global-transitions> as 'real' (well, we eliminate cut and paste, anyway) global transitions (mostly for menuing).

Also, the exception handling method is good BUT the out of the box methods do not track serializability when attempting to place the exception data into 'flash' scope ( which, of course, immediately generates a 'non-serializable' exception). I'm finding more and more third party exceptions that contain non-serializable objects not marked as transient.

Comment

Firstly, and most importantly, certain view states aren't well-supported. Take this for an example:

You have an application process flow. At the end it creates a pre-populated PDF for you to print, sign and send in. This situation does not have a good solution in SWF 1.0.2.

If you have a view state that returns the PDF there are several issues:

1. There is no way to progress from the new state (since it triggers a transition). As such, when you continue from the page that launched the view, you have the overhead of a continuation. This also creates all sorts of problems because the new view can't put something on the flow scope because that flow isn't continued. A new flow is. This means using conversation scope or soem other method;

2. The URL is not "nice", meaning with standard implementation there URL contains the flow execution key. Firefox ignores a content disposition HTTP header and uses whatever is after the last slash as the name of the file (which is stupid and not SWF's fault but it needs to be worked around). The workaround seems to be appending ";/real_file_name.pdf" to the end of the URL, which is pretty ugly.

.3. This one may be my ignorance talking but it'd be nice if the flow execution key didn't have to be part of the URL at all and could be passed around purely as a hidden form field; and

4. You have all sorts of issues with alwaysRedirectOnPause set to true, as we've discovered. Some combination of IE and Acrobat Reader 8 produces undesirable results. You can turn off redirect on pause and use redirect: for your view states but this isn't desirable either. Is there a forward: or similar prefix that could be used instead?

The best solution we've thus far been able to come up with is taking the PDF creation out of SWF entirely, which creates the mess required to access the flow exeuction repository from outside SWF. None of the above are desirable solutions. To me, it seems like theres no current state type which accurately models a PDF view state so SWF 1.1 should probably add one. I don't know what it would be called or what its semantics would be. This isn't an idea in the true sense, merely pointing out a shortcoming that (imho) needs a solution.

Intermediate End States

Another thing I'd like to see in SWF 1.1 is the idea of "savepoints" (in database parlance). That's not exactly what I'd call them but it kind of illustrates what I mean. When you hit an end-state in SWF, you can't click back and go through again. This is usally a good thing but there are times in a flow when you perform some action that you can't ignore and can't rolblack. As such you really want to make the flow execution to say that you can't continue the flow from before the intermediate end state.

This could also have the benefit of allowing SWF to clean up flows prior to this intermediate state.

Attempting to continue from prior to the intermediate state will create a similar "error" as trying to do so after you've hit an end state. The semantics of such a thing obviously need work and more thought but the idea seems worthy of consideration to me.

Better client-side continuation.

Currently client-side continuation is basically unusable for several reasons:

1. Tomcat 5.5 on JBoss 3.2 for example has a predefined limit on HTTP response headers of about 8192 bytes. You hit that pretty quick with client-side continuation;

2. Client-side continuation is not secure (as noted in the SWF reference); and

1. Don't use HTTP response headers. Use form fields. If necessary this may mean multi-part messages if its sufficiently large. Either way, this level of complexity should be (mostly if not entirely) hidden from the developer. POST responses handle large amounts of data much better than HTTP response headers do;

2. Security in the form of, say, MD5 checksums on the flow execution data to stop client-side tampering.

Comment

I really hate the term but I haven't yet thought of a better one. "Checkpoint" bears some similarity but even thats not right.

Consider an application process that does three things:

1. Creates user records in a database;
2. Creates some service records in the database; and
3. Sets up some related services over a Web Services interface.

The example flow:

1. Gets user details;
2. Lets a user select what services they want; and
3. Based on what services they've selected, asks for more information (eg CC details).

Typically these things might all be done at the end (within the scope of a single request) but that may not be practical or even possible in some circumstances. If it is, the success (or failure) states that result can be end-states that then preclude the user from clicking Back and changing details. If a database call is made (or information is otherwise persisted), this could potentially be a problem. You don't want the user doing that. You either have to check to see if (in the case of a new user registration) the user exists at the beginning and at the end (persistence), which is a bit ugly.

Additionally, you may be dealing with third-party systems that, for example, allow you to create a user via an external interface but closing accounts is a manual process and thus not available from the same Web Services interface. Just to add even more complexity, Web Services are non-transactional.

4. Persist the user to the database.
a) If it fails, say so and end; or
b) If it succeeds, say the user has been created.

If you don't want the user going back you could make this an end-state. Clicking continue would, in fact, trigger a new flow but it's hard to pass information to the new flow without it being a subflow and that's not always appropriate. Thus my idea for some sort of intermediate end state. Alternatively, it may be syntax for chaining from one flow to the next (without it being a call thats returned aka subflow).

The flow continues:

5. Present user with a list of services they'd like to subscribe for.
a) If none, we're done;
b) If one or more, do extra processing. Service A requires more information. Service B requires a Web Services call. Both require a database call. The user may select A, B or A and B.

First is the database call. If the user can, say, only have one instance of either service then the code to create them has to be clever enough to figure out if it's already run (because, beyond this, the user may have clicked Back to change his or her mind). Service B also requires a WS call that, as I metnioned above, may not have the semantics to reverse itself.

.3. This one may be my ignorance talking but it'd be nice if the flow execution key didn't have to be part of the URL at all and could be passed around purely as a hidden form field;

I assume you are referring to using RequestPathFlowExecutorArgumentHandler as your argumentHandler. Have you also taken a look at RequestParameterFlowExecutorArgumentHandler?

The reason the flow execution key is part of the URL is to allow for automatic handling of the browser's back and forward buttons for continuation-based repositories. Including the key in the URL as part of the path (as opposed to passing it via a request parameter) generates a different, unique URL per request. When a user clicks back or forward in the browser, the browser interprets this as loading a different page (assuming the browser did not cache the page), and the SWF engine can then respond appropriately by loading the corresponding continuation snapshot.

Note that this functionality is also coupled with the use of the GET-after-POST pattern (i.e., alwaysRedirectOnPause=true). Consider what would happen if the flow execution key were not part of the URL and the user clicked the back button (or selected a different page from the browser's history):

if alwaysRedirectOnPause=true, based on the URL alone, SWF would not know how to identify which continuation snapshot to load.

if alwaysRedirectOnPause=false, the browser would warn the user that it was a POST request and that the form needs to be resubmitted, which confuses many users, etc.

In summary, you could certainly pass the flow execution key around as a hidden request parameter; however, you would then lose the out-of-the-box transparent handling of the browser's back and forward buttons.

Another thing I'd like to see in SWF 1.1 is the idea of "savepoints" (in database parlance). That's not exactly what I'd call them but it kind of illustrates what I mean. When you hit an end-state in SWF, you can't click back and go through again. This is usally a good thing but there are times in a flow when you perform some action that you can't ignore and can't rolblack. As such you really want to make the flow execution to say that you can't continue the flow from before the intermediate end state.

This could also have the benefit of allowing SWF to clean up flows prior to this intermediate state.

Attempting to continue from prior to the intermediate state will create a similar "error" as trying to do so after you've hit an end state. The semantics of such a thing obviously need work and more thought but the idea seems worthy of consideration to me.

Did you take a look at the roadmap in JIRA as Keith suggested?

In any case, you might want to check out SWF-84 "Support for metadata-driven continuation invalidation to prevent back tracking once a certain step of a flow is completed":

Comment

Keith, I'd like SWF to be much more sparing on the size and number of request parameters.

For example, I don't need a flow-id if I decide that the mapping of the FlowController already identifies a flow (of course, I would do without the ability to handle multiple flows with one controller, which I don't consider important)

Another example, if I don't want to support multiple conversations in one browser session, I would not need the conversation identifier.

Ideally I'd like to be able to strip SWF down to no request parameter at all, except for the events.

Here is why: I am implementing an web UI to a chess game. Each of the 64 fields (much more in certain chess variants) is potentially clickable, which means I really have to keep URL sizes down for the links (64 * 100 chars is already 7 kB just for the links!). Currently (without SWF), I just use the URL "?id=a4" for field a4 (6 bytes). This has kept me from introducing SWF to my project.

For example, I don't need a flow-id if I decide that the mapping of the FlowController already identifies a flow (of course, I would do without the ability to handle multiple flows with one controller, which I don't consider important)

This is already supported out-of-the-box! Just configure a defaultFlowId for your FlowControllers on a per-controller basis.

Another example, if I don't want to support multiple conversations in one browser session, I would not need the conversation identifier.

Ideally I'd like to be able to strip SWF down to no request parameter at all, except for the events.

Interesting idea, but I wonder if this is more of a corner case. I suppose we would have to see if there is a sufficient number of users who require such functionality.

As an aside, I suppose you could just implement your own custom FlowExecutorArgumentHandler that stores the conversation key in the session for createFlowExecutionUrl() and then retrieves the conversation key from the session for extractFlowExecutionKey(), etc. (note: I haven't fully thought this through. thus it may not be feasible. )

Here is why: I am implementing an web UI to a chess game. Each of the 64 fields (much more in certain chess variants) is potentially clickable, which means I really have to keep URL sizes down for the links (64 * 100 chars is already 7 kB just for the links!). Currently (without SWF), I just use the URL "?id=a4" for field a4 (6 bytes). This has kept me from introducing SWF to my project.

If you have the option to switch to an AJAX or DHTML implementation of your page, you could certainly cut down greatly on the size by using JavaScript to dynamically build the chess board, links, etc. Just a thought.

cheers,

Sam

Comment

Better Back Button Management
I would like to see better back button management. Specifically, backing into a sub flow. I realize that it is possible to handle this declaratively however, if declaring was optional that would be great. Especially in instances where a user triggers a back event which takes the user to the last view-state within a sub-flow. Now it gets ugly when you have nested sub-flows and need to handle back events because, it just adds a lot of unnecessary XML. If webflow could have some sort of history manager that allows webflow to retrace it's footsteps without losing the information going forward, that would be great. I'm not sure how to implement this, I have tried on my own and do not have a complete solution.

Error Handling within Test Cases
I would like to be able to get validation errors within test cases easier possibly through a convenience method like: getErrors().

Dependency Injection within Test Classes that extend org.springframework.webflow.test.AbstractXmlFlowEx ecutionTests
It would be nice if classes that extend AbstractXmlFlowExecutionTests could participate in dependency injection instead of having to create a constructor that initializes the class.

Explicit Set of Listeners in Test Cases
It would be nice if I didn't have to set the listeners of a flow on the startFlow method in the AbstractXmlFlowExecutionTests class. Its easy to forget this step and when deployed as a web application this is a step one doesn't normally take.

Keep up the good work!

Comment

Working with Object Sub Types
This may/may not be solved with that but I think we need to address issues with working on subclasses of objects (not just subclassing flows). Yar, okay maybe it will be addressed by inheriting flows... but some good examples of this will be fantastic.

Currently I'm working with a domain object in my system called a Format. A Format has a few different options and corresponding views available to it depending on the implementation type. What I'd like to see in the inheritance work in Spring Web Flows, in addition to being able inherit flows, is also the ability to easily choose a flow based upon the type of object. This is kinda doable now via expressions on the view attribute of a view-state, but a good best practice example would be fantastic since there are a few ways of doing this and I'm guessing some approaches are better then others.

Spring Web Flows for Entire Presentation Tier
From the sounds of it, many people are going down this path, and I'd like to see more work/examples which cover some of the pitfalls when going down this path:
- Stopping sub-flow depth explosion... to stop a user bouncing between new flows
- Working with bookmarks
- "Escaping" the flow stack
- General thoughts on this approach vs hybrids (like Spring MVC and SWF)

Comment

By inheritance I would like to be able to add new actions to an existing flow, by using a different config file. This allows me to have a "basic main flow" and to change it slightly in different implementations of my application.

Comment

1. a standard 'breadcrumbs' facility (I currently use a custom FlowExcutionListener adapted from a long-running thread in this forum)

2. better JMX support (I have tried exporting the flowregistry as an MBean, but that is not too useful). I am after statistics: how many flows have been started, how many have finished, how many are active NOW, how many have thrown exceptions, etc. I currently have my own FlowExcutionListener doing some of this, but I am sure that more could be done. These stats are needed when tuning/testing a system. (Micro)Managers also love to be told these things...

I'd love to have been able to have a template/super state that would pick up much of the boilerplate (as I DO have with my bean configs).

4. a standard 'back' facility. Again I am using a FlowExcutionListener adapted from discussions on this forum. Very similar to the breadcrumbs listener. Would have been nice to have been able to pick something up "out of the box", however.

5. I had to do a lot of popups for my current project...these were a pain point for me. I initially tried to use SWF for everything, spawning popups as subflows (see my earlier posting on popups in this forum). Unfortunately, once a popup is closed, there doesn't seem to be any easy way to transition back to a point in the 'main' flow (some fancy JavaScript might have done it,but I didn't have time to 'experiment' to the extent needed). I eventually gave up and adopted a spring MVC controller for the main application and spawned popups as top-level flows...this proved easier (but not as 'intellectually' satisfying...)

6. I NEVER was able to get JMeter working for me (loadrunner was a no-brainer, however...worked fine). IMHO, this IS a SWF issue. What does one do after development: functional and load testing. A demo (WITH Redirect after POST still turned on) would be nice. Would make people (ME anyway :-) ) feel more comfortable about adopting this new/hoopy technology. For Functional testing, Canoo WebTest is A Good Thing, by the way.

7. Keep encouraging the Good Work being done by the SpringIDE guys! Managers LOVE pretty pictures and Christian is really making progress with the visualiser...Once I was able to put the images of my flows on my cubicle wall, my managers started to 'get it' and began to grasp the amount of work that was ACTUALLY involved in what I was doing. Up to that point, all I had was text and hand waving: "a picture paints a thousand words"...usually because people don't actually read the thousand words anyway.

8. maybe the ability to 'scaffold' a new project...an out of the box, fill in the blanks application with breadcrumbs, back button handling, JMX support, cluster-ability, etc. The existing demo apps didn't really help me that much (sorry).

Anyway...IMHO SWF is a really good tool. THANK YOU, to all the developers. I'd have hated to have used struts or plain Spring MVC for my current project!