1 /*
2 * Copyright (C) 2002 Carsten Krebs (Team-Konzept GmbH & Co.KG)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 package com.teamkonzept.dom4jb.beans;
19
20 import java.beans.BeanInfo;
21 import java.beans.IntrospectionException;
22 import java.beans.PropertyDescriptor;
23 import java.lang.reflect.Method;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.WeakHashMap;
33
34 import com.teamkonzept.dom4jb.schema.DataDescriptor;
35 import com.teamkonzept.dom4jb.schema.ElementDescriptor;
36 import com.teamkonzept.dom4jb.schema.GroupDescriptor;
37 import com.teamkonzept.dom4jb.schema.Sequence;
38
39 public class Introspector {
40
41 private static final String XML_BEAN_INFO = "XMLBeanInfo";
42
43 private static final Map infoCache = new WeakHashMap();
44 private static final List searchPackages = new ArrayList();
45
46 static {
47 searchPackages.add("com.teamkonzept.dom4jb.beans.infos");
48 }
49
50 public static XMLBeanInfo getBeanInfo(final Class beanClass)
51 throws IntrospectionException {
52
53 XMLBeanInfo info = (XMLBeanInfo) infoCache.get(beanClass);
54 if (info != null) {
55 return info;
56 }
57
58 final String[] names = getBeanInfoNames(beanClass);
59 for (int i = 0; i < names.length; i++) {
60 try {
61 final Class beanInfoClass = Class.forName(names[i]);
62 info = (XMLBeanInfo) beanInfoClass.newInstance();
63 put(beanClass, info);
64 return info;
65 } catch (ClassNotFoundException e) {
66 /* NOP */
67 } catch (InstantiationException e) {
68 /* NOP */
69 } catch (IllegalAccessException e) {
70 /* NOP */
71 } catch (NoClassDefFoundError e) {
72 /* NOP */
73 }
74
75 }
76
77 return buildBeanInfo(beanClass, new HashSet());
78 }
79
80 public static XMLBeanInfo getBeanInfo(final Class beanClass,
81 final Set defined)
82 throws IntrospectionException {
83
84 XMLBeanInfo info = (XMLBeanInfo) infoCache.get(beanClass);
85 if (info != null) {
86 return info;
87 }
88
89 final String[] names = getBeanInfoNames(beanClass);
90 for (int i = 0; i < names.length; i++) {
91 try {
92 final Class beanInfoClass = Class.forName(names[i]);
93 info = (XMLBeanInfo) beanInfoClass.newInstance();
94 put(beanClass, info);
95 extend(beanClass, defined);
96 return info;
97 } catch (ClassNotFoundException e) {
98 /* NOP */
99 } catch (InstantiationException e) {
100 /* NOP */
101 } catch (IllegalAccessException e) {
102 /* NOP */
103 }
104 }
105
106 return buildBeanInfo(beanClass, defined);
107 }
108
109 public static XMLBeanInfo buildBeanInfo(final Class beanClass,
110 final Set defined)
111 throws IntrospectionException {
112
113 final LinkedList content = new LinkedList();
114 final LinkedList attributes = new LinkedList();
115
116 final BeanInfo beanInfo =
117 java.beans.Introspector.getBeanInfo(
118 beanClass,
119 java.beans.Introspector.IGNORE_ALL_BEANINFO);
120
121 final PropertyDescriptor[] properties =
122 beanInfo.getPropertyDescriptors();
123 final HashMap propertySet = new HashMap(properties.length);
124 for (int i = 0; i < properties.length; i++) {
125 final Method readMethod = properties[i].getReadMethod();
126 if (readMethod == null) {
127 continue;
128 }
129 if (readMethod.getDeclaringClass() != beanClass) {
130 continue;
131 }
132
133 // propertySet.put( readMethod, properties[i] );
134 propertySet.put(properties[i].getName(), properties[i]);
135 }
136
137 //
138 // remove all superclass properties
139 //
140 final Class superclass = beanClass.getSuperclass();
141 if (superclass != null && !defined.contains(superclass)) {
142
143 final BeanInfo superclassInfo =
144 java.beans.Introspector.getBeanInfo(
145 superclass,
146 java.beans.Introspector.IGNORE_ALL_BEANINFO);
147 final PropertyDescriptor[] superclassProperties =
148 superclassInfo.getPropertyDescriptors();
149
150 for (int i = 0; i < superclassProperties.length; i++) {
151 propertySet.remove(superclassProperties[i].getName());
152 }
153
154 // add xml-bean-info for superclass
155 final XMLBeanInfo superclassXMLInfo =
156 getBeanInfo(superclass, defined);
157
158 // add content descriptors
159 final GroupDescriptor contentGroup =
160 superclassXMLInfo.getContentDescriptors();
161 if (contentGroup != null && !contentGroup.isEmpty()) {
162 content.add(contentGroup);
163 }
164
165 // add attribute descriptors
166 final GroupDescriptor attributeGroup =
167 superclassXMLInfo.getAttributeDescriptors();
168 if (attributeGroup != null && !attributeGroup.isEmpty()) {
169 attributes.add(attributeGroup);
170 }
171 extend(superclass, defined);
172 }
173
174 //
175 // remove all interface properties
176 //
177 final Class[] interfaces = beanClass.getInterfaces();
178 for (int i = 0; i < interfaces.length; i++) {
179
180 if (defined.contains(interfaces[i])) {
181 continue;
182 }
183
184 final BeanInfo interfaceInfo =
185 java.beans.Introspector.getBeanInfo(
186 interfaces[i],
187 java.beans.Introspector.IGNORE_ALL_BEANINFO);
188 final PropertyDescriptor[] interfaceProperties =
189 interfaceInfo.getPropertyDescriptors();
190
191 if (interfaceProperties != null) {
192 for (int j = 0; j < interfaceProperties.length; j++) {
193 propertySet.remove(interfaceProperties[j].getName());
194 }
195
196 // add xml-bean-info for interface[i]
197 final XMLBeanInfo interfaceXMLInfo =
198 getBeanInfo(interfaces[i], defined);
199
200 // add content descriptors
201 final GroupDescriptor contentGroup =
202 interfaceXMLInfo.getContentDescriptors();
203 if (contentGroup != null && !contentGroup.isEmpty()) {
204 content.add(contentGroup);
205 }
206
207 // add attribute descriptors
208 final GroupDescriptor attributeGroup =
209 interfaceXMLInfo.getAttributeDescriptors();
210 if (attributeGroup != null && !attributeGroup.isEmpty()) {
211 attributes.add(attributeGroup);
212 }
213 }
214 // extends the set of defined interfaces an superclasses
215 extend(interfaces[i], defined);
216 }
217
218 // add rest of properties as element-content
219 final Iterator ownProperties = propertySet.values().iterator();
220 while (ownProperties.hasNext()) {
221 final PropertyDescriptor property =
222 (PropertyDescriptor) ownProperties.next();
223
224 content.add(new ElementDescriptor(property));
225 }
226
227 final XMLBeanInfo info = new ElementInfo(content, attributes);
228 put(beanClass, info);
229
230 return info;
231 }
232
233 public static void extend(final Class beanClass, final Set defined) {
234 defined.add(beanClass);
235
236 final Class[] interfaces = beanClass.getInterfaces();
237 for (int i = 0; i < interfaces.length; i++) {
238 if (defined.contains(interfaces[i])) {
239 // extends the set of defined interfaces an superclasses
240 extend(interfaces[i], defined);
241 } else {
242 defined.add(interfaces[i]);
243 }
244 }
245 }
246
247 protected static String getBaseName(final Class beanClass) {
248 final String fullName = beanClass.getName();
249 final int idx = fullName.lastIndexOf('.');
250 return (idx < 0 ? fullName : fullName.substring(idx + 1));
251 }
252
253 protected static String getBeanInfoName(final String packageName,
254 final String className) {
255 final StringBuffer name;
256 if (packageName == null || packageName.length() <= 0) {
257 name = new StringBuffer(className);
258 } else {
259 name = new StringBuffer(packageName);
260 name.append('.');
261 name.append(className);
262 }
263 name.append(XML_BEAN_INFO);
264 return name.toString();
265 }
266
267 protected static final String[] getBeanInfoNames(final Class beanClass) {
268 final String[] names = new String[searchPackages.size() + 1];
269
270 final String className = getBaseName(beanClass);
271 final Iterator packages = searchPackages.iterator();
272 final Package pack = beanClass.getPackage();
273 String packageName = (pack != null ? pack.getName() : null);
274 int i = 0;
275 do {
276 names[i++] = getBeanInfoName(packageName, className);
277
278 if (packages.hasNext()) {
279 packageName = (String) packages.next();
280 }
281 } while (i < names.length);
282
283 return names;
284 }
285
286 public static void put(final Class beanClass, final XMLBeanInfo info) {
287 synchronized (infoCache) {
288 infoCache.put(beanClass, info);
289 }
290 }
291
292 public static void addSearchPath(final String path) {
293 if (!searchPackages.contains(path)) {
294 searchPackages.add(path);
295 }
296 }
297
298 public static void clearCache() {
299 synchronized (infoCache) {
300 infoCache.clear();
301 }
302 }
303 }
304
305 final class ElementInfo implements XMLBeanInfo {
306
307 private final GroupDescriptor content;
308 private final GroupDescriptor attributes;
309
310 public ElementInfo() {
311 this.content = GroupDescriptor.EMPTY_DESCRIPTOR;
312 this.attributes = GroupDescriptor.EMPTY_DESCRIPTOR;
313 }
314
315 public ElementInfo(final List content, final List attributes) {
316 this.content = new Sequence(content);
317 this.attributes = new Sequence(attributes);
318 }
319
320 /***
321 * Liefert alle direketen Content-Deskriptoren der Klasse
322 */
323 public GroupDescriptor getContentDescriptors() {
324 return this.content;
325 }
326
327 /***
328 * Liefert alle Attribut-Deskriptoren der Klasse
329 */
330 public GroupDescriptor getAttributeDescriptors() {
331 return this.attributes;
332 }
333
334 /***
335 * Liefert den DataDescriptor, zur Konvertierung der Bean
336 * in ihre entsprechende String-Repräsentation
337 */
338 public DataDescriptor getDataDescriptor() {
339 return DataDescriptor.STRING;
340 }
341
342 /***
343 * Liefert den Namen des Elementes, falls dieser nicht explizit angegeben
344 * wurde
345 */
346 public String getItemName() {
347 return "item";
348 }
349 }
This page was automatically generated by Maven