View Javadoc

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         // TODO: Get namespace from XML?
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 }