Friday, April 23, 2010

Sortable JSF DataModel for Spring Webflow

When JSF is integrated with Spring webflow, the DataModel needs to be Serializable. But the standard javax.faces.model.DataModel does not implement the Serializable interface. To get around this problem, we can extend the model. We can also add some artifacts for the column sorting purpose. The following are the two classes for this.

The Serializable DataModel

package mypackage;

import java.io.Serializable;
import java.util.List;

import javax.faces.model.DataModel;
import javax.faces.model.DataModelEvent;
import javax.faces.model.DataModelListener;

/**
 
 * SerializableListDataModel is basically the ListDataModel class from
 * jsf-api-1.1, except that it implements the Serializable interface. This
 * interface is needed by ICEfaces when rendering the table.
 */
public class SerializableListDataModel extends DataModel
    implements
      Serializable
{

  public SerializableListDataModel()
  {
    this(null);
  }

  public SerializableListDataModel(List list)
  {
    index = -1;
    setWrappedData(list);
  }

  public boolean isRowAvailable()
  {
    if (list == nullreturn false;
    return index >= && index < list.size();
  }

  public int getRowCount()
  {
    if (list == nullreturn -1;
    else
      return list.size();
  }

  public Object getRowData()
  {
    if (list == nullreturn null;
    if (!isRowAvailable()) throw new IllegalArgumentException();
    else
      return list.get(index);
  }

  public int getRowIndex()
  {
    return index;
  }

  public void setRowIndex(int rowIndex)
  {
    if (rowIndex < -1throw new IllegalArgumentException();
    int old = index;
    index = rowIndex;
    if (list == nullreturn;
    DataModelListener listeners[] = getDataModelListeners();
    if (old != index && listeners != null)
    {
      Object rowData = null;
      if (isRowAvailable()) rowData = getRowData();
      DataModelEvent event = new DataModelEvent(this, index, rowData);
      int n = listeners.length;
      for (int i = 0; i < n; i++)
        if (null != listeners[i]) listeners[i].rowSelected(event);

    }
  }

  public Object getWrappedData()
  {
    return list;
  }

  public void setWrappedData(Object data)
  {
    if (data == null)
    {
      list = null;
      setRowIndex(-1);
    }
    else
    {
      list = (Listdata;
      index = -1;
      setRowIndex(0);
    }
  }

  private int index;
  private List list;
}

The Sortable DataModel

package mypackage;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Date;

import javax.faces.model.DataModel;
import javax.faces.model.DataModelListener;

import org.springframework.util.StringUtils;

/**
 
 * SortableDataModel to make the table columns sortable.
 
 */
public class SortableDataModel extends DataModel implements Serializable
{

  private DataModel model;

  private Row[] rows;

  public SortableDataModel()
  {
  }

  public SortableDataModel(DataModel dataModel)
  {
    this.model = dataModel;
    if (model != null)
    {
      initializeRows();
    }
    else
    {
      rows = null;
    }
  }

  protected Row[] getRows()
  {
    return rows;
  }

  private void initializeRows()
  {
    int rowCnt = model.getRowCount();
    if (rowCnt != -1)
    {
      rows = new Row[rowCnt];
      for (int i = 0; i < rowCnt; ++i)
      {
        rows[inew Row(i);
      }
    }
  }

  @Override
  public int getRowCount()
  {
    return model.getRowCount();
  }

  @Override
  public Object getRowData()
  {
    return model.getRowData();
  }

  @Override
  public int getRowIndex()
  {
    return model.getRowIndex();
  }

  @Override
  public Object getWrappedData()
  {
    if (model == null)
    {
      return null;
    }
    return model.getWrappedData();
  }

  @Override
  public boolean isRowAvailable()
  {
    return model.isRowAvailable();
  }

  @Override
  public void setWrappedData(Object data)
  {
    model.setWrappedData(data);
  }

  @Override
  public void addDataModelListener(DataModelListener listener)
  {
    model.addDataModelListener(listener);
  }

  @Override
  public DataModelListener[] getDataModelListeners()
  {
    return model.getDataModelListeners();
  }

  @Override
  public void removeDataModelListener(DataModelListener listener)
  {
    model.removeDataModelListener(listener);
  }

  public void setRowIndex(int rowIndex)
  {
    if (rowIndex == -|| rowIndex >= model.getRowCount())
    {
      model.setRowIndex(rowIndex);
    }
    else
    {
      model.setRowIndex(rows[rowIndex].row);
    }
  }

  protected class Row implements Serializable
  {
    private int row;

    public Row(int row)
    {
      this.row = row;
    }

    public Object getData()
    {
      int originalIndex = model.getRowIndex();
      model.setRowIndex(row);
      Object thisRowData = model.getRowData();
      model.setRowIndex(originalIndex);
      return thisRowData;
    }
  }

  protected abstract static class BaseComparator implements Comparator<Row>
  {
    private boolean ascending;

    public BaseComparator(boolean ascending)
    {
      this.ascending = ascending;
    }

    public abstract int compareRowData(Row o1, Row o2);

    // if the compareRowData returns 0, then use this method to further sort the
    // rows. Usually this will use the column that will definitely return a
    // non-zero value. The subclass comparator can override this method.
    public int compareDefault(Row o1, Row o2)
    {
      return 0;
    }

    protected int compareNullValues(Object obj1, Object obj2)
    {
      if (obj1 != null && obj2 != null)
      {
        throw new IllegalArgumentException("Neither input is null.");
      }
      boolean s1 = (obj1 == null);
      boolean s2 = (obj2 == null);
      int diff = 0;
      if (s1 && !s2)
      {
        diff = 1;
      }
      else if (!s1 && s2)
      {
        diff = -1;
      }
      return diff;
    }

    public int compare(Row o1, Row o2)
    {
      int diff = compareRowData(o1, o2);
      if (diff == 0)
      {
        diff = compareDefault(o1, o2);
      }
      return ascending ? diff : -diff;
    }
  }

  protected abstract static class StringComparator extends BaseComparator
  {
    public StringComparator(boolean ascending)
    {
      super(ascending);
    }

    public abstract String getString(Row row);

    public int compareRowData(Row row1, Row row2)
    {
      String str1 = getString(row1);
      String str2 = getString(row2);
      boolean s1 = StringUtils.hasText(str1);
      boolean s2 = StringUtils.hasText(str2);
      int diff = 0;
      if (s1 && !s2)
      {
        diff = 1;
      }
      else if (!s1 && s2)
      {
        diff = -1;
      }
      else if (!s1 && !s2)
      {
        diff = 0;
      }
      else if (s1 && s2)
      {
        diff = str1.compareTo(str2);
      }
      return diff;
    }
  }

  protected abstract static class IntegerComparator extends BaseComparator
  {
    public IntegerComparator(boolean ascending)
    {
      super(ascending);
    }

    public abstract Integer getInteger(Row row);

    public int compareRowData(Row bean1, Row bean2)
    {
      Integer int1 = getInteger(bean1);
      Integer int2 = getInteger(bean2);
      if (int1 != null && int2 != null)
      {
        return int1.intValue() - int2.intValue();
      }
      return compareNullValues(int1, int2);
    }
  }
  protected abstract static class LongComparator extends BaseComparator
  {
    public LongComparator(boolean ascending)
    {
      super(ascending);
    }

    public abstract Long getLong(Row row);

    public int compareRowData(Row row1, Row row2)
    {
      Long n1 = getLong(row1);
      Long n2 = getLong(row2);
      if (n1 != null && n2 != null)
      {
        Long temp = n1 - n2;
        return temp.intValue();
      }
      return compareNullValues(n1, n2);
    }
  }

  protected abstract static class DateComparator extends BaseComparator
  {
    public DateComparator(boolean ascending)
    {
      super(ascending);
    }

    public abstract Date getDate(Row row);

    public int compareRowData(Row row1, Row row2)
    {
      Date date1 = getDate(row1);
      Date date2 = getDate(row2);
      if (date1 != null && date2 != null)
      {
        return date1.compareTo(date2);
      }
      return compareNullValues(date1, date2);
    }
  }
}

A Sample JSP File Using the Sortable DataModel

The following is a sample jsp file. It is actually an xhtml file because it uses a facelet template. This page also uses IceFaces to display the data page by page. It also uses Spring webflow.

<ui:composition template="myFaceletTemplate.xhtml"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:ice="http://www.icesoft.com/icefaces/component"
  xmlns:c="http://java.sun.com/jstl/core">

  <ui:define name="content">

    <ice:outputText styleClass="pageHeading"
      value="My Page heading" />
    <br />
    <br />

    <ice:form>
      <ice:panelGroup>
        <!-- Display counts about the table and the currently displayed page -->
        <ice:dataPaginator id="dataScroll_2"
          for="myAppData" rowsCountVar="rowsCount"
          displayedRowsCountVar="displayedRowsCountVar"
          firstRowIndexVar="firstRowIndex" lastRowIndexVar="lastRowIndex"
          pageCountVar="pageCount" pageIndexVar="pageIndex">
          <ice:outputFormat
            value="{0} records found. Displaying reocrds {2} to {3} on page {4} of {5}."
            styleClass="standard">
            <f:param value="#{rowsCount}" />
            <f:param value="#{displayedRowsCountVar}" />
            <f:param value="#{firstRowIndex}" />
            <f:param value="#{lastRowIndex}" />
            <f:param value="#{pageIndex}" />
            <f:param value="#{pageCount}" />
          </ice:outputFormat>
        </ice:dataPaginator>

        <ice:panelGrid columns="2">
          <!-- Layout table columns with column headings and 11 table rows per page -->
          <ice:dataTable id="myAppData"
            var="myAppSelection" styleClass="dataPaginatorTable"
            value="#{myAppAdminForm.myAppSelections}"
            rows="11" columnClasses="firstCol,lastCol,phoneCol,emailCol">
            <ice:rowSelector
              value="#{myAppSelection.selected}" multiple="true" />
            <ice:column>
              <f:facet name="header">
                <ice:outputText id="columnSelection"
                  value="Selected" />
              </f:facet>
              <ice:selectBooleanCheckbox id="selection"
                value="#{myAppSelection.selected}"
                partialSubmit="true" />
            </ice:column>

            <ice:column>
              <f:facet name="header">
                <h:commandLink
                  action="#{myAppAdminForm.myAppSelections.sortByName}">
                  <ice:outputText id="columnName"
                    value="Name" />
                </h:commandLink>
              </f:facet>
              <ice:outputText id="name"
                value="#{myAppSelection.myApp.name}" />
            </ice:column>

            <ice:column>
              <f:facet name="header">
                <h:commandLink
                  action="#{myAppAdminForm.myAppSelections.sortByStartDate}">
                  <ice:outputText id="columnStartDate"
                    value="Start Date" />
                </h:commandLink>
              </f:facet>
              <ice:outputText id="startDate"
                value="#{myAppSelection.myApp.startDate}">
                <f:convertDateTime type="date"
                  dateStyle="medium" />
              </ice:outputText>
            </ice:column>

          </ice:dataTable>

        </ice:panelGrid>
      </ice:panelGroup>

      <!-- Set up the buttons and links for browsing through the table
        No. of pages to fast forward or rewind: 3
        No. of direct links to pages: -->
      <ice:dataPaginator id="dataScroll_1"
        for="myAppData" fastStep="3" pageCountVar="pageCount"
        pageIndexVar="pageIndex" paginator="true" paginatorMaxPages="20"
        styleClass="formBorderHighlight" renderFacetsIfSinglePage="false">
        <f:facet name="first">
          <ice:graphicImage id="firstpage_1"
            url="./xmlhttp/css/xp/css-images/arrow-first.gif"
            style="border:none;" title="first page" />
        </f:facet>
        <f:facet name="last">
          <ice:graphicImage id="lastpage_1"
            url="./xmlhttp/css/xp/css-images/arrow-last.gif"
            style="border:none;" title="last page" />
        </f:facet>
        <f:facet name="previous">
          <ice:graphicImage id="previouspage_1"
            url="./xmlhttp/css/xp/css-images/arrow-previous.gif"
            style="border:none;" title="previous page" />
        </f:facet>
        <f:facet name="next">
          <ice:graphicImage id="nextpage_1"
            url="./xmlhttp/css/xp/css-images/arrow-next.gif"
            style="border:none;" title="next page" />
        </f:facet>
        <f:facet name="fastforward">
          <ice:graphicImage id="fastforward_1"
            url="./xmlhttp/css/xp/css-images/arrow-ff.gif"
            style="border:none;" title="fast forward" />
        </f:facet>
        <f:facet name="fastrewind">
          <ice:graphicImage id="fastrewind_1"
            url="./xmlhttp/css/xp/css-images/arrow-fr.gif"
            style="border:none;" title="fast backward" />
        </f:facet>
      </ice:dataPaginator>

      <table>
        <tr>
          <td>
            <ice:commandButton id="cmdSubmitSelection"
              action="reviewSelections" value="Review Selections" />
            <ice:commandButton action="cancel"
              value="Cancel" immediate="true" />
          </td>
        </tr>
      </table>
    </ice:form>
  </ui:define>
</ui:composition>

Wednesday, April 7, 2010

A Sample Spring Webflow File

The Sample Webflow File

<?xml version="1.0" encoding="UTF-8"?>

<flow xmlns="http://www.springframework.org/schema/webflow"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">

 <var name="sampleEventCreateForm"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventCreateForm" />
 <var name="sampleEventEditForm"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventEditForm" />
 <var name="sampleEventAdminForm"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventAdminForm" />
 <var name="sampleEventViewForm"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventViewForm" />

 <start-state idref="menuAction" />

 <view-state id="menuAction"
  view="/sampleevent/sampleEventMenu.xhtml">
  <transition on="createSampleEvent" to="createSampleEvent">
   <action bean="sampleEventCreateFormAction"
    method="initializeData" />
   <action bean="sampleEventCreateFormAction"
    method="setEventType" />
  </transition>
  <transition on="editSampleEvent" to="editSelectSampleEvent">
   <action bean="sampleEventEditFormAction"
    method="initializeData" />
   <action bean="sampleEventEditFormAction"
    method="setEventType" />
   <action bean="sampleEventEditFormAction"
    method="searchSampleEvent" />
  </transition>
  <transition on="viewSampleEvent" to="viewSampleEvent">
   <action bean="sampleEventViewFormAction"
    method="setEventType" />
  </transition>
  <transition on="adminSampleEvent" to="adminSampleEvent">
   <action bean="sampleEventAdminFormAction"
    method="setEventType" />
  </transition>
 </view-state>

 <!-- create event -->
 <view-state id="createSampleEvent"
  view="/sampleevent/createSampleEvent.xhtml">
  <transition on="createSampleEvent" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="createSampleEvent" />
  </transition>
 </view-state>

 <view-state id="createSearchItems"
  view="/sampleevent/createSearchItems.xhtml">
  <transition on="search" to="createSearchResults">
   <action bean="sampleEventCreateFormAction" method="search" />
  </transition>
  <transition on="addManufacturers" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="addManufacturers" />
  </transition>
  <transition on="removeManufacturers" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="removeManufacturers" />
  </transition>
  <transition on="addItemModelAlias" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="addItemModelAlias" />
  </transition>
  <transition on="removeItemModelAlias" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="removeItemModelAlias" />
  </transition>
 </view-state>

 <view-state id="createSearchResults"
  view="/sampleevent/createSearchResults.xhtml">
  <transition on="backToSearch" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="resetForReturnedSearch" />
  </transition>
  <transition on="reviewSelections" to="createReviewSelections">
   <action bean="sampleEventCreateFormAction"
    method="reviewSelections" />
  </transition>
 </view-state>

 <view-state id="createReviewSelections"
  view="/sampleevent/createReviewSelections.xhtml">
  <transition on="modifySelections" to="createSearchResults" />
  <transition on="saveSelections" to="createSuccess">
   <action bean="sampleEventCreateFormAction"
    method="saveSelections" />
  </transition>
 </view-state>

 <view-state id="createSuccess"
  view="/sampleevent/createSuccess.xhtml">
  <transition on="addMoreItems" to="createSearchItems">
   <action bean="sampleEventCreateFormAction"
    method="resetForReturnedSearch" />
  </transition>
 </view-state>

 <!-- edit event -->
 <view-state id="editSelectSampleEvent"
  view="/sampleevent/editSelectSampleEvent.xhtml">
  <transition on="submitSelectedSampleEvent"
   to="displayOperationOptions">
   <action bean="sampleEventEditFormAction"
    method="setSelectedSampleEvent" />
  </transition>
 </view-state>

 <view-state id="displayOperationOptions"
  view="/sampleevent/editOperationOptions.xhtml">
  <transition on="editSavedItems" to="displaySavedItems">
   <action bean="sampleEventEditFormAction"
    method="searchSavedItems" />
  </transition>
  <transition on="addOtherItems" to="editAddOtherItems">
  </transition>
  <transition on="backToEditSampleEventSearchResults"
   to="editSelectSampleEvent">
  </transition>

 </view-state>

 <!-- add new items -->
 <view-state id="editAddOtherItems"
  view="/sampleevent/editAddOtherItems.xhtml">
  <transition on="search" to="editOtherItemsResults">
   <action bean="sampleEventEditFormAction"
    method="searchOtherItems" />
  </transition>
  <transition on="addManufacturers" to="editAddOtherItems">
   <action bean="sampleEventEditFormAction"
    method="addManufacturers" />
  </transition>
  <transition on="removeManufacturers" to="editAddOtherItems">
   <action bean="sampleEventEditFormAction"
    method="removeManufacturers" />
  </transition>
  <transition on="addItemModelAlias" to="createSearchItems">
   <action bean="sampleEventEditFormAction"
    method="addItemModelAlias" />
  </transition>
  <transition on="removeItemModelAlias" to="createSearchItems">
   <action bean="sampleEventEditFormAction"
    method="removeItemModelAlias" />
  </transition>
 </view-state>

 <view-state id="editOtherItemsResults"
  view="/sampleevent/editOtherItemsResults.xhtml">
  <transition on="reviewSelections"
   to="editReviewOtherItemSelections">

  </transition>
 </view-state>

 <view-state id="editReviewOtherItemSelections"
  view="/sampleevent/editReviewOtherItemSelections.xhtml">
  <transition on="modifySelections" to="editOtherItemsResults" />
  <transition on="saveSelections" to="editSuccessSaveOthers">
   <action bean="sampleEventEditFormAction"
    method="saveOtherSelections" />
  </transition>
 </view-state>

 <view-state id="editSuccessSaveOthers"
  view="/sampleevent/editSuccessSaveOthers.xhtml">
  <transition on="backToOperationOptions"
   to="displayOperationOptions" />
 </view-state>

 <!-- remove saved items -->
 <view-state id="displaySavedItems"
  view="/sampleevent/editDisplaySavedItems.xhtml">
  <transition on="reviewDeSelections" to="reviewDeSelections">
   <action bean="sampleEventEditFormAction"
    method="reviewDeSelections" />
  </transition>
 </view-state>

 <view-state id="reviewDeSelections"
  view="/sampleevent/editReviewDeSelections.xhtml">
  <transition on="modifySelections" to="displaySavedItems" />
  <transition on="saveDeSelections"
   to="editSuccessDeSelections">
   <action bean="sampleEventEditFormAction"
    method="saveDeSelections" />
  </transition>
 </view-state>

 <view-state id="editSuccessDeSelections"
  view="/sampleevent/editSuccessDeSelections.xhtml">
  <transition on="backToOperationOptions"
   to="displayOperationOptions" />
 </view-state>


 <!-- Cancel/close/Reactive Item Event -->
 <view-state id="adminSampleEvent"
  view="/sampleevent/adminChooseType.xhtml">
  <transition on="submitAdminSelection" to="adminSearchResults">
   <action bean="sampleEventAdminFormAction"
    method="searchSampleEvents" />
  </transition>
 </view-state>

 <view-state id="adminSearchResults"
  view="/sampleevent/adminSearchResults.xhtml">
  <transition on="reviewSelections" to="adminReviewSelections">

  </transition>
 </view-state>

 <view-state id="adminReviewSelections"
  view="/sampleevent/adminReviewSelections.xhtml">
  <render-actions>
   <action bean="sampleEventAdminFormAction"
    method="reviewUpdates" />
  </render-actions>
  <transition on="modifySelections" to="adminSearchResults" />
  <transition on="saveSelections" to="adminSuccess">
   <action bean="sampleEventAdminFormAction"
    method="saveSelections" />
  </transition>
 </view-state>

 <view-state id="adminSuccess"
  view="/sampleevent/adminSuccess.xhtml">
 </view-state>

 <!-- View Completed Events -->
 <view-state id="viewSampleEvent"
  view="/sampleevent/viewSearchCriteria.xhtml">
  <transition on="searchSampleEvents"
   to="viewDecideShowSearchResults">
   <action bean="sampleEventViewFormAction"
    method="searchSampleEvents" />
  </transition>
 </view-state>

 <decision-state id="viewDecideShowSearchResults">
  <if
   test="${flowScope.sampleEventViewForm.numberOfSampleEvents == 1}"
   then="viewInfoForSingleSampleEvent"
   else="viewSampleEventSearchResults" />
 </decision-state>

 <!-- when searching returns only one event -->
 <view-state id="viewInfoForSingleSampleEvent"
  view="/sampleevent/viewInfoForSampleEventID.xhtml">
  <transition on="searchItems" to="viewItemsForSampleEventID">
   <action bean="sampleEventViewFormAction"
    method="searchItemsForSelectedSampleEventId" />
  </transition>
  <transition on="backToMenuAction" to="menuAction" />
 </view-state>

 <!-- when user clicks on the ID of event which is a link -->
 <view-state id="viewInfoForSampleEventLinkID"
  view="/sampleevent/viewInfoForSampleEventID.xhtml">
  <transition on="searchItems" to="viewItemsForSampleEventID">
   <action bean="sampleEventViewFormAction"
    method="searchItemsForSelectedSampleEventId" />
  </transition>
  <transition on="backToMenuAction" to="menuAction" />
 </view-state>

 <view-state id="viewItemsForSampleEventID"
  view="/sampleevent/viewItemsForSampleEventID.xhtml">
  <transition on="backToMenuAction" to="menuAction" />
 </view-state>

 <view-state id="viewSampleEventSearchResults"
  view="/sampleevent/viewSampleEventSearchResults.xhtml">
  <transition on="viewInfoForSampleEventLinkID"
   to="viewInfoForSampleEventLinkID">
   <action bean="sampleEventViewFormAction"
    method="searchSampleEventForLinkID" />
  </transition>
 </view-state>

 <end-state id="restart" view="flowRedirect:sampleEvent-flow">
 </end-state>

 <global-transitions>
  <transition on="cancel" to="restart" />
 </global-transitions>

 <import resource="sampleEvent-beans.xml" />

</flow>

The Sample Bean File

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 <bean id="sampleEventCreateFormAction"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventCreateFormAction"
  init-method="init">
  <property name="formObjectClass"
   value="com.mycompany.myapp.server.webflow.sampleevent.SampleEventCreateForm" />
  <property name="formObjectName" value="sampleEventCreateForm" />
  <property name="formObjectScope" value="FLOW" />
  <property name="propertyEditorRegistrar">
   <bean
    class="com.mycompany.myapp.server.web.jsf.CommonPropertyEditorRegistrar" />
  </property>
  <property name="sampleEventBo">
   <ref bean="sampleEventBo" />
  </property>
 </bean>

 <bean id="sampleEventEditFormAction"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventEditFormAction"
  init-method="init">
  <property name="formObjectClass"
   value="com.mycompany.myapp.server.webflow.sampleevent.SampleEventEditForm" />
  <property name="formObjectName" value="sampleEventEditForm" />
  <property name="formObjectScope" value="FLOW" />
  <property name="propertyEditorRegistrar">
   <bean
    class="com.mycompany.myapp.server.web.jsf.CommonPropertyEditorRegistrar" />
  </property>
  <property name="sampleEventBo">
   <ref bean="sampleEventBo" />
  </property>
 </bean>

 <bean id="sampleEventAdminFormAction"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventAdminFormAction"
  init-method="init">
  <property name="formObjectClass"
   value="com.mycompany.myapp.server.webflow.sampleevent.SampleEventAdminForm" />
  <property name="formObjectName" value="sampleEventAdminForm" />
  <property name="formObjectScope" value="FLOW" />
  <property name="propertyEditorRegistrar">
   <bean
    class="com.mycompany.myapp.server.web.jsf.CommonPropertyEditorRegistrar" />
  </property>
  <property name="sampleEventBo">
   <ref bean="sampleEventBo" />
  </property>
 </bean>

 <bean id="sampleEventViewFormAction"
  class="com.mycompany.myapp.server.webflow.sampleevent.SampleEventViewFormAction"
  init-method="init">
  <property name="formObjectClass"
   value="com.mycompany.myapp.server.webflow.sampleevent.SampleEventViewForm" />
  <property name="formObjectName" value="sampleEventViewForm" />
  <property name="formObjectScope" value="FLOW" />
  <property name="propertyEditorRegistrar">
   <bean
    class="com.mycompany.myapp.server.web.jsf.CommonPropertyEditorRegistrar" />
  </property>
  <property name="sampleEventBo">
   <ref bean="sampleEventBo" />
  </property>
 </bean>

</beans>