View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.db;
18  
19  
20  import org.apache.ldap.common.filter.ExprNode;
21  import org.apache.ldap.common.filter.SubstringNode;
22  import org.apache.ldap.common.schema.AttributeType;
23  import org.apache.ldap.common.schema.Normalizer;
24  import org.apache.ldap.server.schema.AttributeTypeRegistry;
25  import org.apache.ldap.server.schema.OidRegistry;
26  import org.apache.regexp.RE;
27  import org.apache.regexp.RESyntaxException;
28  
29  import javax.naming.NamingEnumeration;
30  import javax.naming.NamingException;
31  import javax.naming.directory.Attribute;
32  import javax.naming.directory.Attributes;
33  
34  
35  /***
36   * Evaluates substring filter assertions on an entry.
37   * 
38   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
39   * @version $Rev: 159259 $
40   */
41  public class SubstringEvaluator implements Evaluator
42  {
43      /*** Database used while evaluating candidates */
44      private Database db;
45      /*** Oid Registry used to translate attributeIds to OIDs */
46      private OidRegistry oidRegistry;
47      /*** AttributeType registry needed for normalizing and comparing values */
48      private AttributeTypeRegistry attributeTypeRegistry;
49  
50  
51      /***
52       * Creates a new SubstringEvaluator for substring expressions.
53       *
54       * @param db the database this evaluator uses
55       * @param oidRegistry the OID registry for name to OID mapping
56       * @param attributeTypeRegistry the attributeType registry
57       */
58      public SubstringEvaluator( Database db, OidRegistry oidRegistry,
59                                 AttributeTypeRegistry attributeTypeRegistry )
60      {
61          this.db = db;
62          this.oidRegistry = oidRegistry;
63          this.attributeTypeRegistry = attributeTypeRegistry;
64      }
65  
66  
67      /***
68       * @see org.apache.ldap.server.db.Evaluator#evaluate(ExprNode, IndexRecord)
69       */
70      public boolean evaluate( ExprNode node, IndexRecord record )
71          throws NamingException
72      {
73          RE regex = null; 
74          SubstringNode snode = ( SubstringNode ) node;
75          String oid = oidRegistry.getOid( snode.getAttribute() );
76          AttributeType type = attributeTypeRegistry.lookup( oid );
77          Normalizer normalizer = type.getSubstr().getNormalizer();
78  
79          if ( db.hasUserIndexOn( snode.getAttribute() ) )
80          {
81              Index idx = db.getUserIndex( snode.getAttribute() );
82          
83              /*
84               * Note that this is using the reverse half of the index giving a 
85               * considerable performance improvement on this kind of operation.
86               * Otherwise we would have to scan the entire index if there were
87               * no reverse lookups.
88               */
89          
90              NamingEnumeration list = idx.listReverseIndices( record.getEntryId() );
91  
92              // compile the regular expression to search for a matching attribute
93              try 
94              {
95                  regex = snode.getRegex( normalizer );
96              } 
97              catch ( RESyntaxException e ) 
98              {
99                  NamingException ne = new NamingException( "SubstringNode '" 
100                     + node + "' had " + "incorrect syntax" );
101                 ne.setRootCause( e );
102                 throw ne;
103             }
104 
105             // cycle through the attribute values testing for a match
106             while ( list.hasMore() ) 
107             {
108                 IndexRecord rec = ( IndexRecord ) list.next();
109             
110                 // once match is found cleanup and return true
111                 if ( regex.match( ( String ) rec.getIndexKey() ) ) 
112                 {
113                     list.close();
114                     return true;
115                 }
116             }
117 
118             // we fell through so a match was not found - assertion was false.
119             return false;
120         }
121 
122         // --------------------------------------------------------------------
123         // Index not defined beyond this point
124         // --------------------------------------------------------------------
125         
126         // resusitate the entry if it has not been and set entry in IndexRecord
127         if ( null == record.getAttributes() )
128         {
129             Attributes attrs = db.lookup( record.getEntryId() );
130             record.setAttributes( attrs );
131         }
132         
133         // get the attribute
134         Attribute attr = record.getAttributes().get( snode.getAttribute() );
135         
136         // if the attribute does not exist just return false
137         if ( null == attr )
138         {
139             return false;
140         }
141 
142         // compile the regular expression to search for a matching attribute
143         try 
144         {
145             regex = snode.getRegex( normalizer );
146         } 
147         catch ( RESyntaxException e ) 
148         {
149             NamingException ne = new NamingException( "SubstringNode '" 
150                 + node + "' had " + "incorrect syntax" );
151             ne.setRootCause( e );
152             throw ne;
153         }
154         
155         /*
156          * Cycle through the attribute values testing normalized version 
157          * obtained from using the substring matching rule's normalizer.
158          * The test uses the comparator obtained from the appropriate 
159          * substring matching rule.
160          */ 
161         NamingEnumeration list = attr.getAll(); 
162         while ( list.hasMore() ) 
163         {
164             String value = ( String ) 
165                 normalizer.normalize( list.next() );
166             
167             // Once match is found cleanup and return true
168             if ( regex.match( value ) ) 
169             {
170                 list.close();
171                 return true;
172             }
173         }
174 
175         // we fell through so a match was not found - assertion was false.
176         return false;
177     }
178 }