Coverage Report - uk.co.badgersinfoil.asxsd.components.ChoiceMappingComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
ChoiceMappingComponent
89% 
90% 
3.462
 
 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.XSDCompositor;
 10  
 import org.eclipse.xsd.XSDConcreteComponent;
 11  
 import org.eclipse.xsd.XSDElementDeclaration;
 12  
 import org.eclipse.xsd.XSDModelGroup;
 13  
 import org.eclipse.xsd.XSDParticle;
 14  
 import org.eclipse.xsd.XSDParticleContent;
 15  
 import uk.co.badgersinfoil.asxsd.BasicMappingFunction;
 16  
 import uk.co.badgersinfoil.asxsd.CodegenContext;
 17  
 import uk.co.badgersinfoil.asxsd.CodegenRole;
 18  
 import uk.co.badgersinfoil.asxsd.MappingFunction;
 19  
 import uk.co.badgersinfoil.asxsd.MarshalBuilder;
 20  
 import uk.co.badgersinfoil.asxsd.StringUtils;
 21  
 import uk.co.badgersinfoil.asxsd.TypeBuilder;
 22  
 import uk.co.badgersinfoil.asxsd.TypeDescriptor;
 23  
 import uk.co.badgersinfoil.asxsd.UnmarshalBuilder;
 24  
 import uk.co.badgersinfoil.metaas.ActionScriptFactory;
 25  
 import uk.co.badgersinfoil.metaas.dom.ASArg;
 26  
 import uk.co.badgersinfoil.metaas.dom.ASClassType;
 27  
 import uk.co.badgersinfoil.metaas.dom.ASCompilationUnit;
 28  
 import uk.co.badgersinfoil.metaas.dom.ASExpression;
 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  15
 public class ChoiceMappingComponent extends AbstractMappingComponent {
 34  
 
 35  
         public void generateCode(CodegenContext context,
 36  
                                  XSDConcreteComponent component)
 37  
         {
 38  9
                 CodegenRole role = context.getCurrentRole();
 39  9
                 if (role == CodegenRole.UNMARSHAL) {
 40  3
                         XSDModelGroup modelGroup = (XSDModelGroup)component;
 41  3
                         List particles = modelGroup.getParticles();
 42  3
                         StatementContainer code = context.getCurrentMethodCode();
 43  3
                         XSDParticle particle = (XSDParticle)modelGroup.getContainer();
 44  3
                         code.addComment(" process choice,");
 45  
                         // TODO: could this be expressed as a switch-case rather than a sequence of ifs?
 46  3
                         for (Iterator i=particles.iterator(); i.hasNext(); ) {
 47  6
                                 XSDParticle part = (XSDParticle)i.next();
 48  6
                                 XSDParticleContent partContent = part.getContent();
 49  6
                                 StatementContainer choiceBlock = detectElementContentUnmarshal(context, partContent, code);
 50  6
                                 context.pushAttrScope();
 51  6
                                 context.setCurrentMethodCode(choiceBlock);
 52  6
                                 context.generateCode(part);
 53  6
                                 context.popAttrScope();
 54  6
                         }
 55  3
                 } else if (role == CodegenRole.MARSHAL) {
 56  3
                         XSDModelGroup modelGroup = (XSDModelGroup)component;
 57  3
                         List particles = modelGroup.getParticles();
 58  3
                         StatementContainer code = context.getCurrentMethodCode();
 59  3
                         code.addComment(" process choice,");
 60  
                         // TODO: detect an 'any' entry and handle after all others?
 61  3
                         for (Iterator i=particles.iterator(); i.hasNext(); ) {
 62  6
                                 XSDParticle part = (XSDParticle)i.next();
 63  6
                                 XSDParticleContent partContent = part.getContent();
 64  6
                                 StatementContainer choiceBlock = detectElementContentMarshal(context, partContent, code);
 65  6
                                 context.pushAttrScope();
 66  6
                                 context.setCurrentMethodCode(choiceBlock);
 67  6
                                 context.generateCode(part);
 68  6
                                 context.popAttrScope();
 69  6
                         }
 70  3
                 } else if (role == CodegenRole.TYPE) {
 71  3
                         XSDModelGroup modelGroup = (XSDModelGroup)component;
 72  3
                         List particles = modelGroup.getParticles();
 73  3
                         for (Iterator i=particles.iterator(); i.hasNext(); ) {
 74  6
                                 XSDParticle part = (XSDParticle)i.next();
 75  6
                                 context.generateCode(part);
 76  6
                         }
 77  3
                 } else {
 78  0
                         throw new IllegalArgumentException(getClass().getName() + " does not support role "+role);
 79  
                 }
 80  9
         }
 81  
 
 82  
         private StatementContainer detectElementContentMarshal(CodegenContext context, XSDParticleContent partContent, StatementContainer code) {
 83  6
                 XSDElementDeclaration firstElement = findFirstElementDeclaration(partContent);
 84  6
                 String sourceExpr = MarshalBuilder.getCurrentSourceExpr(context);
 85  6
                 String propertyName = context.variableNameFor(firstElement);
 86  6
                 return code.newIf(sourceExpr+"."+propertyName+" != null");
 87  
         }
 88  
 
 89  
         private static StatementContainer detectElementContentUnmarshal(CodegenContext context, XSDParticleContent partContent, StatementContainer code) {
 90  6
                 context.pushAttrScope();
 91  6
                 context.setCurrentRole(CodegenRole.UNMARSHAL_DETECT);
 92  6
                 ASExpression detect = context.createExpression(partContent);
 93  6
                 context.popAttrScope();
 94  6
                 return code.newIf(detect);
 95  
         }
 96  
 
 97  
 
 98  
         private static XSDElementDeclaration findFirstElementDeclaration(XSDParticleContent particleContent) {
 99  
                 while (true) {
 100  6
                         if (particleContent instanceof XSDElementDeclaration) {
 101  6
                                 return (XSDElementDeclaration)particleContent;
 102  
                         }
 103  0
                         if (particleContent instanceof XSDModelGroup) {
 104  0
                                 XSDModelGroup modelGroup = (XSDModelGroup)particleContent;
 105  0
                                 List particles = modelGroup.getParticles();
 106  0
                                 if (particles.size() > 0) {
 107  0
                                         XSDParticle part = (XSDParticle)particles.get(0);
 108  0
                                         particleContent = part.getContent();
 109  
                                 }
 110  0
                         } else {
 111  0
                                 throw new IllegalArgumentException("unhandled, sorry: "+particleContent);
 112  
                         }
 113  
                 }
 114  
         }
 115  
 
 116  
         public String createTypeNameFor(CodegenContext context,
 117  
                                         XSDConcreteComponent component)
 118  
         {
 119  2
                 return context.createTypeNameFor(component.getContainer()) + "Choice";
 120  
         }
 121  
 
 122  
         public TypeDescriptor createTypeDescriptor(CodegenContext context,
 123  
                                                    XSDConcreteComponent component)
 124  
         {
 125  1
                 String typeName = createTypeNameFor(context, component);
 126  1
                 String docs = null;
 127  1
                 return new TypeDescriptor(typeName, false, docs, component);
 128  
         }
 129  
 
 130  
         public ASCompilationUnit createType(CodegenContext context,
 131  
                                          XSDConcreteComponent component)
 132  
         {
 133  1
                 String typeName = createTypeNameFor(context, component);
 134  1
                 ASCompilationUnit unit = context.getProject().newClass(typeName);
 135  1
                 TypeBuilder.setCurrentTypeCompilationUnit(context, unit);
 136  1
                 context.setCurrentRole(CodegenRole.TYPE);
 137  1
                 context.generateCode(component);
 138  1
                 return unit;
 139  
         }
 140  
 
 141  
         public boolean willAccept(XSDConcreteComponent component) {
 142  2363
                 if (component instanceof XSDModelGroup) {
 143  70
                         XSDModelGroup modelGroup = (XSDModelGroup)component;
 144  70
                         return modelGroup.getCompositor() == XSDCompositor.CHOICE_LITERAL;
 145  
                 }
 146  2293
                 return false;
 147  
         }
 148  
 
 149  
         public String variableNameFor(CodegenContext context,
 150  
                                       XSDConcreteComponent component)
 151  
         {
 152  3
                 return "choice";
 153  
         }
 154  
 
 155  
         public MappingFunction createFunctionRef(CodegenContext context,
 156  
                                               XSDConcreteComponent component)
 157  
         {
 158  1
                 XSDModelGroup modelGroup = (XSDModelGroup)component;
 159  
                 
 160  1
                 CodegenRole role = context.getCurrentRole();
 161  1
                 if (role == CodegenRole.UNMARSHAL) {
 162  1
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 163  1
                         ASCompilationUnit unit = builder.getClassForNamespace(modelGroup.getSchema().getTargetNamespace());
 164  1
                         ASClassType clazz = (ASClassType)unit.getType();
 165  1
                         TypeDescriptor typeDesc = context.typeDescriptorFor(modelGroup);
 166  1
                         String methodName = "unmarshal" + StringUtils.sanitize(localName(typeDesc));
 167  
                         String qname;
 168  1
                         if (unit.getPackageName() != null) {
 169  1
                                 qname = unit.getPackageName()+"."+clazz.getName()+"."+methodName;
 170  
                         } else {
 171  0
                                 qname = clazz.getName()+"."+methodName;
 172  
                         }
 173  1
                         return new BasicMappingFunction(qname);
 174  
                 }
 175  0
                 return super.createFunctionRef(context, component);
 176  
         }
 177  
 
 178  
         public ASMethod createFunction(CodegenContext context,
 179  
                                        XSDConcreteComponent component)
 180  
         {
 181  1
                 XSDModelGroup modelGroup = (XSDModelGroup)component;
 182  
                 
 183  1
                 CodegenRole role = context.getCurrentRole();
 184  1
                 if (role == CodegenRole.UNMARSHAL) {
 185  1
                         UnmarshalBuilder builder = context.getUnmarshalBuilder();
 186  1
                         ASCompilationUnit unit = builder.getClassForNamespace(modelGroup.getSchema().getTargetNamespace());
 187  1
                         ASClassType clazz = (ASClassType)unit.getType();
 188  1
                         TypeDescriptor typeDesc = context.typeDescriptorFor(modelGroup);
 189  1
                         String methodName = "unmarshal" + StringUtils.sanitize(localName(typeDesc));
 190  1
                         ASMethod meth = clazz.newMethod(methodName, Visibility.PUBLIC, localName(typeDesc));
 191  1
                         ASArg arg = meth.addParam("thisElement", "XML");
 192  1
                         meth.setStatic(true);
 193  1
                         context.pushAttrScope();
 194  1
                         meth.addStmt("default xml namespace = NAMESPACE");
 195  1
                         meth.addStmt("var _result:"+typeDesc.getTypeName()+" = new "+typeDesc.getTypeName()+"()");
 196  1
                         UnmarshalBuilder.setCurrentSourceExpr(context, "thisElement");
 197  1
                         context.setAttribute("element-access-expression", "thisElement");
 198  1
                         context.setCurrentMethodCode(meth);
 199  1
                         context.generateCode(modelGroup);
 200  1
                         context.popAttrScope();
 201  1
                         meth.newReturn("_result");
 202  1
                         return meth;
 203  
                 }
 204  0
                 return super.createFunction(context, component);
 205  
         }
 206  
 
 207  
         private String localName(TypeDescriptor typeDesc) {
 208  3
                 String qname = typeDesc.getTypeName();
 209  3
                 int pos = qname.lastIndexOf('.');
 210  3
                 if (pos != -1) {
 211  3
                         return qname.substring(pos + 1);
 212  
                 }
 213  0
                 return qname;
 214  
         }
 215  
 
 216  
         public ASExpression createExpression(CodegenContext context,
 217  
                                              XSDConcreteComponent component)
 218  
         {
 219  3
                 CodegenRole role = context.getCurrentRole();
 220  3
                 XSDModelGroup modelGroup = (XSDModelGroup)component;
 221  3
                 if (role == CodegenRole.UNMARSHAL_DETECT) {
 222  2
                         List particles = modelGroup.getParticles();
 223  2
                         ActionScriptFactory fact = context.getFactory();
 224  2
                         if (particles.isEmpty()) {
 225  0
                                 return fact.newExpression("false");
 226  
                         }
 227  2
                         Iterator i = particles.iterator();
 228  2
                         ASExpression detect = context.createExpression((XSDConcreteComponent)i.next());
 229  4
                         while (i.hasNext()) {
 230  2
                                 ASExpression rhs = context.createExpression((XSDConcreteComponent)i.next());
 231  2
                                 detect = fact.newOrExpression(detect, rhs);
 232  2
                         }
 233  2
                         return detect;
 234  
                 }
 235  1
                 if (role == CodegenRole.MARSHAL_DETECT) {
 236  1
                         List particles = modelGroup.getParticles();
 237  1
                         ActionScriptFactory fact = context.getFactory();
 238  1
                         if (particles.isEmpty()) {
 239  0
                                 return fact.newExpression("false");
 240  
                         }
 241  1
                         Iterator i = particles.iterator();
 242  1
                         ASExpression detect = context.createExpression((XSDConcreteComponent)i.next());
 243  2
                         while (i.hasNext()) {
 244  1
                                 ASExpression rhs = context.createExpression((XSDConcreteComponent)i.next());
 245  1
                                 detect = fact.newOrExpression(detect, rhs);
 246  1
                         }
 247  1
                         return detect;
 248  
                 }
 249  0
                 return super.createExpression(context, component);
 250  
         }
 251  
 }