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