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