1 package org.codehaus.xfire.aegis.type.basic;
2
3 import java.beans.BeanInfo;
4 import java.beans.IntrospectionException;
5 import java.beans.Introspector;
6 import java.beans.PropertyDescriptor;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13
14 import javax.xml.namespace.QName;
15
16 import org.codehaus.xfire.XFireRuntimeException;
17 import org.codehaus.xfire.aegis.type.Type;
18 import org.codehaus.xfire.aegis.type.TypeMapping;
19
20 public class BeanTypeInfo
21 {
22 private Map qname2name = new HashMap();
23 private Class typeClass;
24 private List attributes = new ArrayList();
25 private List elements = new ArrayList();
26 private String defaultNamespace;
27 private PropertyDescriptor[] descriptors;
28 private TypeMapping typeMapping;
29 private boolean initialized;
30
31 public BeanTypeInfo(Class typeClass, String defaultNamespace)
32 {
33 this.typeClass = typeClass;
34 this.defaultNamespace = defaultNamespace;
35
36 initializeProperties();
37 }
38
39 /***
40 * Create a BeanTypeInfo class.
41 *
42 * @param typeClass
43 * @param defaultNamespace
44 * @param initiallize If true attempt default property/xml mappings.
45 */
46 public BeanTypeInfo(Class typeClass, String defaultNamespace, boolean initialize)
47 {
48 this.typeClass = typeClass;
49 this.defaultNamespace = defaultNamespace;
50
51 initializeProperties();
52 setInitialized(!initialize);
53 }
54
55 protected BeanTypeInfo(Class typeClass)
56 {
57 this.typeClass = typeClass;
58
59 initializeProperties();
60 }
61
62 public void initialize()
63 {
64 try
65 {
66 for (int i = 0; i < descriptors.length; i++)
67 {
68
69 if (descriptors[i].getReadMethod() != null &&
70 descriptors[i].getWriteMethod() != null)
71 {
72 mapProperty(descriptors[i]);
73 }
74 }
75 }
76 catch (Exception e)
77 {
78 if(e instanceof XFireRuntimeException) throw (XFireRuntimeException)e;
79 throw new XFireRuntimeException("Couldn't create TypeInfo.", e);
80 }
81
82 setInitialized(true);
83 }
84
85 public boolean isInitialized()
86 {
87 return initialized;
88 }
89
90 private void setInitialized(boolean initialized)
91 {
92 this.initialized = initialized;
93 }
94
95 protected void mapProperty(PropertyDescriptor pd)
96 {
97 String name = pd.getName();
98
99 if (isAttribute(pd))
100 {
101 mapAttribute(name, createQName(pd));
102 }
103 else if (isElement(pd))
104 {
105 mapElement(name, createQName(pd));
106 }
107 }
108
109 protected PropertyDescriptor[] getPropertyDescriptors()
110 {
111 return descriptors;
112 }
113
114 protected PropertyDescriptor getPropertyDescriptor(String name)
115 {
116 for (int i = 0; i < descriptors.length; i++)
117 {
118 if (descriptors[i].getName().equals(name))
119 return descriptors[i];
120 }
121
122 return null;
123 }
124
125 /***
126 * Get the type class for the field with the specified QName.
127 */
128 public Type getType(QName name)
129 {
130 Type type = getTypeMapping().getType(name);
131
132 if (type == null)
133 {
134 PropertyDescriptor desc;
135 try
136 {
137 desc = getPropertyDescriptor(name);
138 }
139 catch (Exception e)
140 {
141 if(e instanceof XFireRuntimeException) throw (XFireRuntimeException)e;
142 throw new XFireRuntimeException("Couldn't get properties.", e);
143 }
144
145 if (desc == null)
146 {
147 return null;
148 }
149
150 if (getTypeMapping().isRegistered(desc.getPropertyType())
151 && !Collection.class.isAssignableFrom(desc.getPropertyType()))
152 {
153 type = getTypeMapping().getType(desc.getPropertyType());
154 }
155 else
156 {
157 try
158 {
159 type = getTypeMapping().getTypeCreator().createType(desc);
160 }
161 catch(XFireRuntimeException e)
162 {
163 e.prepend("Couldn't create type for property " + desc.getName()
164 + " on " + getTypeClass());
165
166 throw e;
167 }
168
169 getTypeMapping().register(type);
170 }
171 }
172
173 if ( type == null )
174 throw new XFireRuntimeException( "Couldn't find type for property " + name );
175
176 return type;
177 }
178
179 public TypeMapping getTypeMapping()
180 {
181 return typeMapping;
182 }
183
184 public void setTypeMapping(TypeMapping typeMapping)
185 {
186 this.typeMapping = typeMapping;
187 }
188
189 protected QName createQName(PropertyDescriptor desc)
190 {
191 return new QName(defaultNamespace, desc.getName());
192 }
193
194 public void mapAttribute(String property, QName type)
195 {
196 qname2name.put(type, property);
197 attributes.add(type);
198 }
199
200 public void mapElement(String property, QName type)
201 {
202 qname2name.put(type, property);
203 elements.add(type);
204 }
205
206 private void initializeProperties()
207 {
208 BeanInfo beanInfo = null;
209 try
210 {
211 if (typeClass.isInterface() || typeClass.isPrimitive())
212 {
213 beanInfo = Introspector.getBeanInfo(typeClass);
214 }
215 else if (typeClass == Object.class)
216 {
217 }
218 else
219 {
220 beanInfo = Introspector.getBeanInfo(typeClass, Object.class);
221 }
222 }
223 catch (IntrospectionException e)
224 {
225 throw new XFireRuntimeException("Couldn't introspect interface.", e);
226 }
227
228 if (beanInfo != null)
229 descriptors = beanInfo.getPropertyDescriptors();
230
231 if (descriptors == null)
232 {
233 descriptors = new PropertyDescriptor[0];
234 }
235 }
236
237 public PropertyDescriptor getPropertyDescriptor(QName name)
238 {
239 return getPropertyDescriptor( getPropertyName(name) );
240 }
241
242 protected boolean isAttribute(PropertyDescriptor desc)
243 {
244 return false;
245 }
246
247 protected boolean isElement(PropertyDescriptor desc)
248 {
249 return true;
250 }
251
252 protected boolean isSerializable(PropertyDescriptor desc)
253 {
254 return true;
255 }
256
257 protected Class getTypeClass()
258 {
259 return typeClass;
260 }
261
262 public boolean isNillable(QName name)
263 {
264 return true;
265 }
266
267 private String getPropertyName(QName name)
268 {
269 return (String) qname2name.get(name);
270 }
271
272 public Iterator getAttributes()
273 {
274 return attributes.iterator();
275 }
276
277 public Iterator getElements()
278 {
279 return elements.iterator();
280 }
281 }