1 package org.codehaus.xfire.aegis.type;
2
3 import java.beans.PropertyDescriptor;
4 import java.lang.reflect.Field;
5 import java.lang.reflect.Method;
6 import java.util.Collection;
7 import java.util.Map;
8
9 import javax.xml.namespace.QName;
10
11 import org.codehaus.xfire.XFireRuntimeException;
12 import org.codehaus.xfire.aegis.type.basic.ArrayType;
13 import org.codehaus.xfire.aegis.type.collection.CollectionType;
14 import org.codehaus.xfire.aegis.type.collection.MapType;
15 import org.codehaus.xfire.util.NamespaceHelper;
16 import org.codehaus.xfire.util.ServiceUtils;
17
18 /***
19 * @author Hani Suleiman
20 * Date: Jun 14, 2005
21 * Time: 11:59:57 PM
22 */
23 public abstract class AbstractTypeCreator implements TypeCreator
24 {
25 protected TypeMapping tm;
26 protected AbstractTypeCreator nextCreator;
27
28 public TypeMapping getTypeMapping()
29 {
30 return tm;
31 }
32
33 public void setTypeMapping(TypeMapping typeMapping)
34 {
35 this.tm = typeMapping;
36 }
37
38 public void setNextCreator(AbstractTypeCreator creator)
39 {
40 this.nextCreator = creator;
41 }
42
43 protected TypeClassInfo createClassInfo(Field f)
44 {
45 return createBasicClassInfo(f.getType());
46 }
47
48 protected TypeClassInfo createBasicClassInfo(Class typeClass)
49 {
50 TypeClassInfo info = new TypeClassInfo();
51
52 info.setTypeClass(typeClass);
53
54 return info;
55 }
56
57 protected Type createTypeForClass(TypeClassInfo info)
58 {
59 Class javaType = info.getTypeClass();
60
61 if (info.getType() != null)
62 {
63 return createUserType(info);
64 }
65 if(javaType.isArray())
66 {
67 return createArrayType(info);
68 }
69 else if(isMap(javaType))
70 {
71 return createMapType(info);
72 }
73 else if(isCollection(javaType))
74 {
75 return createCollectionType(info);
76 }
77 else if(isEnum(javaType))
78 {
79 return createEnumType(info);
80 }
81 else
82 {
83 Type type = getTypeMapping().getType(javaType);
84 if (type == null)
85 {
86 type = createDefaultType(info);
87 }
88
89 return type;
90 }
91 }
92
93 protected Type createUserType(TypeClassInfo info)
94 {
95 try
96 {
97 Type type = (Type) info.getType().newInstance();
98
99 type.setSchemaType(createQName(info.getTypeClass()));
100 type.setTypeClass(info.getTypeClass());
101 type.setTypeMapping(getTypeMapping());
102
103 return type;
104 }
105 catch (InstantiationException e)
106 {
107 throw new XFireRuntimeException("Couldn't instantiate type classs " +
108 info.getType().getName(), e);
109 }
110 catch (IllegalAccessException e)
111 {
112 throw new XFireRuntimeException("Couldn't access type classs " +
113 info.getType().getName(), e);
114 }
115 }
116
117 protected QName createArrayQName(Class javaType)
118 {
119 return createCollectionQName(javaType, javaType.getComponentType());
120 }
121
122 protected Type createArrayType(TypeClassInfo info)
123 {
124 ArrayType type = new ArrayType();
125 type.setSchemaType(createArrayQName(info.getTypeClass()));
126 type.setTypeClass(info.getTypeClass());
127
128 return type;
129 }
130
131 protected QName createQName(Class javaType)
132 {
133 String clsName = javaType.getName();
134
135 String ns = NamespaceHelper.makeNamespaceFromClassName(clsName, "http");
136 String localName = ServiceUtils.makeServiceNameFromClassName(javaType);
137
138 return new QName(ns, localName);
139 }
140
141 protected boolean isCollection(Class javaType)
142 {
143 return Collection.class.isAssignableFrom(javaType);
144 }
145
146 protected Type createCollectionType(TypeClassInfo info, Class component)
147 {
148 CollectionType type = new CollectionType(component);
149 type.setTypeMapping(getTypeMapping());
150
151 QName name = info.getTypeName();
152 if (name == null) name = createCollectionQName(info.getTypeClass(), component);
153 type.setSchemaType(name);
154
155 type.setTypeClass(info.getTypeClass());
156
157 return type;
158 }
159
160 protected Type createMapType(TypeClassInfo info)
161 {
162 Class keyType = (Class) info.getKeyType();
163 Class valueType = (Class) info.getGenericType();
164
165 QName schemaType = createMapQName(keyType, valueType);
166 MapType type = new MapType(schemaType,
167 keyType,
168 valueType);
169 type.setTypeMapping(getTypeMapping());
170 type.setTypeClass(info.getTypeClass());
171
172 return type;
173 }
174
175 protected QName createMapQName(Class keyClass, Class componentClass)
176 {
177 if(keyClass == null)
178 {
179 throw new XFireRuntimeException("Cannot create mapping for map, unspecified key type");
180 }
181
182 if(componentClass == null)
183 {
184 throw new XFireRuntimeException("Cannot create mapping for map, unspecified component type");
185 }
186
187 Type keyType = tm.getType(keyClass);
188 if(keyType == null)
189 {
190 keyType = createType(keyClass);
191 getTypeMapping().register(keyType);
192 }
193
194 Type componentType = tm.getType(componentClass);
195 if(componentType == null)
196 {
197 componentType = createType(componentClass);
198 getTypeMapping().register(componentType);
199 }
200
201 String name = keyType.getSchemaType().getLocalPart()
202 + "2"
203 + componentType.getSchemaType().getLocalPart()
204 + "Map";
205
206
207 return new QName(tm.getEncodingStyleURI(), name);
208 }
209
210 protected boolean isMap(Class javaType)
211 {
212 return Map.class.isAssignableFrom(javaType);
213 }
214
215 public abstract TypeClassInfo createClassInfo(PropertyDescriptor pd);
216
217 protected boolean isEnum(Class javaType)
218 {
219 return false;
220 }
221
222 public Type createEnumType(TypeClassInfo info)
223 {
224 return null;
225 }
226
227 public abstract Type createCollectionType(TypeClassInfo info);
228
229 public abstract Type createDefaultType(TypeClassInfo info);
230
231 protected QName createCollectionQName(Class javaType, Class componentType)
232 {
233 if(componentType == null)
234 {
235 throw new XFireRuntimeException("Cannot create mapping for " + javaType.getName() + ", unspecified component type");
236 }
237 Type type = tm.getType(componentType);
238 if(type == null)
239 {
240 type = createType(componentType);
241 getTypeMapping().register(type);
242 }
243 String ns;
244
245 if(type.isComplex())
246 {
247 ns = type.getSchemaType().getNamespaceURI();
248 }
249 else
250 {
251 ns = tm.getEncodingStyleURI();
252 }
253
254 String first = type.getSchemaType().getLocalPart().substring(0, 1);
255 String last = type.getSchemaType().getLocalPart().substring(1);
256 String localName = "ArrayOf" + first.toUpperCase() + last;
257
258 return new QName(ns, localName);
259 }
260
261 public abstract TypeClassInfo createClassInfo(Method m, int index);
262
263 /***
264 * Create a Type for a Method parameter.
265 *
266 * @param m the method to create a type for
267 * @param index The parameter index. If the index is less than zero, the return type is used.
268 */
269 public Type createType(Method m, int index)
270 {
271 TypeClassInfo info = createClassInfo(m, index);
272
273 return createTypeForClass(info);
274 }
275
276 /***
277 * Create type information for a PropertyDescriptor.
278 *
279 * @param pd the propertydescriptor
280 */
281 public Type createType(PropertyDescriptor pd)
282 {
283 TypeClassInfo info = createClassInfo(pd);
284
285 return createTypeForClass(info);
286 }
287
288 /***
289 * Create type information for a <code>Field</code>.
290 *
291 * @param f the field to create a type from
292 */
293 public Type createType(Field f)
294 {
295 TypeClassInfo info = createClassInfo(f);
296
297 return createTypeForClass(info);
298 }
299
300 public Type createType(Class clazz)
301 {
302 TypeClassInfo info = createBasicClassInfo(clazz);
303
304 return createTypeForClass(info);
305 }
306
307 public static class TypeClassInfo
308 {
309 Class typeClass;
310 Object[] annotations;
311 Object genericType;
312 Object keyType;
313 String mappedName;
314 QName typeName;
315 Class type;
316
317 public Object[] getAnnotations()
318 {
319 return annotations;
320 }
321
322 public void setAnnotations(Object[] annotations)
323 {
324 this.annotations = annotations;
325 }
326
327 public Object getGenericType()
328 {
329 return genericType;
330 }
331
332 public void setGenericType(Object genericType)
333 {
334 this.genericType = genericType;
335 }
336
337 public Object getKeyType()
338 {
339 return keyType;
340 }
341
342 public void setKeyType(Object keyType)
343 {
344 this.keyType = keyType;
345 }
346
347 public Class getTypeClass()
348 {
349 return typeClass;
350 }
351
352 public void setTypeClass(Class typeClass)
353 {
354 this.typeClass = typeClass;
355 }
356
357 public QName getTypeName()
358 {
359 return typeName;
360 }
361
362 public void setTypeName(QName name)
363 {
364 this.typeName = name;
365 }
366
367 public String getMappedName()
368 {
369 return mappedName;
370 }
371
372 public void setMappedName(String mappedName)
373 {
374 this.mappedName = mappedName;
375 }
376
377 public Class getType()
378 {
379 return type;
380 }
381
382 public void setType(Class type)
383 {
384 this.type = type;
385 }
386 }
387 }