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