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 */
020package org.apache.directory.server.xdbm.search.impl;
021
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.apache.directory.api.ldap.model.exception.LdapException;
027import org.apache.directory.api.ldap.model.filter.AndNode;
028import org.apache.directory.api.ldap.model.filter.ApproximateNode;
029import org.apache.directory.api.ldap.model.filter.EqualityNode;
030import org.apache.directory.api.ldap.model.filter.ExprNode;
031import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
032import org.apache.directory.api.ldap.model.filter.LessEqNode;
033import org.apache.directory.api.ldap.model.filter.NotNode;
034import org.apache.directory.api.ldap.model.filter.OrNode;
035import org.apache.directory.api.ldap.model.filter.PresenceNode;
036import org.apache.directory.api.ldap.model.filter.ScopeNode;
037import org.apache.directory.api.ldap.model.filter.SubstringNode;
038import org.apache.directory.api.ldap.model.message.SearchScope;
039import org.apache.directory.api.ldap.model.schema.SchemaManager;
040import org.apache.directory.api.util.exception.NotImplementedException;
041import org.apache.directory.server.core.api.partition.PartitionTxn;
042import org.apache.directory.server.i18n.I18n;
043import org.apache.directory.server.xdbm.Store;
044import org.apache.directory.server.xdbm.search.Evaluator;
045import org.apache.directory.server.xdbm.search.evaluator.AndEvaluator;
046import org.apache.directory.server.xdbm.search.evaluator.ApproximateEvaluator;
047import org.apache.directory.server.xdbm.search.evaluator.EmptyEvaluator;
048import org.apache.directory.server.xdbm.search.evaluator.EqualityEvaluator;
049import org.apache.directory.server.xdbm.search.evaluator.GreaterEqEvaluator;
050import org.apache.directory.server.xdbm.search.evaluator.LessEqEvaluator;
051import org.apache.directory.server.xdbm.search.evaluator.NotEvaluator;
052import org.apache.directory.server.xdbm.search.evaluator.OneLevelScopeEvaluator;
053import org.apache.directory.server.xdbm.search.evaluator.OrEvaluator;
054import org.apache.directory.server.xdbm.search.evaluator.PresenceEvaluator;
055import org.apache.directory.server.xdbm.search.evaluator.SubstringEvaluator;
056import org.apache.directory.server.xdbm.search.evaluator.SubtreeScopeEvaluator;
057
058
059/**
060 * Top level filter expression evaluator builder implemenation.
061 * 
062 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
063 */
064public class EvaluatorBuilder
065{
066    private final Store db;
067    private final SchemaManager schemaManager;
068
069    private static final EmptyEvaluator EMPTY_EVALLUATOR = new EmptyEvaluator();
070
071    /**
072     * Creates a top level Evaluator where leaves are delegated to a leaf node
073     * evaluator which will be created.
074     *
075     * @param db the database this evaluator operates upon
076     * @param schemaManager the schema manager
077     */
078    public EvaluatorBuilder( Store db, SchemaManager schemaManager )
079    {
080        this.db = db;
081        this.schemaManager = schemaManager;
082    }
083
084
085    public <T> Evaluator<? extends ExprNode> build( PartitionTxn partitionTxn, ExprNode node ) throws LdapException
086    {
087        Object count = node.get( "count" );
088
089        if ( ( count != null ) && ( ( Long ) count == 0L ) )
090        {
091            return EMPTY_EVALLUATOR;
092        }
093
094        switch ( node.getAssertionType() )
095        {
096        /* ---------- LEAF NODE HANDLING ---------- */
097
098            case APPROXIMATE:
099                return new ApproximateEvaluator<>( ( ApproximateNode<T> ) node, db, schemaManager );
100
101            case EQUALITY:
102                return new EqualityEvaluator<>( ( EqualityNode<T> ) node, db, schemaManager );
103
104            case GREATEREQ:
105                return new GreaterEqEvaluator<>( ( GreaterEqNode<T> ) node, db, schemaManager );
106
107            case LESSEQ:
108                return new LessEqEvaluator<>( ( LessEqNode<T> ) node, db, schemaManager );
109
110            case PRESENCE:
111                return new PresenceEvaluator( ( PresenceNode ) node, db, schemaManager );
112
113            case SCOPE:
114                if ( ( ( ScopeNode ) node ).getScope() == SearchScope.ONELEVEL )
115                {
116                    return new OneLevelScopeEvaluator<>( db, ( ScopeNode ) node );
117                }
118                else
119                {
120                    return new SubtreeScopeEvaluator( partitionTxn, db, ( ScopeNode ) node );
121                }
122
123            case SUBSTRING:
124                return new SubstringEvaluator( ( SubstringNode ) node, db, schemaManager );
125
126                /* ---------- LOGICAL OPERATORS ---------- */
127
128            case AND:
129                return buildAndEvaluator( partitionTxn, ( AndNode ) node );
130
131            case NOT:
132                return new NotEvaluator( ( NotNode ) node, build( partitionTxn, ( ( NotNode ) node ).getFirstChild() ) );
133
134            case OR:
135                return buildOrEvaluator( partitionTxn, ( OrNode ) node );
136
137                /* ----------  NOT IMPLEMENTED  ---------- */
138
139            case ASSERTION:
140            case EXTENSIBLE:
141                throw new NotImplementedException();
142
143            default:
144                throw new IllegalStateException( I18n.err( I18n.ERR_260, node.getAssertionType() ) );
145        }
146    }
147
148
149    private <T> Evaluator<? extends ExprNode> buildAndEvaluator( PartitionTxn partitionTxn, AndNode node ) throws LdapException
150    {
151        List<ExprNode> children = node.getChildren();
152        List<Evaluator<? extends ExprNode>> evaluators = buildList( partitionTxn, children );
153
154        int size = evaluators.size();
155
156        switch ( size )
157        {
158            case 0:
159                return EMPTY_EVALLUATOR;
160
161            case 1:
162                return evaluators.get( 0 );
163
164            default:
165                return new AndEvaluator( node, evaluators );
166        }
167    }
168
169
170    private <T> Evaluator<? extends ExprNode> buildOrEvaluator( PartitionTxn partitionTxn, OrNode node ) throws LdapException
171    {
172        List<ExprNode> children = node.getChildren();
173        List<Evaluator<? extends ExprNode>> evaluators = buildList( partitionTxn, children );
174
175        int size = evaluators.size();
176
177        switch ( size )
178        {
179            case 0:
180                return EMPTY_EVALLUATOR;
181
182            case 1:
183                return evaluators.get( 0 );
184
185            default:
186                return new OrEvaluator( node, evaluators );
187        }
188    }
189
190
191    private List<Evaluator<? extends ExprNode>> buildList( PartitionTxn partitionTxn, List<ExprNode> children ) throws LdapException
192    {
193        List<Evaluator<? extends ExprNode>> evaluators = new ArrayList<>(
194            children.size() );
195
196        for ( ExprNode child : children )
197        {
198            Evaluator<? extends ExprNode> evaluator = build( partitionTxn, child );
199
200            if ( evaluator != null )
201            {
202                evaluators.add( evaluator );
203            }
204        }
205
206        return evaluators;
207    }
208
209
210    /**
211     * @return the schemaManager
212     */
213    public SchemaManager getSchemaManager()
214    {
215        return schemaManager;
216    }
217}