001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.aegis.type;
019:
020: import java.beans.PropertyDescriptor;
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Method;
023: import java.util.Collection;
024: import java.util.Map;
025:
026: import javax.xml.namespace.QName;
027: import javax.xml.ws.Holder;
028:
029: import org.apache.cxf.aegis.DatabindingException;
030: import org.apache.cxf.aegis.type.basic.ArrayType;
031: import org.apache.cxf.aegis.type.basic.ObjectType;
032: import org.apache.cxf.aegis.type.collection.CollectionType;
033: import org.apache.cxf.aegis.type.collection.MapType;
034: import org.apache.cxf.aegis.util.NamespaceHelper;
035: import org.apache.cxf.aegis.util.ServiceUtils;
036:
037: /**
038: * @author Hani Suleiman Date: Jun 14, 2005 Time: 11:59:57 PM
039: */
040: public abstract class AbstractTypeCreator implements TypeCreator {
041: protected TypeMapping tm;
042:
043: protected AbstractTypeCreator nextCreator;
044:
045: private Configuration typeConfiguration;
046:
047: private TypeCreator parent;
048:
049: public TypeMapping getTypeMapping() {
050: return tm;
051: }
052:
053: public TypeCreator getTopCreator() {
054: TypeCreator top = this ;
055: TypeCreator next = top;
056: while (next != null) {
057: top = next;
058: next = top.getParent();
059: }
060: return top;
061: }
062:
063: public TypeCreator getParent() {
064: return parent;
065: }
066:
067: public void setParent(TypeCreator parent) {
068: this .parent = parent;
069: }
070:
071: public void setTypeMapping(TypeMapping typeMapping) {
072: this .tm = typeMapping;
073:
074: if (nextCreator != null) {
075: nextCreator.setTypeMapping(tm);
076: }
077: }
078:
079: public void setNextCreator(AbstractTypeCreator creator) {
080: this .nextCreator = creator;
081: nextCreator.parent = this ;
082: }
083:
084: public TypeClassInfo createClassInfo(Field f) {
085: TypeClassInfo info = createBasicClassInfo(f.getType());
086: info.setDescription("field " + f.getName() + " in "
087: + f.getDeclaringClass());
088: return info;
089: }
090:
091: public TypeClassInfo createBasicClassInfo(Class typeClass) {
092: TypeClassInfo info = new TypeClassInfo();
093: info.setDescription("class '" + typeClass.getName() + '\'');
094: info.setTypeClass(typeClass);
095:
096: return info;
097: }
098:
099: protected Type createTypeForClass(TypeClassInfo info) {
100: Class javaType = info.getTypeClass();
101: Type result = null;
102: boolean newType = true;
103:
104: if (info.getType() != null) {
105: result = createUserType(info);
106: } else if (isArray(javaType)) {
107: result = createArrayType(info);
108: } else if (isMap(javaType)) {
109: result = createMapType(info);
110: } else if (isHolder(javaType)) {
111: result = createHolderType(info);
112: } else if (isCollection(javaType)) {
113: result = createCollectionType(info);
114: } else if (isEnum(javaType)) {
115: result = createEnumType(info);
116: } else {
117: Type type = getTypeMapping().getType(javaType);
118: if (type == null) {
119: type = createDefaultType(info);
120: } else {
121: newType = false;
122: }
123:
124: result = type;
125: }
126:
127: if (newType && !getConfiguration().isDefaultNillable()) {
128: result.setNillable(false);
129: }
130:
131: return result;
132: }
133:
134: protected boolean isHolder(Class javaType) {
135: return javaType.equals(Holder.class);
136: }
137:
138: protected Type createHolderType(TypeClassInfo info) {
139: if (info.getGenericType() == null) {
140: throw new UnsupportedOperationException(
141: "To use holder types "
142: + "you must have an XML descriptor declaring the component type.");
143: }
144:
145: Class heldCls = (Class) info.getGenericType();
146: info.setTypeClass(heldCls);
147:
148: return createType(heldCls);
149: }
150:
151: protected boolean isArray(Class javaType) {
152: return javaType.isArray() && !javaType.equals(byte[].class);
153: }
154:
155: protected Type createUserType(TypeClassInfo info) {
156: try {
157: Type type = (Type) info.getType().newInstance();
158:
159: QName name = info.getTypeName();
160: if (name == null) {
161: name = createQName(info.getTypeClass());
162: }
163:
164: type.setSchemaType(name);
165: type.setTypeClass(info.getTypeClass());
166: type.setTypeMapping(getTypeMapping());
167:
168: return type;
169: } catch (InstantiationException e) {
170: throw new DatabindingException(
171: "Couldn't instantiate type classs "
172: + info.getType().getName(), e);
173: } catch (IllegalAccessException e) {
174: throw new DatabindingException(
175: "Couldn't access type classs "
176: + info.getType().getName(), e);
177: }
178: }
179:
180: protected Type createArrayType(TypeClassInfo info) {
181: ArrayType type = new ArrayType();
182: type.setTypeMapping(getTypeMapping());
183: type.setTypeClass(info.getTypeClass());
184: type.setSchemaType(createCollectionQName(info, type
185: .getComponentType()));
186:
187: if (info.getMinOccurs() != -1) {
188: type.setMinOccurs(info.getMinOccurs());
189: }
190: if (info.getMaxOccurs() != -1) {
191: type.setMaxOccurs(info.getMaxOccurs());
192: }
193:
194: type.setFlat(info.isFlat());
195:
196: return type;
197: }
198:
199: protected QName createQName(Class javaType) {
200: String clsName = javaType.getName();
201:
202: String ns = NamespaceHelper.makeNamespaceFromClassName(clsName,
203: "http");
204: String localName = ServiceUtils
205: .makeServiceNameFromClassName(javaType);
206:
207: return new QName(ns, localName);
208: }
209:
210: protected boolean isCollection(Class javaType) {
211: return Collection.class.isAssignableFrom(javaType);
212: }
213:
214: protected Type createCollectionTypeFromGeneric(TypeClassInfo info) {
215: Type component = getOrCreateGenericType(info);
216:
217: CollectionType type = new CollectionType(component);
218: type.setTypeMapping(getTypeMapping());
219:
220: QName name = info.getTypeName();
221: if (name == null) {
222: name = createCollectionQName(info, component);
223: }
224:
225: type.setSchemaType(name);
226:
227: type.setTypeClass(info.getTypeClass());
228:
229: if (info.getMinOccurs() != -1) {
230: type.setMinOccurs(info.getMinOccurs());
231: }
232: if (info.getMaxOccurs() != -1) {
233: type.setMaxOccurs(info.getMaxOccurs());
234: }
235:
236: type.setFlat(info.isFlat());
237:
238: return type;
239: }
240:
241: protected Type getOrCreateGenericType(TypeClassInfo info) {
242: return createObjectType();
243: }
244:
245: protected Type getOrCreateMapKeyType(TypeClassInfo info) {
246: return nextCreator.getOrCreateMapKeyType(info);
247: }
248:
249: protected Type createObjectType() {
250: ObjectType type = new ObjectType();
251: type.setSchemaType(DefaultTypeMappingRegistry.XSD_ANY);
252: type.setTypeClass(Object.class);
253: type.setTypeMapping(getTypeMapping());
254: return type;
255: }
256:
257: protected Type getOrCreateMapValueType(TypeClassInfo info) {
258: return nextCreator.getOrCreateMapKeyType(info);
259: }
260:
261: protected Type createMapType(TypeClassInfo info, Type keyType,
262: Type valueType) {
263: QName schemaType = createMapQName(info, keyType, valueType);
264: MapType type = new MapType(schemaType, keyType, valueType);
265: type.setTypeMapping(getTypeMapping());
266: type.setTypeClass(info.getTypeClass());
267:
268: return type;
269: }
270:
271: protected Type createMapType(TypeClassInfo info) {
272: Type keyType = getOrCreateMapKeyType(info);
273: Type valueType = getOrCreateMapValueType(info);
274:
275: return createMapType(info, keyType, valueType);
276: }
277:
278: protected QName createMapQName(TypeClassInfo info, Type keyType,
279: Type valueType) {
280: String name = keyType.getSchemaType().getLocalPart() + '2'
281: + valueType.getSchemaType().getLocalPart() + "Map";
282:
283: // TODO: Get namespace from XML?
284: return new QName(tm.getEncodingStyleURI(), name);
285: }
286:
287: protected boolean isMap(Class javaType) {
288: return Map.class.isAssignableFrom(javaType);
289: }
290:
291: public abstract TypeClassInfo createClassInfo(PropertyDescriptor pd);
292:
293: protected boolean isEnum(Class javaType) {
294: return false;
295: }
296:
297: public Type createEnumType(TypeClassInfo info) {
298: return null;
299: }
300:
301: public abstract Type createCollectionType(TypeClassInfo info);
302:
303: public abstract Type createDefaultType(TypeClassInfo info);
304:
305: protected QName createCollectionQName(TypeClassInfo info, Type type) {
306: String ns;
307:
308: if (type.isComplex()) {
309: ns = type.getSchemaType().getNamespaceURI();
310: } else {
311: ns = tm.getEncodingStyleURI();
312: }
313:
314: String first = type.getSchemaType().getLocalPart().substring(0,
315: 1);
316: String last = type.getSchemaType().getLocalPart().substring(1);
317: String localName = "ArrayOf" + first.toUpperCase() + last;
318:
319: return new QName(ns, localName);
320: }
321:
322: public abstract TypeClassInfo createClassInfo(Method m, int index);
323:
324: /**
325: * Create a Type for a Method parameter.
326: *
327: * @param m the method to create a type for
328: * @param index The parameter index. If the index is less than zero, the
329: * return type is used.
330: */
331: public Type createType(Method m, int index) {
332: TypeClassInfo info = createClassInfo(m, index);
333: info.setDescription((index == -1 ? "return type" : "parameter "
334: + index)
335: + " of method "
336: + m.getName()
337: + " in "
338: + m.getDeclaringClass());
339: return createTypeForClass(info);
340: }
341:
342: public QName getElementName(Method m, int index) {
343: TypeClassInfo info = createClassInfo(m, index);
344:
345: return info.getMappedName();
346: }
347:
348: /**
349: * Create type information for a PropertyDescriptor.
350: *
351: * @param pd the propertydescriptor
352: */
353: public Type createType(PropertyDescriptor pd) {
354: TypeClassInfo info = createClassInfo(pd);
355: info.setDescription("property " + pd.getName());
356: return createTypeForClass(info);
357: }
358:
359: /**
360: * Create type information for a <code>Field</code>.
361: *
362: * @param f the field to create a type from
363: */
364: public Type createType(Field f) {
365: TypeClassInfo info = createClassInfo(f);
366: info.setDescription("field " + f.getName() + " in "
367: + f.getDeclaringClass());
368: return createTypeForClass(info);
369: }
370:
371: public Type createType(Class clazz) {
372: TypeClassInfo info = createBasicClassInfo(clazz);
373: info.setDescription(clazz.toString());
374: return createTypeForClass(info);
375: }
376:
377: public Configuration getConfiguration() {
378: return typeConfiguration;
379: }
380:
381: public void setConfiguration(Configuration tpConfiguration) {
382: this .typeConfiguration = tpConfiguration;
383: }
384:
385: public static class TypeClassInfo {
386: Class typeClass;
387:
388: Object[] annotations;
389:
390: Object genericType;
391:
392: Object keyType;
393:
394: QName mappedName;
395:
396: QName typeName;
397:
398: Class type;
399:
400: String description;
401:
402: long minOccurs = -1;
403: long maxOccurs = -1;
404: boolean flat;
405:
406: public String getDescription() {
407: return description;
408: }
409:
410: public void setDescription(String description) {
411: this .description = description;
412: }
413:
414: public Object[] getAnnotations() {
415: return annotations;
416: }
417:
418: public void setAnnotations(Object[] annotations) {
419: this .annotations = annotations;
420: }
421:
422: public Object getGenericType() {
423: return genericType;
424: }
425:
426: public void setGenericType(Object genericType) {
427: this .genericType = genericType;
428: }
429:
430: public Object getKeyType() {
431: return keyType;
432: }
433:
434: public void setKeyType(Object keyType) {
435: this .keyType = keyType;
436: }
437:
438: public Class getTypeClass() {
439: return typeClass;
440: }
441:
442: public void setTypeClass(Class typeClass) {
443: this .typeClass = typeClass;
444: }
445:
446: public QName getTypeName() {
447: return typeName;
448: }
449:
450: public void setTypeName(QName name) {
451: this .typeName = name;
452: }
453:
454: public Class getType() {
455: return type;
456: }
457:
458: public void setType(Class type) {
459: this .type = type;
460: }
461:
462: public QName getMappedName() {
463: return mappedName;
464: }
465:
466: public void setMappedName(QName mappedName) {
467: this .mappedName = mappedName;
468: }
469:
470: public long getMaxOccurs() {
471: return maxOccurs;
472: }
473:
474: public void setMaxOccurs(long maxOccurs) {
475: this .maxOccurs = maxOccurs;
476: }
477:
478: public long getMinOccurs() {
479: return minOccurs;
480: }
481:
482: public void setMinOccurs(long minOccurs) {
483: this .minOccurs = minOccurs;
484: }
485:
486: public boolean isFlat() {
487: return flat;
488: }
489:
490: public void setFlat(boolean flat) {
491: this.flat = flat;
492: }
493: }
494: }
|