xmlbeans-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From eric...@apache.org
Subject cvs commit: xml-xmlbeans/v2/test/src/erictest EricTest.java
Date Mon, 12 Apr 2004 20:55:14 GMT
ericvas     2004/04/12 13:55:13

  Modified:    v2/src/newstore2/org/apache/xmlbeans/impl/newstore2 Cur.java
                        Cursor.java DomImpl.java Locale.java Public2.java
                        Saver.java
               v2/test/src/erictest EricTest.java
  Added:       v2/src/newstore2/org/apache/xmlbeans/impl/newstore2
                        Path.java
  Log:
  Misc changes
  
  Revision  Changes    Path
  1.31      +866 -326  xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Cur.java
  
  Index: Cur.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Cur.java,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- Cur.java	5 Apr 2004 21:39:40 -0000	1.30
  +++ Cur.java	12 Apr 2004 20:55:13 -0000	1.31
  @@ -102,18 +102,38 @@
       static final int COMMENT  = 4;
       static final int PROCINST = 5;
   
  -    static final int POOLED     = 0;
  -    static final int UNEMBEDDED = 2;
  -    static final int EMBEDDED   = 3;
  -    static final int DISPOSED   = 4;
  +    static final int POOLED       = 0;
  +    static final int UNREGISTERED = 1;
  +    static final int REGISTERED   = 2;
  +    static final int EMBEDDED     = 3;
  +    static final int DISPOSED     = 4;
  +
  +//    static final int POOLED     = 0;
  +//    static final int UNEMBEDDED = 2;
  +//    static final int EMBEDDED   = 3;
  +//    static final int DISPOSED   = 4;
   
       private static final int END_POS = -1;
       private static final int NO_POS  = -2;
       
  -    Cur ( Locale l ) { _locale = l; _pos = NO_POS; }
  +    Cur ( Locale l )
  +    {
  +        _locale = l;
  +        _pos = NO_POS;
  +        _state = UNREGISTERED;
  +
  +        _locations = _locale._locations;
  +        
  +        _textLocations = -1;
  +        _stackTop = -1;
  +        _selectionFirst = -1;
  +        _selectionN = -1;
  +        _selectionNth = -1;
  +        
  +        assert isNormal();
  +    }
   
  -//    boolean isPositioned ( ) { assert isNormal(); return _xobj != null; }
  -    boolean isPositioned ( ) { return _xobj != null; }
  +    boolean isPositioned ( ) { assert isNormal(); return _xobj != null; }
   
       static boolean kindIsContainer ( int k ) { return k ==  ELEM || k ==  ROOT; }
       static boolean kindIsFinish    ( int k ) { return k == -ELEM || k == -ROOT; }
  @@ -270,17 +290,12 @@
           return _xobj == that._xobj && _pos == END_POS;
       }
   
  -    boolean isAtEndOfLastPush ( )
  -    {
  -        assert _stack != null && _stack.size() > 0;
  -
  -        return isAtEndOf( (Cur) _stack.get( _stack.size() - 1 ) );
  -    }
  -
       void setName ( QName name )
       {
           assert isNode() && (_xobj.isElem() || _xobj.isAttr() || _xobj.isProcinst());
           assert name != null;
  +
  +        notifyGeneralChange();
           
           _xobj._name = name;
           
  @@ -297,23 +312,62 @@
       {
           // This cursor may not be normalized upon entry ...
           
  -        if (_state == EMBEDDED && x != _xobj)
  +        assert x == null || x.isNormal( p );
  +        
  +        assert _state == UNREGISTERED || _state == REGISTERED || _state == EMBEDDED;
  +
  +        assert _state != REGISTERED || (_xobj == null || !isOnList( _xobj._embedded ));
  +        assert _state != REGISTERED || _curKind != PERM;
  +
  +        if (_state == UNREGISTERED)
           {
  -            _xobj._embedded = listRemove( _xobj._embedded );
  +            assert _xobj == null || !isOnList( _xobj._embedded );
  +            assert !isOnList( _locale._registered );
   
  -            _locale._unembedded = listInsert( _locale._unembedded );
  -            _state = UNEMBEDDED;
  +            if (x != null)
  +            {
  +                if (_curKind == PERM)
  +                {
  +                    x._embedded = listInsert( x._embedded );
  +                    _state = EMBEDDED;
  +                }
  +                else if (p > 0)
  +                {
  +                    _locale._registered = listInsert( _locale._registered );
  +                    _state = REGISTERED;
  +                }
  +            }
           }
  +        else if (_state == EMBEDDED)
  +        {
  +            assert _xobj != null && isOnList( _xobj._embedded );
  +
  +            if (x != _xobj)
  +            {
  +                _xobj._embedded = listRemove( _xobj._embedded );
   
  +                if (x != null)
  +                {
  +                    if (_curKind == PERM)
  +                        x._embedded = listInsert( x._embedded );
  +                    else if (p > 0)
  +                    {
  +                        _locale._registered = listInsert( _locale._registered );
  +                        _state = REGISTERED;
  +                    }
  +                    else
  +                        _state = UNREGISTERED;
  +                }
  +                else
  +                    _state = UNREGISTERED;
  +            }
  +        }
  +        
           _xobj = x;
           _pos = p;
   
  -        if (_curKind == PERM && _state == UNEMBEDDED && _xobj != null)
  -        {
  -            _locale._unembedded = listRemove( _locale._unembedded );
  -            _xobj._embedded = listInsert( _xobj._embedded );
  -            _state = EMBEDDED;
  -        }
  +        if (p > 0 && _state == UNREGISTERED)
  +            registerForTextChange();
   
           assert isNormal();
       }
  @@ -337,78 +391,377 @@
           moveTo( d instanceof Xobj ? (Xobj) d : ((SoapPartDom) d)._docXobj );
       }
   
  -    void addToSelection ( )
  +    static final class Locations
       {
  -        if (_selection == null)
  -            _selection = new ArrayList();
  +        Locations ( )
  +        {
  +            _xobjs = new Xobj [ _initialSize ];
  +            _ints  = new int  [ _initialSize ];
  +            _curs  = new Cur  [ _initialSize ];
  +            _next  = new int  [ _initialSize ];
  +            _prev  = new int  [ _initialSize ];
  +            _nextT = new int  [ _initialSize ];
  +            _prevT = new int  [ _initialSize ];
   
  -        // TODO - make this more efficient ....
  -        //        Need to add call changeCallback ....
  -        _selection.add( permCur() );
  -    }
  -    
  -    void removeSelection ( int i )
  -    {
  -        assert i >= 0 && i < _selection.size();
  +            _next [ _initialSize - 1 ] = -1;
  +
  +            for ( int i = _initialSize - 2 ; i >= 0 ; i-- )
  +            {
  +                _next  [ i ] = i + 1;
  +                _prev  [ i ] = -1;
  +                _nextT [ i ] = -1;
  +                _prevT [ i ] = -1;
  +                _ints  [ i ] = -1;
  +            }
  +
  +            _free = 0;
  +        }
  +
  +        boolean isAtEndOf ( int i, Cur c )
  +        {
  +            assert _ints[ i ] == 0;
  +            
  +            if (_curs[ i ] == null)
  +                return c._xobj == _xobjs[ i ] && c._pos == END_POS;
  +            else
  +                return c.isAtEndOf( _curs[ i ] );
  +        }
  +
  +        void moveTo ( int i, Cur c )
  +        {
  +            if (_curs[ i ] == null)
  +                c.moveTo( _xobjs[ i ], _ints[ i ] );
  +            else
  +                c.moveToCur( _curs[ i ] );
  +        }
  +
  +        int insert ( int head, int before, int i )
  +        {
  +            return insert( head, before, i, _next, _prev );
  +        }
  +
  +        int remove ( int head, int i, Cur owner )
  +        {
  +            Cur c = _curs[ i ];
  +            
  +            assert c != null || _xobjs[ i ] != null;
  +
  +            if (c != null)
  +            {
  +                _curs[ i ].release();
  +                _curs[ i ] = null;
  +
  +                assert _xobjs[ i ] == null;
  +                assert _ints [ i ] == -1;
  +            }
  +            else
  +            {
  +                assert _xobjs[ i ] != null;
  +                
  +                if (_ints[ i ] > 0)
  +                    owner._textLocations = remove( owner._textLocations, i, _nextT, _prevT );
  +
  +                _xobjs[ i ] = null;
  +                _ints [ i ] = -1;
  +            }
  +            
  +            head = remove( head, i, _next, _prev );
  +            
  +            _next[ i ] = _free;
  +            _free = i;
  +
  +            return head;
  +        }
  +
  +        int allocate ( Cur addThis, Cur toThis )
  +        {
  +            assert addThis.isPositioned() && toThis.isPositioned();
  +            
  +            if (_free == -1)
  +                makeRoom();
  +
  +            int i = _free;
  +            
  +            _free = _next [ i ];
  +
  +            _next [ i ] = -1;
  +            assert _prev [ i ] == -1;
  +
  +            assert _curs [ i ] == null;
  +            assert _xobjs[ i ] == null;
  +            assert _ints [ i ] == -1;
  +
  +            _xobjs [ i ] = addThis._xobj;
  +            _ints  [ i ] = addThis._pos;
  +
  +            if (addThis._pos > 0)
  +            {
  +                toThis._textLocations =
  +                    insert( toThis._textLocations, toThis._textLocations, i, _nextT, _prevT );
  +                
  +                toThis.registerForTextChange();
  +            }
  +            
  +            return i;
  +        }
  +        
  +        private static int insert ( int head, int before, int i, int[] next, int[] prev )
  +        {
  +            if (head == -1)
  +            {
  +                assert before == -1;
  +                prev[ i ] = i;
  +                head = i;
  +            }
  +            else if (before != -1)
  +            {
  +                prev[ i ] = prev[ before ];
  +                next[ i ] = before;
  +                prev[ before ] = i;
  +
  +                if (head == before)
  +                    head = i;
  +            }
  +            else
  +            {
  +                prev[ i ] = prev[ head ];
  +                assert next[ i ] == -1;
  +                next[ prev[ head ] ] = i;
  +                prev[ head ] = i;
  +            }
  +
  +            return head;
  +        }
  +
  +        private static int remove ( int head, int i, int[] next, int[] prev )
  +        {
  +            if (prev[ i ] == i)
  +            {
  +                assert head == i;
  +                head = -1;
  +            }
  +            else
  +            {
  +                if (head == i)
  +                    head = next[ i ];
  +                else
  +                    next[ prev [ i ] ] = next[ i ];
  +
  +                if (next[ i ] == -1)
  +                    prev[ head ] = prev[ i ];
  +                else
  +                {
  +                    prev[ next[ i ] ] = prev[ i ];
  +                    next[ i ] = -1;
  +                }
  +            }
  +
  +            prev[ i ] = -1;
  +            assert next[ i ] == -1;
  +
  +            return head;
  +        }
  +
  +        void textChangeNotification ( Cur owner )
  +        {
  +            while ( owner._textLocations >= 0 )
  +            {
  +                int i = owner._textLocations;
  +                
  +                Xobj x = _xobjs[ i ];
  +
  +                assert _curs[ i ] == null && x != null && _ints[ i ] > 0;
  +                
  +                _curs[ i ] = x._locale.permCur();
  +                _curs[ i ].moveTo( x, _ints[ i ] );
  +
  +                _xobjs[ i ] = null;
  +                _ints [ i ] = -1;
  +
  +                owner._textLocations = remove( owner._textLocations, i, _nextT, _prevT );
  +            }
  +        }
  +        
  +        int next ( int i ) { return _next[ i ]; }
  +        int prev ( int i ) { return _prev[ i ]; }
  +
  +        private void makeRoom ( )
  +        {
  +            assert _free == -1;
  +            
  +            int l = _xobjs.length;
  +
  +            Xobj [] oldXobjs = _xobjs;
  +            int  [] oldInts  = _ints;
  +            Cur  [] oldCurs  = _curs;
  +            int  [] oldNext  = _next;
  +            int  [] oldPrev  = _prev;
  +            int  [] oldNextT = _nextT;
  +            int  [] oldPrevT = _prevT;
  +
  +            _xobjs = new Xobj [ l * 2 ];
  +            _ints  = new int  [ l * 2 ];
  +            _curs  = new Cur  [ l * 2 ];
  +            _next  = new int  [ l * 2 ];
  +            _prev  = new int  [ l * 2 ];
  +            _nextT = new int  [ l * 2 ];
  +            _prevT = new int  [ l * 2 ];
  +
  +            System.arraycopy( oldXobjs, 0, _xobjs, 0, l );
  +            System.arraycopy( oldInts,  0, _ints,  0, l );
  +            System.arraycopy( oldCurs,  0, _curs,  0, l );
  +            System.arraycopy( oldNext,  0, _next,  0, l );
  +            System.arraycopy( oldPrev,  0, _prev,  0, l );
  +            System.arraycopy( oldNextT, 0, _nextT, 0, l );
  +            System.arraycopy( oldPrevT, 0, _prevT, 0, l );
  +
  +            _next [ l * 2 - 1 ] = -1;
  +
  +            for ( int i = l * 2 - 2 ; i >= l ; i-- )
  +            {
  +                _next  [ i ] = i + 1;
  +                _prev  [ i ] = -1;
  +                _ints  [ i ] = -1;
  +                _nextT [ i ] = -1;
  +                _prevT [ i ] = -1;
  +            }
  +
  +            _free = l;
  +        }
  +
  +        private static final int _initialSize = 32;
           
  -        _selection.remove( i );
  +        private Xobj [] _xobjs;
  +        private int  [] _ints;
  +        private Cur  [] _curs;
  +        private int  [] _next;
  +        private int  [] _prev;
  +        private int  [] _nextT;
  +        private int  [] _prevT;
  +        
  +        private int     _free;
       }
   
  -    int selectionCount ( )
  +    void push ( )
       {
  -        return _selection == null ? 0 : _selection.size();
  +        assert isPositioned();
  +
  +        int i = _locations.allocate( this, this );
  +        _stackTop = _locations.insert( _stackTop, _stackTop, i );
       }
   
  -    void moveToSelection ( int i )
  +    void popButStay ( )
  +    {
  +        if (_stackTop != -1)
  +            _stackTop = _locations.remove( _stackTop, _stackTop, this );
  +    }
  +    
  +    boolean pop ( )
       {
  -        assert i >= 0 && i < _selection.size();
  +        if (_stackTop == -1)
  +            return false;
   
  -        moveToCur( (Cur) _selection.get( i ) );
  +        _locations.moveTo( _stackTop, this );
  +        _stackTop = _locations.remove( _stackTop, _stackTop, this );
  +
  +        return true;
       }
   
  -    void clearSelection ( )
  +    boolean isAtEndOfLastPush ( )
       {
  -        if (_selection != null)
  -        {
  -            for ( int i = 0 ; i < _selection.size() ; i++ )
  -                ((Cur) _selection.get( i )).release();
  +        assert _stackTop != -1;
   
  -            _selection.clear();
  -        }
  +        return _locations.isAtEndOf( _stackTop, this );
       }
   
  -    void push ( )
  +    void addToSelection ( Cur c )
       {
  -        // TODO - make this more efficient ....
  +        assert isPositioned() && c.isPositioned();
   
  -        if (_stack == null)
  -            _stack = new ArrayList();
  +        int i = _locations.allocate( c, this );
  +        _selectionFirst = _locations.insert( _selectionFirst, -1, i );
  +        
  +        _selectionCount++;
  +    }
  +    
  +    void addToSelection ( )
  +    {
  +        assert isPositioned();
   
  -        _stack.add( permCur() );
  +        int i = _locations.allocate( this, this );
  +        _selectionFirst = _locations.insert( _selectionFirst, -1, i );
  +        
  +        _selectionCount++;
       }
   
  -    void popButStay ( )
  +    private int selectionIndex ( int i )
       {
  -        if (_stack == null || _stack.size() == 0)
  -            return;
  +        assert _selectionN >= -1 && i >= 0 && i < _selectionCount;
           
  -        Cur c = (Cur) _stack.remove( _stack.size() - 1 );
  +        if (_selectionN == -1)
  +        {
  +            _selectionN = 0;
  +            _selectionNth = _selectionFirst;
  +        }
  +
  +        while ( _selectionN < i )
  +        {
  +            _selectionNth = _locations.next( _selectionNth );
  +            _selectionN++;
  +        }
  +            
  +        while ( _selectionN > i )
  +        {
  +            _selectionNth = _locations.prev( _selectionNth );
  +            _selectionN--;
  +        }
   
  -        c.release();
  +        return _selectionNth;
       }
       
  -    boolean pop ( )
  +    void removeSelection ( int i )
       {
  -        if (_stack == null || _stack.size() == 0)
  -            return false;
  +        assert i >= 0 && i < _selectionCount;
  +
  +        int j = selectionIndex( i );
  +
  +        // Update the nth selection indices to accomodate the deletion
  +        
  +        if (i < _selectionN)
  +            _selectionN--;
  +        else if (i == _selectionN)
  +        {
  +            _selectionN--;
  +            
  +            if (i == 0)
  +                _selectionNth = -1;
  +            else
  +                _selectionNth = _locations.prev( _selectionNth );
  +        }
  +
  +        _selectionFirst = _locations.remove( _selectionFirst, j, this );
           
  -        Cur c = (Cur) _stack.remove( _stack.size() - 1 );
  +        _selectionCount--;
  +    }
   
  -        moveToCur( c );
  +    int selectionCount ( )
  +    {
  +        return _selectionCount;
  +    }
   
  -        c.release();
  +    void moveToSelection ( int i )
  +    {
  +        assert i >= 0 && i < _selectionCount;
   
  -        return true;
  +        _locations.moveTo( selectionIndex( i ), this );
  +    }
  +
  +    void clearSelection ( )
  +    {
  +        assert _selectionCount >= 0;
  +        
  +        while ( _selectionCount > 0 )
  +            removeSelection( 0 );
       }
   
       boolean toParent ( )
  @@ -470,13 +823,14 @@
       boolean hasText ( )
       {
           assert isNode();
  +        _xobj.ensureOccupancy();
           return _xobj.hasText();
       }
       
       boolean hasAttrs ( )
       {
           assert isNode();
  -        return _xobj._firstChild != null && _xobj._firstChild.isAttr();
  +        return _xobj.hasAttrs();
       }
       
       boolean hasChildren ( )
  @@ -489,7 +843,10 @@
       {
           assert isNode();
   
  -        for ( Xobj x = _xobj._firstChild ; x != null ; x = x._nextSibling )
  +        if (!_xobj.hasChildren())
  +            return false;
  +
  +        for ( Xobj x = _xobj._firstChild ; ; x = x._nextSibling )
           {
               if (!x.isAttr())
               {
  @@ -497,15 +854,13 @@
                   return true;
               }
           }
  -
  -        return false;
       }
       
       protected boolean toLastChild ( )
       {
           assert isNode();
   
  -        if (_xobj._lastChild == null || _xobj._lastChild.isAttr())
  +        if (!_xobj.hasChildren())
               return false;
   
           moveTo( _xobj._lastChild );
  @@ -597,6 +952,8 @@
   
           CharNode n;
   
  +        _xobj.ensureOccupancy();
  +        
           n = _xobj._charNodesValue =
               updateCharNodes( _locale, _xobj, _xobj._charNodesValue, _xobj._cchValue );
           
  @@ -642,13 +999,11 @@
               p = pa;
           else if (p == pa)
           {
  -            //
               // Text after an attr is allowed only on the last attr,
               // and that text belongs to the parent container..  
               //
               // If we're a thte end of the last attr, then we were just
               // inside the container, and we need to skip the attrs.
  -            //
               
               if (x.isAttr() &&
                   (x._cchAfter > 0 || x._nextSibling == null || !x._nextSibling.isAttr()))
  @@ -661,6 +1016,7 @@
           }
           else if (p == pa - 1)
           {
  +            x.ensureOccupancy();
               p = x._cchValue > 0 ? 1 : 0;
           }
           else if (p > 1)
  @@ -732,6 +1088,8 @@
           else
           {
               assert p == 0;
  +
  +            x.ensureOccupancy();
               
               p = 1;
               
  @@ -807,6 +1165,9 @@
   
           for ( ; nodes != null ; nodes = nodes._next )
               nodes._src = x;
  +
  +        // No Need to notify text change or alter version, text nodes are
  +        // not part of the infoset
       }
   
       CharNode getCharNodes ( )
  @@ -815,17 +1176,18 @@
           assert !isRoot();
           
           Xobj x = getDenormal();
  -        int  p = _posTemp;
   
           CharNode nodes;
   
  -        if (p >= x.posAfter())
  +        if (_posTemp >= x.posAfter())
           {
               nodes = x._charNodesAfter =
                   updateCharNodes( _locale, x, x._charNodesAfter, x._cchAfter );
           }
           else
           {
  +            x.ensureOccupancy();
  +            
               nodes = x._charNodesValue =
                   updateCharNodes( _locale, x, x._charNodesValue, x._cchValue );
           }
  @@ -928,17 +1290,22 @@
           assert to == null || to.isPositioned();
           assert to == null || !ancestorOf( to );
           assert to == null || (!to.isNode() || !to.isRoot());
  +
  +        notifyGeneralChange();
           
  +        // Note that all changes to text in are handled by other fcns,
  +        // thus, I do not need to notify text changes here.
  +
           // TODO - this code may not handle targets near attributes
  -        // perfectly ... 
  +        // perfectly ... check this
   
  -        // We're moveing this node, if there is anyu text after it,
  +        // We're moveing this node, if there is any text after it,
           // move this text to before this node.
           
           if (_xobj.cchAfter() > 0)
           {
               Cur fromChars = tempCur( _xobj, _xobj.posAfter() );
  -            fromChars.moveChars( this, _xobj.cchAfter() );
  +            fromChars.moveChars( this, -1 );
               fromChars.release();
           }
           
  @@ -985,7 +1352,13 @@
           assert isPositioned();
           assert cchMove == 0 || isText();
           assert to == null || to.isNormal();
  -        assert cchMove >= 0 && cchMove <= cchRight();
  +
  +        int cchRight = cchRight();
  +
  +        if (cchMove < 0)
  +            cchMove = cchRight();
  +        
  +        assert cchMove >= 0 && cchMove <= cchRight;
           
           if (cchMove == 0)
           {
  @@ -994,12 +1367,21 @@
               return null;
           }
   
  +        notifyGeneralChange();
  +        
  +        // No need to ensureOccupancy, because if we're at text, then
  +        // we must be occupied
  +        
  +        assert _xobj.isOccupied();
  +                    
           if (to == null)
           {
               // If there is a cursor in the sequence of chars to remove,
               // then create a new place for these chars to live and move
               // them there, taking the cursors with them.
               
  +            notifyTextChange();
  +
               for ( Cur e = _xobj.getEmbedded() ; e != null ; e = e._next )
               {
                   if (e != this && inChars( e, cchMove ))
  @@ -1023,7 +1405,7 @@
   
               // Check for no-op, but return the text "moved"
               
  -            if (_xobj == to._xobj && inChars( to, cchMove ))
  +            if (inChars( to, cchMove ))
               {
                   Object src;
   
  @@ -1051,6 +1433,12 @@
                   to.insertChars( _xobj._srcAfter, _xobj._offAfter + _pos - pa, cchMove );
           }
   
  +        notifyTextChange();
  +        
  +        for ( Cur e = _xobj.getEmbedded() ; e != null ; e = e._next )
  +            if (e != this && inChars( e, cchMove ))
  +                e.moveTo( to._xobj, to._pos + e._pos - _pos );
  +
           Object srcMoved;
           int    offMoved;
           
  @@ -1070,6 +1458,8 @@
   
               _xobj._offValue = _locale._charUtil._offSrc;
               _xobj._cchValue = _locale._charUtil._cchSrc;
  +
  +            _xobj.invalidateUser();
           }
           else
           {
  @@ -1085,12 +1475,11 @@
   
               _xobj._offAfter = _locale._charUtil._offSrc;
               _xobj._cchAfter = _locale._charUtil._cchSrc;
  +
  +            if (_xobj._parent != null)
  +                _xobj._parent.invalidateUser();
           }
           
  -        for ( Cur e = _xobj.getEmbedded() ; e != null ; e = e._next )
  -            if (e != this && inChars( e, cchMove ))
  -                e.moveTo( to._xobj, to._pos + e._pos - _pos );
  -
           // The case where I delete all value text, _pos will be at end of node,
           // need to normalize to the first child (if any)
           
  @@ -1112,40 +1501,71 @@
           assert isNormal() && cch >= 0;
           assert !isRoot();
   
  -        if (cch > 0)
  -        {
  -            Xobj x = getDenormal();
  -            int  p = _posTemp;
  +        if (cch <= 0)
  +            return;
   
  -            assert p > 0;
  +        notifyGeneralChange();
  +        
  +        // If _pos == 0, then I'll insert in the after of the
  +        // denormailzed Xobj or in the value of the container (which
  +        // cannot be vacant). No need to ensureOccupancy for these
  +        // cases.  The only case I need to ensuringOccupancy is if the
  +        // current pos is POS_END, which is the only valid position in
  +        // the value when the value is vacant.
  +
  +        if (_pos == END_POS)
  +            _xobj.ensureOccupancy();
  +        
  +        Xobj x = getDenormal();
  +        int p = _posTemp;
  +
  +        assert p > 0;
  +
  +        // Only need to notify a text change and update cursors if we're inserting text
  +        // before any text in the node
  +
  +        if (x._cchValue + x._cchAfter > 0 && p != x.posMax() &&
  +                (x._cchAfter != 0 || p != x.posAfter() - 1))
  +        {
  +            notifyTextChange();
   
               for ( Cur e = x.getEmbedded() ; e != null ; e = e._next )
                   if (e != this && e._pos >= p)
                       e._pos += cch;
  +        }
   
  -            if (p >= x.posAfter())
  -            {
  -                x._srcAfter =
  -                    _locale._charUtil.insertChars(
  -                        p - x.posAfter(),
  -                        x._srcAfter, x._offAfter, x._cchAfter, src, off, cch );
  -                
  -                x._offAfter = _locale._charUtil._offSrc;
  -                x._cchAfter = _locale._charUtil._cchSrc;
  -            }
  -            else
  -            {
  -                x._srcValue =
  -                    _locale._charUtil.insertChars(
  -                        p - 1,
  -                        x._srcValue, x._offValue, x._cchValue, src, off, cch );
  -                
  -                x._offValue = _locale._charUtil._offSrc;
  -                x._cchValue = _locale._charUtil._cchSrc;
  -            }
  -            
  -            _locale._versionAll++;
  +        if (p >= x.posAfter())
  +        {
  +            x._srcAfter =
  +                _locale._charUtil.insertChars(
  +                    p - x.posAfter(),
  +                    x._srcAfter, x._offAfter, x._cchAfter, src, off, cch );
  +
  +            x._offAfter = _locale._charUtil._offSrc;
  +            x._cchAfter = _locale._charUtil._cchSrc;
  +
  +            if (x._parent != null)
  +                x.invalidateUser();
  +        }
  +        else
  +        {
  +            x._srcValue =
  +                _locale._charUtil.insertChars(
  +                    p - 1,
  +                    x._srcValue, x._offValue, x._cchValue, src, off, cch );
  +
  +            x._offValue = _locale._charUtil._offSrc;
  +            x._cchValue = _locale._charUtil._cchSrc;
  +
  +            x.invalidateUser();
           }
  +
  +        // If the normalized pos was -1 (before the end), need to set
  +        // this cursor to be before the text.
  +        
  +        moveTo( x, p );
  +
  +        _locale._versionAll++;
       }
   
       protected final void setBookmark ( Class c, Object o )
  @@ -1198,6 +1618,8 @@
       String getValueString ( )
       {
           assert isNode();
  +
  +        _xobj.ensureOccupancy();
           
           // TODO - make sure there are no children (ok for an element to have
           // attrs)
  @@ -1216,6 +1638,8 @@
       {
           assert isNode();
           
  +        _xobj.ensureOccupancy();
  +        
           return _xobj.getChars( 1, -1, this );
       }
       
  @@ -1234,6 +1658,8 @@
           walk:
           for ( ; ; )
           {
  +            xo.ensureOccupancy();
  +            
               Xobj newXo = xo.newNode();
   
               newXo._srcValue = xo._srcValue;
  @@ -1284,17 +1710,46 @@
           copy._srcAfter = null;
           copy._offAfter = 0;
           copy._cchAfter = 0;
  -
  -        if (cTo._xobj == null)
  -            cTo.moveTo( copy );
  -        else
  +
  +        if (cTo.isPositioned())
           {
               // TODO - how to operate between mcur and fcur
  -            
  +
               Cur from = cTo._locale.tempCur();
               from.moveNode( cTo );
               from.release();
           }
  +        else
  +            cTo.moveTo( copy );
  +    }
  +
  +    void notifyGeneralChange ( )
  +    {
  +        _locale.notifyGeneralChangeListeners();
  +    }
  +    
  +    void notifyTextChange ( )
  +    {
  +        _locale.notifyTextChangeListeners();
  +    }
  +
  +    void registerForTextChange ( )
  +    {
  +        // If next != null, then we're already on the list
  +        
  +        if (_nextTextChangeListener == null)
  +            _locale.registerForTextChange( this );
  +    }
  +
  +    public void textChangeNotification ( )
  +    {
  +        if (_state == UNREGISTERED)
  +        {
  +            _locale._registered = listInsert( _locale._registered );
  +            _state = REGISTERED;
  +        }
  +
  +        _locations.textChangeNotification( this );
       }
   
       Cur weakCur ( Object o )
  @@ -1332,15 +1787,17 @@
           return c;
       }
   
  -    // Is s a cursor in the chars defined by cch chars after where this
  -    // is positioned.
  +    // Is a cursor (c) in the chars defined by cch chars after where this
  +    // Cur is positioned.
       
       private boolean inChars ( Cur c, int cch )
       {
           assert isPositioned() && isText() && cchRight() >= cch;
           assert c.isPositioned();
   
  -        return c._xobj != _xobj || c._pos < 0 ? false : c._pos >= _pos && c._pos < _pos + cch;
  +        // No need to ensureOccupancy here
  +
  +        return (c._xobj != _xobj || c._pos <= 0) ? false : c._pos >= _pos && c._pos < _pos + cch;
       }
   
       private Xobj getNormal ( Xobj x, int p )
  @@ -1406,41 +1863,19 @@
           return x;
       }
   
  -//    boolean isInvalid ( )
  +//    void setType ( SchemaType type )
   //    {
   //        assert isNormal() && isPositioned() && _pos == 0;
  -//
  -//        return _xobj.isInvalid();
  +//        _xobj.setType( type );
   //    }
   
  -    void setType ( SchemaType type )
  +    void setRootType ( TypeStoreUser user )
       {
  -        assert isNormal() && isPositioned() && _pos == 0;
  -        _xobj.setType( type );
  +        assert isNode();
  +        
  +        _xobj.setRootType( user );
       }
       
  -//    TypeStoreUser getTypeStoreUser ( )
  -//    {
  -//        assert isNormal() && isPositioned() && _pos == 0;
  -//
  -//        return _xobj.getTypeStoreUser();
  -//    }
  -    
  -//    void setTypeStoreUser ( TypeStoreUser user )
  -//    {
  -//        assert isNormal() && isPositioned() && _pos == 0;
  -//
  -//        _xobj.setTypeStoreUser( user );
  -//    }
  -
  -//    TypeStore getTypeStore ( )
  -//    {
  -//        assert isNormal() && isPositioned();
  -//        assert isElem() || isAttr() || isRoot();
  -//
  -//        return (TypeStore) _xobj;
  -//    }
  -    
       Dom getDom ( )
       {
           assert isNormal();
  @@ -1476,9 +1911,10 @@
   
           _curKind = -1;
   
  -        assert _state == UNEMBEDDED;
  -
  -        _locale._unembedded = listRemove( _locale._unembedded );
  +        assert _state == REGISTERED || _state == UNREGISTERED;
  +        
  +        if (_state == REGISTERED)
  +            _locale._registered = listRemove( _locale._registered );
   
           if (_locale._curPoolCount < 16)
           {
  @@ -1492,13 +1928,8 @@
               _state = DISPOSED;
           }
   
  -        if (_stack != null)
  -        {
  -            for ( int i = 0 ; i < _stack.size() ; i++ )
  -                ((Cur) _stack.get( i )).release();
  -
  -            _stack.clear();
  -        }
  +        while ( _stackTop != -1 )
  +            popButStay();
   
           clearSelection();
       }
  @@ -1550,6 +1981,8 @@
           }
   
           _prev = null;
  +        assert _next == null;
  +        
           _state = -1;
   
           return head;
  @@ -1557,16 +1990,24 @@
   
       private boolean isNormal ( )
       {
  -        if (_state == POOLED)
  +        if (_state == POOLED || _state == DISPOSED)
  +            return false;
  +        
  +        if (_xobj == null)
  +            return _pos == NO_POS;
  +
  +        if (!_xobj.isNormal( _pos ))
               return false;
   
  -        if (_state == DISPOSED)
  -            return _xobj == null && _pos == NO_POS;
  +        if (_state == UNREGISTERED)
  +            return _pos == 0 || _pos == END_POS;
   
  -        if (_xobj == null)
  -            return _state == UNEMBEDDED && _pos == NO_POS;
  +        if (_state == EMBEDDED)
  +            return isOnList( _xobj._embedded );
  +
  +        assert _state == REGISTERED;
   
  -        return _xobj.isNormal( _pos );
  +        return isOnList( _locale._registered );
       }
   
       static final class CurLoadContext extends LoadContext
  @@ -1735,6 +2176,8 @@
               _bits = (domType << 4) + kind;
           }
   
  +        boolean entered ( ) { return _locale.entered(); }
  +
           final int kind    ( ) { return _bits & 0xF; }
           final int domType ( ) { return (_bits & 0xF0) >> 4; }
           
  @@ -1752,148 +2195,28 @@
           final int posAfter ( ) { return 2 + _cchValue; }
           final int posMax   ( ) { return 2 + _cchValue + _cchAfter; }
   
  -        boolean isXmlns ( )
  -        {
  -            return isAttr() ? Locale.isXmlns( _name ) : false;
  -        }
  -
  -        String getXmlnsPrefix ( )
  -        {
  -            return Locale.xmlnsPrefix( _name );
  -        }
  -
  -        String getXmlnsUri ( )
  -        {
  -            return getString( 1, _cchValue );
  -        }
  -
  -        boolean hasChildren ( )
  -        {
  -            for ( Xobj x = _firstChild ; x != null ; x = x._nextSibling )
  -                if (!x.isAttr())
  -                    return true;
  +        boolean isXmlns ( ) { return isAttr() ? Locale.isXmlns( _name ) : false; }
   
  -            return false;
  -        }
  +        String getXmlnsPrefix ( ) { return Locale.xmlnsPrefix( _name ); }
  +        String getXmlnsUri    ( ) { return getString( 1, _cchValue );   }
   
  -        boolean hasText ( )
  -        {
  -            return _cchValue > 0;
  -        }
  +        boolean hasText ( ) { return _cchValue > 0; }
  +        
  +        boolean hasAttrs    ( ) { return _firstChild != null &&  _firstChild.isAttr(); }
  +        boolean hasChildren ( ) { return _lastChild  != null && !_lastChild .isAttr(); }
   
           abstract Dom getDom ( );
           
           abstract Xobj newNode ( );
   
  -        //
  -        // 
  -        //
  -
  -//        final boolean isValid    ( ) { return (_bits & 0x100) == 0; }
  -//        final boolean isInvalid  ( ) { return (_bits & 0x100) != 0; }
  -//        final void    setValid   ( ) { _bits &= ~0x100; }
  -//        final void    setInvalid ( ) { _bits &=  0x100; }
  -
  -        final boolean isVacant    ( ) { return (_bits & 0x100) != 0; }
  -        final boolean isOccupied  ( ) { return (_bits & 0x100) == 0; }
  -        final void    setOccupied ( ) { _bits &=  0x100;             }
  -        final void    setVacant   ( ) { _bits |= ~0x100;             }
  -
  -//        final void fillVacancy ( )
  -//        {
  -//            assert isOccupied();
  -//
  -//            throw new RuntimeException( "Not implemented" );
  -//        }
  -
  -        final void vacate ( )
  -        {
  -            assert getTypeStoreUser() != null;
  -            
  -            if (isOccupied())
  -            {
  -                setVacant();
  -                
  -                throw new RuntimeException( "Not impl" );
  -//
  -//                if (hasText() || hasChildren())
  -//
  -//                    ....
  -            }
  -        }
  -
  -        void setType ( SchemaType type )
  -        {
  -            TypeStoreUser user = getTypeStoreUser();
  -
  -            if (user == null || user.get_schema_type() == type)
  -            {
  -                if (isRoot())
  -                {
  -                    disconnectTree();
  -                    setTypeStoreUserLocal( ((TypeStoreUserFactory) type).createTypeStoreUser() );
  -                }
  -                else
  -                    throw new RuntimeException( "Not impl" );
  -            }
  -        }
  -
  -        private void disconnectTree ( )
  -        {
  -            // Disconnect all type store uses in this tree.  If there is no
  -            // user at the top, then there can be no children.
  -
  -            // TODO - make not recursive
  -            if (getTypeStoreUser() != null)
  -            {
  -                setTypeStoreUserLocal( null );
  -
  -                for ( Xobj x = _firstChild ; x != null ; x = x._nextSibling )
  -                    x.disconnectTree();
  -            }
  -        }
  -    
  -        final TypeStoreUser getTypeStoreUser ( )
  +        final int cchRight ( int p )
           {
  -            // Don't assert isNormal() here ... infinite recursion
  -            return _user;
  +            assert isNormal( p );
  +            if (p <= 0) return 0;
  +            int pa = posAfter();
  +            return p < pa ? pa - p - 1 : posMax() - p;
           }
  -        
  -//        private final void setTypeStoreUserHelper ( TypeStoreUser user )
  -//        {
  -//            assert isValid();
  -//            _user = user;
  -//        }
  -
  -        // Just set the local user without dealing with disconnecting
  -        // children...
  -        
  -        void setTypeStoreUserLocal ( TypeStoreUser newUser )
  -        {
  -            if (isVacant())
  -            {
  -                assert _cchValue == 0 && getTypeStoreUser() != null;
  -
  -                TypeStoreUser oldUser = getTypeStoreUser();
  -
  -                String newValue = oldUser.build_text( this );
  -
  -                setOccupied();
  -
  -                oldUser.disconnect_store();
  -
  -                Cur c = tempCur();
  -                c.next();
  -                c.insertChars( newValue, 0, newValue.length() );
  -                c.release();
  -            }
   
  -            _user = newUser;
  -            
  -            if (newUser != null)
  -                newUser.attach_store( this );
  -        }
  -        
           //
           // Dom interface
           //
  @@ -1902,12 +2225,7 @@
           public final int    nodeType ( ) { return domType(); }
           public final QName  getQName ( ) { return _name;     }
           
  -        public final Cur tempCur ( )
  -        {
  -            Cur c = _locale.tempCur();
  -            c.moveTo( this );
  -            return c;
  -        }
  +        public final Cur tempCur ( ) { Cur c = _locale.tempCur(); c.moveTo( this ); return c; }
   
           public void dump ( PrintStream o, Object ref ) { Cur.dump( o, (Xobj) this, ref ); }
           public void dump ( PrintStream o ) { Cur.dump( o, this, this ); }
  @@ -1917,24 +2235,19 @@
           //
           //
   
  -        // TODO - should be able to have Cur's which are not pointing
  -        // at text not be on either list.
           Cur getEmbedded ( )
           {
  -            Cur c = _locale._unembedded;
  -
  -            while ( c != null )
  +            for ( Cur c ; (c = _locale._registered) != null ; )
               {
  -                Cur next = c._next;
  +                assert c.isNormal();
  +                
  +                _locale._registered = c.listRemove( _locale._registered );
   
  -                if (c.isPositioned())
  +                if (c._pos > 0)
                   {
  -                    _locale._unembedded = c.listRemove( _locale._unembedded );
                       c._xobj._embedded = c.listInsert( c._xobj._embedded );
                       c._state = EMBEDDED;
                   }
  -
  -                c = next;
               }
               
               return _embedded;
  @@ -1950,16 +2263,19 @@
               return _parent == null ? new DocumentFragXobj( _locale ).appendXobj( this ) : _parent;
           }
   
  -        final int cchRight ( int p )
  +        final boolean isValid ( )
           {
  -            assert isNormal( p );
  -            if (p <= 0) return 0;
  -            int pa = posAfter();
  -            return p < pa ? pa - p - 1 : posMax() - p;
  +            if (isVacant() && (_cchValue != 0 || _user == null))
  +                return false;
  +
  +            return true;
           }
   
           final boolean isNormal ( int p )
           {
  +            if (!isValid())
  +                return false;
  +            
               if (p == END_POS)
                   return true;
   
  @@ -1988,9 +2304,6 @@
                       return false;
               }
   
  -            if (isVacant() && (_cchAfter != 0 || getTypeStoreUser() == null))
  -                return false;
  -
               return true;
           }
   
  @@ -2116,19 +2429,225 @@
           }
   
           //
  +        // 
  +        //
  +
  +        private final void setBit     ( int mask ) { _bits |=  mask; }
  +        private final void clearBit   ( int mask ) { _bits &= ~mask; }
  +        
  +        private final boolean bitIsSet   ( int mask ) { return (_bits & mask) != 0; }
  +        private final boolean bitIsClear ( int mask ) { return (_bits & mask) == 0; }
  +
  +        private static final int VACANT   = 0x100;
  +        private static final int ROOTUSER = 0x200;
  +
  +        final boolean isVacant     ( ) { return bitIsSet  ( VACANT ); }
  +        final boolean isOccupied   ( ) { return bitIsClear( VACANT ); }
  +        final void    setOccupied  ( ) {        clearBit  ( VACANT ); }
  +        final void    setVacant    ( ) {        setBit    ( VACANT ); }
  +        
  +        final boolean isRootUser    ( ) { return bitIsSet( ROOTUSER ); }
  +        final void    setRootUser   ( ) {        setBit  ( ROOTUSER ); }
  +        final void    clearRootUser ( ) {        setBit  ( ROOTUSER ); }
  +
  +        void setRootType ( TypeStoreUser user )
  +        {
  +            // TODO - need to remove all descendent users (except those
  +            // which are roots)
  +
  +            // TODO - if there is a user here already and we're vacant,
  +            // need to get the text from the old user before putting in
  +            // the new user
  +
  +            _user = user;
  +
  +            _user.attach_store( this );
  +        }
  +
  +        void invalidateUser ( )
  +        {
  +            if (_user != null)
  +                _user.invalidate_value();
  +        }
  +        
  +        void ensureOccupancy ( )
  +        {
  +            assert isValid();
  +            
  +            if (isVacant())
  +            {
  +                // In order to use Cur to set the value, I mark the
  +                // value as occupied and remove the user to prohibit
  +                // user invalidations
  +                
  +                setOccupied();
  +
  +                TypeStoreUser user = _user;
  +                _user = null;
  +                
  +                String value = user.build_text( this );
  +
  +                Cur c = tempCur();
  +
  +                c.next();
  +
  +                c.insertChars( value, 0, value.length() );
  +
  +                c.release();
  +
  +                _user = user;
  +            }
  +        }
  +
  +//        final void fillVacancy ( )
  +//        {
  +//            assert isOccupied();
  +//
  +//            throw new RuntimeException( "Not implemented" );
  +//        }
  +//
  +//        final void vacate ( )
  +//        {
  +//            assert getTypeStoreUser() != null;
  +//            
  +//            if (isOccupied())
  +//            {
  +//                setVacant();
  +//                
  +//                throw new RuntimeException( "Not impl" );
  +// //
  +// //                if (hasText() || hasChildren())
  +// // 
  +// //                    ....
  +//            }
  +//        }
  +//
  +//        void setType ( SchemaType type )
  +//        {
  +//            TypeStoreUser user = getTypeStoreUser();
  +//
  +//            if (user == null || user.get_schema_type() == type)
  +//            {
  +//                if (isRoot())
  +//                {
  +//                    disconnectTree();
  +//                    setTypeStoreUserLocal( ((TypeStoreUserFactory) type).createTypeStoreUser() );
  +//                }
  +//                else
  +//                    throw new RuntimeException( "Not impl" );
  +//            }
  +//        }
  +//
  +//        private void disconnectTree ( )
  +//        {
  +//            // Disconnect all type store uses in this tree.  If there is no
  +//            // user at the top, then there can be no children.
  +//
  +//            // TODO - make not recursive
  +//            if (getTypeStoreUser() != null)
  +//            {
  +//                setTypeStoreUserLocal( null );
  +//
  +//                for ( Xobj x = _firstChild ; x != null ; x = x._nextSibling )
  +//                    x.disconnectTree();
  +//            }
  +//        }
  +//    
  +//        final TypeStoreUser getTypeStoreUser ( )
  +//        {
  +//            // Don't assert isNormal() here ... infinite recursion
  +//            return _user;
  +//        }
  +//        
  +//        private final void setTypeStoreUserHelper ( TypeStoreUser user )
  +//        {
  +//            assert isValid();
  +//            _user = user;
  +//        }
  +//
  +//        // Just set the local user without dealing with disconnecting
  +//        // children...
  +//        
  +//        void setTypeStoreUserLocal ( TypeStoreUser newUser )
  +//        {
  +//            if (isVacant())
  +//            {
  +//                assert _cchValue == 0 && getTypeStoreUser() != null;
  +//
  +//                TypeStoreUser oldUser = getTypeStoreUser();
  +//
  +//                String newValue = oldUser.build_text( this );
  +//
  +//                setOccupied();
  +//
  +//                oldUser.disconnect_store();
  +//
  +//                Cur c = tempCur();
  +//                c.next();
  +//                c.insertChars( newValue, 0, newValue.length() );
  +//                c.release();
  +//            }
  +//
  +//            _user = newUser;
  +//            
  +//            if (newUser != null)
  +//                newUser.attach_store( this );
  +//        }
  +        
  +        //
           // TypeStore
           //
           
  -        public boolean is_attribute ( ) { return isAttr(); }
  -        public boolean validate_on_set ( ) { return _locale._validateOnSet; }
  -        public void invalidate_text ( ) { vacate(); }
  +        public boolean is_attribute    ( ) { assert isValid(); return isAttr();               }
  +        public boolean validate_on_set ( ) { assert isValid(); return _locale._validateOnSet; }
  +        
  +        public void invalidate_text ( )
  +        {
  +            assert isValid();
  +
  +            if (!isVacant())
  +            {
  +                if (hasText() || hasChildren())
  +                {
  +                    // TODO - may have to inhibit invalidations here
  +
  +                    Cur c = tempCur();
  +
  +                    c.push();
  +                    c.next();
  +
  +                    do
  +                    {
  +                        assert !c.isAtEndOfLastPush();
  +                        
  +                        if (c.isText())
  +                            c.moveChars( null, -1 );
  +                        else
  +                            c.moveNode( null );
  +                    }
  +                    while ( !c.isAtEndOfLastPush() );
  +
  +                    c.release();
  +                }
  +
  +                setVacant();
  +            }
  +
  +            assert isValid();
  +        }
  +        
  +        public String fetch_text ( int whitespaceRule )
  +        {
  +            assert isValid() && isOccupied();
  +
  +            return getString( 1, -1 );
  +        }
           
           public XmlCursor new_cursor ( ) { return TypeImpl.typeStore_new_cursor( this ); }
           public void validate ( ValidatorListener vEventSink ) { TypeImpl.typeStore_validate( this, vEventSink ); }
           public SchemaTypeLoader get_schematypeloader ( ) { return TypeImpl.typeStore_get_schematypeloader( this ); }
           public TypeStoreUser change_type ( SchemaType sType ) { return TypeImpl.typeStore_change_type( this, sType ); }
           public QName get_xsi_type ( ) { return TypeImpl.typeStore_get_xsi_type( this ); }
  -        public String fetch_text ( int whitespaceRule ) { return TypeImpl.typeStore_fetch_text( this, whitespaceRule ); }
           public void store_text ( String text ) { TypeImpl.typeStore_store_text( this, text ); }
           public String compute_default_text ( ) { return TypeImpl.typeStore_compute_default_text( this ); }
           public int compute_flags ( ) { return TypeImpl.typeStore_compute_flags( this ); }
  @@ -2809,10 +3328,10 @@
           for ( Cur c = xo._embedded ; c != null ; c = c._next )
               dumpCur( o, "E:", c, ref );
           
  -        for ( Cur c = xo._locale._unembedded ; c != null ; c = c._next )
  +        for ( Cur c = xo._locale._registered ; c != null ; c = c._next )
           {
               if (c._xobj == xo)
  -                dumpCur( o, "U:", c, ref );
  +                dumpCur( o, "R:", c, ref );
           }
       }
       
  @@ -2834,6 +3353,17 @@
           if (xo == null)
               return;
   
  +        if (ref instanceof Cur)
  +        {
  +            Cur c = (Cur) ref;
  +
  +            if (c._state == UNREGISTERED)
  +            {
  +                c._locale._registered = c.listInsert( c._locale._registered );
  +                c._state = REGISTERED;
  +            }
  +        }
  +
           if (xo == ref)
               o.print( "* " );
           else
  @@ -2916,12 +3446,22 @@
       Cur _nextTemp;
       int _tempFrame;
   
  -    Cur _next, _prev;
  +    Cur _next;
  +    Cur _prev;
       
       Object _obj;
   
  -    ArrayList _stack;
  -    ArrayList _selection;
  +    Cur _nextTextChangeListener;
  +
  +    Locations _locations;
  +    int       _textLocations;
  +
  +    int _stackTop;
  +
  +    int _selectionFirst;
  +    int _selectionN;       // the selection user index 0 .. N
  +    int _selectionNth;     // Index in _locations
  +    int _selectionCount;
       
       private int _posTemp;
       
  
  
  
  1.16      +93 -55    xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Cursor.java
  
  Index: Cursor.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Cursor.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- Cursor.java	9 Apr 2004 18:26:40 -0000	1.15
  +++ Cursor.java	12 Apr 2004 20:55:13 -0000	1.16
  @@ -25,6 +25,7 @@
   
   import org.apache.xmlbeans.XmlCursor;
   import org.apache.xmlbeans.XmlCursor.TokenType;
  +import org.apache.xmlbeans.XmlCursor.ChangeStamp;
   import org.apache.xmlbeans.XmlObject;
   import org.apache.xmlbeans.XmlOptions;
   import org.apache.xmlbeans.XmlDocumentProperties;
  @@ -49,8 +50,10 @@
   import org.xml.sax.SAXException;
   
   import org.apache.xmlbeans.impl.newstore2.Saver.TextSaver;
  +import org.apache.xmlbeans.impl.newstore2.Locale.GeneralChangeListener;
  +import org.apache.xmlbeans.impl.newstore2.Path.PathEngine;
   
  -public final class Cursor implements XmlCursor
  +public final class Cursor implements XmlCursor, GeneralChangeListener
   {
       static final int ROOT     = Cur.ROOT;
       static final int ELEM     = Cur.ELEM;
  @@ -63,6 +66,7 @@
       {
           _locale = c._locale;
           _cur = c.weakCur( this );
  +        _currentSelection = -1;
       }
   
       private static boolean isValid ( Cur c )
  @@ -380,6 +384,28 @@
           return true;
       }
   
  +    private static final class ChangeStampImpl implements ChangeStamp
  +    {
  +        ChangeStampImpl ( Locale l )
  +        {
  +            _locale = l;
  +            _versionStamp = _locale.version();
  +        }
  +
  +        public boolean hasChanged ( )
  +        {
  +            return _versionStamp != _locale.version();
  +        }
  +
  +        private final Locale _locale;
  +        private final long   _versionStamp;
  +    }
  +
  +    public ChangeStamp _getDocChangeStamp ( )
  +    {
  +        return new ChangeStampImpl( _locale );
  +    }
  +    
       public XmlDocumentProperties _documentProperties ( )
       {
           return Locale.getDocProps( _cur, true );
  @@ -547,52 +573,92 @@
       
       public void _push ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        _cur.push();
       }
       
       public boolean _pop ( )
       {
  +        return _cur.pop();
  +    }
  +    
  +    public void notifyGeneralChange ( )
  +    {
           throw new RuntimeException( "Not implemented" );
       }
  +
  +    public void setNextGeneralChangeListener ( GeneralChangeListener listener )
  +    {
  +        _nextGeneralChangeListener = listener;
  +    }
  +        
  +    public GeneralChangeListener getNextGeneralChangeListener ( )
  +    {
  +        return _nextGeneralChangeListener;
  +    }
       
       public void _selectPath ( String path )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        _selectPath( path, null );
       }
       
  -    public void _selectPath ( String path, XmlOptions options )
  +    public void _selectPath ( String pathExpr, XmlOptions options )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        _cur.clearSelection();
  +        _pathEngine = Path.getCompiledPath( pathExpr, options ).execute( _cur );
       }
       
       public boolean _hasNextSelection ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        push();
  +
  +        try
  +        {
  +            return toNextSelection();
  +        }
  +        finally
  +        {
  +            pop();
  +        }
       }
       
       public boolean _toNextSelection ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        return _toSelection( _currentSelection + 1 );
       }
       
       public boolean _toSelection ( int i )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        while ( i >= _cur.selectionCount() )
  +        {
  +            if (_pathEngine == null || !_pathEngine.next( _cur ))
  +                return false;
  +        }
  +
  +        _cur.moveToSelection( _currentSelection = i );
  +        
  +        return true;
       }
       
       public int _getSelectionCount ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        _toSelection( Integer.MAX_VALUE );
  +        
  +        return _cur.selectionCount();
       }
       
       public void _addToSelection ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        _toSelection( Integer.MAX_VALUE );
  +
  +        _cur.addToSelection();
       }
       
       public void _clearSelections ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        _cur.clearSelection();
  +        _pathEngine.release();
  +        _pathEngine = null;
  +        _currentSelection = 0;
       }
       
       public boolean _toBookmark ( XmlBookmark bookmark )
  @@ -668,31 +734,8 @@
       public boolean _toNextSibling ( )
       {
           assert isValid();
  -
  -        if (!_cur.hasParent())
  -            return false;
  -
  -        Cur c = tempCur();
           
  -        int k = c.kind();
  -
  -        if (k == ATTR)
  -            c.toParent();
  -        else if (k == ELEM)
  -        {
  -            c.toEnd();
  -            c.next();
  -        }
  -
  -        while ( (k = c.kind()) > 0 && k != ELEM )
  -            c.next();
  -
  -        if (k == ELEM)
  -            _cur.moveToCur( c );
  -
  -        c.release();
  -
  -        return k == ELEM;
  +        return Locale.toNextSiblingElement( _cur );
       }
       
       public boolean _toPrevSibling ( )
  @@ -744,18 +787,7 @@
       
       public boolean _toFirstChild ( )
       {
  -        if (!Locale.pushToContainer( _cur ))
  -            return false;
  -
  -        if (!_cur.hasChildren() || (_cur.next() && !_cur.isElem() && !_toNextSibling()))
  -        {
  -            _cur.pop();
  -            return false;
  -        }
  -
  -        _cur.popButStay();
  -
  -        return true;
  +        return Locale.toFirstChildElement( _cur );
       }
   
       public boolean _toChild ( String local )
  @@ -835,7 +867,13 @@
       
       public String _getTextValue ( )
       {
  -        throw new RuntimeException( "Not implemented" );
  +        if (!_cur.isNode())
  +        {
  +            throw new IllegalStateException(
  +                "Can't get text value, current token can have no text value" );
  +        }
  +
  +        return Locale.getTextValue ( _cur, Locale.WS_PRESERVE );
       }
       
       public int _getTextValue ( char[] returnedChars, int offset, int maxCharacterCount )
  @@ -909,11 +947,6 @@
           throw new RuntimeException( "Not implemented" );
       }
       
  -    public ChangeStamp _getDocChangeStamp ( )
  -    {
  -        throw new RuntimeException( "Not implemented" );
  -    }
  -    
       public void _setBookmark ( XmlBookmark bookmark )
       {
           throw new RuntimeException( "Not implemented" );
  @@ -1228,6 +1261,11 @@
       //
       //
   
  -    private Locale _locale;
  -    private Cur    _cur;
  +    private Locale     _locale;
  +    private Cur        _cur;
  +    private PathEngine _pathEngine;
  +    private int        _currentSelection;
  +
  +    
  +    private GeneralChangeListener _nextGeneralChangeListener;
   }
  
  
  
  1.30      +0 -51     xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/DomImpl.java
  
  Index: DomImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/DomImpl.java,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -u -r1.29 -r1.30
  --- DomImpl.java	30 Mar 2004 00:10:08 -0000	1.29
  +++ DomImpl.java	12 Apr 2004 20:55:13 -0000	1.30
  @@ -1211,57 +1211,6 @@
           default : throw new RuntimeException( "Unknown kind" );
           }
   
  -        //
  -        // If the parent is a non DOM root (kind: ROOT), then I need to check
  -        // to see if there are multiple DOM nodes number this root and turn it
  -        // into a DOM fragment.
  -        //
  -
  -//        if (c != null && c.isNonDomRoot())
  -//        {
  -//            c.next();
  -//            
  -//            assert c.kind() > 0;
  -//
  -//            if (c.isText())
  -//                c.next();
  -//            else
  -//            {
  -//                c.toEnd();
  -//                c.next();
  -//            }
  -//            
  -//            if (c.isFinish())
  -//            {
  -//                c.release();
  -//                c = null;
  -//            }
  -//            else
  -//            {
  -//                Cur frag = n.locale().tempCur();
  -//                
  -//                frag.createDomDocFragRoot();
  -//
  -//                frag.next();
  -//
  -//                c.toParent();
  -//                c.next();
  -//
  -//                while ( !c.isFinish() )
  -//                {
  -//                    if (c.isText())
  -//                        c.moveChars( frag, -1 );
  -//                    else
  -//                        c.moveNode( frag );
  -//                }
  -//
  -//                c.moveToCur( frag );
  -//                c.toParent();
  -//
  -//                frag.release();
  -//            }
  -//        }
  -
           if (c == null)
               return null;
           
  
  
  
  1.16      +228 -37   xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Locale.java
  
  Index: Locale.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Locale.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- Locale.java	30 Mar 2004 21:29:26 -0000	1.15
  +++ Locale.java	12 Apr 2004 20:55:13 -0000	1.16
  @@ -59,6 +59,8 @@
   import org.apache.xmlbeans.impl.newstore2.DomImpl.SaajTextNode;
   import org.apache.xmlbeans.impl.newstore2.DomImpl.SaajCdataNode;
   
  +import org.apache.xmlbeans.impl.newstore2.Cur.Locations;
  +
   import org.apache.xmlbeans.XmlOptions;
   import org.apache.xmlbeans.QNameSet;
   import org.apache.xmlbeans.QNameCache;
  @@ -69,6 +71,8 @@
   
   import javax.xml.namespace.QName;
   
  +import org.apache.xmlbeans.impl.values.TypeStore;
  +
   final class Locale implements DOMImplementation, SaajCallback
   {
       static final int ROOT     = Cur.ROOT;
  @@ -78,6 +82,11 @@
       static final int PROCINST = Cur.PROCINST;
       static final int TEXT     = Cur.TEXT;
   
  +    static final int WS_UNSPECIFIED = TypeStore.WS_UNSPECIFIED;
  +    static final int WS_PRESERVE    = TypeStore.WS_PRESERVE;
  +    static final int WS_REPLACE     = TypeStore.WS_REPLACE;
  +    static final int WS_COLLAPSE    = TypeStore.WS_COLLAPSE;
  +                                        
       static final String _xsi         = "http://www.w3.org/2001/XMLSchema-instance";
       static final String _schema      = "http://www.w3.org/2001/XMLSchema";
       static final String _openFragUri = "http://www.openuri.org/fragment";
  @@ -144,54 +153,231 @@
           return props;
       }
   
  -    static boolean pushToContainer ( Cur c )
  +    void registerForTextChange ( Cur c )
       {
  -        if (c.isContainer())
  -            return true;
  +        // The end of this list points to itself so that I can know if
  +        // any cur is on the list by seeing if netx != null.
  +        
  +        assert c._nextTextChangeListener == null;
  +        
  +        if (_textChangeListeners == null)
  +            _textChangeListeners = c._nextTextChangeListener = c;
  +        else
  +        {
  +            c._nextTextChangeListener = _textChangeListeners;
  +            _textChangeListeners = c;
  +        }
  +    }
   
  -        c.push();
  +    interface GeneralChangeListener
  +    {
  +        void notifyGeneralChange ( );
  +
  +        void setNextGeneralChangeListener ( GeneralChangeListener listener );
  +        
  +        GeneralChangeListener getNextGeneralChangeListener ( );
  +    }
   
  -        boolean move = false;
  +    void registerForGeneralChange ( GeneralChangeListener listener )
  +    {
  +        if (listener.getNextGeneralChangeListener() == null)
  +        {
  +            if (_generalChangeListeners == null)
  +                listener.setNextGeneralChangeListener( listener );
  +            else
  +                listener.setNextGeneralChangeListener( _generalChangeListeners );
  +        
  +            _generalChangeListeners = listener;
  +        }
  +    }
   
  -        if (c.isAttr())
  +    void notifyGeneralChangeListeners ( )
  +    {
  +        while ( _generalChangeListeners != null )
           {
  -            c.toParent();
  -            c.next();
  +            _generalChangeListeners.notifyGeneralChange();
  +
  +            if (_generalChangeListeners.getNextGeneralChangeListener() == _generalChangeListeners)
  +                _generalChangeListeners.setNextGeneralChangeListener( null );
  +
  +            GeneralChangeListener next = _generalChangeListeners.getNextGeneralChangeListener();
  +
  +            _generalChangeListeners.setNextGeneralChangeListener( null );
  +
  +            _generalChangeListeners = next;
  +        }
  +    }
  +    
  +    void notifyTextChangeListeners ( )
  +    {
  +        while ( _textChangeListeners != null )
  +        {
  +            _textChangeListeners.textChangeNotification();
  +
  +            if (_textChangeListeners._nextTextChangeListener == _textChangeListeners)
  +                _textChangeListeners._nextTextChangeListener = null;
  +
  +            _textChangeListeners = _textChangeListeners._nextTextChangeListener;
           }
  +    }
  +
  +    //
  +    // Cursor helpers
  +    //
  +
  +    static String getTextValue ( Cur c, int wsRule )
  +    {
  +        assert c.isNode();
  +        
  +        if (!c.hasChildren() && wsRule == WS_UNSPECIFIED || wsRule == WS_PRESERVE)
  +            return c.getValueString();
  +
  +        int scrubState = START_STATE;
  +        StringBuffer sb = new StringBuffer();
  +
  +        c.push();
  +
  +        for ( c.next() ; !c.isAtEndOfLastPush() ; c.next() )
  +            if (c.isText())
  +                scrubState = scrubText( c.getChars( -1 ), c._offSrc, c._cchSrc, wsRule, sb );
   
  -        loop:
  +        c.pop();
  +                
  +        return sb.toString();
  +    }
  +
  +    private static final int START_STATE = 0;
  +    private static final int SPACE_SEEN_STATE = 1;
  +    private static final int NOSPACE_STATE = 2;
  +
  +    private static final int scrubText(
  +        Object src, int off, int cch, int wsRule, StringBuffer sb )
  +    {
  +        throw new RuntimeException( "Not impl" );
  +        
  +//        assert text != null;
  +//
  +//        if (text._buf == null)
  +//        {
  +//            assert cch == 0;
  +//            assert cp == 0;
  +//            return state;
  +//        }
  +//
  +//        if (cch == 0)
  +//            return state;
  +//
  +//        boolean replace = false;
  +//        boolean collapse = false;
  +//
  +//        switch ( ws )
  +//        {
  +//        case TypeStore.WS_UNSPECIFIED :                            break;
  +//        case TypeStore.WS_PRESERVE    :                            break;
  +//        case TypeStore.WS_REPLACE     :            replace = true; break;
  +//        case TypeStore.WS_COLLAPSE    : collapse = replace = true; break;
  +//
  +//		default : assert false: "Unknown white space rule " +ws;
  +//        }
  +//
  +//        if (!replace && !collapse)
  +//        {
  +//            text.fetch(sb, cp, cch);
  +//            return state;
  +//        }
  +//
  +//        int off = text.unObscure( cp, cch );
  +//        int startpt = 0;
  +//
  +//        for ( int i = 0 ; i < cch ; i++ )
  +//        {
  +//            char ch = text._buf[ off + i ];
  +//
  +//            if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')
  +//            {
  +//                sb.append(text._buf, off + startpt, i - startpt);
  +//                startpt = i + 1;
  +//
  +//                if (collapse)
  +//                {
  +//                    if (state == NOSPACE_STATE)
  +//                        state = SPACE_SEEN_STATE;
  +//                }
  +//                else
  +//                    sb.append(' ');
  +//            }
  +//            else
  +//            {
  +//                if (state == SPACE_SEEN_STATE)
  +//                    sb.append( ' ' );
  +//
  +//                state = NOSPACE_STATE;
  +//            }
  +//        }
  +//
  +//        sb.append( text._buf, off + startpt, cch - startpt );
  +//
  +//        return state;
  +    }
  +
  +    static boolean pushToContainer ( Cur c )
  +    {
  +        c.push();
  +        
           for ( ; ; )
           {
  -            assert c.isContainer() || c.isFinish() || c.isComment() || c.isProcinst() || c.isText();
  -            
               switch ( c.kind() )
               {
  -            case ROOT :
  -            case ELEM :
  -                move = true;
  -                break loop;
  -
  -            case - ROOT :
  -            case - ELEM :
  -                break loop;
  -
  -            case COMMENT :
  -            case PROCINST :
  -                c.toEnd();
  -                // Fall thru
  -
  -            default :
  -                c.next();
  -                break;
  +            case    ROOT : case     ELEM : return true;
  +            case  - ROOT : case   - ELEM : c.pop(); return false;
  +            case COMMENT : case PROCINST : c.toEnd(); c.next(); break;
  +            default                      : c.nextWithAttrs();   break;
               }
           }
  +    }
   
  -        if (move)
  -            return true;
  +    static boolean toFirstChildElement ( Cur c )
  +    {
  +        if (!pushToContainer( c ))
  +            return false;
   
  -        c.pop();
  +        if (!c.toFirstChild() || (!c.isElem() && !toNextSiblingElement( c )))
  +        {
  +            c.pop();
  +            return false;
  +        }
   
  -        return false;
  +        c.popButStay();
  +
  +        return true;
  +    }
  +    
  +    static boolean toNextSiblingElement ( Cur c )
  +    {
  +        if (!c.hasParent())
  +            return false;
  +
  +        c.push();
  +
  +        int k = c.kind();
  +
  +        if (k == ATTR)
  +            c.toParent();
  +        else if (k == ELEM)
  +        {
  +            c.toEnd();
  +            c.next();
  +        }
  +
  +        while ( (k = c.kind()) > 0 && k != ELEM )
  +            c.next();
  +
  +        if (k == ELEM)
  +            c.popButStay();
  +        else
  +            c.pop();
  +
  +        return k == ELEM;
       }
   
       static boolean toChild ( Cur c, String uri, String local, int i )
  @@ -365,6 +551,7 @@
           _tempFrames = new Cur [ _numTempFramesLeft = 8 ];
           _charUtil = CharUtil.getThreadLocalCharUtil();
           _qnameFactory = new DefaultQNameFactory();
  +        _locations = new Locations();
       }
   
       long version ( )
  @@ -441,25 +628,23 @@
           if (_curPool == null)
           {
               c = new Cur( this );
  -            c._state = Cur.POOLED;
               c._tempFrame = -1;
           }
           else
           {
               c = _curPool;
               _curPool = c.listRemove( _curPool );
  +            c._state = Cur.UNREGISTERED;
               _curPoolCount--;
           }
   
  +        assert c._state == Cur.UNREGISTERED;
           assert c._prev == null && c._next == null;
           assert !c.isPositioned();
           assert c._obj == null;
                   
           c._curKind = curKind;
   
  -        c._state = Cur.UNEMBEDDED;
  -        _unembedded = c.listInsert( _unembedded );
  -
           return c;
       }
   
  @@ -1128,10 +1313,16 @@
       Cur _curPool;
       int _curPoolCount;
   
  -    Cur _unembedded;
  +    Cur _registered;
  +
  +    GeneralChangeListener _generalChangeListeners;
  +    
  +    Cur _textChangeListeners;
       
       long _versionAll;
       long _versionSansText;
  +
  +    Locations _locations;
       
       CharUtil _charUtil;
       
  
  
  
  1.14      +123 -9    xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Public2.java
  
  Index: Public2.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Public2.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- Public2.java	2 Apr 2004 16:27:53 -0000	1.13
  +++ Public2.java	12 Apr 2004 20:55:13 -0000	1.14
  @@ -35,6 +35,21 @@
   
   import org.apache.xmlbeans.impl.newstore2.Saver.TextSaver;
   
  +import org.apache.xmlbeans.impl.values.TypeStore;
  +import org.apache.xmlbeans.impl.values.TypeStoreUser;
  +import org.apache.xmlbeans.impl.values.TypeStoreVisitor;
  +import org.apache.xmlbeans.impl.values.TypeStoreUserFactory;
  +
  +import org.apache.xmlbeans.SchemaType;
  +
  +import org.apache.xmlbeans.impl.values.NamespaceManager;
  +
  +import javax.xml.namespace.QName;
  +
  +import org.apache.xmlbeans.SchemaField;
  +
  +import org.apache.xmlbeans.QNameSet;
  +
   public final class Public2
   {
       private static Locale newLocale ( Saaj saaj )
  @@ -59,6 +74,11 @@
           l._noSync = ! sync;
       }
   
  +    public static String compilePath ( String path, XmlOptions options )
  +    {
  +        return Path.compilePath( path, options );
  +    }
  +
       public static DOMImplementation getDomImplementation ( )
       {
           return newLocale( null );
  @@ -255,20 +275,114 @@
       public static void dump ( Node n )      { dump( System.out, n ); }
       public static void dump ( XmlCursor c ) { dump( System.out, c ); }
   
  +    static class MyTypeStoreUser implements org.apache.xmlbeans.impl.values.TypeStoreUser
  +    {
  +        MyTypeStoreUser ( Cur c )
  +        {
  +            c.setRootType( this );
  +
  +            assert _store != null;
  +        }
  +        
  +        void setValue ( String newValue )
  +        {
  +            assert newValue != null;
  +            
  +            _store.invalidate_text();
  +            _value = newValue;
  +        }
  +
  +        String getValue ( )
  +        {
  +            if (_value == null)
  +                _value = _store.fetch_text( TypeStore.WS_UNSPECIFIED );
  +            
  +            assert _value != null;
  +
  +            return _value;
  +        }
  +        
  +        public void attach_store ( TypeStore store )
  +        {
  +            _store = store;
  +        }
  +        
  +        public TypeStore get_store ( )
  +        {
  +            return _store;
  +        }
  +        
  +        public String build_text ( NamespaceManager nsm )
  +        {
  +            assert _value != null;
  +            return _value;
  +        }
  +        
  +        public void invalidate_value()
  +        {
  +            _value = null;
  +        }
  +        
  +        public SchemaType get_schema_type() { throw new RuntimeException( "Not impl" ); }
  +        public boolean uses_invalidate_value() { throw new RuntimeException( "Not impl" ); }
  +        public boolean build_nil() { throw new RuntimeException( "Not impl" ); }
  +        public void invalidate_nilvalue() { throw new RuntimeException( "Not impl" ); }
  +        public void invalidate_element_order() { throw new RuntimeException( "Not impl" ); }
  +        public void validate_now() { throw new RuntimeException( "Not impl" ); }
  +        public void disconnect_store() { throw new RuntimeException( "Not impl" ); }
  +        public TypeStoreUser create_element_user(QName eltName, QName xsiType) { throw new RuntimeException( "Not impl" ); }
  +        public TypeStoreUser create_attribute_user(QName attrName) { throw new RuntimeException( "Not impl" ); }
  +        public SchemaType get_element_type(QName eltName, QName xsiType) { throw new RuntimeException( "Not impl" ); }
  +        public SchemaType get_attribute_type(QName attrName) { throw new RuntimeException( "Not impl" ); }
  +        public String get_default_element_text(QName eltName) { throw new RuntimeException( "Not impl" ); }
  +        public String get_default_attribute_text(QName attrName) { throw new RuntimeException( "Not impl" ); }
  +        public int get_elementflags(QName eltName) { throw new RuntimeException( "Not impl" ); }
  +        public int get_attributeflags(QName attrName) { throw new RuntimeException( "Not impl" ); }
  +        public SchemaField get_attribute_field(QName attrName) { throw new RuntimeException( "Not impl" ); }
  +        public boolean is_child_element_order_sensitive() { throw new RuntimeException( "Not impl" ); }
  +        public QNameSet get_element_ending_delimiters(QName eltname) { throw new RuntimeException( "Not impl" ); }
  +        public TypeStoreVisitor new_visitor() { throw new RuntimeException( "Not impl" ); }
  +
  +        private TypeStore _store;
  +        private String    _value;
  +    }
  +
       public static void test ( Node n )
       {
  -        CharUtil cu = CharUtil.getThreadLocalCharUtil();
  +        Dom d = (Dom) n;
  +        
  +        Locale l = d.locale();
  +
  +        l.enter();
  +
  +        try
  +        {
  +            doTest( d );
  +        }
  +        finally
  +        {
  +            l.exit();
  +        }
  +    }
  +        
  +    public static void doTest ( Dom d )
  +    {
  +        Cur c = d.locale().tempCur();
  +
  +        c.moveToDom( d );
  +
  +        MyTypeStoreUser user = new MyTypeStoreUser( c );
   
  -        Object src = null;
  -        int off = 0;
  -        int cch = 0;
  +        c.next();
   
  -        src = cu.insertChars( 0, src, off, cch, "1234567890123456789012345678901234567890", 0, 40 );
  -        off = cu._offSrc;
  -        cch = cu._cchSrc;
  +        user.setValue( "abc" );
  +
  +        c.insertChars( "123", 0, 3 );
           
  -        CharUtil.dumpChars( System.out, src, cu._offSrc, cu._cchSrc );
  +        c.release();
   
  -        cu.getChars( new char [ 100 ], 0, src, cu._offSrc, cu._cchSrc );
  +        System.out.println( user.getValue() );
  +        
  +        user.setValue( "abc" );
       }
   }
  
  
  
  1.24      +2 -2      xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Saver.java
  
  Index: Saver.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Saver.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- Saver.java	5 Apr 2004 21:21:18 -0000	1.23
  +++ Saver.java	12 Apr 2004 20:55:13 -0000	1.24
  @@ -362,7 +362,7 @@
   
               _postProcess = false;
           }
  -        
  +
           if (_done)
           {
               if (_cur != null)
  @@ -370,7 +370,7 @@
                   _cur.release();
                   _cur = null;
               }
  -
  +            
               return false;
           }
   
  
  
  
  1.1                  xml-xmlbeans/v2/src/newstore2/org/apache/xmlbeans/impl/newstore2/Path.java
  
  Index: Path.java
  ===================================================================
  /*   Copyright 2004 The Apache Software Foundation
   *
   *   Licensed under the Apache License, Version 2.0 (the "License");
   *   you may not use this file except in compliance with the License.
   *   You may obtain a copy of the License at
   *
   *       http://www.apache.org/licenses/LICENSE-2.0
   *
   *   Unless required by applicable law or agreed to in writing, software
   *   distributed under the License is distributed on an "AS IS" BASIS,
   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *   See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  
  package org.apache.xmlbeans.impl.newstore2;
  
  import org.apache.xmlbeans.impl.common.XPath;
  import org.apache.xmlbeans.impl.common.XPath.XPathCompileException;
  import org.apache.xmlbeans.impl.common.XPath.ExecutionContext;
  
  import org.apache.xmlbeans.XmlOptions;
  
  import java.util.ConcurrentModificationException;
  import java.util.HashMap;
  
  // TODO - This class handled query *and* path ... rename it?
  
  public abstract class Path
  {
      Path ( String key )
      {
          _pathKey = key;
      }
  
      public static String _useXqrlForXpath = "use xqrl for xpath";
  
      public static String _useXbeanForXpath = "use xbean for xpath";
  
      static interface PathEngine
      {
          void release ( );
          boolean next ( Cur c );
      }
  
      abstract PathEngine execute ( Cur c );
  
      static Path getCompiledPath ( String pathExpr, XmlOptions options )
      {
          options = XmlOptions.maskNull( options );
  
          int force = 
              options.hasOption( _useXqrlForXpath )
                  ? FORCE_XQRL
                  : options.hasOption( _useXbeanForXpath )
                     ? FORCE_XBEAN
                     : FORCE_NEITHER;
  
          return getCompiledPath( pathExpr, force, getCurrentNodeVar( options ) );
      }
  
      private static final int FORCE_XQRL    = 0;
      private static final int FORCE_XBEAN   = 1;
      private static final int FORCE_NEITHER = 2;
  
  
      // TODO - This is a global lock ... make it not be a global lock?
      static synchronized Path getCompiledPath ( String pathExpr, int force, String currentVar )
      {
          Path path = null;
  
          // TODO - remove this when integrate xqrl
          if (force == FORCE_XQRL)
              throw new RuntimeException( "Not XQRL support yet" );
  
          // TODO - when integrate xqrl, add this back
  //        if (force != FORCE_XQRL)
              path = (Path) _xbeanPathCache.get( pathExpr );
  
          // Check for other engine caches here .. make sure to check  force
  
          // Could not find the path in the caches, try to compile it
              
          if (path == null && force != FORCE_XQRL)
          {
              path = XbeanPath.create( pathExpr, currentVar );
  
              if (path != null)
                  _xbeanPathCache.put( pathExpr, path );
          }
  
          // TODO - for xqrl integ, check for null and try to compile
          
          if (path == null)
              throw new RuntimeException( "XQRL no integrated yet, path too complex or invalid" );
  
          return path;
     }
      
      public static synchronized String compilePath ( String pathExpr, XmlOptions options )
      {
          return getCompiledPath( pathExpr, options )._pathKey;
      }
  
      //
      // Xbean store specific implementation of compiled path
      //
  
      private static final class XbeanPath extends Path
      {
          static Path create ( String pathExpr, String currentVar )
          {
              try
              {
                  return
                      new XbeanPath(
                          pathExpr, currentVar, XPath.compileXPath( pathExpr, currentVar ) );
              }
              catch ( XPathCompileException e )
              {
                  return null;
              }
          }
          
          private XbeanPath ( String pathExpr, String currentVar, XPath xpath )
          {
              super( pathExpr );
  
              _currentVar = currentVar;
              _compiledPath = xpath;
          }
          
          PathEngine execute ( Cur c )
          {
              // The builtin XPath engine works only on containers.  Delegate to
              // xqrl otherwise.  Also, if the path had a //. at the end, the
              // simple xpath engine can't do the generate case, it only handles
              // attrs and elements.
  
              if (!c.isContainer() || _compiledPath.sawDeepDot())
                  return getCompiledPath( _pathKey, FORCE_XQRL, _currentVar ).execute( c );
  
              return new XbeanPathEngine( _compiledPath, c );
          }
  
          private final String _currentVar;
          private final XPath  _compiledPath;
      }
  
      private static final class XbeanPathEngine extends ExecutionContext implements PathEngine
      {
          XbeanPathEngine ( XPath xpath, Cur c )
          {
              assert c.isContainer();
              
              _version = c._locale.version();
              _cur = c.weakCur( this );
  
              _cur.push();
              
              init( xpath );
  
              int ret = start();
  
              if ((ret & HIT) != 0)
                  c.addToSelection();
  
              doAttrs( ret, c );
  
              if ((ret & DESCEND) == 0 || !Locale.toFirstChildElement( _cur ))
                  release();
          }
  
          private void advance ( Cur c )
          {
              assert _cur != null;
  
              if (_cur.isFinish())
              {
                  if (_cur.isAtEndOfLastPush())
                      release();
                  else
                  {
                      end();
                      _cur.next();
                  }
              }
              else if (_cur.isElem())
              {
                  int ret = element( _cur.getName() );
                  
                  if ((ret & HIT) != 0)
                      c.addToSelection( _cur );
  
                  doAttrs( ret, c );
                  
                  if ((ret & DESCEND) == 0 || !Locale.toFirstChildElement( _cur ))
                  {
                      _cur.toEnd();
                      _cur.next();
                  }
              }
              else
                  _cur.next();
          }
          
          private void doAttrs ( int ret, Cur c )
          {
              assert _cur.isContainer();
              
              if ((ret & ATTRS) != 0)
              {
                  if (_cur.toFirstAttr())
                  {
                      do
                      {
                          if (attr( _cur.getName() ))
                              c.addToSelection( _cur );
                      }
                      while ( _cur.toNextAttr() );
  
                      _cur.toParent();
                  }
              }
          }
  
          public boolean next ( Cur c )
          {
              if (_version != _cur._locale.version())
                  throw new ConcurrentModificationException( "Document changed during select" );
              
              int startCount = c.selectionCount();
  
              while ( _cur != null )
              {
                  advance( c );
  
                  if (startCount != c.selectionCount())
                      return true;
              }
  
              return false;
          }
  
          public void release( )
          {
              if (_cur != null)
              {
                  _cur.release();
                  _cur = null;
              }
          }
          
          private final long _version;
          private       Cur  _cur;
      }
  
      //
      //
      //
  
      private static String getCurrentNodeVar ( XmlOptions options )
      {
          String currentNodeVar = "this";
  
          options = XmlOptions.maskNull( options );
          
          if (options.hasOption( XmlOptions.XQUERY_CURRENT_NODE_VAR ))
          {
              currentNodeVar = (String) options.get( XmlOptions.XQUERY_CURRENT_NODE_VAR );
  
              if (currentNodeVar.startsWith( "$" ))
              {
                  throw
                      new IllegalArgumentException(
                          "Omit the '$' prefix for the current node variable" );
              }
          }
  
          return currentNodeVar;
      }
  
      //
      //
      //
      
      protected final String _pathKey;
      
      private static HashMap _xbeanPathCache = new HashMap();
  }
  
  
  1.45      +94 -1     xml-xmlbeans/v2/test/src/erictest/EricTest.java
  
  Index: EricTest.java
  ===================================================================
  RCS file: /home/cvs/xml-xmlbeans/v2/test/src/erictest/EricTest.java,v
  retrieving revision 1.44
  retrieving revision 1.45
  diff -u -r1.44 -r1.45
  --- EricTest.java	2 Apr 2004 16:27:53 -0000	1.44
  +++ EricTest.java	12 Apr 2004 20:55:13 -0000	1.45
  @@ -33,6 +33,7 @@
   import org.apache.xmlbeans.XmlBeans;
   import org.apache.xmlbeans.XmlCursor.TokenType;
   import org.apache.xmlbeans.XmlCursor.XmlBookmark;
  +import org.apache.xmlbeans.XmlCursor.ChangeStamp;
   import org.apache.xmlbeans.XmlCursor;
   import org.apache.xmlbeans.GDateBuilder;
   import org.apache.xmlbeans.SimpleValue;
  @@ -67,6 +68,7 @@
   import java.util.Arrays;
   import java.util.Date;
   import java.util.HashMap;
  +import java.util.Collection;
   import java.util.List;
   import java.util.Map;
   import java.util.Random;
  @@ -111,7 +113,98 @@
   {
       public static void main ( String[] args ) throws Exception
       {
  -        Public2.test( null );
  +        Document doc = Public2.parse( "<a><b id='1'/><b id='2'/></a>" );
  +
  +        Cache cache = new Cache( doc, new QName( "id" ) );
  +
  +        Public2.dump( cache.lookup( "1" ) );
  +        Public2.dump( cache.lookup( "2" ) );
  +    }
  +
  +    public static class Cache
  +    {
  +        public Cache ( Node n, QName attrName )
  +        {
  +            QName[] names = new QName[ 1 ];
  +            names[ 0 ] = attrName;
  +            
  +            init( n, names );
  +        }
  +        
  +        public Cache ( Node n, QName[] attrNames )
  +        {
  +            init( n, attrNames );
  +        }
  +
  +        public Node lookup ( String key )
  +        {
  +            ensureCache();
  +
  +            return (Node) _map.get( key );
  +        }
  +
  +        private void init ( Node n, QName[] attrNames )
  +        {
  +            _node = n;
  +            _map = new HashMap();
  +
  +            StringBuffer sb = new StringBuffer();
  +
  +            for ( int i = 0 ; i < attrNames.length ; i++ )
  +            {
  +                if (attrNames[ i ].getNamespaceURI().length() > 0)
  +                {
  +                    sb.append( "declare namespace ns" );
  +                    sb.append( i );
  +                    sb.append( "='" );
  +                    sb.append( attrNames[ i ].getNamespaceURI() );
  +                    sb.append( "' " );
  +                }
  +            }
  +
  +            for ( int i = 0 ; i < attrNames.length ; i++ )
  +            {
  +                if (i > 0)
  +                    sb.append( "|" );
  +                
  +                sb.append( ".//@" );
  +
  +                if (attrNames[ i ].getNamespaceURI().length() > 0)
  +                {
  +                    sb.append( "ns" );
  +                    sb.append( i );
  +                    sb.append( ":" );
  +                }
  +
  +                sb.append( attrNames[ i ].getLocalPart() );
  +            }
  +
  +            _path = Public2.compilePath( sb.toString(), null );
  +        }
  +
  +        private void ensureCache ( )
  +        {
  +            if (_stamp != null && !_stamp.hasChanged())
  +                return;
  +
  +            XmlCursor c = Public2.getCursor( _node );
  +            
  +            _stamp = c.getDocChangeStamp();
  +
  +            _map.clear();
  +
  +            c.selectPath( _path );
  +
  +            while ( c.toNextSelection() )
  +                _map.put( c.getTextValue(), c.getDomNode() );
  +
  +            c.dispose();
  +        }
  +
  +        private Node        _node;
  +        private String      _path;
  +        private ChangeStamp _stamp;
  +        private HashMap     _map;
       }
   }
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xmlbeans-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xmlbeans-cvs-help@xml.apache.org


Mime
View raw message