I’m trying to construct an app by OpenJPA, Spring and Vaadin. I’ve got a table I want to show. Source data is a pretty straightforward domain object behing a service layer. My database table has maybe 40k rows.
I can create a container for my table real easily, using new IndexedContainer (Collection allRowIds). But where do I insert my code of fetching the actual data from the database?
Reading from the Vaadin source code, I would probably have to use setProperty(Object value) at some point for my properties, but when? Where is the spot I should be inserting my getDataForObjectWithThisId™ method?
IndexedContainer stores data in memory - so you would have to copy all the row data to the container.
With 40k rows you might want to consider creating a container implementation of your own - one that would load data from database on lazily when needed. This can be done by implementing Container.Indexed. With that implemented you can bind it easily to Table with setContainerDataSource().
Thanks for the response. I’ve been toying around with creating a custom Container, now I’ll have to really concentrate on it. Hopefully I can create a generic class that will work with other domain objects as well. Should be doable.
I am somewhat surprised that the ready containers don’t support a SOA (Service Oriented Architecture) better, I would have thought that it’s the most common Java EE architecture used nowadays. I’ve got a project team that’s somewhat discouraged with Vaadin after the initial excitement: Our first user story to implement was simply to list users and relevant information from our database. A table seemed appropriate and on day 2 we face a need to create a custom Container which appears to be one of the most difficult tasks of Vaadin.
Hopefully I can still turn their heads around from looking back at JSP… at least they’ll appreciate the paging capability of Table. Sorting, filtering and such will have to be done at a lower level, I guess. Since the objects will be loaded lazily, the Table naturally can’t do the tricks by itself.
There are quite a few container implementations and widgets we would love add to Vaadin. Now after 6.0 we’ll start to focus on adding new components on top of the core framework.
I hope you give it a try. When you are not trying to create a 100% generic container implementation, you can create a container implementation without too much effort.
Sorting and filtering are usually done in the container. Please note that these are completely optional features. If you do not implement Container.Sortable, sorting just isn’t enabled in the table.
Hmm… I’ll have to take a further look at the sorting. We need the feature, but I don’t know yet how I’ll incorporate it into the container. Because of the size of the data, sorting has to be done with the database query, same as filtering. I guess I’ll have to look at that after I implement basic functionality.
My first attempt to create a custom container from scratch ended soon because there were so many methods to implement. I guess I had too many interfaces included in the class definition. I’ll try implementing just the very basics for the beginning, then see how sorting, filtering and other functionality changes the world.
Got it done. Following code provides Club items to a table. Hopefully it initializes them lazily, I expect that getItem() and getContainerProperty() will only be called when the item in question is actually viewed.
And on the plus side, the class is somewhat easier to grasp for other team members than trying to read the IndexedContainer source code. The amount of Collections contained in that class is pretty mind-boggling.
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.openjpa.util.UnsupportedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import com.mypackage.ClubService;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItem;
@Configurable
public class ClubContainer implements Container {
private static final long serialVersionUID = -7700331528296553114L;
private ArrayList<Object> propertyIds = new ArrayList<Object>();
private LinkedHashMap<Object, Object> items = new LinkedHashMap<Object, Object>();
@Autowired
private ClubService clubService;
public ClubContainer(List<Long> itemIds) {
for (Long id : itemIds) {
addItem(id);
}
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
if (propertyIds.contains(propertyId)) {
return false;
}
propertyIds.add(propertyId);
return true;
}
@Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
items.put(itemId, null);
return null;
}
@Override
public boolean containsId(Object itemId) {
return items.containsKey(itemId);
}
@Override
public Property getContainerProperty(Object itemId, Object propertyId) {
return ((BeanItem)getItem(itemId)).getItemProperty(propertyId);
}
@Override
public Collection<?> getContainerPropertyIds() {
return propertyIds;
}
@Override
public Item getItem(Object itemId) {
BeanItem item = (BeanItem)items.get(itemId);
if (item == null) {
item = new BeanItem(clubService.load((Long)itemId));
}
return item;
}
@Override
public Collection<?> getItemIds() {
return items.keySet();
}
@Override
public Class<?> getType(Object propertyId) {
return String.class;
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
items.clear();
return true;
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
throw new UnsupportedException();
}
@Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
items.remove(itemId);
return true;
}
@Override
public int size() {
return items.size();
}
}