View Javadoc

1   package org.shortbrain.vaadin.container;
2   
3   import java.io.InvalidClassException;
4   import java.lang.reflect.Constructor;
5   import java.lang.reflect.InvocationTargetException;
6   import java.util.Collection;
7   import java.util.List;
8   
9   import org.apache.commons.beanutils.ConstructorUtils;
10  import org.shortbrain.vaadin.container.property.PropertyMetadata;
11  import org.shortbrain.vaadin.container.property.PropertyReaderAlgorithm;
12  
13  import com.vaadin.data.Container;
14  import com.vaadin.data.Container.Filterable;
15  import com.vaadin.data.Container.Hierarchical;
16  import com.vaadin.data.util.AbstractBeanContainer;
17  import com.vaadin.data.util.AbstractBeanContainer.BeanIdResolver;
18  import com.vaadin.data.util.BeanContainer;
19  import com.vaadin.data.util.BeanItemContainer;
20  
21  import static org.shortbrain.vaadin.container.ContainerUtils.addContainerProperty;
22  
23  /**
24   * Default abstract implementation of {@link BeanContainerFactory}
25   * 
26   * @author Vincent Demeester <vincent@shortbrain.org>
27   * 
28   * @param <IDTYPE>
29   *            The type of the item identifier
30   * @param <BEANTYPE>
31   *            The type of the Bean
32   * @since 0.2.0
33   * 
34   * @see BeanContainerFactory
35   */
36  @SuppressWarnings({ "rawtypes", "unchecked" })
37  public abstract class AbstractBeanContainerFactory<IDTYPE, BEANTYPE> extends BeanContainerFactory<IDTYPE, BEANTYPE> {
38  
39      /**
40       * Type of the bean.
41       */
42      private final Class<? super BEANTYPE> beanClass;
43  
44      private Constructor<? extends AbstractBeanContainer> containerConstructor;
45  
46      private String propertyId;
47  
48      private BeanIdResolver<IDTYPE, BEANTYPE> beanIdResolver;
49  
50      /**
51       * The property reader algorithm.
52       */
53      private final PropertyReaderAlgorithm propertyReaderAlgorithm;
54  
55      /**
56       * Create an {@link AbstractBeanContainerFactory}.
57       * 
58       * @param beanClass
59       *            the type of the Bean.
60       * @param propertyReaderAlgorithm
61       *            the algorithm to be used to get properties.
62       * @param beanContainerType
63       *            the type of beanContainer to instantiate
64       * @param propertyId
65       *            the identifier of the property to use to find item identifiers.
66       */
67      public AbstractBeanContainerFactory(Class<? super BEANTYPE> beanClass,
68              PropertyReaderAlgorithm propertyReaderAlgorithm, Class<? extends AbstractBeanContainer> beanContainerType,
69              String propertyId) {
70          this(beanClass, propertyReaderAlgorithm, beanContainerType, propertyId, null);
71      }
72  
73      /**
74       * Create an {@link AbstractBeanContainerFactory}.
75       * 
76       * @param beanClass
77       *            the type of the Bean.
78       * @param propertyReaderAlgorithm
79       *            the algorithm to be used to get properties.
80       * @param beanContainerType
81       *            the type of beanContainer to instantiate.
82       * @param beanIdResolver
83       *            the beanIdResolver to use to find item identifier.
84       */
85      public AbstractBeanContainerFactory(Class<? super BEANTYPE> beanClass,
86              PropertyReaderAlgorithm propertyReaderAlgorithm, Class<? extends AbstractBeanContainer> beanContainerType,
87              BeanIdResolver<IDTYPE, BEANTYPE> beanIdResolver) {
88          this(beanClass, propertyReaderAlgorithm, beanContainerType, null, beanIdResolver);
89      }
90  
91      /**
92       * Create an {@link AbstractBeanContainerFactory}.
93       * 
94       * This is a private constructor to be used by the others.
95       * 
96       * @param beanClass
97       *            the type of the Bean.
98       * @param propertyReaderAlgorithm
99       *            the algorithm to be used to get properties.
100      * @param beanContainerType
101      *            the type of beanContainer to instantiate.
102      * @param propertyId
103      *            the identifier of the property to use to find item identifiers.
104      * @param beanIdResolver
105      *            the beanIdResolver to use to find item identifier.
106      * @param beanBuilder
107      *            the hierarchical beanBuilder to use to build a {@link Hierarchical}
108      */
109     private AbstractBeanContainerFactory(Class<? super BEANTYPE> beanClass,
110             PropertyReaderAlgorithm propertyReaderAlgorithm, Class<? extends AbstractBeanContainer> beanContainerType,
111             String propertyId, BeanIdResolver<IDTYPE, BEANTYPE> beanIdResolver) {
112         this.beanClass = beanClass;
113         this.containerConstructor = ConstructorUtils.getAccessibleConstructor(beanContainerType, Class.class);
114         this.propertyReaderAlgorithm = propertyReaderAlgorithm;
115         this.propertyId = propertyId;
116         this.beanIdResolver = beanIdResolver;
117     }
118 
119     /**
120      * {@inheritDoc}
121      */
122     @Override
123     public Container getContainerFromCollection(Container container, Collection<BEANTYPE> beans) {
124         Class<? extends Container> containerClass = (container != null) ? container.getClass() : Filterable.class;
125         return getContainerFromCollection(container, beans, containerClass);
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
132     public Container getContainerFromCollection(Collection<BEANTYPE> beans, Class<? extends Container> containerClass) {
133         return getContainerFromCollection(null, beans, containerClass);
134     }
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public Container getContainerFromCollection(Container container, Collection<BEANTYPE> beans,
141             Class<? extends Container> containerClass) {
142         // Instansiate it
143         // FIXME How to handle Exception ?
144         try {
145             if (container == null || !(container instanceof AbstractBeanContainer<?, ?>)) {
146                 container = initContainer(containerClass);
147             }
148             updateProperties(container);
149             if (container.removeAllItems()) {
150                 // Re-add them
151                 if (container instanceof BeanContainer<?, ?>) {
152                     ((BeanContainer<IDTYPE, BEANTYPE>) container).addAll(beans);
153                 } else if (container instanceof BeanItemContainer<?>) {
154                     ((BeanItemContainer<BEANTYPE>) container).addAll(beans);
155                 } else {
156                     // Should never happen
157                     throw new InvalidClassException("container class is not supported.");
158                 }
159             }
160         } catch (IllegalArgumentException e) {
161             // TODO Auto-generated catch block
162             e.printStackTrace();
163         } catch (InstantiationException e) {
164             // TODO Auto-generated catch block
165             e.printStackTrace();
166         } catch (IllegalAccessException e) {
167             // TODO Auto-generated catch block
168             e.printStackTrace();
169         } catch (InvocationTargetException e) {
170             // TODO Auto-generated catch block
171             e.printStackTrace();
172         } catch (InvalidClassException e) {
173             // TODO Auto-generated catch block
174             e.printStackTrace();
175         }
176         return container;
177     }
178 
179     private Container initContainer(Class<? extends Container> containerClass) throws InvalidClassException,
180             IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
181         Container container = containerConstructor.newInstance(beanClass);
182         if (container instanceof BeanContainer<?, ?>) {
183             if (beanIdResolver != null) {
184                 ((BeanContainer<IDTYPE, BEANTYPE>) container).setBeanIdResolver(beanIdResolver);
185             } else if (propertyId != null) {
186                 ((BeanContainer<IDTYPE, BEANTYPE>) container).setBeanIdProperty(propertyId);
187             }
188         } else if (container instanceof BeanItemContainer<?> || container instanceof ShortcutBeanItemContainer<?>) {
189             // Nothing to do
190         } else {
191             // Should never happen
192             throw new InvalidClassException("container class is not supported.");
193         }
194         return container;
195     }
196 
197     /**
198      * Create or update properties of the given container.
199      * 
200      * @param container
201      *            the container to be updated.
202      */
203     private List<PropertyMetadata> updateProperties(Container container) {
204         if (propertyReaderAlgorithm != null) {
205             List<PropertyMetadata> properties = propertyReaderAlgorithm.getProperties(beanClass);
206             Collection<?> containerProperties = container.getContainerPropertyIds();
207             for (PropertyMetadata property : properties) {
208                 if (!containerProperties.contains(property.getPropertyName())) {
209                     addContainerProperty(container, property);
210                 }
211             }
212             return properties;
213         }
214         return null;
215     }
216 
217 }