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.normalization;
18  
19  
20  import java.util.Map;
21  
22  import javax.naming.Name;
23  import javax.naming.NamingEnumeration;
24  import javax.naming.NamingException;
25  import javax.naming.directory.Attributes;
26  import javax.naming.directory.ModificationItem;
27  import javax.naming.directory.SearchControls;
28  
29  import org.apache.ldap.common.filter.ExprNode;
30  import org.apache.ldap.common.filter.LeafNode;
31  import org.apache.ldap.common.filter.BranchNode;
32  import org.apache.ldap.common.name.DnParser;
33  import org.apache.ldap.common.name.NameComponentNormalizer;
34  import org.apache.ldap.common.schema.AttributeType;
35  import org.apache.ldap.common.util.EmptyEnumeration;
36  import org.apache.ldap.server.DirectoryServiceConfiguration;
37  import org.apache.ldap.server.configuration.InterceptorConfiguration;
38  import org.apache.ldap.server.interceptor.BaseInterceptor;
39  import org.apache.ldap.server.interceptor.NextInterceptor;
40  import org.apache.ldap.server.partition.DirectoryPartitionNexus;
41  import org.apache.ldap.server.schema.AttributeTypeRegistry;
42  import org.slf4j.LoggerFactory;
43  import org.slf4j.Logger;
44  
45  
46  /***
47   * A name normalization service.  This service makes sure all relative and distinuished
48   * names are normalized before calls are made against the respective interface methods
49   * on {@link DirectoryPartitionNexus}.
50   *
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   * @version $Rev: 328545 $
53   */
54  public class NormalizationService extends BaseInterceptor
55  {
56      /*** logger used by this class */
57      private static final Logger log = LoggerFactory.getLogger( NormalizationService.class );
58  
59      /*** the parser used for normalizing distinguished names */
60      private DnParser parser;
61      /*** a filter node value normalizer and undefined node remover */
62      private ValueNormalizingVisitor visitor;
63      /*** the attributeType registry used for normalization and determining if some filter nodes are undefined */
64      private AttributeTypeRegistry registry;
65  
66  
67      public void init( DirectoryServiceConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
68      {
69          registry = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
70          NameComponentNormalizer ncn = new PerComponentNormalizer();
71          parser = new DnParser( ncn );
72          visitor = new ValueNormalizingVisitor( ncn );
73      }
74  
75  
76      public void destroy() {}
77  
78  
79      // ------------------------------------------------------------------------
80      // Normalize all Name based arguments for ContextPartition interface operations
81      // ------------------------------------------------------------------------
82  
83  
84      public void add( NextInterceptor nextInterceptor, String upName, Name normName, Attributes attrs ) throws NamingException
85      {
86          normName = parser.parse( normName.toString() );
87          nextInterceptor.add( upName, normName, attrs );
88      }
89  
90  
91      public void delete( NextInterceptor nextInterceptor, Name name ) throws NamingException
92      {
93          name = parser.parse( name.toString() );
94          nextInterceptor.delete( name );
95      }
96  
97  
98      public void modify( NextInterceptor nextInterceptor, Name name, int modOp, Attributes attrs ) throws NamingException
99      {
100         name = parser.parse( name.toString() );
101         nextInterceptor.modify( name, modOp, attrs );
102     }
103 
104 
105     public void modify( NextInterceptor nextInterceptor, Name name, ModificationItem[] items ) throws NamingException
106     {
107         name = parser.parse( name.toString() );
108         nextInterceptor.modify( name, items );
109     }
110 
111 
112     public void modifyRn( NextInterceptor nextInterceptor, Name name, String newRn, boolean deleteOldRn ) throws NamingException
113     {
114         name = parser.parse( name.toString() );
115         nextInterceptor.modifyRn( name, newRn, deleteOldRn );
116     }
117 
118 
119     public void move( NextInterceptor nextInterceptor, Name name, Name newParentName ) throws NamingException
120     {
121         name = parser.parse( name.toString() );
122         newParentName = parser.parse( newParentName.toString() );
123         nextInterceptor.move( name, newParentName );
124     }
125 
126 
127     public void move( NextInterceptor nextInterceptor, Name name, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException
128     {
129         name = parser.parse( name.toString() );
130         newParentName = parser.parse( newParentName.toString() );
131         nextInterceptor.move( name, newParentName, newRn, deleteOldRn );
132     }
133 
134 
135     public NamingEnumeration search( NextInterceptor nextInterceptor,
136                                      Name base, Map env, ExprNode filter,
137                                      SearchControls searchCtls ) throws NamingException
138     {
139         base = parser.parse( base.toString() );
140 
141         if ( filter.isLeaf() )
142         {
143             LeafNode ln = ( LeafNode ) filter;
144             if ( ! registry.hasAttributeType( ln.getAttribute() ) )
145             {
146                 StringBuffer buf = new StringBuffer();
147                 buf.append( "undefined filter based on undefined attributeType '" );
148                 buf.append( ln.getAttribute() );
149                 buf.append( "' not evaluted at all.  Returning empty enumeration." );
150                 log.warn( buf.toString() );
151                 return new EmptyEnumeration();
152             }
153         }
154 
155         filter.accept( visitor );
156 
157         // check that after pruning we have valid branch node at the top
158         if ( ! filter.isLeaf() )
159         {
160             BranchNode child = ( BranchNode ) filter;
161 
162             // if the remaining filter branch node has no children return an empty enumeration
163             if ( child.getChildren().size() == 0 )
164             {
165                 log.warn( "Undefined branchnode filter without child nodes not evaluted at all.  Returning empty enumeration." );
166                 return new EmptyEnumeration();
167             }
168 
169             // now for AND & OR nodes with a single child left replace them with their child
170             if ( child.getChildren().size() == 1 && child.getOperator() != BranchNode.NOT )
171             {
172                 filter = child.getChild();
173             }
174         }
175         return nextInterceptor.search( base, env, filter, searchCtls );
176     }
177 
178 
179     public boolean hasEntry( NextInterceptor nextInterceptor, Name name ) throws NamingException
180     {
181         name = parser.parse( name.toString() );
182         return nextInterceptor.hasEntry( name );
183     }
184 
185 
186     public boolean isSuffix( NextInterceptor nextInterceptor, Name name ) throws NamingException
187     {
188         name = parser.parse( name.toString() );
189         return nextInterceptor.isSuffix( name );
190     }
191 
192 
193     public NamingEnumeration list( NextInterceptor nextInterceptor, Name base ) throws NamingException
194     {
195         base = parser.parse( base.toString() );
196         return nextInterceptor.list( base );
197     }
198 
199 
200     public Attributes lookup( NextInterceptor nextInterceptor, Name name ) throws NamingException
201     {
202         name = parser.parse( name.toString() );
203         return nextInterceptor.lookup( name );
204     }
205 
206 
207     public Attributes lookup( NextInterceptor nextInterceptor, Name name, String[] attrIds ) throws NamingException
208     {
209         name = parser.parse( name.toString() );
210         return nextInterceptor.lookup( name, attrIds );
211     }
212 
213 
214     // ------------------------------------------------------------------------
215     // Normalize all Name based arguments for other interface operations
216     // ------------------------------------------------------------------------
217 
218 
219     public Name getMatchedName( NextInterceptor nextInterceptor, Name name, boolean normalized ) throws NamingException
220     {
221         name = parser.parse( name.toString() );
222         return nextInterceptor.getMatchedName( name, normalized );
223     }
224 
225 
226     public Name getSuffix( NextInterceptor nextInterceptor, Name name, boolean normalized ) throws NamingException
227     {
228         name = parser.parse( name.toString() );
229         return nextInterceptor.getSuffix( name, normalized );
230     }
231 
232 
233     public boolean compare( NextInterceptor next, Name name, String oid, Object value ) throws NamingException
234     {
235         name = parser.parse( name.toString() );
236         return next.compare( name, oid, value );
237     }
238 
239 
240     /***
241      * A normalizer that normalizes each name component specifically according to
242      * the attribute type of the name component.
243      */
244     private class PerComponentNormalizer implements NameComponentNormalizer
245     {
246         public String normalizeByName( String name, String value ) throws NamingException
247         {
248             AttributeType type = registry.lookup( name );
249             return ( String ) type.getEquality().getNormalizer().normalize( value );
250         }
251 
252 
253         public String normalizeByOid( String oid, String value ) throws NamingException
254         {
255             AttributeType type = registry.lookup( oid );
256             return ( String ) type.getEquality().getNormalizer().normalize( value );
257         }
258 
259 
260         public boolean isDefined( String id )
261         {
262             return registry.hasAttributeType( id );
263         }
264     }
265 }