View Javadoc

1   /*
2      Copyright 2002-2006 Martin van den Bemt
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15  */
16  package org.xulux.dataprovider.bean;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.xulux.api.dataprovider.IConverter;
26  import org.xulux.api.dataprovider.IDataProvider;
27  import org.xulux.api.dataprovider.IMapping;
28  import org.xulux.utils.ClassLoaderUtils;
29  
30  /**
31   * The BeanDataProvider is the main entry point for the dataprovider.
32   * It is the datasource 
33   *
34   * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
35   * @version $Id: BeanDataProvider.java,v 1.1 2005/12/18 12:58:23 mvdb Exp $
36   */
37  public final class BeanDataProvider implements IDataProvider {
38  
39      /**
40       * The map containing all the mappings
41       */
42      private HashMap mappings;
43  
44      /**
45       * the baseclass of all the mappings
46       */
47      private Class baseClass;
48      /**
49       * A mappingcache is used temporarily to add
50       * classes that have been discovered, this way
51       * we can test for infinite loop troubles
52       */
53      private ArrayList mappingCache;
54      /**
55       * the depth of the mappings.
56       */
57      private int mappingDepth = 0;
58  
59      /**
60       * A map containg the converters
61       */
62      private HashMap converters;
63  
64      /**
65       * Constructor for BeanDataProvider.
66       */
67      public BeanDataProvider() {
68      }
69  
70      /**
71       * @param name the name of the mapping
72       * @return the mapping
73       */
74      public IMapping getMapping(String name) {
75          IMapping mapping = null;
76          if (mappings != null) {
77              mapping = (BeanMapping) mappings.get(name);
78          }
79          if (mapping == null) {
80              mapping = getMapping(ClassLoaderUtils.getClass(name));
81          }
82          return mapping;
83      }
84  
85      /**
86       * Returns a clone of the original mapping
87       * map, so alteration doesn't effect the
88       * registry..
89       *
90       * @return the mappings in a Map
91       */
92      public Map getMappings() {
93          if (mappings == null) {
94              return new HashMap();
95          }
96          return (HashMap) mappings.clone();
97      }
98  
99      /**
100      * @see org.xulux.dataprovider.IDataProvider#addMapping(org.xulux.dataprovider.IMapping)
101      */
102     public void addMapping(IMapping mapping) {
103         if (mappings == null) {
104             mappings = new HashMap();
105         }
106         if (mappingCache == null) {
107             mappingCache = new ArrayList();
108         }
109         BeanMapping beanMapping = (BeanMapping) mapping;
110         beanMapping.setDataProvider(this);
111         mappingCache.add(beanMapping.getBean());
112         mappingDepth++;
113         beanMapping.discover();
114         mappings.put(beanMapping.getName(), beanMapping);
115         mappingDepth--;
116         if (mappingDepth == 0) {
117             mappingCache = null;
118         }
119     }
120 
121     /**
122      * @param clazz the class
123      * @return the mapping of the specified clazz
124      */
125     public IMapping getMapping(Class clazz) {
126         if (clazz == null) {
127             return null;
128         }
129         return getMapping(clazz, false);
130     }
131 
132     /**
133      * Convenience method. This calls the
134      * getMapping(Class)
135      *
136      * @param object the object to get the mapping for
137      * @return the beanmapping that is connected
138      *          to the class of the specified instance
139      *          or null when the object is null.
140      */
141     public IMapping getMapping(Object object) {
142         if (object == null) {
143             return null;
144         }
145         if (object instanceof String) {
146           return getMapping((String) object);
147         } else if (object instanceof Class) {
148           return getMapping((Class) object);
149         }
150         return getMapping(object.getClass());
151     }
152 
153     /**
154      * @param clazz the class to get the mapping for
155      * @param newMapping if true it creates the mapping and adds
156      *                      it to the  dictionary, if the name is not
157      *                      yet known.
158      * @return the beanmapping or null when no mapping could be created
159      */
160     public BeanMapping getMapping(Class clazz, boolean newMapping) {
161         String name = null;
162         if (newMapping) {
163             name = getPossibleMappingName(clazz);
164         } else {
165             name = getPlainBeanName(clazz);
166         }
167         return getMapping(clazz, name);
168     }
169     /**
170      * Tries to get a mapping based on the specified bean
171      * @param clazz the class
172      * @param preferredName the name to use for the mapping if it needs to be created
173      * @return the beanmapping found
174      */
175     public BeanMapping getMapping(Class clazz, String preferredName) {
176 //        if (getBaseClass() == null) {
177 //            if (log.isDebugEnabled()) {
178 //                log.debug("Base class is not set. Xulux will possibly not be able to disover data beans correctly");
179 //            }
180 //        }
181         BeanMapping mapping = (BeanMapping) getMapping(preferredName);
182         if (mapping == null) {
183             mapping = new BeanMapping(preferredName);
184             mapping.setBean(clazz);
185             mapping.setDiscovery(true);
186             addMapping(mapping);
187         }
188         return mapping;
189     }
190 
191     /**
192      * Creates a mapping from the specified with the specified name
193      * Do not use, since it doesn't do much...
194      * @param bean the bean to create a mapping for
195      * @param name the name of the mapping
196      * @return the newly creating mapping.
197      */
198     private BeanMapping createMapping(Object bean, String name) {
199         // first
200         BeanMapping mapping = new BeanMapping(name);
201         return mapping;
202     }
203 
204     /**
205      * @param clazz the class
206      * @return the plaing bean name for the specified class
207      */
208     public String getPlainBeanName(Class clazz) {
209         int pLength = clazz.getPackage().getName().length();
210         String mapName = clazz.getName().substring(pLength + 1);
211         return mapName;
212     }
213     /**
214      * Tries to find a possible name for the mapping
215      * @param clazz the class to investigate
216      * @return the possible mapping name
217      */
218     public String getPossibleMappingName(Class clazz) {
219         String mapName = getPlainBeanName(clazz);
220         int i = 1;
221         if (getMapping(mapName) != null) {
222             while (true) {
223                 if (getMapping(mapName + i) == null) {
224                     mapName += i;
225                     break;
226                 }
227                 i++;
228             }
229         }
230         return mapName;
231     }
232 
233     /**
234      * @see org.xulux.dataprovider.IDictionary#initialize(java.lang.Object)
235      */
236     public void initialize(Object object) {
237         if (object instanceof InputStream) {
238             initialize((InputStream) object);
239         } else {
240             System.out.println("Cannot initialize dictionary, object is not an InputStream");
241         }
242     }
243 
244     /**
245      * Initializes the dictionary from a stream
246      * The stream will be closed.
247      * @param stream - a stream with the dictionary.xml
248      * @todo move init like stuff to API / CORE..
249      */
250     public void initialize(InputStream stream) {
251         if (stream == null) {
252             return;
253         }
254 //        new DictionaryHandler().read(stream);
255         try {
256             stream.close();
257         } catch (IOException e) {
258             e.printStackTrace();
259         }
260     }
261     /**
262      * Returns the baseClass.
263      * @return Class
264      */
265     public Class getBaseClass() {
266         return baseClass;
267     }
268 
269     /**
270      * Sets the baseClass.
271      * @param baseClass The baseClass to set
272      */
273     public void setBaseClass(Class baseClass) {
274         this.baseClass = baseClass;
275     }
276 
277     /**
278      * Clears all the mappings currently available
279      */
280     public void clearMappings() {
281         if (mappings != null) {
282             mappings.clear();
283         }
284     }
285 
286     /**
287      * Reset all dictionary settings..
288      *
289      */
290     public void reset() {
291         clearMappings();
292         if (converters != null) {
293             converters.clear();
294         }
295     }
296 
297     /**
298      * Checks to see if this class is currently being
299      * discovered. This is a nice way to prevent
300      * infinite loops.
301      *
302      * @param clazz the class to look for
303      * @return boolean if the class is already in the cache
304      */
305     public boolean isInCache(Class clazz) {
306         if (mappingCache == null) {
307             return false;
308         }
309         return mappingCache.indexOf(clazz) != -1;
310     }
311 
312     /**
313      *
314      * @return a clone of the current cache.
315      */
316     public List getCache() {
317         if (mappingCache != null) {
318             return (List) mappingCache.clone();
319         }
320         return null;
321     }
322 
323     /**
324      * @param clazz - the class of the converter.
325      */
326     public void addConverter(Class clazz) {
327         if (converters == null) {
328             converters = new HashMap();
329         }
330         Object object = ClassLoaderUtils.getObjectFromClass(clazz);
331         if (object instanceof IConverter) {
332             IConverter c = (IConverter) object;
333             converters.put(c.getType(), c);
334         }
335 //        else {
336 //            if (log.isWarnEnabled()) {
337 //                String clazzName = "null";
338 //                if (clazz != null) {
339 //                    clazzName = clazz.getName();
340 //                }
341 //                log.warn(clazzName + " class does not implement IConverter, not registering object");
342 //            }
343         }
344 //    }
345 
346     /**
347      * Convenience method. see addConverter(Class) for more
348      * details.
349      *
350      * @param clazz the clazz to add the converter for
351      */
352     public void addConverter(String clazz) {
353         if (clazz == null) {
354             return;
355         }
356         Class clz = ClassLoaderUtils.getClass(clazz);
357         if (clz != null) {
358             addConverter(clz);
359         }
360 //      } else {
361 //      }
362 //            if (log.isWarnEnabled()) {
363 //                log.warn(clz + " does not exists or could not be loaded");
364 //            }
365     }
366 
367     /**
368      *
369      * @param object the object to get the convert for
370      * @return the converter for the object specified or
371      *          null when no converter is present
372      */
373     public IConverter getConverter(Object object) {
374         if (object != null) {
375             return getConverter(object.getClass());
376         }
377         return null;
378     }
379     /**
380      *
381      * @return all registered converters
382      */
383     public Map getConverters() {
384         return converters;
385     }
386     /**
387      *
388      * @param clazz the class to get the convert for
389      * @return the coverter for the clazz specified or null
390      *          when no converter is present
391      */
392     public IConverter getConverter(Class clazz) {
393         if (clazz != null && converters != null) {
394             return (IConverter) converters.get(clazz);
395         }
396         return null;
397     }
398 
399     /**
400      * @see org.xulux.api.dataprovider.IDataProvider#initialize()
401      */
402     public void initialize() {
403     }
404 
405     /**
406      * @see org.xulux.api.dataprovider.IDataProvider#setValue(java.lang.Object, java.lang.String, java.lang.Object, 
407      *                                                                                              java.lang.Object)
408      */
409     public Object setValue(Object mapping, String field, Object object, Object value) {
410         IMapping iMapping = getMapping(mapping);
411         if (iMapping != null) {
412             return iMapping.setValue(field, object, value);
413         }
414         return null;
415     }
416 
417     /**
418      * @see org.xulux.api.dataprovider.IDataProvider#getValue(java.lang.Object, java.lang.String, java.lang.Object)
419      */
420     public Object getValue(Object mapping, String field, Object object) {
421       return null;
422     }
423 
424     /**
425      * @see org.xulux.api.dataprovider.IDataProvider#needsPartValue()
426      */
427     public boolean needsPartValue() {
428         return false;
429     }
430 
431     /**
432      * @see org.xulux.api.dataprovider.IDataProvider#setProperty(java.lang.String, java.lang.String)
433      */
434     public void setProperty(String name, String value) {
435         if (name == null) {
436             return;
437         }
438         if (name.equalsIgnoreCase("baseclass")) {
439             setBaseClass(ClassLoaderUtils.getClass(value));
440         }
441     }
442 
443     /**
444      * @see org.xulux.api.dataprovider.IDataProvider#createMapping(java.lang.Object)
445      */
446     public IMapping createMapping(Object object) {
447         if (object == null) {
448             return null;
449         }
450         if (object instanceof String) {
451             BeanMapping mapping = new BeanMapping((String) object);
452             mapping.setDataProvider(this);
453             return mapping;
454         }
455         return null;
456     }
457 
458 }