org.shortbrain.vaadin.container.AbstractContainerFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.shortbrain.vaadin.container.AbstractContainerFactory.java

Source

/*
 * Copyright 2012 Vincent Demeester<vincent+shortbrain@demeester.fr>.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.shortbrain.vaadin.container;

import static org.shortbrain.vaadin.container.ContainerUtils.addContainerProperty;
import static org.shortbrain.vaadin.container.ContainerUtils.initContainer;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.shortbrain.vaadin.container.property.PropertyMetadata;
import org.shortbrain.vaadin.container.property.PropertyReaderAlgorithm;

import com.vaadin.data.Container;
import com.vaadin.data.Container.Filterable;
import com.vaadin.data.Container.Hierarchical;
import com.vaadin.data.Item;

/**
 * Default abstract implementation of {@link ContainerFactory}.
 * 
 * @author Vincent Demeester <vincent@demeester.fr>
 * 
 * @param <BEAN>
 *            type of the beans.
 */
public abstract class AbstractContainerFactory<BEAN> extends ContainerFactory<BEAN> {

    /**
     * Default BEAN property name.
     */
    private static final String DEFAULT_BEAN_PROPERTY = "bean";

    /**
     * Type of the bean.
     */
    private Class<? extends BEAN> beanClass;

    /**
     * The property reader algorithm.
     */
    private PropertyReaderAlgorithm propertyReaderAlgorithm;

    /**
     * The name of the property that holds the bean.
     */
    private String beanProperty = DEFAULT_BEAN_PROPERTY;

    /**
     * Creates an AbstractContainerFactory.
     * 
     * @param beanClass
     *            the type of BEAN.
     * @param propertyReaderAlgorithm
     *            the algorithm to be used to get properties.
     * @throws IllegalArgumentException
     *             if beanClass or propertyReaderAlgorithm are null.
     */
    public AbstractContainerFactory(Class<? extends BEAN> beanClass,
            PropertyReaderAlgorithm propertyReaderAlgorithm) {
        if (beanClass == null || propertyReaderAlgorithm == null) {
            throw new IllegalArgumentException("beanClass and propertyReaderAlgorithm cannot be null.");
        }
        this.beanClass = beanClass;
        this.propertyReaderAlgorithm = propertyReaderAlgorithm;
    }

    /**
     * {@inheritDoc}
     * 
     * If container is null, the default type will be {@link Filterable}
     */
    @Override
    public Container getContainerFromList(Container container, List<BEAN> beans) {
        return getContainerFromCollection(container, beans);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Container getContainerFromList(List<BEAN> beans, Class<? extends Container> containerClass) {
        return getContainerFromCollection(beans, containerClass);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Container getContainerFromList(Container container, List<BEAN> beans,
            Class<? extends Container> containerClass) {
        return getContainerFromCollection(container, beans, containerClass);
    }

    /**
     * {@inheritDoc}
     * 
     * If container is null, the default type will be {@link Filterable}
     */
    @Override
    public Container getContainerFromCollection(Container container, Collection<BEAN> beans) {
        Class<? extends Container> containerClass = (container != null) ? container.getClass() : Filterable.class;
        return getContainerFromCollection(container, beans, containerClass);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Container getContainerFromCollection(Collection<BEAN> beans, Class<? extends Container> containerClass) {
        return getContainerFromCollection(null, beans, containerClass);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Container getContainerFromCollection(Container container, Collection<BEAN> beans,
            Class<? extends Container> containerClass) {
        try {
            // Initialize the container if null
            if (container == null) {
                container = initContainer(containerClass);
            }
            // Property
            List<PropertyMetadata> properties = updateProperties(container);
            // Clean it
            if (container.removeAllItems()) {
                populateContainer(container, properties, beans);
            }
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
        }
        return container;
    }

    /**
     * Create or update properties of the given container.
     * 
     * @param container
     *            the container to be updated.
     */
    private List<PropertyMetadata> updateProperties(Container container) {
        List<PropertyMetadata> properties = propertyReaderAlgorithm.getProperties(beanClass);
        Collection<?> containerProperties = container.getContainerPropertyIds();
        for (PropertyMetadata property : properties) {
            if (!containerProperties.contains(property.getPropertyName())) {
                addContainerProperty(container, property);
            }
        }
        // Add a bean property at the end.
        addContainerProperty(container, getBeanProperty(), beanClass, null);
        return properties;
    }

    /**
     * Populate the given container with the list of BEAN.
     * 
     * There is a few different case to handle. An example is a
     * {@link Hierarchical} containers, that could have children, so this method
     * needs a way to identify the children, etc
     * 
     * Notes : the default behavior for now is to look for an attribute
     * <code>children</code> of the BEAN object. But in the future it will need
     * to support more flexible way to know how to handle specific case.
     * 
     * @param container
     *            the container to be populated.
     * @param properties
     *            the properties.
     * @param beans
     *            the list of beans.
     */
    private void populateContainer(Container container, List<PropertyMetadata> properties, Collection<BEAN> beans) {
        if (beans != null) {
            if (container instanceof Hierarchical) {
                for (BEAN bean : beans) {
                    addHierarchicalItem((Hierarchical) container, properties, bean, null);
                }
            } else {
                for (BEAN bean : beans) {
                    addItem(container, properties, bean, true);
                }
            }
        }
    }

    /**
     * Add an item (using bean) to the container, and look for
     * <code>children</code> if needed.
     * 
     * @param container
     *            the container.
     * @param properties
     *            the properties.
     * @param bean
     *            the bean to add.
     * @param introspect
     *            introspect for children.
     * @return the id of the added item
     */
    @SuppressWarnings("unchecked")
    protected Object addItem(Container container, List<PropertyMetadata> properties, BEAN bean,
            boolean introspect) {
        Object itemId = container.addItem();
        for (PropertyMetadata metadata : properties) {
            String propertyId = metadata.getPropertyName();
            Object value = null;
            try {
                value = PropertyUtils.getProperty(bean, metadata.getPropertyAttribute());
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            container.getContainerProperty(itemId, propertyId).setValue(value);
        }
        // At the end, add the bean to the container (just in case)
        container.getContainerProperty(itemId, getBeanProperty()).setValue(bean);
        if (introspect) {
            Collection<BEAN> children;
            try {
                children = (Collection<BEAN>) PropertyUtils.getProperty(bean, "children");
                if (children != null && !children.isEmpty()) {
                    for (BEAN child : children) {
                        addItem(container, properties, child, introspect);
                    }
                }
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
            } catch (NoSuchMethodException e) {
                // TODO Auto-generated catch block
            } catch (RuntimeException e) {
                // FIXME This is evil (but I need this temporarly forhibernate
                // lazyInitialisation)
                // e.printStackTrace();
            }
        }
        return itemId;
    }

    /**
     * Add a hierarchical item (using bean) to the container.
     * 
     * @param container
     *            the container.
     * @param properties
     *            the properties.
     * @param bean
     *            the bean to add.
     * @param parentId
     *            the parent of the bean.
     */
    @SuppressWarnings("unchecked")
    protected void addHierarchicalItem(Hierarchical container, List<PropertyMetadata> properties, BEAN bean,
            Object parentId) {
        Object itemId = addItem(container, properties, bean, false);
        if (parentId != null) {
            // Parent id can have children.
            container.setChildrenAllowed(parentId, true);
            // Set the parent for the current id.
            container.setParent(itemId, parentId);
            // Set no children by default
            container.setChildrenAllowed(itemId, false);
        }
        Collection<BEAN> children;
        try {
            children = (Collection<BEAN>) PropertyUtils.getProperty(bean, "children");
            if (children != null && !children.isEmpty()) {
                for (BEAN child : children) {
                    addHierarchicalItem(container, properties, child, itemId);
                }
            }
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
        } catch (RuntimeException e) {
            // FIXME This is evil (but I need this temporarly forhibernate
            // lazyInitialisation)
            // e.printStackTrace();
        }
    }

    /**
     * Get the name of the bean property.
     * 
     * @return the name of the property that holds the bean
     */
    public String getBeanProperty() {
        return beanProperty;
    }

    /**
     * {@inheritDoc}
     */
    public void setBeanProperty(String name) {
        if (beanProperty == null || beanProperty.equals("")) {
            this.beanProperty = DEFAULT_BEAN_PROPERTY;
        } else {
            this.beanProperty = name;
        }
    }

    @Override
    public Item newItem(BEAN bean) {
        return null;
    }

}