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.Iterator;
24  
25  import org.apache.directory.api.ldap.model.entry.Attribute;
26  import org.apache.directory.api.ldap.model.entry.Entry;
27  import org.apache.directory.api.ldap.model.entry.Value;
28  import org.apache.directory.api.ldap.model.exception.LdapException;
29  import org.apache.directory.api.ldap.model.exception.LdapOtherException;
30  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
31  import org.apache.directory.api.ldap.model.schema.AttributeType;
32  import org.apache.directory.api.ldap.model.schema.MatchingRule;
33  import org.apache.directory.api.ldap.model.schema.SchemaManager;
34  import org.apache.directory.server.core.api.partition.PartitionTxn;
35  import org.apache.directory.server.i18n.I18n;
36  import org.apache.directory.server.xdbm.Index;
37  import org.apache.directory.server.xdbm.IndexEntry;
38  import org.apache.directory.server.xdbm.IndexNotFoundException;
39  import org.apache.directory.server.xdbm.Store;
40  
41  
42  /**
43   * An Evaluator which determines if candidates are matched by ApproximateNode
44   * assertions.  Same as equality for now.
45   *
46   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
47   */
48  public class ApproximateEvaluator<T> extends LeafEvaluator<T>
49  {
50      /**
51       * Creates a new ApproximateEvaluator
52       * 
53       * @param node The ApproximateNode
54       * @param db The Store
55       * @param schemaManager The SchemaManager
56       * @throws LdapException If the creation failed
57       */
58      public ApproximateEvaluator( ApproximateNode<T> node, Store db, SchemaManager schemaManager )
59          throws LdapException
60      {
61          super( node, db, schemaManager );
62  
63          if ( db.hasIndexOn( attributeType ) )
64          {
65              try
66              {
67                  idx = ( Index<T, String> ) db.getIndex( attributeType );
68              }
69              catch ( IndexNotFoundException infe )
70              {
71                  throw new LdapOtherException( infe.getMessage(), infe );
72              }
73              normalizer = null;
74              ldapComparator = null;
75          }
76          else
77          {
78              idx = null;
79  
80              MatchingRule mr = attributeType.getEquality();
81  
82              if ( mr == null )
83              {
84                  throw new IllegalStateException( I18n.err( I18n.ERR_709, node ) );
85              }
86  
87              normalizer = mr.getNormalizer();
88              ldapComparator = mr.getLdapComparator();
89          }
90      }
91  
92  
93      /**
94       * {@inheritDoc}
95       */
96      @Override
97      public ApproximateNode<T> getExpression()
98      {
99          return ( ApproximateNode<T> ) node;
100     }
101 
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
107     public boolean evaluate( Entry entry ) throws LdapException
108     {
109         // get the attribute
110         Attribute attr = entry.get( attributeType );
111 
112         // if the attribute does not exist just return false
113         if ( ( attr != null ) && evaluate( attr ) )
114         {
115             return true;
116         }
117 
118         // If we do not have the attribute, loop through the sub classes of
119         // the attributeType.  Perhaps the entry has an attribute value of a
120         // subtype (descendant) that will produce a match
121         if ( schemaManager.getAttributeTypeRegistry().hasDescendants( attributeType ) )
122         {
123             // TODO check to see if descendant handling is necessary for the
124             // index so we can match properly even when for example a name
125             // attribute is used instead of more specific commonName
126             Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( attributeType );
127 
128             while ( descendants.hasNext() )
129             {
130                 AttributeType descendant = descendants.next();
131 
132                 attr = entry.get( descendant );
133 
134                 if ( attr != null && evaluate( attr ) )
135                 {
136                     return true;
137                 }
138             }
139         }
140 
141         // we fell through so a match was not found - assertion was false.
142         return false;
143     }
144 
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
150     public boolean evaluate( PartitionTxn partitionTxn, IndexEntry<?, String> indexEntry ) throws LdapException
151     {
152         Entry entry = indexEntry.getEntry();
153 
154         // resuscitate the entry if it has not been and set entry in IndexEntry
155         if ( null == entry )
156         {
157             entry = db.fetch( partitionTxn, indexEntry.getId() );
158 
159             if ( null == entry )
160             {
161                 // The entry is not anymore present : get out
162                 return false;
163             }
164 
165             indexEntry.setEntry( entry );
166         }
167 
168         return evaluate( entry );
169     }
170 
171 
172     // TODO - determine if comparator and index entry should have the Value
173     // wrapper or the raw normalized value
174     private boolean evaluate( Attribute attribute )
175     {
176         /*
177          * Cycle through the attribute values testing normalized version
178          * obtained from using the ordering or equality matching rule's
179          * normalizer.  The test uses the comparator obtained from the
180          * appropriate matching rule to perform the check.
181          */
182 
183         for ( Value value : attribute )
184         {
185             if ( value.compareTo( node.getValue() )  == 0 )
186             {
187                 return true;
188             }
189         }
190 
191         return false;
192     }
193 
194 
195     /**
196      * @see Object#toString()
197      */
198     @Override
199     public String toString( String tabs )
200     {
201         StringBuilder sb = new StringBuilder();
202 
203         sb.append( tabs ).append( "ApproximateEvaluator : " ).append( super.toString() ).append( "\n" );
204 
205         return sb.toString();
206     }
207 
208 
209     /**
210      * @see Object#toString()
211      */
212     @Override
213     public String toString()
214     {
215         return toString( "" );
216     }
217 }