Coverage Report - uk.co.badgersinfoil.asxsd.components.ElementDeclarationComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
ElementDeclarationComponent
96% 
100% 
4.071
 
 1  
 /*
 2  
  * Copyright (c) 2007 David Holroyd
 3  
  */
 4  
 
 5  
 package uk.co.badgersinfoil.asxsd.components;
 6  
 
 7  
 import org.eclipse.xsd.XSDComplexTypeDefinition;
 8  
 import org.eclipse.xsd.XSDConcreteComponent;
 9  
 import org.eclipse.xsd.XSDElementDeclaration;
 10  
 import org.eclipse.xsd.XSDSimpleTypeDefinition;
 11  
 import org.eclipse.xsd.XSDTypeDefinition;
 12  
 import org.eclipse.xsd.XSDVariety;
 13  
 import uk.co.badgersinfoil.asxsd.BasicMappingFunction;
 14  
 import uk.co.badgersinfoil.asxsd.CodegenContext;
 15  
 import uk.co.badgersinfoil.asxsd.CodegenRole;
 16  
 import uk.co.badgersinfoil.asxsd.MappingFunction;
 17  
 import uk.co.badgersinfoil.asxsd.MarshalBuilder;
 18  
 import uk.co.badgersinfoil.asxsd.StringUtils;
 19  
 import uk.co.badgersinfoil.asxsd.TypeBuilder;
 20  
 import uk.co.badgersinfoil.asxsd.TypeDescriptor;
 21  
 import uk.co.badgersinfoil.asxsd.UnmarshalBuilder;
 22  
 import uk.co.badgersinfoil.asxsd.XSDUtils;
 23  
 import uk.co.badgersinfoil.metaas.ActionScriptFactory;
 24  
 import uk.co.badgersinfoil.metaas.dom.ASArg;
 25  
 import uk.co.badgersinfoil.metaas.dom.ASClassType;
 26  
 import uk.co.badgersinfoil.metaas.dom.ASCompilationUnit;
 27  
 import uk.co.badgersinfoil.metaas.dom.ASExpression;
 28  
 import uk.co.badgersinfoil.metaas.dom.ASField;
 29  
 import uk.co.badgersinfoil.metaas.dom.ASMethod;
 30  
 import uk.co.badgersinfoil.metaas.dom.StatementContainer;
 31  
 import uk.co.badgersinfoil.metaas.dom.Visibility;
 32  
 
 33  16
 public class ElementDeclarationComponent extends AbstractMappingComponent {
 34  
         
 35  
         private static final String KEY_CURRENT_FUNCTION_ELEMENT = "uk.co.badgersinfoil.asxsd.components.ElementDeclarationComponent.currentFunctionElement";
 36  
 
 37  
         public TypeDescriptor createTypeDescriptor(CodegenContext context,
 38  
                                                 XSDConcreteComponent component)
 39  
         {
 40  3
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 41  3
                 context.pushAttrScope();
 42  3
                 String docs = null;
 43  3
                 String typeName = context.createTypeNameFor(elementDecl);
 44  3
                 TypeDescriptor result = new TypeDescriptor(typeName, false, docs, component);
 45  3
                 context.popAttrScope();
 46  3
                 return result;
 47  
         }
 48  
 
 49  
         public TypeDescriptor typeDescriptorFor(CodegenContext context,
 50  
                                                 XSDConcreteComponent component)
 51  
         {
 52  89
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 53  89
                 XSDTypeDefinition typeDef = elementDecl.getTypeDefinition();
 54  89
                 if (XSDUtils.isAnonymous(typeDef) && !nonAtomic(typeDef)) {
 55  12
                         return super.typeDescriptorFor(context, elementDecl);
 56  
                 }
 57  77
                 return context.typeDescriptorFor(typeDef);
 58  
         }
 59  
 
 60  
         private static boolean nonAtomic(XSDTypeDefinition typeDef) {
 61  15
                 if (typeDef instanceof XSDComplexTypeDefinition) {
 62  12
                         return false;
 63  
                 }
 64  3
                 XSDSimpleTypeDefinition simpleType = (XSDSimpleTypeDefinition)typeDef;
 65  3
                 return simpleType.getVariety() != XSDVariety.ATOMIC_LITERAL;
 66  
         }
 67  
 
 68  
         public ASCompilationUnit createType(CodegenContext context,
 69  
                                          XSDConcreteComponent component)
 70  
         {
 71  3
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 72  3
                 String typeName = createTypeNameFor(context, elementDecl);
 73  3
                 ASCompilationUnit unit = context.getProject().newClass(typeName);
 74  3
                 TypeBuilder.setCurrentTypeCompilationUnit(context, unit);
 75  3
                 context.setCurrentRole(CodegenRole.TYPE);
 76  3
                 context.generateCode(elementDecl.getType());
 77  3
                 return unit;
 78  
         }
 79  
 
 80  
         public String createTypeNameFor(CodegenContext context,
 81  
                                         XSDConcreteComponent component)
 82  
         {
 83  6
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 84  6
                 return StringUtils.toPackageName(elementDecl.getTargetNamespace())
 85  
                                                + ".Element_" + StringUtils.sanitize(elementDecl.getName());
 86  
         }
 87  
 
 88  
         public boolean willAccept(XSDConcreteComponent component) {
 89  2314
                 return component instanceof XSDElementDeclaration;
 90  
         }
 91  
 
 92  
         public ASExpression createExpression(CodegenContext context,
 93  
                                              XSDConcreteComponent component)
 94  
         {
 95  27
                 CodegenRole role = context.getCurrentRole();
 96  27
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 97  27
                 ActionScriptFactory fact = context.getFactory();
 98  27
                 if (role == CodegenRole.UNMARSHAL_DETECT) {
 99  18
                         String acc = (String)context.getAttribute("element-access-expression");
 100  18
                         ASExpression elementAccess = fact.newExpression(acc+".name()");
 101  18
                         ASExpression qname = fact.newExpression("new QName("+ActionScriptFactory.str(elementDecl.getTargetNamespace())+", "+ActionScriptFactory.str(elementDecl.getName())+")");
 102  18
                         return fact.newEqualsExpression(elementAccess, qname);
 103  
                 }
 104  9
                 if (role == CodegenRole.MARSHAL_DETECT) {
 105  9
                         String propertyName = context.variableNameFor(elementDecl);
 106  9
                         String sourceExpr = MarshalBuilder.getCurrentSourceExpr(context);
 107  9
                         String accessExpr = sourceExpr+"."+propertyName;
 108  9
                         return fact.newExpression(accessExpr + " != null");
 109  
                 }
 110  0
                 return super.createExpression(context, component);
 111  
         }
 112  
 
 113  
         public void generateCode(CodegenContext context, final XSDConcreteComponent component) {
 114  147
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 115  147
                 CodegenRole role = context.getCurrentRole();
 116  147
                 if (role == CodegenRole.UNMARSHAL) {
 117  8
                         XSDTypeDefinition typeDef = elementDecl.getType();
 118  8
                         StatementContainer block = context.getCurrentMethodCode();
 119  8
                         String accessExpr = UnmarshalBuilder.getCurrentSourceExpr(context);
 120  8
                         if (typeDef instanceof XSDComplexTypeDefinition) {
 121  4
                                 if (elementDecl.isGlobal()) {
 122  2
                                         TypeDescriptor typeDesc = context.typeDescriptorFor(component);
 123  2
                                         block.addStmt("var _result:"+typeDesc.getTypeName()+" = new "+typeDesc.getTypeName()+"()");
 124  2
                                         context.generateCode(typeDef);
 125  2
                                 } else {
 126  2
                                         if (isCurrentFuctionElement(context, elementDecl)) {
 127  1
                                                 TypeDescriptor typeDesc = context.typeDescriptorFor(typeDef);
 128  1
                                                 block.addStmt("var _result:"+typeDesc.getTypeName()+" = new "+typeDesc.getTypeName()+"()");
 129  1
                                                 context.generateCode(typeDef);
 130  1
                                         } else {
 131  1
                                                 String result = "_result";
 132  1
                                                 String propertyName = context.variableNameFor(elementDecl);
 133  1
                                                 String targetExpr = result+"."+propertyName;
 134  1
                                                 MappingFunction conv = context.functionFor(elementDecl);
 135  1
                                                 block.addStmt(targetExpr + " = " + conv.appliedTo(accessExpr));
 136  1
                                         }
 137  
                                 }
 138  
                         } else {
 139  
                                 MappingFunction conv;
 140  4
                                 if (XSDUtils.isAnonymous(typeDef)) {
 141  2
                                         conv = context.functionFor(elementDecl);
 142  
                                 } else {
 143  2
                                         conv = context.functionFor(typeDef);
 144  
                                 }
 145  4
                                 block.addStmt("return "+conv.appliedTo(accessExpr + ".text()"));
 146  
                         }
 147  8
                 } else if (role == CodegenRole.MARSHAL) {
 148  71
                         XSDTypeDefinition typeDef = elementDecl.getType();
 149  71
                         if (isCurrentFuctionElement(context, elementDecl)) {
 150  6
                                 if (typeDef instanceof XSDSimpleTypeDefinition) {
 151  2
                                         StatementContainer block = context.getCurrentMethodCode();
 152  2
                                         MappingFunction conv = context.functionFor(typeDef);
 153  2
                                         String accessExpr = "thisValue";  // TODO: get expression from context instead
 154  2
                                         String converted = conv.appliedTo(accessExpr);
 155  2
                                         block.addStmt("_result.appendChild("+converted+")");
 156  2
                                 } else {
 157  4
                                         if (XSDUtils.isAnonymous(typeDef)) {
 158  3
                                                 context.generateCode(typeDef);
 159  
                                         } else {
 160  1
                                                 StatementContainer block = context.getCurrentMethodCode();
 161  1
                                                 MappingFunction conv = context.functionFor(typeDef);
 162  1
                                                 String accessExpr = MarshalBuilder.getCurrentSourceExpr(context);
 163  1
                                                 block.addStmt(conv.appliedTo("_result, "+accessExpr));
 164  1
                                         }
 165  
                                 }
 166  
                         } else {
 167  65
                                 StatementContainer block = context.getCurrentMethodCode();
 168  65
                                 String propertyName = context.variableNameFor(elementDecl);
 169  65
                                 String accessExpr = MarshalBuilder.getCurrentSourceExpr(context);
 170  65
                                 String targetParentExpr = MarshalBuilder.getCurrentTargetParentElementExpr(context);
 171  65
                                 block.addStmt("var "+propertyName+":XML = <"+elementDecl.getName()+"/>");
 172  65
                                 MappingFunction conv = context.functionFor(elementDecl);
 173  65
                                 if (typeDef instanceof XSDSimpleTypeDefinition || XSDUtils.isAnonymous(typeDef)) {
 174  64
                                         String converted = conv.appliedTo(accessExpr);
 175  64
                                         block.addStmt(propertyName+".appendChild("+converted+")");
 176  64
                                 } else {
 177  1
                                         String converted = conv.appliedTo(propertyName+", "+accessExpr);
 178  1
                                         block.addStmt(converted);
 179  
                                 }
 180  65
                                 block.addStmt(targetParentExpr+".appendChild("+propertyName+")");
 181  
                         }
 182  71
                 } else if (role == CodegenRole.TYPE) {
 183  68
                         ASClassType clazz = TypeBuilder.getCurrentType(context);
 184  68
                         TypeDescriptor typeDesc = context.typeDescriptorFor(elementDecl);
 185  68
                         ASField field = clazz.newField(context.variableNameFor(elementDecl), Visibility.PUBLIC, typeDesc.getTypeName());
 186  68
                         field.setDescription(typeDesc.getDocumentation());
 187  68
                 } else {
 188  0
                         throw new RuntimeException(getClass().getName()+" does not suppport operation generateCodeFor(role="+role+")");
 189  
                 }
 190  147
         }
 191  
 
 192  
         public MappingFunction createFunctionRef(CodegenContext context, XSDConcreteComponent component) {
 193  10
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 194  10
                 CodegenRole role = context.getCurrentRole();
 195  10
                 if (role == CodegenRole.UNMARSHAL) {
 196  4
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 197  4
                         ASCompilationUnit unit = builder.getClassForNamespace(elementDecl.getTargetNamespace());
 198  4
                         ASClassType clazz = (ASClassType)unit.getType();
 199  4
                         String name = StringUtils.sanitize(elementDecl.getName());
 200  4
                         String methodName = "unmarshal" + name;
 201  
                         String qname;
 202  4
                         if (unit.getPackageName() != null) {
 203  4
                                 qname = unit.getPackageName()+"."+clazz.getName()+"."+methodName;
 204  
                         } else {
 205  0
                                 qname = clazz.getName()+"."+methodName;
 206  
                         }
 207  4
                         return new BasicMappingFunction(qname);
 208  
                 }
 209  6
                 if (role == CodegenRole.MARSHAL) {
 210  6
                         MarshalBuilder builder = context.getMarshalBuilder();
 211  6
                         ASCompilationUnit unit = builder.getClassForNamespace(elementDecl.getTargetNamespace());
 212  6
                         ASClassType clazz = (ASClassType)unit.getType();
 213  6
                         String methodName = builder.methodNameFor(elementDecl);
 214  
                         String qname;
 215  6
                         if (unit.getPackageName() != null) {
 216  6
                                 qname = unit.getPackageName()+"."+clazz.getName()+"."+methodName;
 217  
                         } else {
 218  0
                                 qname = clazz.getName()+"."+methodName;
 219  
                         }
 220  6
                         return new BasicMappingFunction(qname);
 221  
                 }
 222  0
                 throw new IllegalArgumentException(getClass().getName() + " does not support role "+role);
 223  
         }
 224  
 
 225  
         public ASMethod createFunction(CodegenContext context, XSDConcreteComponent component) {
 226  10
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 227  10
                 CodegenRole role = context.getCurrentRole();
 228  10
                 if (role == CodegenRole.UNMARSHAL) {
 229  4
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 230  4
                         ASCompilationUnit unit = builder.getClassForNamespace(elementDecl.getTargetNamespace());
 231  4
                         ASClassType clazz = (ASClassType)unit.getType();
 232  4
                         TypeDescriptor typeDesc = context.typeDescriptorFor(elementDecl);
 233  4
                         String name = StringUtils.sanitize(elementDecl.getName());
 234  4
                         String methodName = "unmarshal" + name;
 235  4
                         ASMethod meth = clazz.newMethod(methodName, Visibility.PUBLIC, typeDesc.getTypeName());
 236  4
                         ASArg arg = meth.addParam("thisElement", "XML");
 237  4
                         String doc = "a &lt;" + elementDecl.getName()+"/&gt; element";
 238  4
                         arg.setDescription(doc);
 239  4
                         if (!elementDecl.isGlobal()) {
 240  2
                                 meth.setVisibility(Visibility.PRIVATE);
 241  
                         }
 242  4
                         meth.setStatic(true);
 243  4
                         XSDTypeDefinition typeDef = elementDecl.getType();
 244  4
                         if (typeDef instanceof XSDComplexTypeDefinition) {
 245  3
                                 meth.addStmt("default xml namespace = NAMESPACE");
 246  
                         }
 247  4
                         context.pushAttrScope();
 248  4
                         setCurrentFuctionElement(context, elementDecl);
 249  4
                         UnmarshalBuilder.setCurrentSourceExpr(context, arg.getName());
 250  4
                         context.setCurrentMethodCode(meth);
 251  4
                         context.generateCode(elementDecl);
 252  4
                         context.popAttrScope();
 253  4
                         return meth;
 254  
                 }
 255  6
                 if (role == CodegenRole.MARSHAL) {
 256  6
                         MarshalBuilder builder = context.getMarshalBuilder();
 257  6
                         ASCompilationUnit unit = builder.getClassForNamespace(elementDecl.getTargetNamespace());
 258  6
                         ASClassType clazz = (ASClassType)unit.getType();
 259  6
                         String typeName = "XML";
 260  6
                         String methodName = builder.methodNameFor(elementDecl);
 261  6
                         ASMethod meth = clazz.newMethod(methodName, Visibility.PUBLIC, typeName);
 262  6
                         builder.buildMethodParams(meth, elementDecl);
 263  6
                         meth.setStatic(true);
 264  6
                         meth.addStmt("var _result:XML = <"+elementDecl.getName()+"/>");
 265  6
                         context.pushAttrScope();
 266  6
                         setCurrentFuctionElement(context, elementDecl);
 267  6
                         context.setCurrentMethodCode(meth);
 268  6
                         MarshalBuilder.setCurrentSourceExpr(context, ((ASArg)meth.getArgs().get(0)).getName());
 269  6
                         context.generateCode(elementDecl);
 270  6
                         context.popAttrScope();
 271  6
                         meth.addStmt("return _result");
 272  6
                         return meth;
 273  
                 }
 274  0
                 throw new IllegalArgumentException(getClass().getName() + " does not support role "+role);
 275  
         }
 276  
 
 277  
         private static void setCurrentFuctionElement(CodegenContext context,
 278  
                                                      XSDElementDeclaration elementDecl)
 279  
         {
 280  10
                 context.setAttribute(KEY_CURRENT_FUNCTION_ELEMENT, elementDecl);
 281  10
         }
 282  
         
 283  
         private static boolean isCurrentFuctionElement(CodegenContext context,
 284  
                                                        XSDElementDeclaration elementDecl)
 285  
         {
 286  73
                 return context.getAttribute(KEY_CURRENT_FUNCTION_ELEMENT) == elementDecl;
 287  
         }
 288  
 
 289  
         public MappingFunction functionFor(CodegenContext context,
 290  
                                            XSDConcreteComponent component)
 291  
         {
 292  141
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 293  141
                 CodegenRole role = context.getCurrentRole();
 294  141
                 if (role == CodegenRole.UNMARSHAL) {
 295  70
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 296  70
                         XSDTypeDefinition typeDef = elementDecl.getType();
 297  70
                         if (XSDUtils.isAnonymous(typeDef)) {
 298  5
                                 return context.getOrCreateFunction(elementDecl);
 299  
                         }
 300  65
                         return context.getOrCreateFunction(typeDef);
 301  
                 }
 302  71
                 if (role == CodegenRole.MARSHAL) {
 303  71
                         MarshalBuilder builder = context.getMarshalBuilder();
 304  71
                         XSDTypeDefinition typeDef = elementDecl.getType();
 305  71
                         if (XSDUtils.isAnonymous(typeDef) || elementDecl.isGlobal()) {
 306  7
                                 return context.getOrCreateFunction(elementDecl);
 307  
                         }
 308  64
                         return context.getOrCreateFunction(typeDef);
 309  
                 }
 310  0
                 throw new IllegalArgumentException(getClass().getName() + " does not support role "+role);
 311  
         }
 312  
 
 313  
         public String variableNameFor(CodegenContext context,
 314  
                                       XSDConcreteComponent component)
 315  
         {
 316  284
                 XSDElementDeclaration elementDecl = (XSDElementDeclaration)component;
 317  284
                 return context.toVariableName(elementDecl.getName());
 318  
         }
 319  
 }