How to invoke method with event from custom component - jsf-2.2

I have my component :
public class Training extends UIOutput
and own renderer:
public class TrainingRenderer extends Renderer
with taglibrary:
<tag>
<tag-name>training</tag-name>
<attribute>
<name>style</name>
</attribute>
<attribute>
<name>action</name>
<method-signature>java.lang.String action()</method-signature>
</attribute>
<attribute>
<name>listener</name>
<method-signature>void actionListener(javax.faces.event.ActionListener)</method-signature>
</attribute>
<component>
<component-type>training</component-type>
<renderer-type>pl.spiid.app.spiidcharts.beans.training.Training</renderer-type>
</component>
</tag>
and this is in my index.xhtml
<spiid:training rendered="true" style="width: 100%; height: 500px;" action="#{training.actionFromChart()}" listener="#{userBeanData.bindingMessage(arg1)}/>
and listening method
public void bindingMessage(ActionEvent actionEvent) {...}
Method can be invoked by:
Map<String, Object> attrMap = component.getAttributes();
Object tmp = attrMap.get("listener");
I want to invoke this method with event argument. I think about using eventQueue, but I don't know how to use it correctly.
Using:
JSF 2.2.14
Edited.
Edit2:
Soon I will add a answer.

Related

Using the setAllowedFields() method in Spring

I'm using Spring 3.2.0. I have registered a few custom property editors for some basic needs as follows.
import editors.DateTimeEditor;
import editors.StrictNumberFormatEditor;
import java.math.RoundingMode;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import org.joda.time.DateTime;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.beans.propertyeditors.URLEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.WebRequest;
#ControllerAdvice
public final class GlobalDataBinder
{
#InitBinder
public void initBinder(WebDataBinder binder, WebRequest request)
{
binder.setIgnoreInvalidFields(true);
binder.setIgnoreUnknownFields(true);
//binder.setAllowedFields(someArray);
NumberFormat numberFormat=DecimalFormat.getInstance();
numberFormat.setGroupingUsed(false);
numberFormat.setMaximumFractionDigits(2);
numberFormat.setRoundingMode(RoundingMode.HALF_UP);
binder.registerCustomEditor(DateTime.class, new DateTimeEditor("MM/dd/yyyy HH:mm:ss", true));
binder.registerCustomEditor(Double.class, new StrictNumberFormatEditor(Double.class, numberFormat, true));
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
binder.registerCustomEditor(URL.class, new URLEditor());
}
}
I have this many editors registered so far. Two of them DateTimeEditor and StrictNumberFormatEditor have been customized by overriding respective methods to fulfill custom needs of number format and Joda-Time.
Since I'm using Spring 3.2.0, I can take advantage of #ControllerAdvice.
Spring recommends to list a set of allowed fields with the setAllowedFields() method so that malicious users can not inject values into bound objects.
From the docs about DataBinder
Binder that allows for setting property values onto a target object,
including support for validation and binding result analysis. The
binding process can be customized through specifying allowed fields,
required fields, custom editors, etc.
Note that there are potential security implications in failing to set
an array of allowed fields. In the case of HTTP form POST data for
example, malicious clients can attempt to subvert an application by
supplying values for fields or properties that do not exist on the
form. In some cases this could lead to illegal data being set on
command objects or their nested objects. For this reason, it is highly
recommended to specify the allowedFields property on the DataBinder.
I have a big application and obviously there are thousands of fields. Specifying and listing all of them with the setAllowedFields() is a tedious job. Additionally, somehow I need to remember them.
Changing a web page to remove some fields or add additional fields as the need arises again requires to modify the parameter value of the setAllowedFields() method to reflect those changes.
Is there any alternative to this?
Instead of using setAllowedFields() to white-list, you can use setDisallowedFields() to black-list. For example, from the petclinic sample application:
#InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
From a pure security standpoint white-listing is preferred to black-listing, but it maybe help ease the burden some.
setAllowedFields() is very handy when using entity objects directly in web layer. Alternatively, one could use dedicated data transfer objects (DTO), from which entity objects are constructed in the service layer. Not only can the factories be re-used, but also used outside the web context, e.g. for asynchronous messages. Besides, DTO inheritance doesn't have to follow entity inheritance, so you are free to design the DTO hierarchy according to the needs of the use-cases.
from http://static.springsource.org/spring-webflow/docs/2.0.x/reference/htmlsingle/spring-webflow-reference.html#view-model
4.9. Specifying bindings explicitly
Use the binder element to configure the exact set of model bindings usable by the view. This is particularly useful in a Spring MVC environment for restricting the set of "allowed fields" per view.
<view-state id="enterBookingDetails" model="booking">
<binder>
<binding property="creditCard" />
<binding property="creditCardName" />
<binding property="creditCardExpiryMonth" />
<binding property="creditCardExpiryYear" />
</binder>
<transition on="proceed" to="reviewBooking" />
<transition on="cancel" to="cancel" bind="false" />
</view-state>
If the binder element is not specified, all public properties of the model are eligible for binding by the view. With the binder element specified, only the explicitly configured bindings are allowed.
Each binding may also apply a converter to format the model property value for display in a custom manner. If no converter is specified, the default converter for the model property's type will be used.
<view-state id="enterBookingDetails" model="booking">
<binder>
<binding property="checkinDate" converter="shortDate" />
<binding property="checkoutDate" converter="shortDate" />
<binding property="creditCard" />
<binding property="creditCardName" />
<binding property="creditCardExpiryMonth" />
<binding property="creditCardExpiryYear" />
</binder>
<transition on="proceed" to="reviewBooking" />
<transition on="cancel" to="cancel" bind="false" />
</view-state>
In the example above, the shortDate converter is bound to the checkinDate and checkoutDate properties. Custom converters may be registered with the application's ConversionService.
Each binding may also apply a required check that will generate a validation error if the user provided value is null on form postback:
<view-state id="enterBookingDetails" model="booking">
<binder>
<binding property="checkinDate" converter="shortDate" required="true" />
<binding property="checkoutDate" converter="shortDate" required="true" />
<binding property="creditCard" required="true" />
<binding property="creditCardName" required="true" />
<binding property="creditCardExpiryMonth" required="true" />
<binding property="creditCardExpiryYear" required="true" />
</binder>
<transition on="proceed" to="reviewBooking">
<transition on="cancel" to="bookingCancelled" bind="false" />
</view-state>
In the example above, all of the bindings are required. If one or more blank input values are bound, validation errors will be generated and the view will re-render with those errors.
A solution to use binder with DTO (companydata in example) in case most of the form input values should be converted to null if empty, but there is a need to add few exceptions (setDisallowedFields didn't work for me).
#InitBinder()
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
#InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
binder.registerCustomEditor(String.class, "companydata.companyName", new StringTrimmerEditor(false));
binder.registerCustomEditor(String.class, "companydata.companyNumber", new StringTrimmerEditor(false));
}

commandButton which is enabled by f:ajax does not invoke action when form is submitted

I am trying to make a commandButton enabled/disabled by using a checkbox. The commandbutton is disabled initially. When user checks the checkbox, the commandbutton turns into enabled. But it does not response when clicked the button.
If I make the commandbutton independent from checkbox, it works fine. But with checkbox, I get the problem that I mentioned above. Please help me
Here are codes.
index.xhtml
<h:form>
<h:selectBooleanCheckbox value="#{formSettings.licenseAccepted}" id="cb">
<f:ajax event="click" render="suB cb"/>
</h:selectBooleanCheckbox>
<h:outputText value="#{formSettings.msg}"/><br/>
<h:commandButton id="suB" disabled="false" value="Save" action="loginSuccessfull"/>
</h:form>
FormSettings.java
package classes;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class FormSettings
{
private boolean licenseAccepted = false;
private String msg = "Accept License";
public FormSettings(){};
public boolean isLicenseAccepted(){return this.licenseAccepted;};
public void setLicenseAccepted(boolean licenseAccepted){this.licenseAccepted = licenseAccepted;};
public String getMsg(){return this.msg;};
public void setMsg(String msg){this.msg = msg;};
}
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-outcome>loginSuccessfull</from-outcome>
<to-view-id>/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
The bean has to be placed in the view scope in order to get it to work.
#ManagedBean
#ViewScoped
public class FormSettings {}
Enabling the button by ajax counts as one HTTP request. Submitting the form with the button thereafter counts as another HTTP request. As your bean is request scoped, it get freshly created on every HTTP request and garbaged by the end of request. As the boolean property defaults to false, the button get effectively disabled again when JSF is about to process the form submit on the second request.
See also:
How to choose the right bean scope?

Sponsorship of remotely instanced objects

I have a singleton service on remote server, this has a method who returns new objects to clients:
public class MySingleton : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null;
}
public MarshalByRefObject GetService()
{
return new Model();
}
}
public class Model : MarshalByRefObject
{
}
I don't want that Model instances live forever on server, so I just wanted to use the normal sponsorship procedure, on client side I create a sponsor for my Model, and I attach the remote lease to this sponsor:
var sponsor = new ClientSponsor();
_service = _mySingleton.GetService();
var success = sponsor.Register(_service);
Well, this does not work. The remote object Model, dies after a while.
Do you confirm this behavior ?
I guess it's because the lifetime manager on server doesn't have the opportunity to initialize the lease, because the object Model is instanced and returned directly.
I know this is an old post but during my search for an similar issue I stumbled on this post.
Maybe it will depend on the SinkProvider configuration. Because the Renewal call on Client side from server require an deserialization. In the app.exe.config on server side you have to setup the serverProvider and also the clientProvider like this:
<channel ref="tcp" port="50220" useIpAddress="false">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
<clientProviders>
<formatter ref="binary" />
</clientProviders>
</channel>
<channel ref="http" port="50221" useIpAddress="false">
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full" />
</serverProviders>
<clientProviders>
<formatter ref="soap" />
</clientProviders>
</channel>
On the client side use the following app.config.exe:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="0">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

Spring webflow 'Property not found' exception

I am using spring webflow, this is my flow
<view-state id="welcome">
<transition on="emailEntered" to="checkEmail"></transition>
</view-state>
<decision-state id="checkEmail">
<if test="alta.checkEmail(requestParameters.email)"
then="okState"
else="errorState"/>
</decision-state>
<view-state id="okState"/>
<view-state id="errorState"/>
I have enabled auto-scanning in my servlet-context:
<context:component-scan base-package="com.me.myproj" />
I get a org.springframework.binding.expression.PropertyNotFoundException: Property not found error for state checkEmail. The problem is that it doesn't recognize my 'alta' bean, this is my Alta class (placed in com.me.myproj):
#Component
public class Alta {
public Alta(){
System.out.println("constructor ok");
}
public boolean checkEmail(String email){
return "my.name#email.com".equals(email);
}
}
If I explicitly create the bean:
<bean id="alta" class="com.me.myproj.Alta"/>
Then it works fine. So it seems that flow context doesn't recognize auto-scanned components, although alta is instanciated (as I saw when I debugged).
What can I do to avoid declaring explictly all beans involved in my flow?
Did you include
<context:annotation-config/>
in your servlet-context.xml?
When you explicitly create the bean in the XML you are naming the bean with name "alta" (id value). That is why you can execute methods from class Alta refering to "alta.checkEmail(...)".
<bean id="alta" class="com.me.myproj.Alta"/>
If you want to avoid XML declaration and use annotations only, you should specify that name in the annotation by just passing the name as argument [1]. For example:
#Component("alta")
public class Alta {
public Alta(){
System.out.println("constructor ok");
}
public boolean checkEmail(String email){
return "my.name#email.com".equals(email);
}
}
Hope this helps.
[1] http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/stereotype/Component.html

How can i register a global custom editor in Spring-MVC?

I use the following custom editor in MANY Spring-MVC controllers according to:
A controller
binder.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, NumberFormat.getNumberInstance(new Locale("pt", "BR"), true));
Other controller
binder.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, NumberFormat.getNumberInstance(new Locale("pt", "BR"), true));
Another controller
binder.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, NumberFormat.getNumberInstance(new Locale("pt", "BR"), true));
Notice the same custom editor registered
Question: how can i set up a global custom editor like this one in order to avoid set up each controller ?
regards,
Starting Spring 3.2, you can use #ControllerAdvice instead of using #ExceptionHandler, #InitBinder, and #ModelAttribute in each Controller. They will be applied to all #Controller beans.
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.WebRequest;
#ControllerAdvice
public class GlobalBindingInitializer {
#InitBinder
public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, NumberFormat.getNumberInstance(new Locale("pt", "BR"), true));
}
}
If you had started out with Spring Roo generated code, or limit the annotations scanned by component-scan using include-filter, then add the required filter in webmvc-config.xml
<!-- The controllers are autodetected POJOs labeled with the #Controller annotation. -->
<context:component-scan base-package="com.sensei.encore.maininterface" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<!-- ADD THE BELOW LINE -->
<context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
</context:component-scan>
You need to declare it in your application context:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors"><map>
<entry key="java.math.BigDecimal">
<bean class="org.springframework.beans.propertyeditors.CustomNumberEditor">
... <!-- specify constructor-args here -->
</bean>
</entry>
</map></property>
</bean>
Details are here
If you use a annotation based controller (Spring 2.5+), you can use a WebBindingInitializer to register global property editors. Something like
public class GlobalBindingInitializer implements WebBindingInitializer {
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd/MM/yyyy"), true));
}
}
So in your web application context file, declare
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="GlobalBindingInitializer"/>
</property>
</bean>
This way all annotation based controller can use any property editor declared in GlobalBindingInitializer.
One alternative option. Instead of #ControllerAdvice, you can create abstract class, inherited by your controllers:
public abstract class BaseController {
#InitBinder
public void initBinder(WebDataBinder binder) {
// Replace empty strings with nulls for submitted form fields.
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
}

Resources