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(javaType.isArray())
62 {
63 return createArrayType(info);
64 }
65 else if(isMap(javaType))
66 {
67 return createMapType(info);
68 }
69 else if(isCollection(javaType))
70 {
71 return createCollectionType(info);
72 }
73 else if(isEnum(javaType))
74 {
75 return createEnumType(info);
76 }
77 else
78 {
79 Type type = getTypeMapping().getType(javaType);
80 if (type == null)
81 {
82 type = createDefaultType(info);
83 }
84
85 return type;
86 }
87 }
88
89 protected QName createArrayQName(Class javaType)
90 {
91 return createCollectionQName(javaType, javaType.getComponentType());
92 }
93
94 protected Type createArrayType(TypeClassInfo info)
95 {
96 ArrayType type = new ArrayType();
97 type.setSchemaType(createArrayQName(info.getTypeClass()));
98 type.setTypeClass(info.getTypeClass());
99
100 return type;
101 }
102
103 protected QName createQName(Class javaType)
104 {
105 String clsName = javaType.getName();
106
107 String ns = NamespaceHelper.makeNamespaceFromClassName(clsName, "http");
108 String localName = ServiceUtils.makeServiceNameFromClassName(javaType);
109
110 return new QName(ns, localName);
111 }
112
113 protected boolean isCollection(Class javaType)
114 {
115 return Collection.class.isAssignableFrom(javaType);
116 }
117
118 protected Type createCollectionType(TypeClassInfo info, Class component)
119 {
120 CollectionType type = new CollectionType(component);
121 type.setTypeMapping(getTypeMapping());
122
123 QName name = info.getName();
124 if (name == null) name = createCollectionQName(info.getTypeClass(), component);
125 type.setSchemaType(name);
126
127 type.setTypeClass(info.getTypeClass());
128
129 return type;
130 }
131
132 protected Type createMapType(TypeClassInfo info)
133 {
134 Class keyType = (Class) info.getKeyType();
135 Class valueType = (Class) info.getGenericType();
136
137 QName schemaType = createMapQName(keyType, valueType);
138 MapType type = new MapType(schemaType,
139 keyType,
140 valueType);
141 type.setTypeMapping(getTypeMapping());
142 type.setTypeClass(info.getTypeClass());
143
144 return type;
145 }
146
147 protected QName createMapQName(Class keyClass, Class componentClass)
148 {
149 if(keyClass == null)
150 {
151 throw new XFireRuntimeException("Cannot create mapping for map, unspecified key type");
152 }
153
154 if(componentClass == null)
155 {
156 throw new XFireRuntimeException("Cannot create mapping for map, unspecified component type");
157 }
158
159 Type keyType = tm.getType(keyClass);
160 if(keyType == null)
161 {
162 keyType = createType(keyClass);
163 getTypeMapping().register(keyType);
164 }
165
166 Type componentType = tm.getType(componentClass);
167 if(componentType == null)
168 {
169 componentType = createType(componentClass);
170 getTypeMapping().register(componentType);
171 }
172
173 String name = keyType.getSchemaType().getLocalPart()
174 + "2"
175 + componentType.getSchemaType().getLocalPart()
176 + "Map";
177
178
179 return new QName(tm.getEncodingStyleURI(), name);
180 }
181
182 protected boolean isMap(Class javaType)
183 {
184 return Map.class.isAssignableFrom(javaType);
185 }
186
187 public abstract TypeClassInfo createClassInfo(PropertyDescriptor pd);
188
189 protected boolean isEnum(Class javaType)
190 {
191 return false;
192 }
193
194 public Type createEnumType(TypeClassInfo info)
195 {
196 return null;
197 }
198
199 public abstract Type createCollectionType(TypeClassInfo info);
200
201 public abstract Type createDefaultType(TypeClassInfo info);
202
203 protected QName createCollectionQName(Class javaType, Class componentType)
204 {
205 if(componentType == null)
206 {
207 throw new XFireRuntimeException("Cannot create mapping for " + javaType.getName() + ", unspecified component type");
208 }
209 Type type = tm.getType(componentType);
210 if(type == null)
211 {
212 type = createType(componentType);
213 getTypeMapping().register(type);
214 }
215 String ns;
216
217 if(type.isComplex())
218 {
219 ns = type.getSchemaType().getNamespaceURI();
220 }
221 else
222 {
223 ns = tm.getEncodingStyleURI();
224 }
225
226 String first = type.getSchemaType().getLocalPart().substring(0, 1);
227 String last = type.getSchemaType().getLocalPart().substring(1);
228 String localName = "ArrayOf" + first.toUpperCase() + last;
229
230 return new QName(ns, localName);
231 }
232
233 public abstract TypeClassInfo createClassInfo(Method m, int index);
234
235 /***
236 * Create a Type for a Method parameter.
237 *
238 * @param m the method to create a type for
239 * @param index The parameter index. If the index is less than zero, the return type is used.
240 */
241 public Type createType(Method m, int index)
242 {
243 TypeClassInfo info = createClassInfo(m, index);
244
245 return createTypeForClass(info);
246 }
247
248 /***
249 * Create type information for a PropertyDescriptor.
250 *
251 * @param pd the propertydescriptor
252 */
253 public Type createType(PropertyDescriptor pd)
254 {
255 TypeClassInfo info = createClassInfo(pd);
256
257 return createTypeForClass(info);
258 }
259
260 /***
261 * Create type information for a <code>Field</code>.
262 *
263 * @param f the field to create a type from
264 */
265 public Type createType(Field f)
266 {
267 TypeClassInfo info = createClassInfo(f);
268
269 return createTypeForClass(info);
270 }
271
272 public Type createType(Class clazz)
273 {
274 TypeClassInfo info = createBasicClassInfo(clazz);
275
276 return createTypeForClass(info);
277 }
278
279 public static class TypeClassInfo
280 {
281 Class typeClass;
282 Object[] annotations;
283 Object genericType;
284 Object keyType;
285 QName name;
286
287 public Object[] getAnnotations()
288 {
289 return annotations;
290 }
291
292 public void setAnnotations(Object[] annotations)
293 {
294 this.annotations = annotations;
295 }
296
297 public Object getGenericType()
298 {
299 return genericType;
300 }
301
302 public void setGenericType(Object genericType)
303 {
304 this.genericType = genericType;
305 }
306
307 public Object getKeyType()
308 {
309 return keyType;
310 }
311
312 public void setKeyType(Object keyType)
313 {
314 this.keyType = keyType;
315 }
316
317 public Class getTypeClass()
318 {
319 return typeClass;
320 }
321
322 public void setTypeClass(Class typeClass)
323 {
324 this.typeClass = typeClass;
325 }
326
327 public QName getName()
328 {
329 return name;
330 }
331
332 public void setName(QName name)
333 {
334 this.name = name;
335 }
336 }
337 }