Hello,

I've successfully added orchestra to my Faces web applications, using
MyFaces 1.2.2, Facelets and JBoss RichFaces. Normal Ajax operations
with a4j:commandButton and the likes work as they should, but the
rich:datascroller does not.

I have created a custom ExtendedDataModel for a rich:datatable, using
Hibernate, based on what I found on the JBoss forums. I added this
datamodel as a bean in conversation scope. Now, when I open the page
in two browser windows it seems as if the datascroller is using the
model in session scope, because when scrolling in one window, the
selected range in the other window is also updated.

Here is the spring configuration for my datamodel bean:

<bean id="personDataModel"
class="org.edoframework.dev.orchestra.view.handler.PersonTableDataModel"
scope="conversation.access" orchestra:conversationName="personView">
     <property name="repository" ref="personDao" />
</bean>


My xhtml page:

<h:form>
   <rich:messages />
   <a4j:outputPanel id="table">
     <h:outputText value="#{personCrud.conversationName}" />
   <rich:dataTable id="personTableModel" value="#{personDataModel}"
    var="person" rows="10" width="100%">
    <rich:column>
     <f:facet name="header">
      <h:outputText value="Name" />
     </f:facet>
     <h:outputText value="#{person.name}" />
    </rich:column>
    <rich:column>
     <f:facet name="header">
      <h:outputText value="First Name" />
     </f:facet>
     <h:outputText value="#{person.firstname}" />
    </rich:column>
    <f:facet name="footer">
     <rich:datascroller  />
    </f:facet>
   </rich:dataTable>
   </a4j:outputPanel>
  </h:form>

My datamodel bean:


package org.edoframework.dev.orchestra.view.handler;

import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.ajax4jsf.model.SequenceRange;

import org.edoframework.domainmodel.Identifiable;

import java.io.IOException;
import java.io.Serializable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;


/**
 * DataModel for displaying persistent objects in RichFaces datatables.
 *
 * @author Jurgen Lust
 * @author $LastChangedBy$
 *
 * @version $LastChangedRevision$
 *
 * @param <T> The type of persistent object
 * @param <ID> The type of the Id
 */
public abstract class GenericPersistentTableDataModel<T extends
Identifiable, ID extends Serializable>
        extends ExtendedDataModel {
    //~ Instance fields --------------------------------------------------------

    public List<T> listRow;
    int rowNum = -1;
    private ID currentId;
    private List<ID> wrappedKeys;
    private Map<ID, T> wrappedData = new HashMap<ID, T>();

    //~ Methods ----------------------------------------------------------------

    public int getRowNum() {
        return ++rowNum;
    }

    public abstract Long getCount();

    public abstract List<T> getList(
        final Integer firstRow,
        final Integer maxResults
    );

    private List<T> loadList(
        final Integer firstRow,
        final Integer maxResults
    ) {
        return listRow = getList(firstRow, maxResults);
    }

    public abstract T findById(final ID id);

    @SuppressWarnings("unchecked")
    public ID getId(final T row) {
        ID id = (ID) row.getIdentity();

        return id;
    }

    public void wrap(
        final FacesContext context,
        final DataVisitor visitor,
        final Range range,
        final Object argument,
        final List<T> list
    )
            throws IOException {
        wrappedKeys = new ArrayList<ID>();
        wrappedData = new HashMap<ID, T>();

        for (final T row : list) {
            ID id = getId(row);
            wrappedKeys.add(id);
            wrappedData.put(id, row);
            visitor.process(context, id, argument);
        }
    }

    public boolean hasById(final ID id) {
        for (final T row : listRow) {
            ID rowId = getId(row);

            if (rowId.equals(id)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public void walk(
        final FacesContext context,
        final DataVisitor visitor,
        final Range range,
        final Object argument
    )
            throws IOException {
        int firstRow = ((SequenceRange) range).getFirstRow();
        int maxResults = ((SequenceRange) range).getRows();
        wrap(context, visitor, range, argument, loadList(firstRow, maxResults));
    }

    /*
     * This method normally called by Visitor before request Data Row.
     */
    @Override
    @SuppressWarnings("unchecked")
    public void setRowKey(final Object key) {
        this.currentId = (ID) key;
    }

    @Override
    public int getRowCount() {
        return this.getCount().intValue();
    }

    @Override
    public boolean isRowAvailable() {
        if (currentId == null) {
            return false;
        } else {
            return hasById(currentId);
        }
    }

    /**
     * This is main way to obtain data row. It is intensively used by framework.
     * We strongly recommend use of local cache in that method.
     */
    @Override
    public Object getRowData() {
        if (currentId == null) {
            return null;
        } else {
            T ret = wrappedData.get(currentId);

            if (ret == null) {
                ret = this.findById(currentId);
                wrappedData.put(currentId, ret);

                return ret;
            } else {
                return ret;
            }
        }
    }

    // Unused rudiment from old JSF staff.
    @Override
    public int getRowIndex() {
        return 0;
    }

    @Override
    public void setRowIndex(final int rowIndex) {}

    @Override
    public Object getWrappedData() {
        return this;
    }

    @Override
    public void setWrappedData(final Object data) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object getRowKey() {
        return currentId;
    }
}


Jurgen

Reply via email to