Open spring-operator opened 17 years ago
Hideyuki Suzumi commented
Is the Flow class that is not Serializable possible? Many DAOs are not Serializable.
Hideyuki Suzumi commented
I think it is better to use constants instead of inner classes.
Example:
@Flow
@Component
@Scope
("request") // scope is free
public class FooFlow {
// view-state
@View("/foo/foo.jsp")
public static final String FOO_VIEW = "FOO_VIEW";
// subflow-state
@Subflow("barFlow")
// subflow's transitions
@Transitions(
@Transition(on=BarFlow.OK, to="barFlowOK"),
@Transition(on=BarFlow.CANCEL, to=FOO_VIEW)
}
public static final String BAR_FLOW = "BAR_FLOW";
// end-state
@End
public static final String END = "END";
...
@Autowired
private FooData fooData;
@Autowired
private FooDao fooDao;
...
// this flow's input-mapper
@FlowInput
public void setInput1(Long in1) {
...
}
@FlowInput
public void setInput2(String in2) {
...
}
// this flow's output-mapper
@FlowOutput
public FooFlowOutput getOutput() {
...
}
// subflow's input-mapper
@SubflowInput(subflow=BAR_FLOW, name="param")
public String getBarFlowParam() {
...
}
// subflow's output-mapper
@SubflowOutput(subflow=BAR_FLOW, name="result")
public void setBarFlowResult(Boolean result) {
...
}
...
// start-state
@Start
// action-state
@Action
public String start() {
...
return FOO_VIEW; // return the next view
}
...
@Action
public String barFlowOK() {
...
return END; // end flow
}
...
// flow end callback
@EndAction
public void end() {
...
}
}
FooFlow, FooData and FooDao need not be Serializable.
Joseph commented
i also prefer not to use inner classes
Keith Garry Boyce commented
Is it also possible to support this in JDK 1.4 using conventions rather than annotations
!!Use pwebb rather than philw commented
Looking at the initial cut of the code I was wondering if perhaps transition methods should return Class<? extends State> rather than a state instance. I am specifically thinking about what might happen when you need to start to serialize the state into HTTP session when the flow is paused. Making each state serializable is one option but you then may run into issues if you want a state to be injected with a singleton bean.
You could even make Class<? extends State> an attribute of @Transition
, this should help guide the user a bit as they have IDE code-assist. Also having the option in the annotation means that you could do away with the start() method and just use a standard constructor annotated with @Transition
(in this context @Transition
being more akin to start-state in webflow 2).
Eg:
@Flow
public class BookingFlow {
private Booking booking;
@Transition(to=EnteringBookingDetails.class)
public BookingFlow(@EventParam("hotelId") Long hotelId, Principal currentUser) {
booking = Booking.newBooking(hotelId, currentUser);
}
class EnteringBookingDetails extends ViewState {
@Transition(to=ReviewingBooking.class)
public void next() {
}
}
class ReviewingBooking extends ViewState {
@Transition(to=Finished.class)
public void confirm() {
booking.persist();
}
}
class Finished extends EndState {}
}
Keith Donald commented
Phil, How could you see handling dynamic transitions with your approach? The main reason methods are transitions is to allow for dynamic logic/branching using plain Java code (removing the need for action or decision state types with this model).
I'm wondering if serialization of state instances will be an issue in practice, given Spring 3's support for serializable scoped proxies (even supported for singleton beans).
!!Use pwebb rather than philw commented
Hi Keith,
I was thinking thinking:
@Transition
public Class<? extends State> next() {
if(someThing()) {
return Here.class;
}
return There.class.
}
Or I guess you could use the same model that you have and just store the class of the object returned rather than the instance.
I was not aware of the new Spring 3 serialization proxy support, so that probably provides a clean way to deal with it. Also, thinking about it some more you can't just use an annotation on the flow constructor to indicate a start state as you have no way to re-create the flow when it is resumed.
Still, something does not feel entirely right about needing to have all Flows and States serializable but I can't quite work out why, just a gut instinct. States and Flows feel closer to singletons than objects that you would want in session. I find serialization exceptions from objects in flow/viewScope seem to come up quite often so I guess another area where you need to think about this worries me.
If the @Flow
lifecycle is changed so that webflow is responsible for serializing only the objects that end up in flow/viewScope on pause and re-injecting them on resume this may help. Eg:
@Flow
public class SomeFlow implements Serializable {
@Autowired
@Scope
(proxyMode=ScopedProxyMode.INTERFACES)
private SomeServiceBean service;
@Autowired
@Scope
(proxyMode=ScopedProxyMode.TARGET_CLASS)
private Some3rdPartyServiceWithoutInterface service2;
//NOTE: now you need cglib
//A flowScope varaible private Booking booking; ... }
Becomes:
@Flow
public class SomeFlow {
@Autowired
private SomeServiceBean service;
@Autowired
private Some3rdPartyServiceWithoutInterface service2;
@FlowScope
private Booking booking;
//Only this is serialized
...
}
PS. Is there any reason why JIRA is not emailing me?
Keith Donald commented
Phil,
Flow and State definitions are singletons, I agree. Flow executions (or flow instances), however, are stateful objects, generally stored in the user session and scoped by a conversation boundary. Apply this to the Java-based flow programming model, and the Flow and State classes are definition constructs--singleton FlowDefinition/StateDefinition Web Flow objects are actually compiled from them. But @Flow
and State instances are stateful, and correspond to the FlowExecution/FlowSession Web Flow engine counterparts. To this end, they feel very much like session scoped beans to me, where instance state is implicitly session scoped (flow scoped in this case). Semantically this feels quite natural to me, and yes it does carry the serialization requirement, the same requirement a typical session-scoped bean would have. I'm interested to see if this will raise issues in practice... we should know real soon.
!!Use pwebb rather than philw commented
It probably wont be an issue if the @Scope
option sorts it, until the serialization code is needed it is probably a bit early to know. I see what you are saying about flow executions being instances, and I completely agree that having instance state as flowScope is very natural. I had just envisaged that the flow resume would create a new instance and then use reflection to set the instance state from the flowScope in session.
One other really small thing, in fact this is so dumb I almost feel stupid saying it. Would it be worth renaming the classes in the engine package so that they are different to the .java package? I can see a lot of people accidentally importing from the wrong package.
Keith Donald opened SWF-295 and commented
There are several opportunities for defining simpler flow definitions in native Java. This ticket should realize some of these opportunities.
Specifically:
Example Java-based flow:
@Flow
("editAccount") public class EditAccountFlow {}
Affects: 1.0
Attachments:
15 votes, 19 watchers