001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.xdbm.search.impl;
021    
022    
023    import org.apache.directory.server.xdbm.IndexEntry;
024    import org.apache.directory.server.xdbm.Store;
025    import org.apache.directory.server.xdbm.AbstractIndexCursor;
026    import org.apache.directory.server.xdbm.IndexCursor;
027    import org.apache.directory.server.xdbm.search.Evaluator;
028    import org.apache.directory.server.i18n.I18n;
029    import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
030    import org.apache.directory.shared.ldap.entry.ServerEntry;
031    import org.apache.directory.shared.ldap.filter.ExprNode;
032    
033    
034    /**
035     * A Cursor returning candidates satisfying a logical negation expression.
036     *
037     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038     * @version $$Rev$$
039     */
040    public class NotCursor<V, ID> extends AbstractIndexCursor<V, ServerEntry, ID>
041    {
042        private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_718 );
043        private final IndexCursor<V, ServerEntry, ID> ndnCursor;
044        private final Evaluator<? extends ExprNode, ServerEntry, ID> childEvaluator;
045        private boolean available = false;
046    
047    
048        @SuppressWarnings("unchecked")
049        public NotCursor( Store<ServerEntry, ID> db, Evaluator<? extends ExprNode, ServerEntry, ID> childEvaluator )
050            throws Exception
051        {
052            this.childEvaluator = childEvaluator;
053            this.ndnCursor = ( IndexCursor<V, ServerEntry, ID> ) db.getNdnIndex().forwardCursor();
054        }
055    
056    
057        public boolean available()
058        {
059            return available;
060        }
061    
062    
063        public void beforeValue( ID id, V value ) throws Exception
064        {
065            throw new UnsupportedOperationException( UNSUPPORTED_MSG );
066        }
067    
068    
069        public void before( IndexEntry<V, ServerEntry, ID> element ) throws Exception
070        {
071            throw new UnsupportedOperationException( UNSUPPORTED_MSG );
072        }
073    
074    
075        public void after( IndexEntry<V, ServerEntry, ID> element ) throws Exception
076        {
077            throw new UnsupportedOperationException( UNSUPPORTED_MSG );
078        }
079    
080    
081        public void afterValue( ID id, V value ) throws Exception
082        {
083            throw new UnsupportedOperationException( UNSUPPORTED_MSG );
084        }
085    
086    
087        public void beforeFirst() throws Exception
088        {
089            checkNotClosed( "beforeFirst()" );
090            ndnCursor.beforeFirst();
091            available = false;
092        }
093    
094    
095        public void afterLast() throws Exception
096        {
097            checkNotClosed( "afterLast()" );
098            ndnCursor.afterLast();
099            available = false;
100        }
101    
102    
103        public boolean first() throws Exception
104        {
105            beforeFirst();
106            return next();
107        }
108    
109    
110        public boolean last() throws Exception
111        {
112            afterLast();
113            return previous();
114        }
115    
116    
117        public boolean previous() throws Exception
118        {
119            while ( ndnCursor.previous() )
120            {
121                checkNotClosed( "previous()" );
122                IndexEntry<?, ServerEntry, ID> candidate = ndnCursor.get();
123                if ( !childEvaluator.evaluate( candidate ) )
124                {
125                    return available = true;
126                }
127            }
128    
129            return available = false;
130        }
131    
132    
133        public boolean next() throws Exception
134        {
135            while ( ndnCursor.next() )
136            {
137                checkNotClosed( "next()" );
138                IndexEntry<?, ServerEntry, ID> candidate = ndnCursor.get();
139                if ( !childEvaluator.evaluate( candidate ) )
140                {
141                    return available = true;
142                }
143            }
144    
145            return available = false;
146        }
147    
148    
149        public IndexEntry<V, ServerEntry, ID> get() throws Exception
150        {
151            checkNotClosed( "get()" );
152            if ( available )
153            {
154                return ndnCursor.get();
155            }
156    
157            throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) );
158        }
159    
160    
161        public boolean isElementReused()
162        {
163            return ndnCursor.isElementReused();
164        }
165    
166    
167        public void close() throws Exception
168        {
169            super.close();
170            ndnCursor.close();
171        }
172    }