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.ExprNode;
30  import org.apache.directory.api.ldap.model.filter.OrNode;
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 disjunction (OR) expressions.
39   *
40   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
41   */
42  public class OrEvaluator implements Evaluator<OrNode>
43  {
44      /** The list of evaluators associated with each of the children */
45      private final List<Evaluator<? extends ExprNode>> evaluators;
46  
47      /** The OrNode */
48      private final OrNode node;
49  
50  
51      /**
52       * Creates a new OrEvaluator
53       * 
54       * @param node The OrNode
55       * @param evaluators The inner evaluators
56       */
57      public OrEvaluator( OrNode node, List<Evaluator<? extends ExprNode>> evaluators )
58      {
59          this.node = node;
60          this.evaluators = optimize( evaluators );
61      }
62  
63  
64      /**
65       * Takes a set of Evaluators and copies then sorts them in a new list with
66       * decreasing scan counts on their expression nodes.  This is done to have
67       * the Evaluators with the greatest scan counts which have the highest
68       * probability of accepting a candidate first.  That will increase the
69       * chance of shorting the checks on evaluators early so extra lookups and
70       * comparisons are avoided.
71       *
72       * @param unoptimized the unoptimized list of Evaluators
73       * @return optimized Evaluator list with decreasing scan count ordering
74       */
75      private List<Evaluator<? extends ExprNode>> optimize(
76          List<Evaluator<? extends ExprNode>> unoptimized )
77      {
78          List<Evaluator<? extends ExprNode>> optimized = new ArrayList<>(
79              unoptimized.size() );
80          optimized.addAll( unoptimized );
81  
82          Collections.sort( optimized, new ScanCountComparator() );
83  
84          return optimized;
85      }
86  
87  
88      /**
89       * {@inheritDoc}
90       */
91      @Override
92      public boolean evaluate( PartitionTxn partitionTxn, IndexEntry<?, String> indexEntry ) throws LdapException
93      {
94          for ( Evaluator<?> evaluator : evaluators )
95          {
96              if ( evaluator.evaluate( partitionTxn, indexEntry ) )
97              {
98                  return true;
99              }
100         }
101 
102         return false;
103     }
104 
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
110     public boolean evaluate( Entry entry ) throws LdapException
111     {
112         for ( Evaluator<?> evaluator : evaluators )
113         {
114             if ( evaluator.evaluate( entry ) )
115             {
116                 return true;
117             }
118         }
119 
120         return false;
121     }
122 
123 
124     /**
125      * {@inheritDoc}
126      */
127     @Override
128     public OrNode getExpression()
129     {
130         return node;
131     }
132 
133 
134     /**
135      * Dumps the evaluators
136      */
137     private String dumpEvaluators( String tabs )
138     {
139         StringBuilder sb = new StringBuilder();
140 
141         for ( Evaluator<? extends ExprNode> evaluator : evaluators )
142         {
143             sb.append( evaluator.toString( tabs + "  " ) );
144         }
145 
146         return sb.toString();
147     }
148 
149 
150     /**
151      * @see Object#toString()
152      */
153     public String toString( String tabs )
154     {
155         StringBuilder sb = new StringBuilder();
156 
157         sb.append( tabs ).append( "OrEvaluator : " ).append( node ).append( "\n" );
158 
159         if ( ( evaluators != null ) && !evaluators.isEmpty() )
160         {
161             sb.append( dumpEvaluators( tabs ) );
162         }
163 
164         return sb.toString();
165     }
166 
167 
168     /**
169      * @see Object#toString()
170      */
171     public String toString()
172     {
173         return toString( "" );
174     }
175 }