UICellSetTable, Initial Design

Monday, November 28, 2011

The class UICellSetTable will implement the renderer independent part of the cellSetTable Facelet tag. Extends from UIComponentBase and implements NamingContainer.

It must have three children components, one for each cellSetTable area (column axis, row axis and data cells). This class specializes the processDecodes(), processValidators() and processUpdates() methods to call setCurrentArea to establish de proper area before calling the corresponding method on each children.

This class also specializes getClientId to create area independent identifiers for child controls. It specializes queueEvent to wrap any bubbled up event with a wrapper event identifying the area where the event was produced. Specializes broadcastEvent to unwrap any wrapped event and set the current area before dispatching it.

The classes UICellSetAxis and UICellSetCells will implement the renderer independent part of the children of UICellSetTable: the former will implement the components for both query axis (rows and columns) and the later will implement the table of data cells.

Both classes have a setCellIndex method that parallel the setRowIndex method of the standard component UIData; saves the state of the current cell and sets the cell (i,j)  as the current cell. The meaning of cell depends on the component class:

·         For UICellSetCells it’s the CellSet data cell cs.getCell(Arrays.asList(j,i)), where cs is the CellSet bound to the component.

·         For UICellSetAxis it’s the i-esim member at position j csa.getPositions().get(i).getMembers().get(j) where csa is the CellSetAxis instance bound to the component.

As the UIData component these classes specialize the processDecodes, processValidators and processUpdates to iterate over every cell in its bound data set and call setCellIndex before call the corresponding method on its children.

So, our Facelet sample in the previous post must be slightly modified to fit into this design

<olap:cellSetTable value=”…”>

  <olap:cellSetAxis for=”columns” var=”m”>

    <f:facet name=”header”>

     

    </f:facet>

   

  </olap:cellSetAxis>

  <olap:cellSetAxis for=”rows” var=”m”>

    <f:facet name=”header”>

   

    </f:facet>

   

  </olap:cellSetAxis>

  <olap:cellSetCells var=”cell”>

   

  </olap:cellSetCells>

</olap:cellSetTable>

The cellSetTable Facelet tag

Friday, November 25, 2011

This tag renders an org.olap4j.CellSet instance. It mimics someway the behavior of <h:dataTable>: provides the main structure for displaying the CellSet and allows the page designer to specify the contents for each part of the table.

The tag’s structure is as follows:

<olap:cellSet value=”…” var=”cell”>

  <olap:columnAxis>

    <f:facet name=”header”>

      <!—

        This content is rendered in the headers

        of the column axis dimensions

      -->

    </f:facet>

    <!—

      This content is rendered in the members

      of the column axis dimensions

    -->

  </olap:columnAxis>

  <olap:rowAxis>

    <f:facet name=”header”>

      <!—

        This content is rendered in the headers

        of the row axis dimensions

      -->

    </f:facet>

    <!—

      This content is rendered in the members

      of the row axis dimensions

    -->

  </olap:columnAxis>

  <olap:dataCell>

  <!—

    This content is rendered in the cells

    of the CellSet

  -->

  </olap:dataCell>

</olap:cellSet>



This markup would produce the following HTML table, where the background color of the cell identifies the markup piece used to generate its content


Region
USA
Canada
Measures
Gender
Promotions
Unit Sales
Store Cost
Unit Sales
StoreCost
Male
TV Spot
0
0
0
0
Newspaper Ad
0
0
0
0
Female
TV Spot
0
0
0
0
Newspaper Ad
0
0
0
0



The var attribute in the cellSetTable tag allows the page to use its value as a variable in EL expressions used within the children of the cellSetTable. This variable will refer to an instance of the CellSetItemInfo interface defined as follows:

interface CellSetItemInfo {

  public Hierarchy getHierarchy();

  public Member getMember();

  public List<Member> getPosition();

  public Cell getData()

  public Axis getAxis();

}



The following table shows, for each property of this instance, he areas of the table where such a property is non-null

axis
hierarchy
position
member
cell




























The code below shows a simple example for a <olap:cellSetTable>

<olap:cellSetTable value=”#{olapSample.cellSet}” var=”cell”>

  <olap:columnAxis>

    <f:facet name=”header>

      <h:outputText value=”#{cell.hierarchy.caption}”/>

    </f:facet>

    <h:outputText value=”#{cell.member.caption}”/>

  </olap:columnAxis>

  <olap:rowAxis>

    <f:facet name=”header>

      <h:outputText value=”#{cell.hierarchy.caption}”/>

    </f:facet>

    <h:outputText value=”#{cell.member.caption}”/>

  </olap:rowAxis>

  <olap:dataCell>

    <h:outputText value=”#{cell.data.formattedValue}”/>

  </olap:dataCell>

</olap:cellSetTable>



The managed bean providing the CellSet would have the following structure.

@ManagedBean

@RequestScoped

public OlapSample {

  private OlapConnection cn;



  @PostConstruct

  public void init() {

    Connection jdbcCn = DriverManager.getConnection(“The olap4j connection string goes here”);

    cn = jdbcCn.unwrap(OlapConnection.class);

  }



  @PreDestroy

  public void tearDown() {

    if ( cn != null )

      cn.close();

  }



  public CellSet getCellSet() {

    return cn.createStatement().executeOlapQuery(“The MDX query goes here”);

  }

}

I use a RequestScoped in combination with @PostConstruct and @PreDestroy methods to open a connection to the olap4j server before any use of the bean, and close that connection once the request process lifecycle has ended.
In a real-world example the connection can be retrieved lazily, and we can store the resulting CellSet in a field to avoid executing the same query several times within the same request.

Antecedentes

Friday, November 18, 2011
Mi primer contacto con el lado Open Source de BI (ya había participado anteriormente en un proyecto con SAP BI) ha sido supervisando una implantación de Pentaho. Así que, cuando me enfrente al desarrollo de una pequeña utilidad que requería de funcionalidades BI, decidí utilizar algunos de los componentes básicos de esta suite. En concreto Mondrian como motor OLAP y JPivot para la representación de los datos.
Mientras que Mondrian me pareció muy sencillo de integrar, JPivot lo encontré bastante más engorroso y poco flexible y me puse a buscar alternativas. Dado que en ese mismo momento estaba esperimentando con la versión 2.0 de JSF, intenté encontrar alguna biblioteca de componentes JSF que proporcionase una funcionalidad similar a la de JPivot.
No la encontré y posteriormente el desarrollo de la citada utilidad acabó cancelándose.
De todos modos, personalmente la idea de tal bibloteca de componentes me parecía interesante y una buena forma de aprender el desarrollo de componentes JSF personalizados.Lo que me terminó por dar el empujon definitivo fue la liberación de la versión 1.0 de olap4j.
La idea de unos componentes de visualización BI, conectables a diversos proveedores OLAP mediante una interfase estandarizada (olap4j), y que pudiesen integrarse en un marco de desarrollo de Web tambien estandar (JSF 2.0) con solo añadir un archivo .jar al classpath del proyecto, cada vez me resultaba más atractiva.

Background

I initially got in touch with Open Source BI while managing a Pentaho deployment (previously I was involved in another project using SAP BI). So when I faced the development of a small utility requiring BI functionallity, I choose to use some of the foundations of this BI suite. Specifically Mondrian as the OLAP engine and JPivot for data visualization.
While Mondrian seemed very easy to integrate, JPivot was quite more cumbersome and unwieldy so I started looking for alternatives. I was experimenting with version 2.0 of JSF, at that moment, so I tried to find a JSF components library to provide JPivot like functionality.
I could not find it, and the utility development was finally cancelled.
Anyway, personally, the idea of such a component library seemed appealing, and was a nice path to learn about JSF custom components development. For me, the finall push was the release of version 1.0 of olap4j.
The vision of a suite of BI presentation-tier components, pluggable to several OLAP providers using an standarized interface (olap4j), and tha could be integrated into an also standard Web framework (JSF 2.0), by just dropping a .jar file into the project's classpath attracted me more and more.