View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.xdbm.search.evaluator;
21  
22  
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.List;
26  
27  import org.apache.directory.api.ldap.model.entry.Entry;
28  import org.apache.directory.api.ldap.model.exception.LdapException;
29  import org.apache.directory.api.ldap.model.filter.AndNode;
30  import org.apache.directory.api.ldap.model.filter.ExprNode;
31  import org.apache.directory.server.core.api.partition.PartitionTxn;
32  import org.apache.directory.server.xdbm.IndexEntry;
33  import org.apache.directory.server.xdbm.search.Evaluator;
34  import org.apache.directory.server.xdbm.search.impl.ScanCountComparator;
35  
36  
37  /**
38   * An Evaluator for logical conjunction (AND) expressions.
39   *
40   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
41   */
42  public class AndEvaluator implements Evaluator<AndNode>
43  {
44      /** The list of evaluators associated with each of the children */
45      private final List<Evaluator<? extends ExprNode>> evaluators;
46  
47      /** The AndNode */
48      private final AndNode node;
49  
50  
51      /**
52       * Creates an instance of AndEvaluator
53       * @param node The And Node
54       * @param evaluators The list of evaluators for all the contaned nodes
55       */
56      public AndEvaluator( AndNode node, List<Evaluator<? extends ExprNode>> evaluators )
57      {
58          this.node = node;
59          this.evaluators = optimize( evaluators );
60      }
61  
62  
63      /**
64       * Takes a set of Evaluators and copies then sorts them in a new list with
65       * increasing scan counts on their expression nodes.  This is done to have
66       * the Evaluators with the least scan count which have the highest
67       * probability of rejecting a candidate first.  That will increase the
68       * chance of shorting the checks on evaluators early so extra lookups and
69       * comparisons are avoided.
70       *
71       * @param unoptimized the unoptimized list of Evaluators
72       * @return optimized Evaluator list with increasing scan count ordering
73       */
74      private List<Evaluator<? extends ExprNode>> optimize(
75          List<Evaluator<? extends ExprNode>> unoptimized )
76      {
77          switch ( unoptimized.size() )
78          {
79              case 0 :
80              case 1 :
81                  return unoptimized;
82                  
83              case 2 :
84                  Object count1 = unoptimized.get( 0 ).getExpression().get( "count" );
85                  Object count2 = unoptimized.get( 1 ).getExpression().get( "count" );
86                  
87                  if ( count1 == null )
88                  {
89                      if ( count2 != null )
90                      {
91                          unoptimized.add( unoptimized.remove( 0 ) );
92                      }
93                  }
94                  else
95                  {
96                      if ( ( count2 != null ) && ( ( Long ) count1 > ( Long ) count2 ) )
97                      {
98                          unoptimized.add( unoptimized.remove( 0 ) );
99                      }
100                 }
101                 
102                 return unoptimized;
103 
104             default :
105                 List<Evaluator<? extends ExprNode>> optimized = new ArrayList<>(
106                     unoptimized.size() );
107                 optimized.addAll( unoptimized );
108 
109                 Collections.sort( optimized, new ScanCountComparator() );
110 
111                 return optimized;
112         }
113         
114         /* Potential speed up, for when we do'nt care about the evaluation itself.
115     private List<Evaluator<? extends ExprNode>> optimize(
116         List<Evaluator<? extends ExprNode>> evaluators )
117     {
118         long minCount = Long.MAX_VALUE;
119         int pos = 0;
120         int minPos = 0;
121         
122         for ( Evaluator<? extends ExprNode> evaluator : evaluators )
123         {
124             long count = ( Long ) evaluator.getExpression().get( "count" );
125             
126             if ( count < minCount )
127             {
128                 minCount = count;
129                 minPos = pos;
130             }
131             
132             pos++;
133         }
134         
135         if ( minPos > 0 )
136         {
137             Evaluator<? extends ExprNode> minEvaluator = evaluators.remove( minPos );
138             evaluators.set( 0,  minEvaluator );
139             
140         }
141 
142         return evaluators;
143     }
144 
145          */
146     }
147 
148 
149     /**
150      * {@inheritDoc}
151      */
152     public boolean evaluate( Entry entry ) throws LdapException
153     {
154         for ( Evaluator<?> evaluator : evaluators )
155         {
156             if ( !evaluator.evaluate( entry ) )
157             {
158                 return false;
159             }
160         }
161 
162         return true;
163     }
164 
165 
166     /**
167      * {@inheritDoc}
168      */
169     public boolean evaluate( PartitionTxn partitionTxn, IndexEntry<?, String> indexEntry ) throws LdapException
170     {
171         for ( Evaluator<?> evaluator : evaluators )
172         {
173             if ( !evaluator.evaluate( partitionTxn, indexEntry ) )
174             {
175                 return false;
176             }
177         }
178 
179         return true;
180     }
181 
182 
183     /**
184      * {@inheritDoc}
185      */
186     public AndNode getExpression()
187     {
188         return node;
189     }
190 
191 
192     /**
193      * Dumps the evaluators
194      */
195     private String dumpEvaluators( String tabs )
196     {
197         StringBuilder sb = new StringBuilder();
198 
199         for ( Evaluator<? extends ExprNode> evaluator : evaluators )
200         {
201             sb.append( evaluator.toString( tabs + "  " ) );
202         }
203 
204         return sb.toString();
205     }
206 
207 
208     /**
209      * @see Object#toString()
210      */
211     public String toString( String tabs )
212     {
213         StringBuilder sb = new StringBuilder();
214 
215         sb.append( tabs ).append( "AndEvaluator : " ).append( node ).append( "\n" );
216 
217         if ( ( evaluators != null ) && !evaluators.isEmpty() )
218         {
219             sb.append( dumpEvaluators( tabs + "  " ) ).append( "\n" );
220         }
221 
222         return sb.toString();
223     }
224 
225 
226     /**
227      * @see Object#toString()
228      */
229     public String toString()
230     {
231         return toString( "" );
232     }
233 }