BeanELResolver #Override getValue(ELContext context, Object base, Object property) - jsf

I have
public class ExtendedBeanELResolver extends BeanELResolver {
private static final Pattern regExpDn = Pattern.compile("PLMN-PLMN/\\w+.\\d+(.*)");
#Override
public Object getValue(ELContext context, Object base, Object property)
try {
// remake DIST.NAME appearance
if (property.equals("dn") && base instanceof Alarm && ((Alarm) base).getCustomer().getNameEng().equalsIgnoreCase("mts")) {
String dn = null;
try {
dn = ((Alarm) base).getDn();
Matcher mtch = regExpDn.matcher(dn);
mtch.find();
((Alarm) base).setDn(mtch.group(1));
} catch (Throwable e) {
// logger.error("error in dn - " + dn);
} finally {
return super.getValue(context, base, property);
}
}
}
for change some visible values in object depending on some conditions. I do not want to change value if this called from jsf <ui:param name="fullDistName" value="#{alarm.dn}" />
How i can get id of component from which this EL called?
sorry for my english.

You can get the current JSF component by programmatically evaluating #{component} or by invoking UIComponent#getCurrentComponent().
UIComponent component = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance();
// ...
Please note that this tight-couples your EL resolver to JSF.

Related

PrimeFaces primeDateRangeValidator - Get variable

I need help with a problem i have using the primeDateRangeValidator.I need to get a variable (private boolean validacionFechas;) from this class and use it in another one. (Sorry for my bad english).
#FacesValidator("primeDateRangeValidator")
public class PrimeDateRangeValidator implements Validator {
private boolean validacionFechas;
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (value == null) {
return;
}
//Leave the null handling of startDate to required="true"
Object startDateValue = component.getAttributes().get("fi");
if (startDateValue==null) {
return;
}
Date startDate = (Date)startDateValue;
Date endDate = (Date)value;
if (endDate.before(startDate)) {
this.validacionFechas = false;
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "¡Error!", "La fecha inicial no puede ser mayor a la final."));
}
}
public boolean getValidacionFechas() {
return validacionFechas;
}
public void setValidacionFechas(boolean validacionFechas) {
this.validacionFechas = validacionFechas;
}
}
The validation between the dates are correct, and the message too. But from another class(where i have my Save method) i'm calling the variable this way:
PrimeDateRangeValidator pdrv = new PrimeDateRangeValidator();
pdrv.getValidacionFechas();
And i'm always getting TRUE, cousing this to save the information if the dates are correct, and when the dates are incorrect show the error message but saves the information too.
Is there any problem with the #FacesValidator or with the set and get?
Your implementation can't work. You are creating a new instance of PrimeDateRangeValidator which has nothing to do with the
validator instance that JSF creates and uses itself. I'm just wondering why getValidacionFechas always returns true. It should
return false.
I think the best way is to put the information of the validation into the session map, for example:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("VALIDACION_FECHAS", false);
And read it like that:
boolean validacionFechas = (boolean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("VALIDACION_FECHAS");

How to add condition based action to command button in ADF?

How to navigate to the next page based on the return value from the method called inside the action attribute of the command button.
<af:button id="tt_b2"
rendered="#{attrs.nextRendered}"
partialSubmit="true"
action="#{attrs.backingBean.nextAction}"
text="Next"
disabled="#{attrs.nextDisabled}"/>
private static final String NEXT_NAVIGATION_ACTION = "controllerContext.currentViewPort.taskFlowContext.trainModel.getNext";
public String nextAction() {
if (validate()) {
updateModel();
return NEXT_NAVIGATION_ACTION;
}
return null;
}
The use case is done for train model, which is implemented based on this blog : http://javacollectibles.blogspot.co.uk/2014/10/adf-train-template.html
We need to define a generic next action in the template but the action should be called conditionally, based on whether all the validation checks has been passed on not.
Try using ADFUtils.invokeEl
public String nextAction() {
if (validate()) {
updateModel();
return (String)ADFUtils.invokeEL(NEXT_NAVIGATION_ACTION);
}
return null;
}
Its ain't necessary to hardcode any steps, you can query TaskFlowTrainModel
/**
* Navigates to the next stop in a train
* #return outcome string
*/
public String navigateNextStop() {
String nextStopAction = null;
ControllerContext controllerContext = ControllerContext.getInstance();
ViewPortContext currentViewPortCtx = controllerContext.getCurrentViewPort();
TaskFlowContext taskFlowCtx = currentViewPortCtx.getTaskFlowContext();
TaskFlowTrainModel taskFlowTrainModel = taskFlowCtx.getTaskFlowTrainModel();
TaskFlowTrainStopModel currentStop = taskFlowTrainModel.getCurrentStop();
TaskFlowTrainStopModel nextStop = taskFlowTrainModel.getNextStop(currentStop);
//is either null or has the value of outcome
return nextStopAction;
}
Full code of the sample can be found on the ADF Code Corner.
To navigate by taskflow outcomes you just need to provide exact outcome String as return of your method:
private static final String NEXT_NAVIGATION_ACTION = "next";
public String nextAction() {
if (validate()) {
updateModel();
return NEXT_NAVIGATION_ACTION;
}
return null;
}
Can you verify, you can do it in through phase listener.
Verify you condition in the phase listener and allow it to move ahead if it validates else stop the thread execution.
Below is the sample phase listener code.
public class MyPhaseListener implements PagePhaseListener{
public MyPhaseListener() {
super();
}
#Override
public void afterPhase(PagePhaseEvent pagePhaseEvent) {
if (pagePhaseEvent.getPhaseId() == Lifecycle.PREPARE_RENDER_ID ) {
// DO your logic here
}
}
#Override
public void beforePhase(PagePhaseEvent pagePhaseEvent) {
}
}

How to specify command attribute in h:inputText?

I have a function that I derclare beans in my manager and I want to return the value in inputText but when I put the name of my function in the value attribute of inputText tag like this:
<p: inputText value = "#{ticketBean.getLastIndexTache} "/>
this error appear:
Etat HTTP 500 - /pages/test.xhtml #13,106 value="#{ticketBean.getLastIndexTache}": Property 'getLastIndexTache' not found on type com.bean.TicketBean
here is the java code
#ManagedBean(name="ticketBean")
public class TicketBean {
public int getLastIndexTache() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
int index = 0;
try {
session.beginTransaction();
String sql = "select MAX(t.IDTICKET) from ticket t ";
Query query = session.createSQLQuery(sql);
if( query.uniqueResult()==null){
index=0;
}else{
index=(int) query.uniqueResult();
index=index+1;
}
} catch (HibernateException e) {
// TODO: handle exception
session.getTransaction().rollback();
e.printStackTrace();
}
return index;
}
}
You should use the bean property in value like
<p:inputText value="#{ticketBean.lastIndexTache}"/>
as JSF by itself adds "get" to the property name. Currently it will look for the method getGetLastIndexTache().
Besides its very bad practice to have logic in any getter as they are called multiple times by JSF. Instead you should make an property like
private Integer lastIndexTache; // +getter/setter
and set the value in a #PostConstruct method:
#PostConstruct
public void init() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
// etc....
lastIndexTache = index;
}
The getter would then simply be
public Integer getLastIndexTache() {
return lastIndexTache;
}
and don't forget a setter:
public void setLastIndexTache(Integer newValue) {
lastIndexTache = newValue;
}
Also you should probably put a scope on the bean (for example #ViewScoped).

how to get jsf clientid of a component in datatable?

i am trying to get the client id of a component in a datatable. the problem is that jsf puts row index before the component id automatically, i.e.
<a id="mappedidentifier_table:1:mappedidentifier_Update" href="#">Update</a>
for a link in the second row (index=1).
i am using the following methods to get the clientId
public static String findClientId(String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot view = context.getViewRoot();
if (view == null) {
throw new IllegalStateException("view == null");
}
UIComponent component = findComponent(view, id);
if (component == null) {
throw new IllegalStateException("no component has id='" + id + "'");
}
return component.getClientId(context);
}
private static UIComponent findComponent(UIComponent component, String id) {
if (id.equals(component.getId())) {
return component;
}
Iterator<UIComponent> kids = component.getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = kids.next();
UIComponent found = findComponent(kid, id);
if (found != null) {
return found;
}
}
return null;
}
however this returns
mappedidentifier_table:mappedidentifier_Update,
instead of
mappedidentifier_table:1:mappedidentifier_Update,
therefore it does not match any element cause the row index in id is missing.
i've read http://illegalargumentexception.blogspot.com/2009/05/jsf-using-component-ids-in-data-table.html
however i intend to have a simpler implementation, rather than TLD function or facelets like the author did.
does anyone have any thoughts ?
thanks,
dzh
however this returns mappedidentifier_table:mappedidentifier_Update instead of mappedidentifier_table:1:mappedidentifier_Update
This will happen if you resolve the clientId outside the context of a row. The row context is set up at each stage of the lifecycle by the UIData control.
It might also happen if you're using immediate evaluation instead of deferred evaluation in your EL expressions - ${} instead of #{}.
As an aside, and as noted in the article, that lookup algorithm will only work if the component identifier is unique to the view; the spec says it need only be unique to the NamingContainer; this need not be a problem if you are careful about using unique component IDs on your page.

Use argument in EL expression

I need to use function with argument in a EL expression (with JSF) like this:
<h:outputText value="#{object.test(10)}" ></h:outputText>
But it doesn't work.
I read on the web that it's impossible to do this with JSF. I use facelet with JSF.
Someone knows how to do that ?
Thanks.
You could provide the method as a custom facelet function in your own taglib. The method must be static, so if you are trying to call a method on a specific bean, you would have to pass the bean, and the parameters to your static facelet function. In your case, it would be something like
<h:outputText value="#{my:doStuff(object,10)}" ></h:outputText>
and your facelet function would be
public static String doStuff( MyType o, int param )
{
return o.test( param );
}
Then, using the information in the facelets docbook you would define your function in your taglib.xml file.
It's not the prettiest solution, especially if you plan on doing this a lot, but I believe the next version of the EL (in java EE 6) will allow for using parameters in some cases.
Edit: Some info about parameterized method calls in the next version of el can be found on Ryan Lubke's Blog
I find a sad solution but it's working. I overload a map like this:
new AbstractMap<Integer, String>()
{
#Override
public Set<Entry<Integer, String>> entrySet()
{
return null;
}
#Override
public String get(final Object arg0)
{
Integer keywordDb = (Integer)arg0;
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
HashMap<String, String> params = new HashMap<String, String>();
params.put("keywordDb", keywordDb.toString());
params.put("month", new Integer(cal.get(Calendar.MONTH) + 1).toString());
params.put("year", new Integer(cal.get(Calendar.YEAR)).toString());
DataAnalyzeManager manager = new DataAnalyzeManager();
manager.setEm(modelPosition.getEm());
DataAnalyze data = manager.findDataByParams(params, modelPosition.getSite(), false, DataAnalyzeManager.VISITBYMONTHBYKEYWORD);
if (data != null)
return data.getDataInt().toString();
return "0";
}
};
Thereby, I can do that in my JSF:
#{homePositionController.visitByMonth[keyword.keyword.keywordDb]}
And my function is executed.
You may have to have <%# page isELIgnored ="false" %>
at the top of your pages. Read more here. The default is to ignore el expressions. What version of the JSP spec are you using with JSF? If you are using JSF 2 with JSP < 2.1 you are going to run into problems.
Also, what version of el are you using? You can't pass method params with older versions.
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.1.2-b05</version>
</dependency>
There is couple ways about doing that, you could use JBoss EL expression implementation they support method calls with parameters check out Seam, or use similar approach as #digitaljoel suggested.
This is what I created for that purpose, you can call static and static methods, not a great solution but it does the job.
<c:if test="#{t:call(null, '#Util.SecurityUtility', 'isPanelWorkbookEnabledForUser','')}">
Hello Panel
</c:if>
#Util is just an alias to com.mycomp.util where
Example 2
<c:if test="#{item != null and t:call(item, 'java.lang.String', 'indexOf', t:params(t:param('flash-alert',''))) == 0}">
#{t:call(session, 'org.apache.catalina.session.StandardSessionFacade', 'removeAttribute', t:params(t:param(item,'')))}
</c:if>
Syxtax
java.lang.Object call(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object[])
Where Object is object we want to invoke method on, String is the method name, Object[] are parameters to pass.
t:call, t:params, t:param are function defined in project-taglib.xml as so
<function>
<function-name>call</function-name>
<function-class>util.Functions</function-class>
<function-signature>java.lang.Object call(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object[])</function-signature>
</function>
<function>
<function-name>param</function-name>
<function-class>.util.Functions</function-class>
<function-signature>java.lang.String param(java.lang.Object, java.lang.String)</function-signature>
</function>
<function>
<function-name>params</function-name>
<function-class>util.Functions</function-class>
<function-signature>java.lang.Object[] params(java.lang.String)</function-signature>
</function>
Here is the implementation
package mycompany.web.util;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.el.MethodNotFoundException;
public class Functions {
private static HashMap<String, String> alliasMap;
static{
alliasMap=new HashMap<String, String>();
alliasMap.put("#DateUtil", "com.americanbanksystems.compliance.util.DateUtil");
//Match anything following the dot(.)
alliasMap.put("#Util.*", "com.americanbanksystems.compliance.util");
alliasMap.put("#Application.*", "com.americanbanksystems.compliance.application");
}
public static String param(Object obj, String cls) {
//make sure that passed in object is not null
if(obj==null){
obj="";
}
ByteArrayOutputStream baut=new ByteArrayOutputStream();
XMLEncoder encoder=new XMLEncoder( baut );
//Bug in the JDK
//http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=c993c9a3160fd7de44075a2a1fa?bug_id=6525396
if(obj instanceof java.sql.Timestamp){
Date o = new Date(((java.sql.Timestamp)obj).getTime());
obj=o;
}
//Checking if this is possible
if(String.class.isAssignableFrom(obj.getClass())){
//removed trailing +" " because it was causing indexOf return invalid value
//Unknown side effects
obj=FacesUtil.get(obj.toString());
}
encoder.writeObject( obj );
encoder.close();
return new String(baut.toByteArray());
}
private static Object decode(String str){
ByteArrayInputStream bais=new ByteArrayInputStream(str.getBytes());
XMLDecoder decoder=new XMLDecoder(bais);
return decoder.readObject();
}
public static Object[] params(String str){
// (?<=</java>)\s*(?=<?)
String[] obj=str.split("(?<=</java>)\\s*(?=<?)");
Object[] results=new Object[obj.length];
for(int i=0;i<obj.length;i++){
results[i]=decode(obj[i]);
}
return results;
}
#SuppressWarnings("unchecked")
public static Object call(Object owningObject, String qualifiedClassname, String methodName, java.lang.Object... methodArguments) {
if (null == methodName || methodName.equals("")) {
throw new IllegalArgumentException("Method name can't be null or empty");
}
if (null == methodArguments) {
methodArguments = new Object[0];
}
//Check for aliases
if(qualifiedClassname.indexOf("#")>-1){
String subpackage=qualifiedClassname;
String originalClass=qualifiedClassname;
//Split at the dot
boolean isPackageAllias=false;
String[] sp=subpackage.split("\\.");
if(sp.length>1){
subpackage=sp[0]+".*";
isPackageAllias=true;
}
if(alliasMap.containsKey(subpackage)){
String value = alliasMap.get(subpackage);
if(isPackageAllias){
qualifiedClassname=subpackage.replace(sp[0], value);
qualifiedClassname=qualifiedClassname.replace(".*", originalClass.replace(sp[0],""));
}else{
qualifiedClassname=value;
}
}else{
throw new IllegalArgumentException("Allias name '"+qualifiedClassname+"' not found");
}
}
Class clazz;
try {
clazz = Class.forName(qualifiedClassname);
//Find method by methodName,Argument Types
Class[] argumentTypes=new Class[methodArguments.length];
for(int i=0;i<methodArguments.length;i++){
argumentTypes[i]=methodArguments[i].getClass();
//Check if the passed in method argument is a string and if its represented as unicode char
//if it is then convert it into a char and reassign to the original parameter
//example 1: \u0022 == "
//example 2: \u0027 == '
// Reason for this functionality is that we can't pass " and ' from within t:call method
if (argumentTypes[i] == String.class && methodArguments[i].toString().indexOf("\\u") > -1) {
String arg = methodArguments[i].toString();
arg = arg.substring(2, arg.length());
try {
int outchar = Integer.parseInt(arg, 16);
if (Character.isDefined(outchar)) {
methodArguments[i] = String.valueOf((char) outchar);
}
} catch (NumberFormatException nfe) {
// Suppress error and continue assuming this is a regular string
}
}
}
Method methodToInvoke = null;
try{
methodToInvoke = clazz.getMethod(methodName, argumentTypes);
}catch(NoSuchMethodException nsm){//Find by method name/ argument count
for (Method method : clazz.getMethods()) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == methodArguments.length) {
if (null == owningObject) {
owningObject = clazz.newInstance();
}
methodToInvoke=method;
break;
}
}
}
if(methodToInvoke!=null){
return methodToInvoke.invoke(owningObject, methodArguments);
}else{
throw new InstantiationException("method not found :" + methodName);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] arg) {
// StringBuffer buff=new StringBuffer();
// buff.append("Gregs init");
// Functions.call(java.lang.Class<T>, T, java.lang.String, java.lang.String, java.lang.Object...)
/*
* Functions.call(StringBuffer.class, buff, "java.lang.StringBuffer","append"," Init ");
* Functions.call(StringBuffer.class, buff, "java.lang.StringBuffer","append"," greg ");
* System.out.println("output="+ buff);
*/
//#{t:call(null, ".util.DateUtil", "normalizeDate", t:parametize(editRiskActionPlan.riskActionPlan.completionDate,",","java.lang.Object"))}
// c(call(null, "util.DateUtil", "normalizeDate", new Date()));
// #{t:parametize(editRiskActionPlan.riskActionPlan.completionDate,",","java.lang.Object")}
//parametize((new Date()).toString(),",","java.lang.Object");
Date a=new Date();
Date b=new Date();
String rawString=param((Date)b, Date.class.toString() );
//System.out.println(rawString);
//Replaced=#{t:call("Gregs ' car", 'java.lang.String', 'replace', t:params( parameter ))}
String paramA=param("\\u0027","");
String paramB=param("\\u0022","");
String params=paramA+paramB;
String in="I need to ' have a replaced single quote with double";
String out=(String)call(in, "java.lang.String", "replace", params(params));
System.out.println(out);
/*
Object[] obj=params(rawString);
for(Object o:obj){
System.out.println(o);
}
//c(call(null, "#DateUtil", "normalizeDate", obj));
*/
}
}
I hope this helps, btw this was copied/pasted from my project so not sure if I missed anything.

Resources