Clover coverage report - JBind Project
Coverage timestamp: Fr Mai 28 2004 11:17:36 CEST
file stats: LOC: 424   Methods: 16
NCLOC: 295   Classes: 1
This license of Clover is provided to support the development of JBind only. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover.
 
 Source file Conditionals Statements Methods TOTAL
ComplexTypeDefHelper.java 48,4% 55,6% 75% 53,7%
 1   
 /*
 2   
  * JBind
 3   
  *
 4   
  * Copyright (c) by Stefan Wachter. All rights reserved.
 5   
  *
 6   
  * Usage, modification, and redistribution is subject to license terms that are
 7   
  * available at 'http://www.jbind.org'. The JBind license is like the
 8   
  * 'Apache Software License V 1.1'.
 9   
  */
 10   
 package org.jbind.xml.schema.element;
 11   
 
 12   
 import java.util.ArrayList;
 13   
 import java.util.Iterator;
 14   
 import java.util.List;
 15   
 
 16   
 import org.jbind.xml.base.BlockType;
 17   
 import org.jbind.xml.base.Compositor;
 18   
 import org.jbind.xml.base.IHasLocation;
 19   
 import org.jbind.xml.base.IRange;
 20   
 import org.jbind.xml.base.IRef;
 21   
 import org.jbind.xml.base.Range;
 22   
 import org.jbind.xml.core.content.IContentDesc;
 23   
 import org.jbind.xml.core.content.IElemGroupDesc;
 24   
 import org.jbind.xml.core.content.IElemRefOrDecl;
 25   
 import org.jbind.xml.core.content.IElemWildcard;
 26   
 import org.jbind.xml.msg.IConstraintViolations;
 27   
 import org.jbind.xml.msg.XmlException;
 28   
 import org.jbind.xml.msg.XmlMessages;
 29   
 
 30   
 public class ComplexTypeDefHelper {
 31   
 
 32  333
   public static void validateRestriction(IElemGroupDesc aBase, IElemGroupDesc aRestriction, IConstraintViolations aViolations, IHasLocation aHasLocation) {
 33  333
     if (null == aRestriction) {
 34  93
       if ((aBase != null) && !aBase.isEmptiable()) {
 35  0
         aViolations.add(XmlMessages.invalidRestriction(aHasLocation));
 36   
       }
 37  93
       return;
 38   
     }
 39   
 //              if (aDebug) {
 40   
 //                      System.out.println("xxx");
 41   
 //              }
 42   
 //              
 43  240
     IElemGroupDesc b = aBase.replaceSubstitutionsByChoice();
 44  240
     IContentDesc base = b.removePointlessGroups();
 45  240
     IContentDesc restriction = aRestriction.removePointlessGroups();
 46   
 
 47   
 //              if (aDebug) {
 48   
 //                      try {
 49   
 //                              MarshalVisitor v = new MarshalVisitor(System.out);
 50   
 //                              System.out.println("aBase:");
 51   
 //                              aBase.accept(v);
 52   
 //                              System.out.println("aRestricion:");
 53   
 //                              aRestriction.accept(v);
 54   
 //                              System.out.println("base:");
 55   
 //                              base.accept(v);
 56   
 //                              System.out.println("restriction:");
 57   
 //                              restriction.accept(v);
 58   
 //                      } catch (XmlException e) {
 59   
 //                              e.printStackTrace();
 60   
 //                      }
 61   
 //              }
 62   
 //              
 63  240
     try {
 64  240
       doValidate(base, restriction);
 65   
     } catch (XmlException e) {
 66  0
       aViolations.add(e.getXmlMessage());
 67   
     }
 68   
   }
 69   
 
 70  842
   private static void doValidate(IContentDesc aBase, IContentDesc aRestriction) throws XmlException {
 71  842
     if (aBase instanceof IElemRefOrDecl) {
 72  264
       IElemRefOrDecl baseUse = (IElemRefOrDecl)aBase;
 73   
 
 74  264
       if (aRestriction instanceof IElemRefOrDecl) {
 75  256
         validateNameAndType(baseUse, (IElemRefOrDecl)aRestriction);
 76  8
       } else if (aRestriction instanceof IElemWildcard) {
 77  0
         throw new XmlException(XmlMessages.ccrElementCanNotBeRestrictedByWildcard(baseUse.getGlobalRef(), aBase.getLocation(), aRestriction));
 78  8
       } else if (aRestriction instanceof IElemGroupDesc) {
 79  8
         throw new XmlException(XmlMessages.ccrElementCanNotBeRestrictedByGroup(baseUse.getGlobalRef(), aBase.getLocation(), aRestriction));
 80   
       } else {
 81   
         assert false : "unexpected use: " + aRestriction;
 82   
       }
 83   
 
 84  578
     } else if (aBase instanceof IElemWildcard) {
 85  465
       if (aRestriction instanceof IElemRefOrDecl) {
 86  343
         validateNsCompat((IElemWildcard)aBase, (IElemRefOrDecl)aRestriction);
 87  122
       } else if (aRestriction instanceof IElemWildcard) {
 88  27
         validateNsSubset((IElemWildcard)aBase, (IElemWildcard)aRestriction);
 89  95
       } else if (aRestriction instanceof IElemGroupDesc) {
 90  95
         validateNsRecurseCheckCardinality((IElemWildcard)aBase, (IElemGroupDesc)aRestriction);
 91   
       } else {
 92   
         assert false : "unexpected use: " + aRestriction;
 93   
       }
 94   
 
 95  113
     } else if (aBase instanceof IElemGroupDesc) {
 96  113
       if (aRestriction instanceof IElemRefOrDecl) {
 97  6
         validateRecurseAsIfGroup((IElemGroupDesc)aBase, (IElemRefOrDecl)aRestriction);
 98  107
       } else if (aRestriction instanceof IElemWildcard) {
 99  0
         throw new XmlException(XmlMessages.ccrGroupCanNotBeRestrictedByWildcard(aBase.getLocation(), aRestriction));
 100  107
       } else if (aRestriction instanceof IElemGroupDesc) {
 101  107
         validateGroupRestriction((IElemGroupDesc)aBase, (IElemGroupDesc)aRestriction);
 102   
       } else {
 103   
         assert false : "unexpected use: " + aRestriction;
 104   
       }
 105   
 
 106   
     } else {
 107   
       assert false : "unexpected use: " + aBase;
 108   
     }
 109   
 
 110   
   }
 111   
 
 112  107
   private static void validateGroupRestriction(IElemGroupDesc aBase, IElemGroupDesc aRestriction) throws XmlException {
 113  107
     Compositor baseComp = aBase.getCompositor();
 114  107
     Compositor restComp = aRestriction.getCompositor();
 115   
 
 116  107
     if (Compositor.ALL.equals(baseComp)) {
 117  0
       if (Compositor.ALL.equals(restComp)) {
 118  0
         validateRecurse(aBase, aRestriction, false);
 119  0
       } else if (Compositor.CHOICE.equals(restComp)) {
 120  0
         throw new XmlException(XmlMessages.ccrAllCanNotBeRestrictedByChoice(aBase.getLocation(), aRestriction));
 121  0
       } else if (Compositor.SEQUENCE.equals(restComp)) {
 122  0
         validateRecurseUnordered(aBase, aRestriction);
 123   
       } else {
 124   
         assert false : "unknown compositor";
 125   
       }
 126   
 
 127  107
     } else if (Compositor.CHOICE.equals(baseComp)) {
 128  58
       if (Compositor.ALL.equals(restComp)) {
 129  0
         throw new XmlException(XmlMessages.ccrChoiceCanNotBeRestrictedByAll(aBase.getLocation(), aRestriction));
 130  58
       } else if (Compositor.CHOICE.equals(restComp)) {
 131  58
         try {
 132  58
           validateRecurse(aBase, aRestriction, true);
 133   
         } catch (XmlException e) {
 134   
           // EXTENSION; This option is not contained in the specification
 135  2
           validateChoiceOption(aBase, aRestriction);
 136   
         }
 137  0
       } else if (Compositor.SEQUENCE.equals(restComp)) {
 138  0
         try {
 139  0
           validateMapAndSum(aBase, aRestriction);
 140   
         } catch (XmlException e) {
 141   
           // EXTENSION; This option is not contained in the specification
 142  0
           validateChoiceOption(aBase, aRestriction);
 143   
         }
 144   
       } else {
 145   
         assert false : "unknown compositor";
 146   
       }
 147   
 
 148  49
     } else if (Compositor.SEQUENCE.equals(baseComp)) {
 149  49
       if (Compositor.ALL.equals(restComp)) {
 150  0
         throw new XmlException(XmlMessages.ccrSequenceCanNotBeRestrictedByAll(aBase.getLocation(), aRestriction));
 151  49
       } else if (Compositor.CHOICE.equals(restComp)) {
 152  0
         throw new XmlException(XmlMessages.ccrSequenceCanNotBeRestrictedByChoice(aBase.getLocation(), aRestriction));
 153  49
       } else if (Compositor.SEQUENCE.equals(restComp)) {
 154  49
         validateRecurse(aBase, aRestriction, false);
 155   
       } else {
 156   
         assert false : "unknown compositor";
 157   
       }
 158   
 
 159   
     } else {
 160   
       assert false : "unknown compositor";
 161   
     }
 162   
 
 163   
   }
 164   
 
 165  2
   private static void validateChoiceOption(IElemGroupDesc aBase, IElemGroupDesc aRestriction) throws XmlException {
 166  2
     boolean validated = false;
 167  2
     if (aBase.getRange().isOne()) {
 168  0
       for (Iterator i = aBase.iterContent(); !validated && i.hasNext(); ) {
 169  0
         IContentDesc c = (IContentDesc)i.next();
 170  0
         try {
 171  0
           doValidate(c, aRestriction);
 172  0
           validated = true;
 173   
         } catch (XmlException e) {}
 174   
       }
 175   
     }
 176  2
     if (!validated) {
 177  2
       throw new XmlException(XmlMessages.invalidRestriction(aRestriction));
 178   
     }
 179   
   }
 180   
 
 181  819
   private static void validateOccurenceRange(IContentDesc aBase, IRange aRestriction, IHasLocation aRestrictionLocation) throws XmlException {
 182  819
     if (aBase.getMinOccurs() > aRestriction.getMinOccurs()) {
 183  0
       throw new XmlException(XmlMessages.ccrMinOccurs(aBase, aRestrictionLocation));
 184   
     }
 185  819
     if (!aBase.isUnbounded() && (aRestriction.isUnbounded() || (aBase.getMaxOccurs() < aRestriction.getMaxOccurs()))) {
 186  2
       throw new XmlException(XmlMessages.ccrMaxOccurs(aBase, aRestrictionLocation));
 187   
     }
 188   
   }
 189   
 
 190  256
   private static void validateNameAndType(IElemRefOrDecl aBase, IElemRefOrDecl aRestriction) throws XmlException {
 191   
     // 1
 192  256
     IRef baseRef = aBase.getGlobalRef();
 193  256
     IRef restRef = aRestriction.getGlobalRef();
 194  256
     if (!baseRef.getLocalPart().equals(restRef.getLocalPart()) || !baseRef.getNamespace().equals(restRef.getNamespace())) {
 195  9
       throw new XmlException(XmlMessages.ccrElementNameMismatch(aBase.getLocation(), baseRef, restRef, aRestriction));
 196   
     }
 197   
 
 198   
     // 2
 199  247
     if (!aBase.isNillable() && aRestriction.isNillable()) {
 200  0
       throw new XmlException(XmlMessages.ccrNillable(aBase.getLocation(), aRestriction));
 201   
     }
 202   
 
 203   
     // 3
 204  247
     validateOccurenceRange(aBase, aRestriction.getRange(), aRestriction);
 205   
 
 206   
     // 4
 207  247
     if ((null != aBase.getFixed()) && !aBase.getFixed().equals(aRestriction.getFixed())) {
 208  0
       throw new XmlException(XmlMessages.ccrFixedValue(aBase.getLocation(), aRestriction));
 209   
     }
 210   
 
 211   
     // 5
 212   
     // TODO identity constraints (p. 92)
 213   
 
 214   
     // 6
 215  247
     if ((aBase.isActive(BlockType.EXTENSION) && !aRestriction.isActive(BlockType.EXTENSION)) || (aBase.isActive(BlockType.RESTRICTION) && !aRestriction.isActive(BlockType.RESTRICTION)) || (aBase.isActive(BlockType.SUBSTITUTION) && !aRestriction.isActive(BlockType.SUBSTITUTION))) {
 216  0
       throw new XmlException(XmlMessages.ccrDisallowedSubstitutions(aBase.getLocation(), aRestriction));
 217   
     }
 218   
 
 219   
     // 7
 220  247
     if (!aBase.getType().isBaseType(aRestriction.getType()) || aRestriction.getType().isExtension(aBase.getType())) {
 221  0
       throw new XmlException(XmlMessages.ccrElementType(aBase.getLocation(), aRestriction));
 222   
     }
 223   
 
 224   
   }
 225   
 
 226  343
   private static void validateNsCompat(IElemWildcard aBase, IElemRefOrDecl aRestriction) throws XmlException {
 227   
     // 1
 228  343
     if (!aBase.getWildcard().isAllowed(aRestriction)) {
 229  0
       throw new XmlException(XmlMessages.ccrElementNamespaceNotInWildcard(aBase.getLocation(), aRestriction.getGlobalRef().getNamespace(), aRestriction));
 230   
     }
 231   
     // 2
 232  343
     validateOccurenceRange(aBase, aRestriction.getRange(), aRestriction);
 233   
   }
 234   
 
 235  27
   private static void validateNsSubset(IElemWildcard aBase, IElemWildcard aRestriction) throws XmlException {
 236   
     // 1
 237  27
     validateOccurenceRange(aBase, aRestriction.getRange(), aRestriction);
 238   
     // 2
 239  27
     if (!aRestriction.getWildcard().isSubset(aBase.getWildcard())) {
 240  0
       throw new XmlException(XmlMessages.ccrBaseNotSuperset(aBase.getLocation(), aRestriction));
 241   
     }
 242   
   }
 243   
 
 244  95
   private static void validateNsRecurseCheckCardinality(IElemWildcard aBase, IElemGroupDesc aRestriction) throws XmlException {
 245   
     // 1
 246  95
     for (Iterator i = aRestriction.iterContent(); i.hasNext(); ) {
 247  297
       IContentDesc c = (IContentDesc)i.next();
 248  297
       doValidate(aBase, c);
 249   
     }
 250   
     // 2
 251  95
     IRange effectiveRange = aRestriction.getRange(null);
 252  95
     validateOccurenceRange(aBase, effectiveRange, aRestriction);
 253   
   }
 254   
 
 255  6
   private static void validateRecurseAsIfGroup(IElemGroupDesc aBase, IContentDesc aRestriction) throws XmlException {
 256  6
     IElemGroupDesc group = aBase.createGroup(Range.ONE);
 257  6
     group.add(aRestriction);
 258  6
     doValidate(aBase, group);
 259   
   }
 260   
 
 261   
   /**
 262   
    *
 263   
    * @param aLax Determines if particles contained in the base group must be emptiable
 264   
    * if the are not matched by a particle in the restriction.
 265   
    */
 266  107
   private static void validateRecurse(IElemGroupDesc aBase, IElemGroupDesc aRestriction, boolean aLax) throws XmlException {
 267   
     // 1
 268  107
     validateOccurenceRange(aBase, aRestriction.getRange(), aRestriction);
 269   
     // 2
 270  105
     List baseUses = new ArrayList();
 271  105
     for (Iterator i = aBase.iterContent(); i.hasNext(); ) {
 272  319
       baseUses.add(i.next());
 273   
     }
 274  105
     List restUses = new ArrayList();
 275  105
     for (Iterator i = aRestriction.iterContent(); i.hasNext(); ) {
 276  280
       restUses.add(i.next());
 277   
     }
 278  105
     validateOrdered(baseUses, 0, restUses, 0, aLax, aRestriction);
 279   
   }
 280   
 
 281  385
   private static void validateOrdered(List aBaseUses, int aBaseIndex, List aRestUses, int aRestIndex, boolean aLax, IHasLocation aGroupLocation) throws XmlException {
 282  385
     if (aRestIndex < aRestUses.size()) {
 283   
       // There is a particle in the restriction that must be validated.
 284   
       // Search for a matching particle in the base. During this search
 285   
       // non matching base particles that are emptiable may be skipped
 286   
       // if the mode is "lax".
 287   
       // Recursivly try to validate the rest
 288   
 
 289  280
       IContentDesc restUse = (IContentDesc)aRestUses.get(aRestIndex);
 290   
 
 291  280
       boolean matched = false;
 292   
 
 293  299
       for (int baseIndex = aBaseIndex; baseIndex < aBaseUses.size();
 294   
               baseIndex++) {
 295  299
         IContentDesc baseUse = (IContentDesc)aBaseUses.get(baseIndex);
 296   
 
 297  299
         try {
 298  299
           doValidate(baseUse, restUse);
 299  280
           validateOrdered(aBaseUses, baseIndex + 1, aRestUses, aRestIndex + 1, aLax, aGroupLocation);
 300  280
           matched = true;
 301  280
           break;
 302   
         } catch (XmlException e) {
 303  19
           if (!aLax && !baseUse.isEmptiable()) {
 304  0
             throw e;
 305   
           }
 306   
         }
 307   
 
 308   
       }
 309   
 
 310  280
       if (!matched) {
 311  0
         throw new XmlException(XmlMessages.ccrParticlesCouldNotBeMatchedOrdered(restUse.getLocation(), aGroupLocation));
 312   
       }
 313   
 
 314   
     } else {
 315   
       // No more particles in the restriction must be matched.
 316   
       // Check in case of a non-lax validation that the remaining base particles
 317   
       // are emptiable.
 318   
 
 319  105
       if (!aLax) {
 320  49
         for (int idx = aBaseIndex; idx < aBaseUses.size(); idx++) {
 321  6
           IContentDesc use = (IContentDesc)aBaseUses.get(idx);
 322  6
           if (!use.isEmptiable()) {
 323  0
             throw new XmlException(XmlMessages.ccrParticleNotEmptiable(use.getLocation(), aGroupLocation));
 324   
           }
 325   
         }
 326   
 
 327   
       }
 328   
 
 329   
     }
 330   
 
 331   
   }
 332   
 
 333  0
   private static void validateRecurseUnordered(IElemGroupDesc aBase, IElemGroupDesc aRestriction) throws XmlException {
 334   
     // 1
 335  0
     validateOccurenceRange(aBase, aRestriction.getRange(), aRestriction);
 336   
     // 2
 337  0
     List baseUses = new ArrayList();
 338  0
     for (Iterator i = aBase.iterContent(); i.hasNext(); ) {
 339  0
       baseUses.add(i.next());
 340   
     }
 341  0
     List restUses = new ArrayList();
 342  0
     for (Iterator i = aRestriction.iterContent(); i.hasNext(); ) {
 343  0
       restUses.add(i.next());
 344   
     }
 345  0
     validateUnordered(baseUses, restUses, 0, false, aRestriction);
 346   
   }
 347   
 
 348  0
   private static void validateMapAndSum(IElemGroupDesc aBase, IElemGroupDesc aRestriction) throws XmlException {
 349   
     // 1
 350  0
     IRange range = null;
 351  0
     int min = aRestriction.getMinOccurs() * aRestriction.getNbParticles();
 352  0
     if (aRestriction.isUnbounded()) {
 353  0
       range = new Range(min);
 354   
     } else {
 355  0
       int max = aRestriction.getMaxOccurs() * aRestriction.getNbParticles();
 356  0
       range = new Range(min, max);
 357   
     }
 358  0
     validateOccurenceRange(aBase, range, aRestriction);
 359   
     // 2
 360  0
     List baseUses = new ArrayList();
 361  0
     for (Iterator i = aBase.iterContent(); i.hasNext(); ) {
 362  0
       baseUses.add(i.next());
 363   
     }
 364  0
     List restUses = new ArrayList();
 365  0
     for (Iterator i = aRestriction.iterContent(); i.hasNext(); ) {
 366  0
       restUses.add(i.next());
 367   
     }
 368  0
     validateUnordered(baseUses, restUses, 0, true, aRestriction);
 369   
   }
 370   
 
 371  0
   private static void validateUnordered(List aBaseUses, List aRestUses, int aRestIndex, boolean aLax, IHasLocation aGroupLocation) throws XmlException {
 372  0
     if (aRestIndex < aRestUses.size()) {
 373  0
       IContentDesc restUse = (IContentDesc)aRestUses.get(aRestIndex);
 374   
 
 375  0
       boolean matched = false;
 376   
 
 377  0
       for (int baseIndex = 0; baseIndex < aBaseUses.size(); baseIndex++) {
 378  0
         IContentDesc baseUse = (IContentDesc)aBaseUses.get(baseIndex);
 379   
 
 380  0
         try {
 381  0
           doValidate(baseUse, restUse);
 382  0
           List bUses = new ArrayList();
 383  0
           for (int i = 0; i < aBaseUses.size(); i++) {
 384  0
             if (i != baseIndex) {
 385  0
               bUses.add(aBaseUses.get(i));
 386   
             }
 387   
           }
 388  0
           validateUnordered(bUses, aRestUses, aRestIndex + 1, aLax, aGroupLocation);
 389  0
           matched = true;
 390  0
           break;
 391   
         } catch (XmlException e) {
 392   
           // try next base use
 393   
         }
 394   
 
 395   
       }
 396   
 
 397  0
       if (!matched) {
 398  0
         throw new XmlException(XmlMessages.ccrParticlesCouldNotBeMatchedUnordered(restUse.getLocation(), aGroupLocation));
 399   
       }
 400   
 
 401   
     } else {
 402   
       // No more particles in the restriction must be matched.
 403   
       // Check in case of a non-lax validation that the remaining base particles
 404   
       // are emptiable.
 405   
 
 406  0
       if (!aLax) {
 407  0
         for (int idx = 0; idx < aBaseUses.size(); idx++) {
 408  0
           IContentDesc use = (IContentDesc)aBaseUses.get(idx);
 409  0
           if (!use.isEmptiable()) {
 410  0
             throw new XmlException(XmlMessages.ccrParticleNotEmptiable(use.getLocation(), aGroupLocation));
 411   
           }
 412   
         }
 413   
 
 414   
       }
 415   
 
 416   
     }
 417   
 
 418   
   }
 419   
 
 420  0
   private ComplexTypeDefHelper() {}
 421   
 
 422   
 
 423   
 }
 424