Spring Webflow: Can Validators Be Manually Set Per Flow? - spring-webflow

I have multiple flow configured in my application:
<flow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" >
<flow:flow-location id="reservation1" path="/WEB-INF/flows/flow1.xml" />
<flow:flow-location id="reservation2" path="/WEB-INF/flows/flow2.xml" />
</flow:flow-registry>
These two flows use separate classes for their model attribute, call them Flow1DTO.java and Flow2DTO.java. However, they use a set of common JSPs/Tiles for their actual interface.
<form:form modelAttribute="reservationForm">
<!-- etc -->
</form:form>
Is it possible to define a separate Validator class per flow?

You can define a multiple validation methods for the same Model class for each specific view-state id. Where each custom validation method maps to a specific webflow view-state id.
Your validator class name for your model needs to be defined with the name "${model}Validator" (and have #Component annotation) and each validation method name needs to be named like this "validate${state} ([ModelClassType] model, ValidationContext context)"
So lets say you have a model class called "Reservation.java" and 2 different flows definition that use this model and each flow definition having a view-state definitions of
<!-- defined in your first flow file -->
<view-state id="ReservationSameDayViewState" view="sumting" model="reservationForm">
</view-state>
....
<!-- defined in your 2nd flow file -->
<view-state id="ReservationFutureViewState" view="sumting" model="reservationForm">
</view-state>
The validator class for Reservation model would like this:
#Component
public class ReservationValidator {
public void validateReservationSameDayViewState(Reservation reservation, ValidationContext context) {
// perform custom validation for first flow
}
public void validateReservationFutureViewState(Reservation reservation, ValidationContext context) {
// perform custom validation for 2nd flow
}
}
http://docs.spring.io/autorepo/docs/webflow/2.4.x/reference/html/views.html#view-validation-programmatic-validator
Also, it is bad practice to define your flows with integer increments. Change your flow registry definition to look like this. This way you don't have to keep manually adding flows to it every time you create new flows.
<flow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF/flows">
<flow-location-pattern value="/**/*-flow.xml" />
</flow:flow-registry>
note: the flow names end with "-flow.xml". This is the unofficial standard way to define a flow-registry and flow names.

I figured out a solution that allowed me to validate multiple forms with a single implementation of a form validator.
The code looked something like this:
public void validateMethodName(Flow1DTO dto, ValidationContext context) {
valMethodName(dto, context);
}
public void validateMethodName(Flow2DTO dto, ValidationContext context) {
valMethodName(dto, context);
}
private void valMethodName(CommonFlowDTO dto, ValidationContext context) {
// do stuff
}
Putting validation methods in the DTO classes themselves was not an option. Validation required calls to the database, which would have coupled the DTO objects to the business logic and made the creation of the DTOs somewhat more complex.
I discovered that the validation methods could not specify an interface, leading to the duplicate methods for each concrete DTO class.

Related

In Blazor client, how to create a component for an interface?

From reusabilty point of view, I want to create a component for an interface. So I use it with different concrete objects.
For example, the interface is like this
interface ICalculation
{
double Calculate();
}
and the Test component is
<button #onclick="(() => SetResult())">Set</button>
#result
#code{
double result;
ICalculation Calculation;
void SetResult()
{
result = Calculation.Calculate();
}
}
so some where else in another component/page I have some thing like this
<Test inject CalculationA />
<Test inject CalculationB />
So I want to inject Different Calculations into different instances of this component. How can i get this?
I thought using dependency injection of net core, but that is for to inject one object for an interface.
Why important? It helps me to override requests to api, for example, admin and user have different requests but they see the same page structure.
In the Test component you would make it a normal parameter:
[Parameter]
public ICalculation Calculator { get; set; }
and then in 'some where else'
#inject CalculationA CalculationA
#inject CalculationB CalculationB
<Test Calculator="CalculationA" />
<Test Calculator="CalculationB" />
Or replace those '#inject` lines with normal instantiations (2x) because with multiple implementations you can't do DI on the interface anyway.

How to obtain httpServletRequest in validate method of SpringWebFlow

I need to access httpServletRequest in the validate method of spring webflow. Please help me how to do this.
My webflow for view state is:
<var name="search" class="com.test.form.Search"/>
...................
<view-state id="search" model="search" view="searchPage">
<transition on="submit" to="searchAction">
</transition>
</view-state>
...............
validate method in search model class is:
public void validateLoanSearch(ValidationContext context) {
//I need to get a httpServletRequest here...
}
In action/controller class I can get it thru RequestContext but ValidationContext gives only the messageContext. Any idea? Please help.
I got the solution.
In the bean class or validator class inside the validate method use this:
RequestContext rc = RequestContextHolder.getRequestContext();
RequestContextHolder is becoming available inside the validate method.

Collection/List property won't bind or update on form submit

So I have set up a wizard interface with spring web flow that gradually populates a single form object/model. It works fine for the first few steps that have to populate single String or primitive properties and a String array (from a checkbox interface).
Then I have a List<String> property. It renders properly as multiple textboxes with correct initialized values. But when I edit the textboxes on the browser and submit, the values do not take effect on the form bean. It still has the initial values.
Below is the detailed set-up:
Web flow on-start which creates the bean:
<on-start>
<evaluate expression="new mypackage.MyFormBean()" result="flowScope.myFormBean" />
</on-start>
Here are the relevant parts of my form bean:
public class MyFormBean implements Serializable {
...
private List<SlotBean> slots;
...
public List<SlotBean> getSlots() {
return slots;
}
public void setSlots(List<SlotBean> slots) {
this.slots= slots;
}
...
}
public class SlotBean {
...
private int quantity;
...
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity= quantity;
}
...
}
I have a series of view-states in my web flow with simple string or number field bindings set-up that are initialized, displayed and saved without issues to the form.
This view-state generates any number of SlotBean objects then initializes quantity with 2. These are set to the slots property.
<view-state id="generate-criteria" model="disciplineCatalogue">
...
<transition on="next" to="slots-grid">
<evaluate expression="myService.generateSlots(myFormBean)"/>
</transition>
...
</view-state>
Here is the jsp fragment. All it does is render a bunch of textboxes. There's also a next button:
<form:form id="slotsGrid" modelAttribute="myFormBean" action="${flowExecutionUrl}">
...
<c:forEach var="slot" items="${myFormBean.slots}" varStatus="idx">
<form:input path="slots[${idx.index}].quantity" />
</c:forEach>
...
<button type="submit" id="next" name="_eventId_next">Next</button>
...
</form:form>
The above code displays correctly with the initial values (2). It generates multiple textboxes like below:
<input id="slots0.quantity" name="slots[0].quantity" type="text" value="2"/>
So when this page is on the browser, I change the values of the quantity textboxes to different values and click the "next" button. On my browser's network debugger, I see that the form values are sent to the server:
slots[0].quantity:3
slots[1].quantity:1
slots[2].quantity:2
Here is the relevant web flow entry for the next button.
<view-state id="slots-grid" model="myFormBean">
<binder>
...
<binding property="slots" />
</binder>
...
<transition on="next" to="finished">
<evaluate expression="myService.create(myFormBean)"/>
</transition>
...
</view-state>
So I put a break point on the myService.create(myFormBean) method and it shows that all the quantity fields are still set to the original "2". The new values didn't bind to myFormBean.slots.
Is there anything you can see in my set-up that looks wrong?
Thanks for any time you can put into this
Spring Framework 3.1.1
Spring-Webflow 2.3.1
Tomcat 6.0.18
Eclipse Indigo
Cross-posted in:
http://forum.springsource.org/showthread.php?127809-Collection-List-property-won-t-bind-or-update-on-form-submit

gwt css uibinder sharing resource

I've defined a ClientBundle, a Style interface and hooked it up with my css file via the #source annotation.
I have two questions:
when I use <ui:with> in my uibinder file I get the following exception: Deferred binding result type MyStyle should not be abstract. Can someone explain what's going on? And how I can include the style correctly in my uibinder file?
I'd like to share the resource across many uibinder without paying the penalty of initializing the style every time. Gwt's anemic dev guide, suggests using the UiField(provided=true) or using a #uiFactory. Although I've successfully used #uiFactory in order to use my own custom widgets. I have no idea how to use a #uiFactory to inject a style into the uiBinder.
For example:
//in pojo
#UiFactory
public MyStyle getMyStyle() {
return myStyle;
}
//in uibinder
<g:Label addStyleNames="{myStyle.defaultLable}"/>
how can i get this work?
Thanks in advance.
I use the following construction in the uibinder file:
<ui:with field='res' type="com.example.client.resources.MyResource" />
Where MyResource is an interface containing the css resource:
public interface MyResource extends ClientBundle {
#Source("mycss.css")
MyCssResource css();
}
and MyCssResource is:
public interface MyCssResource extends CssResource {
String someStyle();
}
In uibinder file this is used as follows:
<g:TextBox addStyleNames="{res.css.someStyle}" />

flex 3 accessing main mxml from actionscript code

im writting an actionScript class to handle my web service calls. When i retrieve a result i want to call a setter method in my main mxml application. My problem is that i dont know how to access the methods in the actionScript section of my main mxml class from my actionscript class, any ideas?
David is right -- while you can access the public members of your Application.mxml object statically and from anywhere in your application, design-wise that's a bit of a no-no. It's better to strive for loose coupling between your objects, and the way that's done in the Flex idiom is generally to extend EventDispatcher and to dispatch events. So for example, your WebService wrapper might look something like this:
public class MyWrapperClass extends EventDispatcher
{
[Event(name="webserviceComplete", type="flash.events.Event")]
public function MyWrapperClass(target:IEventDispatcher=null)
{
super(target);
}
private function handleWebServiceLoadComplete(event:ResultEvent):void
{
dispatchEvent(new Event("webserviceComplete"));
}
public function doWork():void
{
// Load the service, etc., and ultimately call handleWebServiceLoadComplete()...
}
}
... and your Main.mxml file like this:
<mx:Script>
<![CDATA[
private function app_creationComplete(event:Event):void
{
var myWrapper:MyWrapperClass = new MyWrapperClass();
myWrapper.addEventListener("webserviceComplete", mywrapper_webServiceComplete, false, 0, true);
myWrapper.doWork();
}
private function mywrapper_webServiceComplete(event:Event):void
{
// Do the work you would've otherwise done in the public method
}
]]>
</mx:Script>
In this case, the end result is the same -- completing the web-service load triggers the function in Main.mxml. But notice how mywrapper_webServiceComplete() is declared privately -- it's not called directly by MyWrapperClass. Main.mxml simply subscribes (with addEventListener()) to be notified when MyWrapperClass is finished doing its work, and then does its own work; MyWrapperClass knows nothing about the details of Main.mxml's implementation, nor does Main.mxml know anything about MyWrapperClass other than that it dispatches a webserviceComplete event, and exposes a public doWork() method. Loose coupling and information hiding in action.
Good luck!
If your class is an UIComponent added to the component tree, then you can use its parentApplication attribute. Otherwise, use the static Application.application attribute, but only after the application initialization has completed. Earlier than that, the field is null. Private fields and methods obviously cannot be accessed. Elements declared in the MXML part with explicit ids are public.
Adding such a call creates a rigid binding, though. You might want to consider dispatching an event instead, and handling this event in the main application.
In case anyone has the same problem:
mx.core.FlexGlobals.topLevelApplication.YOUR_FUNCTION
is the syntax to access public functions within the main.mxml.

Resources