Spring WebFlow: What can i do with flow outcome? - spring-webflow

I'm reading Spring WebFlow documentation, but I don't understand what can i do with outcome value in end-state of flow. Could You show me some practical example ? I wonder how to pass outcome variable to MVC Controller or another flow, but don't know how.
<flow>
<end-state id="test2">
<output name="id" value="123" />
</end-state>
</flow>

You can access your output variables from the parent flow (if you have called a subflow) by using currentEvent.attributes (so in your example):
currentEvent.attributes.id
See section 3.10 Calling Subflows
You can also get them programatically in a FlowHandler by implementing the handleExecutionOutcome method. There is an example in the docs under the "Example FlowHandler" section of 11.4 Implementing custom FlowHandlers.

Related

How to override some of ajax based picker logic?

Alfresco Community v5.2 (other versions too) includes some of preconfigured workflows that available on the page /share/page/start-workflow
I'm interested in "Review and Approve (one or more reviewers) - Assign a review task to multiple reviewers".
Actually, to be more precise - in the logic of assigning.
For example, I want to make some customization - Customization of the user task screen
I want to display members in the table, not in the list. For this I need to understand how they appear in the list.
In the file share-config-custom.xml I can find the path to the templates.
For example, for the bpm:workflowDueDate it will be:
...
<field id="bpm:workflowDueDate" set="info" label-id="workflow.field.due">
<control template="/org/alfresco/components/form/controls/info.ftl" />
</field>
...
But for bpm:assignees the template is not specified:
...
<field id="bpm:assignee" label-id="workflow.field.reviewer" set="assignee" />
...
I assume, that there are some back-end beans, that perform most of the logic.
How can I override some of ajax based picker logic?
If a form control is not provided in the share form config, Alfresco Share falls back to some defaults depending on the type of the field.
bpm:assignee is an association to a person node, so I would expect it to point by default to association.ftl !
What I suggest is to copy that file into a new one let's say src/main/amp/alfresco/site-webscripts/${project.groupId}/form/controls/custom-association.ftl
and then in your share-config-custom.xml copy over the form config for the task with one small update :
...
<field id="bpm:assignee" label-id="workflow.field.reviewer" set="assignee" >
<control template="/${project.groupId}/form/controls/custom-association.ftl" />
</field>
...
and then you can safely fiddle with custom-association.ftl because it is almost never a good idea to override alfresco defaults !
UPDATE : The value of that control is a list of nodeRefs referring to the nodes of the selected users. It is the ObjectFinder Java script object who is managing things behind the scene, calling a special endpoint to fetch all sort of data to be shown, then manipulates the DOM accordingly ! You might want to look at object-finder.js and picker.inc.ftl

Alfresco FormService Fundamental WRONG

Alfresco Forms Service does not work properly.
Looks like a fundamental Form functionality does not pass form configs (control-param name="nameHere") to webscripts.
I reproduce it step-by-step.
Create the Freemarker template and register it according to the documentation under /share project. The component renders and shows successfully. Everything works well.
Create a form according to the documentation on wiki Forms page.
Register it in <TOMCAT_INST/shared/classes/alfresco/web-
extension/myclok-form-config.xml> directory and pass it for load in such manner:
<bean id="sampleShareConfig" class="org.springframework.extensions.config.ConfigBootstrap" init-method="register">
<property name="configService" ref="web.config" />
<property name="configs">
<list>
<value>classpath:alfresco/web-extension/myclok-form-config.xml</value>
</list>
</property>
</bean>
<!-- ... share/WEB-INF/classes/org/springframework/extensions/surf/bootstrap/forms-bootstrap-context.xml -->
Form inst:
<config>
<forms>
<form id="myclok">
<view-form template="/org/alfresco/components/myclok/myclok.get.html.ftl" />
<edit-form template="/org/alfresco/components/myclok/myclok.get.html.ftl" />
<create-form template="/org/alfresco/components/myclok/myclok.get.html.ftl" />
<field-visibility>
<show id="currentPath" />
</field-visibility>
<appearance>
<field id="currentPath">
<control name="currentPath" template="/org/alfresco/components/myclok/myclok.get.html.ftl">
<control-param name="currentPath">sampleData1</control-param>
</control>
</field>
<control name="currentPath" template="/org/alfresco/components/myclok/myclok.get.html.ftl">
<control-param name="currentPath">sampleData2</control-param>
</control>
</appearance>
</form>
</forms>
</config>
In official documentation is written:
If the form element exists within a config element without an
evaluator and condition the form is always found, this is useful if
you want a certain field to appear on EVERY form in your application.
So, I specified it in myclok-form-config.xml file, but this approach does not give any result. Thus when the component with such reference to param is loaded by the following URL <http://localhost:8080/share/page/site/wcmqs/myclok> the Alfresco fails with the Exception:
Exception: freemarker.core.InvalidReferenceException - Expression field is undefined on line 6, column 6 in org/alfresco/components/myclok/myclok.get.html.ftl.
freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:125)
freemarker.core.TemplateObject.invalidTypeException(TemplateObject.java:135)
freemarker.core.Dot._getAsTemplateModel(Dot.java:78)
In other words it's impossible to receive the value of the parameter of currentPath that is defined in FormConfigs.
So, the minimal functionality of FormsService / ConfigService does not work.
<#if field.control.params.currentPath??>
<#assign path=field.control.params.currentPath>
<#else>
<#assign path="someOtherDataValue">
</#if>
Does anyone know how to resolve it Or can demonstrate a working sample?
PS: All above described configurations of the form of FormService and the webscript component are attached.
The .AMP file for quick installation is required just to invoke the following command:
java -jar alfresco-mmt.jar install myclokStubFormComponent.amp ../tomcat/webapps/share.war
AMP file.
Config file.
I think you have mis-understood the difference betweent a form template and a field template. You are specifying the same file /org/alfresco/components/myclok/myclok.get.html.ftl to control the layout of the form as well as to render your fields.
When you use a field template to render the form you are getting an error that says the field object has not been populated. This is quite correct as the framework has not yet started to render the individual fields. You are rendering the form.
I'd suggest you try some more basic examples such as those that come with the Forms Development Kit (FDK) before you start implementing your own more complex forms, and especially before you begin to claim that the framework does not work as documented.

add button in show.jspx in a spring roo mvc project

I've created a spring roo project using 'Getting started with spring roo' as a starting point. The project is created in STS using roo 1.1.5. I've added neo4j graph and is able to create nodes with simple edges and create the web-part issuing 'controller all --package ~.web'.
The project is a simple web-app with a Person and Race node and a Participant-edge with start-time, end-time, total-time and race-id. Since the edge Participant is a #RelatedToVia it becomes a #RelationshipEntity and I want to add a button to save Participant.
I found WEB-INF/tags/form/field/table.tagx where the add-, modify-, delete-buttons and friends are defined, ie.:
<c:if test="${update}">
<td class="utilbox">
..
But where do I set the variable update? I've looked through the code that is created by STS, but unable to find it. Pardon if this is obvious.
regards
Claus
Edit:
I found out that WEB-INF/tags/form/show.tagx have the knobs to enable/disable for instance the update-button:
<c:if test="${empty update}">
<c:set var="update" value="true" />
</c:if>
So I will add my new button in this file. The spring framework seems so well laid out. Just have to find the various places.
regards
Claus
The value for update is obtained from attributes you specify when you use the tag created using the tagx.
For an example,
If form:table was used as in a jspx and if the following was set, you will recieve true in your update variable if it was assigned using a directive. However it seems that the true is set as default in the form:table tag within Spring Roo.
If you want to set it to false, when using you have to set the value to the attribute as following.
<form:table update="false" />
If you want to go deeper into this, look in to the table.tagx file you have mentioned you will find the following line which explains it.
<jsp:directive.attribute name="update" type="java.lang.Boolean" required="false" rtexprvalue="true" description="Include 'update' link into table (default true)" />
Cheers.

Spring webflow: how to keep track of persisted entity ids?

I'm working on a webflow (SWF2). The entities are generated using Roo. One of the webflow views, multi-instance.jspx, may be called multiple times to allow for multiple, persisted instances of the same entity (MyClass).
I'd like to keep a list of those persisted entities so that I can reference them on a later point in the flow. So far, I've tried the following.
A simplified version of my flow.xml looks like this:
<on-start>
<evaluate expression="new java.util.ArrayList()" result="flowScope.myList" result-type="java.io.Serializable"/>
</on-start>
<view-state id="multi-instance" view="multi-instance" model="myClass">
<binder>
<binding property="field1"/>
<binding property="field2"/>
</binder>
<on-entry>
<evaluate expression="new com.test.MyClass()" result="flowScope.myClass" />
</on-entry>
<transition on="another_instance" to="multi-instance"/>
<transition on="success" to="confirm"/>
<transition on="cancel" to="abort"/>
<on-exit>
<evaluate expression="myClass.persist()"/>
<evaluate expression="flowScope.myList.add(myClass)"/>
</on-exit>
</view-state>
The confirm and abort view-states are defined in flow.xml as well. The confirm.jspx looks like this:
<div xmlns:spring="http://www.springframework.org/tags" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:form="http://www.springframework.org/tags/form" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:output omit-xml-declaration="yes" />
<form:form>
<c:forEach items="${myList}" var="instance">
<li>${instance.getField1()} ${instance.getField2()}</li>
</c:forEach>
<div class="submit">
<input type="submit" id="success" name="_eventId_success" value="success"/>
<input type="submit" id="cancel" name="_eventId_cancel" value="cancel" />
</div>
</form:form>
</div>
So to the question:
Whenever I hit confirm.jspx, the web return says that there's an exception thrown at org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:569).
EDIT: The Apache log is a little more enlightening. The following is a snippet of the top of the call stack:
SEVERE: Servlet.service() for servlet jsp threw exception org.apache.jasper.JasperException:
/WEB-INF/views/myflow/confirmation.jspx(6,7)
The function getField1 must be used with a prefix when a default namespace is not specified
at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:40)
I'm not sure if the ArrayList-approach is possible; I believe I've read somewhere that the flowScope.myClass instance, as it is defined in the multi-instance-state, is picked up by the GC or at least falls out of scope. I'm not sure. If anyone can shed some light on that particular topic, I'd be thrilled.
(And if you happen to know a better way to keep a list of these persisted entities, please feel free to let me know!) Thanks in advance! :)
Update:
I'm able to count the number of elements in my list like so:
<c:choose>
<c:when test="${myList != null}">myList exists, it contains <c:out value="${fn:length(myList)}" /> items!</c:when>
<c:otherwise>myList doesn't exist.</c:otherwise>
</c:choose>
It shows the same number of elements as I've inserted. However, when I do this:
<c:forEach items="${myList}" var="instance">
<c:if test="${instance != null}">
<li>${instance.field1} ${instance.field2}</li>
</c:if>
</c:forEach>
nothing is displayed. (I can confirm that there is a correct number of <li>-elements when the null-test is omitted. Note also that I'm trying to access the properties directly, as indicated here: jstl/jsp - iterating over a vector of beans) I don't know what to think, regarding the scope here, but it seems clear that I can't access my entities via an ArrayList.
First, with regards to your question(s) around variable scoping, I would suggest looking at section 4.4 of the SWF documentation, where it describes all of the different available scopes.
Flow scope variables live through the lifetime of the flow. So your myClass variable will not go away until the flow exits. However keep in mind that your <on-entry> expression is assigning a new instance every time that view state is entered.
Second, I think you are probably on the right track with your solution. I would note several things:
You are persisting and adding to your list in the <on-exit> element -- this means these two things will always happen when you leave the state, including when you are doing your cancel transition. This may not be what you want. Related:
Your <transition on="another_instance" to="multi-instance"/> is actually exiting the view-state and re-entering it, triggering the <on-exit> and <on-entry> logic. It is possible to remain in the same state, by simply doing <transition on="another_instance">. Doing this will execute any logic you have inside the transition, and then re-render the view without actually changing states.
You may want to consider using the <var> tag to initialize variables... what you are doing with <evaluate expression="new ..."/> works but using <var> may be cleaner. Also, it is not necessary to say result-type="java.io.Serializable". result-type should be used when you need to convert the return type to something elese.
Finally, the error you are getting looks like it is unrelated to webflow. JSTL/EL allow you to access bean properties but not methods, and you are trying to invoke a method. See this question for more info.

How is the Spring MVC spring:bind tag working and what are the meanings of status.expression and status.value?

Let's discuss on the following example:
<spring:bind path="user.userName">
<input type="text" name="${status.expression}" value="${status.value}"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
When this view snippet gets rendered, what do ${status.expression} and ${status.value} get evaluated to? Where do these values come from?
See this link for an explanation of what the status variables mean.
status.expression: the expression that was used to retrieve the bean or property
status.value: the actual value of the bean or property (transformed using registered PropertyEditors)
status.errorMessages: an array of error messages, resulting from validation
The status object is evaluated when the binding is done.
Also have in mind that Spring 2.0 introduced new form tags, which are probable better suited for your needs.
The bind tag documentation of Spring 3.0
See Also: BindStatus

Resources