Coverage Report - uk.co.badgersinfoil.asxsd.components.ComplexTypeComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
ComplexTypeComponent
93% 
100% 
2.474
 
 1  
 /*
 2  
  * Copyright (c) 2007 David Holroyd
 3  
  */
 4  
 
 5  
 package uk.co.badgersinfoil.asxsd.components;
 6  
 
 7  
 import java.util.Iterator;
 8  
 import java.util.List;
 9  
 import org.eclipse.xsd.XSDAttributeGroupContent;
 10  
 import org.eclipse.xsd.XSDComplexTypeContent;
 11  
 import org.eclipse.xsd.XSDComplexTypeDefinition;
 12  
 import org.eclipse.xsd.XSDConcreteComponent;
 13  
 import org.eclipse.xsd.XSDElementDeclaration;
 14  
 import org.eclipse.xsd.XSDParticle;
 15  
 import org.eclipse.xsd.XSDTypeDefinition;
 16  
 import uk.co.badgersinfoil.asxsd.BasicMappingFunction;
 17  
 import uk.co.badgersinfoil.asxsd.CodegenContext;
 18  
 import uk.co.badgersinfoil.asxsd.CodegenRole;
 19  
 import uk.co.badgersinfoil.asxsd.DocUtils;
 20  
 import uk.co.badgersinfoil.asxsd.MappingFunction;
 21  
 import uk.co.badgersinfoil.asxsd.MarshalBuilder;
 22  
 import uk.co.badgersinfoil.asxsd.StringUtils;
 23  
 import uk.co.badgersinfoil.asxsd.TypeBuilder;
 24  
 import uk.co.badgersinfoil.asxsd.TypeDescriptor;
 25  
 import uk.co.badgersinfoil.asxsd.TypeNameGenerator;
 26  
 import uk.co.badgersinfoil.asxsd.UnmarshalBuilder;
 27  
 import uk.co.badgersinfoil.asxsd.XSDUtils;
 28  
 import uk.co.badgersinfoil.metaas.dom.ASArg;
 29  
 import uk.co.badgersinfoil.metaas.dom.ASClassType;
 30  
 import uk.co.badgersinfoil.metaas.dom.ASCompilationUnit;
 31  
 import uk.co.badgersinfoil.metaas.dom.ASMethod;
 32  
 import uk.co.badgersinfoil.metaas.dom.StatementContainer;
 33  
 import uk.co.badgersinfoil.metaas.dom.Visibility;
 34  
 
 35  16
 public class ComplexTypeComponent extends AbstractMappingComponent {
 36  
 
 37  16
         TypeNameGenerator nameGen = new TypeNameGenerator();
 38  
 
 39  
         public TypeDescriptor createTypeDescriptor(CodegenContext context,
 40  
                                                 XSDConcreteComponent component)
 41  
         {
 42  16
                 XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition)component;
 43  16
                 context.pushAttrScope();
 44  16
                 String docs = null;
 45  16
                 String typeName = context.createTypeNameFor(complexType);
 46  16
                 TypeDescriptor result = new TypeDescriptor(typeName, false, docs, component);
 47  16
                 context.popAttrScope();
 48  16
                 return result;
 49  
         }
 50  
 
 51  
         public TypeDescriptor typeDescriptorFor(CodegenContext context,
 52  
                                                 XSDConcreteComponent component)
 53  
         {
 54  83
                 XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition)component;
 55  83
                 if (XSDUtils.isAnonymous(complexType)) {
 56  1
                         return context.typeDescriptorFor(complexType.getContainer());
 57  
                 }
 58  82
                 return super.typeDescriptorFor(context, component);
 59  
         }
 60  
 
 61  
         public ASCompilationUnit createType(CodegenContext context,
 62  
                                          XSDConcreteComponent component)
 63  
         {
 64  16
                 XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition)component;
 65  16
                 String typeName = context.createTypeNameFor(complexType);
 66  16
                 ASCompilationUnit unit = context.getProject().newClass(typeName);
 67  16
                 context.pushAttrScope();
 68  16
                 TypeBuilder.setCurrentTypeCompilationUnit(context, unit);
 69  16
                 context.setCurrentRole(CodegenRole.TYPE);
 70  16
                 context.generateCode(complexType);
 71  16
                 context.popAttrScope();
 72  16
                 return unit;
 73  
         }
 74  
 
 75  
         public String createTypeNameFor(CodegenContext context,
 76  
                                         XSDConcreteComponent component)
 77  
         {
 78  34
                 XSDComplexTypeDefinition typeDef = (XSDComplexTypeDefinition)component;
 79  34
                 return context.getTypeBuilder().typeNameFor(typeDef);
 80  
         }
 81  
 
 82  
         public void generateCode(CodegenContext context,XSDConcreteComponent component) {
 83  57
                 XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition)component;
 84  57
                 CodegenRole role = context.getCurrentRole();
 85  57
                 if (role == CodegenRole.UNMARSHAL) {
 86  19
                         StatementContainer block = context.getCurrentMethodCode();
 87  19
                         if (!XSDUtils.isAnonymous(complexType)) {
 88  16
                                 block.addStmt("default xml namespace = NAMESPACE");
 89  16
                                 TypeDescriptor typeDesc = context.typeDescriptorFor(complexType);
 90  16
                                 block.addStmt("var _result:"+typeDesc.getTypeName()+" = new "+typeDesc.getTypeName()+"()");
 91  
                         }
 92  19
                         processComplexTypeBaseTypeUnmarshal(context, complexType);
 93  19
                         processAllComplexTypeAttributesUnmarshal(context, complexType);
 94  19
                         processAllComplexTypeElementsUnmarshal(context, complexType);
 95  19
                         block.addStmt("return _result");
 96  19
                 } else if (role == CodegenRole.MARSHAL) {
 97  19
                         processComplexTypeBaseTypeMarshal(context, complexType);
 98  19
                         processAllComplexTypeAttributesMarshal(context, complexType);
 99  19
                         processAllComplexTypeElementsMarshal(context, complexType);
 100  19
                 } else if (role == CodegenRole.TYPE) {
 101  
                         //ASClassType clazz = TypeBuilder.getCurrentType(context);
 102  19
                         processComplexTypeBaseType(context, complexType);
 103  19
                         processComplexTypeAnnotation(context, complexType);
 104  19
                         processAllComplexTypeAttributes(context, complexType);
 105  19
                         processContent(context, complexType);
 106  
                 } else {
 107  0
                         super.generateCode(context, component);
 108  
                 }
 109  57
         }
 110  
 
 111  
         private void processComplexTypeBaseTypeUnmarshal(CodegenContext context, XSDComplexTypeDefinition ctype) {
 112  19
                 XSDTypeDefinition baseType = ctype.getBaseType();
 113  19
                 if (isAllowedAsSuperclass(baseType)) {
 114  
                         // TODO: handle base class initialisation
 115  0
                         UnmarshalBuilder.warn("Base class initialisation for "+baseType.getQName()+" (base class of "+ctype.getQName()+") not handled; sorry");
 116  
                 }
 117  19
         }
 118  
 
 119  
         private void processAllComplexTypeAttributesUnmarshal(CodegenContext context, XSDComplexTypeDefinition ctype) {
 120  19
                 List attrs= ctype.getAttributeContents();
 121  19
                 for (Iterator i=attrs.iterator(); i.hasNext(); ) {
 122  8
                         XSDAttributeGroupContent attrContent = (XSDAttributeGroupContent)i.next();
 123  8
                         context.generateCode(attrContent);
 124  8
                 }
 125  19
         }
 126  
 
 127  
         private void processAllComplexTypeElementsUnmarshal(CodegenContext context, XSDComplexTypeDefinition typeDef)
 128  
         {
 129  19
                 XSDComplexTypeContent complexContent = typeDef.getContent();
 130  19
                 if (complexContent == null) {
 131  2
                         return;
 132  
                 }
 133  
 
 134  17
                 if (complexContent instanceof XSDParticle) {
 135  
                         // TODO: test to see if there will really be elements to process?
 136  
                         //       or is presence of an XSDParticle enough?
 137  15
                         StatementContainer block = context.getCurrentMethodCode();
 138  15
                         block.addComment(" process child sequence elements,");
 139  15
                         XSDParticle particle = (XSDParticle)complexContent;
 140  15
                         block.addStmt("var _children:XMLList = thisElement.children()");
 141  15
                         block.addStmt("var _seq:int = 0");
 142  15
                         context.pushAttrScope();
 143  15
                         UnmarshalBuilder.setCurrentSourceExpr(context, "_children[_seq++]");
 144  15
                         context.setAttribute("element-access-expression", "_children[_seq]");
 145  15
                         context.generateCode(particle);
 146  15
                         context.popAttrScope();
 147  15
                 } else {
 148  2
                         context.generateCode(complexContent);
 149  
                 }
 150  17
         }
 151  
         
 152  
         private void processComplexTypeBaseTypeMarshal(CodegenContext context, XSDComplexTypeDefinition ctype) {
 153  19
                 XSDTypeDefinition baseType = ctype.getBaseType();
 154  19
                 if (isAllowedAsSuperclass(baseType)) {
 155  
                         // TODO: handle base class initialisation
 156  0
                         MarshalBuilder.warn("Base class initialisation for "+baseType.getQName()+" (base class of "+ctype.getQName()+") not handled; sorry");
 157  
                 }
 158  19
         }
 159  
 
 160  
         private void processAllComplexTypeAttributesMarshal(CodegenContext context, XSDComplexTypeDefinition ctype) {
 161  19
                 List attrs = ctype.getAttributeContents();
 162  19
                 for (Iterator i=attrs.iterator(); i.hasNext(); ) {
 163  8
                         XSDAttributeGroupContent attrContent = (XSDAttributeGroupContent)i.next();
 164  8
                         context.generateCode(attrContent);
 165  8
                 }
 166  19
         }
 167  
 
 168  
         private void processAllComplexTypeElementsMarshal(CodegenContext context, XSDComplexTypeDefinition typeDef)
 169  
         {
 170  19
                 XSDComplexTypeContent complexContent = typeDef.getContent();
 171  19
                 if (complexContent != null) {
 172  17
                         context.generateCode(complexContent);
 173  
                 }
 174  19
         }
 175  
 
 176  
         private void processComplexTypeBaseType(CodegenContext context, XSDComplexTypeDefinition typeDef) {
 177  19
                 XSDTypeDefinition baseType = typeDef.getBaseType();
 178  19
                 if (isAllowedAsSuperclass(baseType)) {
 179  0
                         ASClassType clazz = TypeBuilder.getCurrentType(context);
 180  0
                         clazz.setSuperclass(nameGen.typeName(baseType));
 181  
                 }
 182  19
         }
 183  
 
 184  
         private boolean isAllowedAsSuperclass(XSDTypeDefinition baseType) {
 185  57
                 return !XSDUtils.isXSDAnyType(baseType)
 186  
                        && baseType instanceof XSDComplexTypeDefinition;
 187  
         }
 188  
 
 189  
         /**
 190  
          * turn attributes defined by the complexType into class properties
 191  
          */
 192  
         private void processAllComplexTypeAttributes(CodegenContext context, XSDComplexTypeDefinition typeDef)
 193  
         {
 194  19
                 List attrs = typeDef.getAttributeContents();
 195  19
                 for (Iterator i=attrs.iterator(); i.hasNext(); ) {
 196  8
                         XSDAttributeGroupContent attrContent = (XSDAttributeGroupContent)i.next();
 197  8
                         context.generateCode(attrContent);
 198  8
                 }
 199  19
         }
 200  
 
 201  
 
 202  
         /**
 203  
          * add any annotation on the given complexType as the documentation
 204  
          * comment for the given AS class.
 205  
          */
 206  
         private void processComplexTypeAnnotation(CodegenContext context, XSDComplexTypeDefinition typeDef)
 207  
         {
 208  19
                 String doc = DocUtils.findDocumentation(typeDef.getAnnotation());
 209  19
                 if (doc != null) {
 210  0
                         ASClassType clazz = TypeBuilder.getCurrentType(context);
 211  0
                         clazz.setDescription(doc);
 212  
                 }
 213  19
         }
 214  
 
 215  
 
 216  
         private void processContent(CodegenContext context,
 217  
                                     XSDComplexTypeDefinition typeDef)
 218  
         {
 219  19
                 XSDComplexTypeContent content = typeDef.getContent();
 220  19
                 if (content != null) {
 221  17
                         context.generateCode(content);
 222  
                 }
 223  19
         }
 224  
 
 225  
         public boolean willAccept(XSDConcreteComponent component) {
 226  436
                 return component instanceof XSDComplexTypeDefinition;
 227  
         }
 228  
 
 229  
         public MappingFunction createFunctionRef(CodegenContext context,
 230  
                                                  XSDConcreteComponent component)
 231  
         {
 232  32
                 XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition)component;
 233  32
                 CodegenRole role = context.getCurrentRole();
 234  
                 String qname;
 235  32
                 if (role == CodegenRole.UNMARSHAL) {
 236  16
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 237  16
                         ASCompilationUnit unit = builder.getClassForNamespace(complexType.getTargetNamespace());
 238  16
                         ASClassType clazz = (ASClassType)unit.getType();
 239  16
                         TypeDescriptor typeDesc = context.typeDescriptorFor(complexType);
 240  16
                         String methodName = "unmarshal" + StringUtils.sanitize(complexType.getName());
 241  16
                         if (unit.getPackageName() != null) {
 242  16
                                 qname = unit.getPackageName()+"."+clazz.getName()+"."+methodName;
 243  
                         } else {
 244  0
                                 qname = clazz.getName()+"."+methodName;
 245  
                         }
 246  16
                 } else if (role == CodegenRole.MARSHAL) {
 247  16
                         MarshalBuilder builder = context.getMarshalBuilder();
 248  16
                         ASCompilationUnit unit = builder.getClassForNamespace(complexType.getTargetNamespace());
 249  16
                         ASClassType clazz = (ASClassType)unit.getType();
 250  16
                         String typeName = MarshalBuilder.xmlReturnTypeFor(complexType);
 251  16
                         String methodName = builder.methodNameFor(complexType);
 252  16
                         if (unit.getPackageName() != null) {
 253  16
                                 qname = unit.getPackageName()+"."+clazz.getName()+"."+methodName;
 254  
                         } else {
 255  0
                                 qname = clazz.getName()+"."+methodName;
 256  
                         }
 257  16
                 } else {
 258  0
                         throw new IllegalArgumentException("role="+role);
 259  
                 }
 260  32
                 return new BasicMappingFunction(qname);
 261  
         }
 262  
 
 263  
         public ASMethod createFunction(CodegenContext context,
 264  
                                        XSDConcreteComponent component)
 265  
         {
 266  32
                 XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition)component;
 267  32
                 CodegenRole role = context.getCurrentRole();
 268  32
                 if (role == CodegenRole.UNMARSHAL) {
 269  16
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 270  16
                         ASCompilationUnit unit = builder.getClassForNamespace(complexType.getTargetNamespace());
 271  16
                         ASClassType clazz = (ASClassType)unit.getType();
 272  16
                         TypeDescriptor typeDesc = context.typeDescriptorFor(complexType);
 273  16
                         String methodName = "unmarshal" + StringUtils.sanitize(complexType.getName());
 274  16
                         ASMethod meth = clazz.newMethod(methodName, Visibility.PUBLIC, typeDesc.getTypeName());
 275  16
                         ASArg arg = meth.addParam("thisElement", "XML");
 276  16
                         String doc = "an element of type "+complexType.getURI();
 277  16
                         arg.setDescription(doc);
 278  16
                         meth.setStatic(true);
 279  16
                         context.pushAttrScope();
 280  16
                         UnmarshalBuilder.setCurrentSourceExpr(context, "thisElement");
 281  16
                         context.setCurrentMethodCode(meth);
 282  16
                         context.generateCode(complexType);
 283  16
                         context.popAttrScope();
 284  16
                         return meth;
 285  
                 }
 286  16
                 if (role == CodegenRole.MARSHAL) {
 287  16
                         MarshalBuilder builder = context.getMarshalBuilder();
 288  16
                         ASCompilationUnit unit = builder.getClassForNamespace(complexType.getTargetNamespace());
 289  16
                         ASClassType clazz = (ASClassType)unit.getType();
 290  16
                         String typeName = MarshalBuilder.xmlReturnTypeFor(complexType);
 291  16
                         String methodName = builder.methodNameFor(complexType);
 292  16
                         ASMethod meth = clazz.newMethod(methodName, Visibility.PUBLIC, typeName);
 293  16
                         builder.buildMethodParams(meth, complexType);
 294  16
                         meth.setStatic(true);
 295  16
                         meth.addStmt("default xml namespace = NAMESPACE");
 296  16
                         if (XSDUtils.isAnonymous(complexType)) {
 297  
                                 // TODO: move this bit to ElementDeclarationComponent?
 298  0
                                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)complexType.getContainer();
 299  0
                                 meth.addStmt("var _result:XML = <"+elementDecl.getName()+"/>");
 300  
                         }
 301  16
                         context.pushAttrScope();
 302  16
                         MarshalBuilder.setCurrentTargetParentElementExpr(context, "_result");
 303  16
                         MarshalBuilder.setCurrentSourceExpr(context, "thisObject");
 304  16
                         context.setCurrentMethodCode(meth);
 305  16
                         context.generateCode(complexType);
 306  16
                         context.popAttrScope();
 307  16
                         meth.addStmt("return _result");
 308  16
                         return meth;
 309  
                 }
 310  0
                 return super.createFunction(context, component);
 311  
         }
 312  
 }