Container Confusion

Hi,
I’m new to Vaadin, having come from ZK, and am struggling with the Container concept. I’ve read the Tutorials, searched the site, and looked at some addon source code, but still don’t understand some things.

My goal is to build a CSV Container that can read CSV data. I’ve already got a class [CSVReader]
that takes care of all the details. It returns each line of the CSV as an array of String. Not fancy but it works.

OK, what I understand about Containers so far:

  1. Containers provide the data model to a range of components, e.g. Table, Select, ComboBox, etc.
  2. The BeanItemContainer works fabulously with lists of beans.
  3. additem() - No parameters confuses the hell out of me.
  4. addItem(Object obj) - Adds an entire ROW of data OR creates an empty row with ‘obj’ as the ‘index’. Not sure which.
  5. Each Item which is returned by addItem(Object id) is the parent of a set of ‘Property’ objects that make up the individual columns of the table, for example.

My assumptions are as follows:

  • Containers are like Models in ZK
  • Containers need some form of Rendering code “attached” to represent the data model to the parent class
  • addItem adds a whole row of data, or if it has a parameter, the parameter is the index/key value and the returned Item is the empty row, which needs data added. See Line #129 in the code


I get an exception trying to add properties to the returned Item, which does not make sense according to what I understand so far. If this is not the correct way, how to I tell the parent component to handle the String[] (in this case) data?

Here is my code so far:


package com.chm.upload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import net.flowspace.utils.CSVReader;

import com.vaadin.data.Container.ItemSetChangeNotifier;
import com.vaadin.data.Container.PropertySetChangeNotifier;
import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Label;



@SuppressWarnings("serial")
public class CSVContainer extends IndexedContainer
                          implements PropertySetChangeNotifier,
                                     ItemSetChangeNotifier
   {
   
   private CSVReader reader = null ;

   
   public CSVContainer(String csvFile) throws FileNotFoundException
      {
      if (null != csvFile)
         {
         reader = new CSVReader (csvFile) ;
         
         processFile () ;
         }
      
      }





   public CSVContainer(String csvFile, boolean hasHeader) throws FileNotFoundException
   {
   if (null != csvFile)
      {
      reader = new CSVReader (csvFile, hasHeader) ;
      
      processFile () ;
      }
   
   }





   public CSVContainer(File csvFile) throws FileNotFoundException
      {
      if (null != csvFile)
         {
         reader = new CSVReader (csvFile.getAbsolutePath()) ;
         
         processFile () ;
         }
         
      }



   
   
   public CSVContainer(File csvFile, boolean hasHeader) throws FileNotFoundException
   {
   if (null != csvFile)
      {
      reader = new CSVReader (csvFile.getAbsolutePath(), hasHeader) ;
      
      processFile () ;
      }
      
   }



   
   private void processFile ()
      {
      boolean headerPresent = reader.hasHeader() ; 

      if (null != reader)
         {
         int headerSize = 0 ;


         if (headerPresent)
            {
            for (String hdr : reader.getHeader())
               {
               addContainerProperty (hdr, String.class, "") ;
               headerSize++ ;
               }
            
            }
         
         
         String[] row;
         
         try
            {
            row = reader.readNext();
            
            // SpecialOffer! One time Only! We'll build a custom header for you!
            if (! headerPresent && null != row && row.length > 0)
               for (int ctr = 1 ; ctr <= row.length ; ctr++ )
                   {
                   addContainerProperty ("col" + ctr, String.class, "") ;
                   headerSize++ ;
                   }
               

            int ctr = 1 ;

            while (null != row)
               {
               Item item = addItem (ctr) ;
               
               for (int id = 0 ; id < headerSize ; id++)
                   {
                   item.addItemProperty(id, new Label(row[id]
) ) ;    //BUG Generates an exception saying cannot add properties to an IndexedContainer!!???
                   System.out.print(row[id]
 + " | ") ;
                   }
               System.out.println (); 

               row = reader.readNext() ;
               ctr++ ;
               }

            reader.close() ;
            }
         catch (IOException e)
            {
            e.printStackTrace();
            }
         
         }  // null != reader

      showContents () ;
      }    // eof: processFile
   
   
   
   private void showContents()
      {
      System.out.println (this.size() + " items in container\n") ;
      

      for (Object id : getAllItemIds())
         {
         System.out.println ("Item: " + id + " = " + getItem(id) + " [" + getItem(id).getClass().getCanonicalName() + "]
") ;
         }
      
      }
   }   //eof: CSVContainer class

The
showContents
method is there for testing purposes to see if the data is stored correctly.

What I am getting right now, is the columns correctly set, if the list has headers, it reads the correct values into the table, or if none present it correctly adds col1…colN depending on the length of the first row. Which also works fine.

However, for the rows, I’m getting a series of lines in the table, one for each row, but no data showing.

I can’t seem to find a rendering process, like I’ve used in ZK for example. The Property.Viewer interface is unclear if that is the way to solve this.

Sorry if my post is vague but I really am confused, esp. around my assumptions on addItem and how to “paint” the row data.
Thanks in advance,
Anthony

I believe I’ve solved this- but I would welcome confirmation I’ve got the gist of this correct:

The code [line 123-136]
:

should be changed to:


       while (null != row)
               {
               Item item = addItem (ctr) ;

               int id = 0 ;

               for (Object ip : item.getItemPropertyIds())
                  {
                  Property prop = item.getItemProperty(ip) ;
                  prop.setValue(new Label (row[id]
) ) ;
                  id++ ;
                  }

               row = reader.readNext() ;
               ctr++ ;
               }

The problem that confused me was that the “language” Vaadin uses around Containers is different from the Java Collection Framework and the expectations of treating the Container like a matrix, e.g. spreadsheet which the documentation implies.

The addItem() with no parameters creates an empty item (row) and returns the item ID (key or “index”). You can set the item properties with getItem(itemId).getItemProperty(“pid”).setValue(foo). In the container implementation, you can have custom item and property types that wrap around your internal data representation.

The addItem(Object id) aso creates an empty item (row), but takes the item ID as the parameter. The parameter object
is not the item
. Well, not normally. To confure you even more, in some containers, such as in BeanItemContainer, the bean object itself is used as the item ID. Also, Table has addItem(Object) helper method which takes an array of property values to initialize the item.

I hope this clarifies a bit.

Thank you Marko. I’m getting there. I still find the syntax of the Containers, especially IndexedContainer a bit weird, but other than that I find Vaadin very clean in design of the APIs.

Thanks for the replies, one more question:

How do I get items out of the Container?

I’m currently using an IndexedContainer to fill in a table and I would like to use the same data to populate a graph (Invient Charts).

I’m really not clear to hot process the contents of the container.

It is possible to add by index (addItemAt) but there is no getItemAt ???

Also, the only method that seems to return an Item is getUnfilteredItem (Object itemID). Is the itemID the text column name I used in filling the list, or is it the internal ID created by the container, if it is the internal ID how do I get it?

Is there no simple way to get a list of Items in the container?
Thanks in advance,
Anthony

There is more about this in the
Book of Vaadin
and many other forum threads etc.

You get an item out with getItem(itemId).

The addItem(Object) method uses the parameter as an explicit identifier and returns the Item, whereas e.g. addItem() generates and returns an identifier - this is all explained in the javadoc for each method.

You can get a list of item IDs with getItemIds(), but there is no method for getting a list of the items. This is intentional - it would be a bad idea to have such a method if you have e.g. a lazy loading container with hundreds of thousands of items.

The interface Container.Indexed implements getIdByIndex(int), so you can use container.getItem(container.getIdByIndex(123)). Many container implementations such as IndexedContainer implement this interface.

The method getUnfilteredItem() is for internal use by container implementations.

Thanks Henri,
I finally got my head around it before I saw your post. I understand the lazy loading issues.

I suppose what has been hard to grasp is the naming conventions chosen, they are not like any others, e.g. Java Collection Frameworks, etc.

I’ve seen the “Data Model” section in the Book of Vaadin, but frankly it does not explain this very well. Some concrete examples of some of the standard containers would help a lot. I’ll happily provide them, based on what I’ve learned, if you’ll let me know where to submit them.

Thanks for clearing that up. I’m still not 100% comfortable with the API design, but at least I can get what I want done.
Regards,
Anthony