waffel’s Weblog

November 28, 2008

how to use EL from java in a JSF 1.2 environment

Filed under: java,JSF,software — Thomas Wabner @ 9:47 pm
Tags: , , ,

There are not much examples, how to use a ELExpression from your java code. The most examples I found, are focussing on „implement your own ELResolver“. The best documentation comes from SUN in form of tutorials and package/javadoc.

Now I will provide some tips how to deal with EL expressions from java. I have tested and implemented this in a JSF 1.2 web application, where I have access to the FacesContext.

In JSF 1.2 you have access to expression factory:

// get application from faces context
Application app = FacesContext.getInstance().getApplication();
ExpressionFactory exprFactory = app.getExpressionFactory();

Now you can use the expression factory to get a MethodExpression or ValueExpression. In my projects we need very often ValueExpressions.

But first you need also an ELContext. There are many implementations available of such context (for JSP, Faces and so on) and enough documentation how to create your own context.
You can access such context again from the faces context:

// getting the ELContext from faces context
ELContext elContext = FacesContext.getInstance().getELContext();
// creating value expression with the help of the expression factory and the ELContext
ValueExpression valExpr = exprFactory.createValueExpression(elContext, "#{devBean.devMode}", Boolean.class);

In this example I will use the boolean value from a „devBean“ to work later with this value. Of course, you can inject the value expression, required class type and so on.
The last needed thing is to assign the value to a local variable:

Boolean developmentMode = (Boolean) valExpr.getValue(elContext);

Thats it!

Oktober 7, 2008

fun with h:dataTable and a4j:form

Filed under: JSF — Thomas Wabner @ 11:41 am
Tags: , , ,

I have some facelet components and want to use them in a h:dataTable. My components containing some form elements like h:inputText, command buttons and so on. To avoid scrolling, I have placed them into a a4j:form.

Now in my h:dataTable loop I call these facelet components and want to have a list of inputText components for example. But every time, I typed in something, only the last input field called correct my setValue() method. All other input components dosn’t call the setter.

Here a very small example to imagine the problem:

The datatable


<h:dataTable value="myBackingBean.list" var="currentItem">
  <h:column>
    <waffel:input item="#{currentItem}"/>
  </h:column>
</h:dataTable>

The facelet component:

  ...
  <a4j:form>
    <h:inputText size="30" value="#{item.value}"/>
    <a4j:commandButton value="ok" action="#{item.applyValue}"/>
  </a4j:form>
  ...

To get this to work you have to place a a4j:region around the a4j:form!

  ...
  <a4j:region>
    <a4j:form>
      <h:inputText size="30" value="#{item.value}"/>
      <a4j:commandButton value="ok" action="#{item.applyValue}"/>
    </a4j:form>
  </a4j:region>
  ...

Now it works fine.

September 9, 2008

expanding richfaces tree on datamodel changes

Filed under: java,JSF — Thomas Wabner @ 2:19 pm
Tags: , , ,

Sometimes you will select a tree node in a richfaces tree, triggered by your datamodel. There are several hints how to do this with a tree state advisor, but I have found another way to do this.

My main problem was, that I do not have a relation between my datamodel and the richfaces UITree components (nodes). This problem was introduced because I use the recursiveTreeAdaptor. I have not found a way to get a TreeRowData object from the UITree for my datamodel object.

I have searched in the richfaces implementation, if there is another way to work with my datamodel which have to expand the tree, if the datamodel is changed.

Lets clearify what I want to do: I have a datamodel with some root nodes and „normal“ nodes in a tree like structure. I have also (in my TreeManager) a parameter which holds a selectedNode. A node can selected from the UI (the user clicks on a tree node and causes a node selection event) or from my datamodel, which calls a method in the TreeManager to select a specific tree node.

The tree manager contains a method to select a specific node like this:

public void select(final Node nextStepNode) {
  this.selectedNode = nextStepNode;

}

To expand the tree to the selected node, I have changed to select method:

public void select(final Node nextStepNode) {
  this.selectedNode = nextStepNode;
  try {
      // walk over the tree which expands the tree and uses a complete tree
      // range
      tree.walk(FacesContext.getCurrentInstance(), expandingDataVisitor, new CompleteTreeRange(), null, null);
    } catch (final IOException e) {
      if (LOG.isErrorEnabled()) {
        LOG.error(String.format("problem %s", e.getMessage()));
      }
    }
}

The tree walk method walks over the tree using my own data visitor and tree range. The tree range implementation tolds the tree to walk also over hidden nodes. You remember? The tree should expand all nodes to the selected node, also if the selected node is hidden.

The tree range implementation looks like:

public class CompleteTreeRange implements TreeRange {

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public boolean processChildren(final TreeRowKey rowKey) {
    return true;
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public boolean processNode(final TreeRowKey rowKey) {
    return true;
  }

Now comes the hard stuff on my solution, the expandingDataVisitor:

public class ExpandingDataVisitor implements DataVisitor {
  public void process(final FacesContext theContext, final Object theRowKey, final Object theArgument)
      throws IOException {
    if (selectedNode.equals(tree.getRowData(theRowKey))) {
      tree.queueNodeExpand((TreeRowKey) tree.getParentRowKey(theRowKey));
    }
}

You can queue node expanding with a tree rowKey to the node, which you want to expand. You don’t need to queue all nodes on the path. The queueNodeExpand method works fine with one rowkey. The row describes itself the complete path to the node. If you use standard jsf ID’s, a possible treeRowKey looks like „jsp123:jsp124:jsp125“ wich is the complete path to your node (row key).

You have to know, that you don’t want expand the selected node (this is in most cases a leafe). You want to expand the tree to the parent of the selected node.

Juni 25, 2008

Reuse facelets xhtml files and taglibs from jar archives

Filed under: JSF,software,Uncategorized — Thomas Wabner @ 4:47 pm
Tags: ,

I have asked myself, if it is possible to use facelets xhtml files and taglibs from a jar file instead from the whole web application.

The short anwser: Yes, it is possible 😉

The facelets documentation gives a hint how to use the tag lib from a jar file. But you cannot found in the documentation, if it is possible also to use a xhtml file (referenced from the taglib for example). Of course facelets uses the same approach to load xhtml files from a jar file as for the tag library.

Example:
The follow tag lib definition is placed in my JAR project under /META-INF/myProject.taglib.xml

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">

<facelet-taglib>

    <namespace>https://thomaswabner.wordpress.com/waffel</namespace>

    <tag>
        <tag-name>select</tag-name>
        <source>components/select.xhtml</source>
    </tag>

</facelet-taglib>

The select.xhtml file is placed in the same project under /META-INF/components/select.xhml and contains some facelets definitions (ui component with a selectbox fo example). The point is, that facelets searches the jar archive under the /META-INF directory for the xhtml file.

Now you can simple use the tag in you web application. You only need to include the jar file with the tag library and xhtml file in you web application classpath.

<?xml version="1.0" encoding="UTF-8" ?>
<jsp:root xmlns="http://www.w3.org/1999/xhtml"
          xmlns:ui="http://java.sun.com/jsf/facelets"
          xmlns:waffel="https://thomaswabner.wordpress.com/waffel"
          version="2.0">
  <ui:component>
     <waffel:select/>
  </ui:component>
</jsp:root>

Update: See comments. I have created a small example.

Juni 13, 2008

getting node data from rich tree on user selection

Filed under: java,JSF,software — Thomas Wabner @ 3:33 pm
Tags: , ,

I have had the problem to get node data from a richfaces tree, if the user selects a node. I have used a recursive tree adapter:

<rich:tree switchType="server"
           stateAdvisor="#{treeStateAdvisor}"
           nodeSelectListener="#{treeMgrt.onSelect}">
                 
   <rich:recursiveTreeNodesAdaptor roots="#{treeMgrt.roots}" var="item" nodes=" {item.nodes}">

     <rich:treeNode>
         <h:outputText value="#{item}"/>
     </rich:treeNode> 
          
  </rich:recursiveTreeNodesAdaptor>
</rich:tree>  

The method in my tree manager onSelect(…) looks like this:

public void onSelect(final NodeSelectedEvent event) {
  final UITree theTree = this.getTree(event);
  if (null == theTree) {
    return;
  }
  final Object rowKey = theTree.getRowKey();
  // this works better
  final Object rowData = theTree.getRowData(rowKey);
  if (rowData instanceof ProductNode) {
    this.selectedNode = (ProductNode) rowData;
  }
}

Normally you can use theTree.getTreeNode(); but with a recursive tree model which method returns alway null. Instead of this I have used the getRowData() method which works for me.
I have filed a bug for richfaces. Hope the problem becomes shortly a solution.

September 27, 2007

Replacing deprecated ValueBindung stuff from JSF with ELResolver

Filed under: JSF,software — Thomas Wabner @ 11:21 am

I have searched for a solution to replace the as deprecated marked ValutBinding stuff with a better solution.

For example if you have a method to retrieve a JSF Bean from the faces context:


public static Object accessBeanFromFacesContext(final String theBeanName, final FacesContext theFacesContext) {
final StringBuffer valueBinding = new StringBuffer();
valueBinding.append('#');
valueBinding.append('{');
valueBinding.append(theBeanName);
valueBinding.append('}');
final Object returnObject = theFacesContext.getApplication().
createValueBinding(valueBinding.toString()).getValue(theFacesContext);
if (returnObject == null) {
LOG
.error("Bean with name " + theBeanName + " was not found. Check the faces-config.xml file if the given bean name is ok."); //$NON-NLS-1$ //$NON-NLS-2$
}
return returnObject;
}

You can replace this now with following code:

public static Object accessBeanFromFacesContext(final String theBeanName, final FacesContext theFacesContext) {
final Object returnObject = theFacesContext.getELContext().getELResolver().getValue(theFacesContext.getELContext(), null, theBeanName);
if (returnObject == null) {
LOG
.error("Bean with name " + theBeanName + " was not found. Check the faces-config.xml file if the given bean name is ok."); //$NON-NLS-1$ //$NON-NLS-2$
}
return returnObject;
}

This retrieves a bean from the faces context. You can use the method for example to retrieve a TestBean form the faces context like

TestBean testBean = (TestBean)JSFUtils.accessBeanFromFacesContext("testBean", FacesContext.getCurrentInstance());

The TestBean object have to be added to the faces-config.xml as a managed bean. If the bean was not created at the point where you ask for it, the default constructor is called and the bean is created for you from the JSF framework.

Bloggen auf WordPress.com.