neilg       2002/08/16 12:58:06

  Modified:    java/src/org/apache/xerces/impl/xs XMLSchemaValidator.java
               java/src/org/apache/xerces/impl/xs/identity Field.java
                        FieldActivator.java Selector.java XPathMatcher.java
  Log:
  "fix" for bug 11571.  The bug report was wrong, but this fixes an NPE that it 
provoked.
  
  Also, identity constraints now properly handle cases where an identity constraint is
  defined on a recursive element.  I have also reworked some code to save
  some method calls.
  
  Revision  Changes    Path
  1.83      +97 -60    
xml-xerces/java/src/org/apache/xerces/impl/xs/XMLSchemaValidator.java
  
  Index: XMLSchemaValidator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/XMLSchemaValidator.java,v
  retrieving revision 1.82
  retrieving revision 1.83
  diff -u -r1.82 -r1.83
  --- XMLSchemaValidator.java   16 Aug 2002 18:08:37 -0000      1.82
  +++ XMLSchemaValidator.java   16 Aug 2002 19:58:05 -0000      1.83
  @@ -236,6 +236,11 @@
           JAXP_SCHEMA_SOURCE
       };
   
  +    // this is the number of valuestores of each kind
  +    // we expect an element to have.  It's almost
  +    // never > 1; so leave it at that.  
  +    protected static final int ID_CONSTRAINT_NUM = 1;
  +
       //
       // Data
       //
  @@ -1368,14 +1373,12 @@
        *
        * @param identityConstraint The identity constraint.
        */
  -    public void startValueScopeFor(IdentityConstraint identityConstraint)
  +    public void startValueScopeFor(IdentityConstraint identityConstraint,
  +                int initialDepth)
       throws XNIException {
   
  -        for (int i=0; i<identityConstraint.getFieldCount(); i++) {
  -            Field field = identityConstraint.getFieldAt(i);
  -            ValueStoreBase valueStore = fValueStoreCache.getValueStoreFor(field);
  -            valueStore.startValueScope();
  -        }
  +        ValueStoreBase valueStore = 
fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
  +        valueStore.startValueScope();
   
       } // startValueScopeFor(IdentityConstraint identityConstraint)
   
  @@ -1385,8 +1388,8 @@
        *
        * @param field The field to activate.
        */
  -    public XPathMatcher activateField(Field field) throws XNIException {
  -        ValueStore valueStore = fValueStoreCache.getValueStoreFor(field);
  +    public XPathMatcher activateField(Field field, int initialDepth) {
  +        ValueStore valueStore = 
fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth);
           field.setMayMatch(true);
           XPathMatcher matcher = field.createMatcher(valueStore);
           fMatcherStack.addMatcher(matcher);
  @@ -1399,10 +1402,10 @@
        *
        * @param identityConstraint The identity constraint.
        */
  -    public void endValueScopeFor(IdentityConstraint identityConstraint)
  +    public void endValueScopeFor(IdentityConstraint identityConstraint, int 
initialDepth)
       throws XNIException {
   
  -        ValueStoreBase valueStore = 
fValueStoreCache.getValueStoreFor(identityConstraint);
  +        ValueStoreBase valueStore = 
fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
           valueStore.endValueScope();
   
       } // endValueScopeFor(IdentityConstraint)
  @@ -1413,7 +1416,7 @@
           FieldActivator activator = this;
           if (selector == null)
               return;
  -        XPathMatcher matcher = selector.createMatcher(activator);
  +        XPathMatcher matcher = selector.createMatcher(activator, fElementDepth);
           fMatcherStack.addMatcher(matcher);
           matcher.startDocumentFragment(fSymbolTable);
       }
  @@ -2087,19 +2090,25 @@
           // handle everything *but* keyref's.
           for (int i = oldCount - 1; i >= newCount; i--) {
               XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
  -            IdentityConstraint id;
  -            if ((id = matcher.getIDConstraint()) != null && id.getCategory() != 
IdentityConstraint.IC_KEYREF) {
  -                fValueStoreCache.transplant(id);
  +            if(matcher instanceof Selector.Matcher) {
  +                Selector.Matcher selMatcher = (Selector.Matcher)matcher;
  +                IdentityConstraint id;
  +                if ((id = selMatcher.getIdentityConstraint()) != null && 
id.getCategory() != IdentityConstraint.IC_KEYREF) {
  +                    fValueStoreCache.transplant(id, selMatcher.getInitialDepth());
  +                }
               }
           }
           // now handle keyref's/...
           for (int i = oldCount - 1; i >= newCount; i--) {
               XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
  -            IdentityConstraint id;
  -            if ((id = matcher.getIDConstraint()) != null && id.getCategory() == 
IdentityConstraint.IC_KEYREF) {
  -                ValueStoreBase values = fValueStoreCache.getValueStoreFor(id);
  -                if (values != null) // nothing to do if nothing matched!
  -                    values.endDocumentFragment();
  +            if(matcher instanceof Selector.Matcher) {
  +                Selector.Matcher selMatcher = (Selector.Matcher)matcher;
  +                IdentityConstraint id;
  +                if ((id = selMatcher.getIdentityConstraint()) != null && 
id.getCategory() == IdentityConstraint.IC_KEYREF) {
  +                    ValueStoreBase values = fValueStoreCache.getValueStoreFor(id, 
selMatcher.getInitialDepth());
  +                    if (values != null) // nothing to do if nothing matched!
  +                        values.endDocumentFragment();
  +                }
               }
           }
           fValueStoreCache.endElement();
  @@ -3098,11 +3107,11 @@
   
           // destroys this ValueStore; useful when, for instance, a
           // locally-scoped ID constraint is involved.
  -        public void destroy() {
  +        public void clear() {
               fValuesCount = 0;
               fValues.clear();
               fValueTuples.removeAllElements();
  -        } // end destroy():void
  +        } // end clear():void
   
           // appends the contents of one ValueStore to those of us.
           public void append(ValueStoreBase newVal) {
  @@ -3498,7 +3507,15 @@
           /** stores all global Values stores. */
           protected final Vector fValueStores = new Vector();
   
  -        /** Values stores associated to specific identity constraints. */
  +        /** 
  +         * Values stores associated to specific identity constraints. 
  +         * This hashtable maps IdentityConstraints and
  +         * the 0-based element on which their selectors first matched to
  +         * a corresponding ValueStore.  This should take care
  +         * of all cases, including where ID constraints with
  +         * descendant-or-self axes occur on recursively-defined
  +         * elements.
  +         */
           protected final Hashtable fIdentityConstraint2ValueStoreMap = new 
Hashtable();
   
           // sketch of algorithm:
  @@ -3574,8 +3591,7 @@
            * Initializes the value stores for the specified element
            * declaration.
            */
  -        public void initValueStoresFor(XSElementDecl eDecl)
  -        throws XNIException {
  +        public void initValueStoresFor(XSElementDecl eDecl) {
               // initialize value stores for unique fields
               IdentityConstraint [] icArray = eDecl.fIDConstraints;
               int icCount = eDecl.fIDCPos;
  @@ -3584,56 +3600,52 @@
                   case (IdentityConstraint.IC_UNIQUE):
                       // initialize value stores for unique fields
                       UniqueOrKey unique = (UniqueOrKey)icArray[i];
  -                    UniqueValueStore uniqueValueStore = 
(UniqueValueStore)fIdentityConstraint2ValueStoreMap.get(unique);
  -                    if (uniqueValueStore != null) {
  -                        // NOTE: If already initialized, don't need to
  -                        //       do it again. -Ac
  -                        continue;
  +                    LocalIDKey toHash = new LocalIDKey (unique, fElementDepth);
  +                    UniqueValueStore  uniqueValueStore = 
(UniqueValueStore)fIdentityConstraint2ValueStoreMap.get(toHash);
  +                    if (uniqueValueStore == null) {
  +                        uniqueValueStore = new UniqueValueStore(unique);
  +                        fIdentityConstraint2ValueStoreMap.put(toHash, 
uniqueValueStore);
  +                    } else {
  +                        uniqueValueStore.clear();
                       }
  -                    uniqueValueStore = new UniqueValueStore(unique);
                       fValueStores.addElement(uniqueValueStore);
  -                    fIdentityConstraint2ValueStoreMap.put(unique, uniqueValueStore);
                       break;
                   case (IdentityConstraint.IC_KEY):
                       // initialize value stores for key fields
                       UniqueOrKey key = (UniqueOrKey)icArray[i];
  -                    KeyValueStore keyValueStore = 
(KeyValueStore)fIdentityConstraint2ValueStoreMap.get(key);
  -                    if (keyValueStore != null) {
  -                        // NOTE: If already initialized, don't need to
  -                        //       do it again. -Ac
  -                        continue;
  +                    toHash = new LocalIDKey(key, fElementDepth);
  +                    KeyValueStore  keyValueStore = 
(KeyValueStore)fIdentityConstraint2ValueStoreMap.get(toHash);
  +                    if (keyValueStore == null) {
  +                        keyValueStore = new KeyValueStore(key);
  +                        fIdentityConstraint2ValueStoreMap.put(toHash, 
keyValueStore);
  +                    } else {
  +                        keyValueStore.clear();
                       }
  -                    keyValueStore = new KeyValueStore(key);
                       fValueStores.addElement(keyValueStore);
  -                    fIdentityConstraint2ValueStoreMap.put(key, keyValueStore);
                       break;
                   case (IdentityConstraint.IC_KEYREF):
  -                    // initialize value stores for key reference fields
  +                    // initialize value stores for keyRef fields
                       KeyRef keyRef = (KeyRef)icArray[i];
  -                    KeyRefValueStore keyRefValueStore = 
(KeyRefValueStore)fIdentityConstraint2ValueStoreMap.get(keyRef);
  -                    if (keyRefValueStore != null) {
  -                        // NOTE: If already initialized, don't need to
  -                        //       do it again. -Ac
  -                        continue;
  +                    toHash = new LocalIDKey(keyRef, fElementDepth);
  +                    KeyRefValueStore  keyRefValueStore = 
(KeyRefValueStore)fIdentityConstraint2ValueStoreMap.get(toHash);
  +                    if (keyRefValueStore == null) {
  +                        keyRefValueStore = new KeyRefValueStore(keyRef, null);
  +                        fIdentityConstraint2ValueStoreMap.put(toHash, 
keyRefValueStore);
  +                    } else {
  +                        keyRefValueStore.clear();
                       }
  -                    keyRefValueStore = new KeyRefValueStore(keyRef, null);
                       fValueStores.addElement(keyRefValueStore);
  -                    fIdentityConstraint2ValueStoreMap.put(keyRef, keyRefValueStore);
                       break;
                   }
               }
           } // initValueStoresFor(XSElementDecl)
   
  -        /** Returns the value store associated to the specified field. */
  -        public ValueStoreBase getValueStoreFor(Field field) {
  -            IdentityConstraint identityConstraint = field.getIdentityConstraint();
  -            
return(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(identityConstraint);
  -        } // getValueStoreFor(Field):ValueStoreBase
  -
           /** Returns the value store associated to the specified IdentityConstraint. 
*/
  -        public ValueStoreBase getValueStoreFor(IdentityConstraint id) {
  -            return(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(id);
  -        } // getValueStoreFor(IdentityConstraint):ValueStoreBase
  +        public ValueStoreBase getValueStoreFor(IdentityConstraint id, int 
initialDepth) {
  +            ValueStoreBase vb = 
(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(new LocalIDKey(id, 
initialDepth));
  +            // vb should *never* be null!
  +            return vb;
  +        } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase
   
           /** Returns the global value store associated to the specified 
IdentityConstraint. */
           public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) {
  @@ -3643,10 +3655,9 @@
           // associated with id and moves them into the global
           // hashtable, if id is a <unique> or a <key>.
           // If it's a <keyRef>, then we leave it for later.
  -        public void transplant(IdentityConstraint id) {
  +        public void transplant(IdentityConstraint id, int initialDepth) {
  +            ValueStoreBase newVals = 
(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(new LocalIDKey(id, 
initialDepth));
               if (id.getCategory() == IdentityConstraint.IC_KEYREF) return;
  -            ValueStoreBase newVals = 
(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(id);
  -            fIdentityConstraint2ValueStoreMap.remove(id);
               ValueStoreBase currVals = 
(ValueStoreBase)fGlobalIDConstraintMap.get(id);
               if (currVals != null) {
                   currVals.append(newVals);
  @@ -3658,7 +3669,7 @@
           } // transplant(id)
   
           /** Check identity constraints. */
  -        public void endDocument() throws XNIException {
  +        public void endDocument() {
   
               int count = fValueStores.size();
               for (int i = 0; i < count; i++) {
  @@ -3875,4 +3886,30 @@
           } // class Entry
   
       } // class OrderedHashtable
  +
  +    // the purpose of this class is to enable IdentityConstraint,int
  +    // pairs to be used easily as keys in Hashtables.
  +    protected class LocalIDKey {
  +        private IdentityConstraint fId;
  +        private int fDepth;
  +
  +        public LocalIDKey (IdentityConstraint id, int depth) {
  +            fId = id;
  +            fDepth = depth;
  +        } // init(IdentityConstraint, int)
  +
  +        // object method
  +        public int hashCode() {
  +            return fId.hashCode()+fDepth;
  +        }
  +
  +        public boolean equals(Object localIDKey) {
  +            if(localIDKey instanceof LocalIDKey) {
  +                LocalIDKey lIDKey = (LocalIDKey)localIDKey;
  +                return (lIDKey.fId == fId && lIDKey.fDepth == fDepth);
  +            }
  +            return false;
  +        }
  +    } // class LocalIDKey
  +
   } // class SchemaValidator
  
  
  
  1.5       +2 -2      
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Field.java
  
  Index: Field.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Field.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Field.java        13 Aug 2002 22:32:44 -0000      1.4
  +++ Field.java        16 Aug 2002 19:58:06 -0000      1.5
  @@ -197,7 +197,7 @@
   
           /** Constructs a field matcher. */
           public Matcher(Field.XPath xpath, ValueStore store) {
  -            super(xpath, null);
  +            super(xpath);
               fStore = store;
           } // <init>(Field.XPath,ValueStore)
   
  
  
  
  1.3       +8 -4      
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/FieldActivator.java
  
  Index: FieldActivator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/FieldActivator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FieldActivator.java       29 Jan 2002 01:15:15 -0000      1.2
  +++ FieldActivator.java       16 Aug 2002 19:58:06 -0000      1.3
  @@ -80,8 +80,10 @@
        * the value store.
        *
        * @param identityConstraint The identity constraint.
  +     * @param initialDepth  the depth at which the selector began matching
        */
  -    public void startValueScopeFor(IdentityConstraint identityConstraint);
  +    public void startValueScopeFor(IdentityConstraint identityConstraint,
  +            int initialDepth);
   
       /** 
        * Request to activate the specified field. This method returns the
  @@ -90,14 +92,16 @@
        * it is permitted to match a value--that is, to call the field's 
setMayMatch(boolean) method.
        *
        * @param field The field to activate.
  +     * @param initialDepth  the 0-indexed depth in the instance document at which 
the Selector began to match.
        */
  -    public XPathMatcher activateField(Field field);
  +    public XPathMatcher activateField(Field field, int initialDepth);
   
       /**
        * Ends the value scope for the specified identity constraint.
        *
        * @param identityConstraint The identity constraint.
  +     * @param initialDepth  the 0-indexed depth where the Selector began to match.
        */
  -    public void endValueScopeFor(IdentityConstraint identityConstraint);
  +    public void endValueScopeFor(IdentityConstraint identityConstraint, int 
initialDepth);
   
   } // interface FieldActivator
  
  
  
  1.8       +36 -13    
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Selector.java
  
  Index: Selector.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Selector.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Selector.java     14 Aug 2002 16:02:22 -0000      1.7
  +++ Selector.java     16 Aug 2002 19:58:06 -0000      1.8
  @@ -88,6 +88,10 @@
       /** Identity constraint. */
       protected IdentityConstraint fIdentityConstraint;
   
  +    // the Identity constraint we're the matcher for.  Only
  +    // used for selectors!
  +    protected IdentityConstraint fIDConstraint;
  +
       //
       // Constructors
       //
  @@ -109,15 +113,19 @@
       } // getXPath():org.apache.xerces.v1.schema.identity.XPath
   
       /** Returns the identity constraint. */
  -    public IdentityConstraint getIdentityConstraint() {
  +    public IdentityConstraint getIDConstraint() {
           return fIdentityConstraint;
  -    } // getIdentityConstraint():IdentityConstraint
  +    } // getIDConstraint():IdentityConstraint
   
       // factory method
   
  -    /** Creates a selector matcher. */
  -    public XPathMatcher createMatcher(FieldActivator activator) {
  -        return new Selector.Matcher(fXPath, activator);
  +    /** Creates a selector matcher. 
  +     * @param activator     The activator for this selector's fields.
  +     * @param initialDepth  The depth in the document at which this matcher began 
its life;
  +     *                          used in correctly handling recursive elements.
  +     */
  +    public XPathMatcher createMatcher(FieldActivator activator, int initialDepth) {
  +        return new Selector.Matcher(fXPath, activator, initialDepth);
       } // createMatcher(FieldActivator):XPathMatcher
   
       //
  @@ -176,7 +184,7 @@
        *
        * @author Andy Clark, IBM
        */
  -    protected class Matcher
  +    public class Matcher
       extends XPathMatcher {
   
           //
  @@ -186,6 +194,9 @@
           /** Field activator. */
           protected FieldActivator fFieldActivator;
   
  +        /** Initial depth in the document at which this matcher was created. */
  +        protected int fInitialDepth;
  +
           /** Element depth. */
           protected int fElementDepth;
   
  @@ -197,9 +208,11 @@
           //
   
           /** Constructs a selector matcher. */
  -        public Matcher(Selector.XPath xpath, FieldActivator activator) {
  -            super(xpath, Selector.this.fIdentityConstraint);
  +        public Matcher(Selector.XPath xpath, FieldActivator activator,
  +                int initialDepth) {
  +            super(xpath);
               fFieldActivator = activator;
  +            fInitialDepth = initialDepth;
           } // <init>(Selector.XPath,FieldActivator)
   
           //
  @@ -234,11 +247,11 @@
               if ((fMatchedDepth == -1 && ((matched & MATCHED) == MATCHED)) ||
                       ((matched & MATCHED_DESCENDANT) == MATCHED_DESCENDANT)) {
                   fMatchedDepth = fElementDepth;
  -                fFieldActivator.startValueScopeFor(fIdentityConstraint);
  +                fFieldActivator.startValueScopeFor(fIdentityConstraint, 
fInitialDepth);
                   int count = fIdentityConstraint.getFieldCount();
                   for (int i = 0; i < count; i++) {
                       Field field = fIdentityConstraint.getFieldAt(i);
  -                    XPathMatcher matcher = fFieldActivator.activateField(field);
  +                    XPathMatcher matcher = fFieldActivator.activateField(field, 
fInitialDepth);
                       matcher.startElement(element, attributes, elementDecl);
                   }
               }
  @@ -249,9 +262,19 @@
               super.endElement(element, eDecl, ePSVI);
               if (fElementDepth-- == fMatchedDepth) {
                   fMatchedDepth = -1;
  -                fFieldActivator.endValueScopeFor(fIdentityConstraint);
  +                fFieldActivator.endValueScopeFor(fIdentityConstraint, 
fInitialDepth);
               }
           }
  +
  +        /** Returns the identity constraint. */
  +        public IdentityConstraint getIdentityConstraint() {
  +            return fIdentityConstraint;
  +        } // getIdentityConstraint():IdentityConstraint
  +
  +        /** get the initial depth at which this selector matched. */
  +        public int getInitialDepth() {
  +            return fInitialDepth;
  +        } // getInitialDepth():  int
   
           //
           // Protected methods
  
  
  
  1.10      +2 -32     
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/XPathMatcher.java
  
  Index: XPathMatcher.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/XPathMatcher.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- XPathMatcher.java 14 Aug 2002 16:02:22 -0000      1.9
  +++ XPathMatcher.java 16 Aug 2002 19:58:06 -0000      1.10
  @@ -147,10 +147,6 @@
        */
       private int [] fNoMatchDepth;
   
  -    // the Identity constraint we're the matcher for.  Only
  -    // used for selectors!
  -    protected IdentityConstraint fIDConstraint;
  -
       // the symbolTable for the XPath parser
       protected SymbolTable fSymbolTable;
   
  @@ -165,22 +161,7 @@
        * @param xpath   The xpath.
        */
       public XPathMatcher(XPath xpath) {
  -        this(xpath, null);
  -    } // <init>(XPath)
  -
  -    /**
  -     * Constructs an XPath matcher that implements a document fragment
  -     * handler.
  -     *
  -     * @param xpath   The xpath.
  -     * @param shouldBufferContent True if the matcher should buffer the
  -     *                            matched content.
  -     * @param idConstraint:  the identity constraint we're matching for;
  -     *      null unless it's a Selector.
  -     */
  -    public XPathMatcher(XPath xpath, IdentityConstraint idConstraint) {
           fLocationPaths = xpath.getLocationPaths();
  -        fIDConstraint = idConstraint;
           fStepIndexes = new IntStack[fLocationPaths.length];
           for(int i=0; i<fStepIndexes.length; i++) fStepIndexes[i] = new IntStack();
           fCurrentStep = new int[fLocationPaths.length];
  @@ -189,7 +170,7 @@
           if (DEBUG_METHODS) {
               System.out.println(toString()+"#<init>()");
           }
  -    } // <init>(XPath,boolean)
  +    } // <init>(XPath)
   
       //
       // Public methods
  @@ -206,16 +187,6 @@
           return 0;
       } // isMatched():int
   
  -    // returns whether this XPathMatcher was matching a Selector
  -    public boolean getIsSelector() {
  -        return (fIDConstraint == null);
  -    } // end getIsSelector():boolean
  -
  -    // returns the ID constraint
  -    public IdentityConstraint getIDConstraint() {
  -        return fIDConstraint;
  -    } // end getIDConstraint():IdentityConstraint
  -
       /** Returns the matched string. */
       public String getMatchedString() {
           return fMatchedString;
  @@ -494,7 +465,6 @@
           if (DEBUG_METHODS2) {
               System.out.println(toString()+"#endElement("+
                                  "element={"+element+"},"+
  -                               "ID constraint="+fIDConstraint+
                                  ")");
           }
           for(int i = 0; i<fLocationPaths.length; i++) {
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to