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.exception;
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.Attribute;
26  import javax.naming.directory.Attributes;
27  import javax.naming.directory.ModificationItem;
28  import javax.naming.directory.SearchControls;
29  
30  import org.apache.ldap.common.exception.LdapContextNotEmptyException;
31  import org.apache.ldap.common.exception.LdapNameAlreadyBoundException;
32  import org.apache.ldap.common.exception.LdapNameNotFoundException;
33  import org.apache.ldap.common.exception.LdapNamingException;
34  import org.apache.ldap.common.filter.ExprNode;
35  import org.apache.ldap.common.message.ResultCodeEnum;
36  import org.apache.ldap.common.name.LdapName;
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.jndi.ContextFactoryConfiguration;
41  import org.apache.ldap.server.partition.ContextPartition;
42  import org.apache.ldap.server.partition.ContextPartitionNexus;
43  
44  
45  /***
46   * An {@link org.apache.ldap.server.interceptor.Interceptor} that detects any operations that breaks integrity
47   * of {@link ContextPartition} and terminates the current invocation chain by
48   * throwing a {@link NamingException}. Those operations include when an entry
49   * already exists at a DN and is added once again to the same DN.
50   *
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   * @version $Rev: 226451 $
53   */
54  public class ExceptionService extends BaseInterceptor
55  {
56      /***
57       * the root nexus of the system
58       */
59      private ContextPartitionNexus nexus;
60  
61  
62      /***
63       * Creates an interceptor that is also the exception handling service.
64       */
65      public ExceptionService()
66      {
67      }
68  
69  
70      public void init( ContextFactoryConfiguration factoryCfg, InterceptorConfiguration cfg )
71      {
72          this.nexus = factoryCfg.getPartitionNexus();
73      }
74  
75  
76      public void destroy()
77      {
78      }
79  
80  
81      /***
82       * In the pre-invocation state this interceptor method checks to see if the entry to be added already exists.  If it
83       * does an exception is raised.
84       */
85      public void add( NextInterceptor nextInterceptor, String upName, Name normName, Attributes entry ) throws NamingException
86      {
87          // check if the entry already exists
88          if ( nexus.hasEntry( normName ) )
89          {
90              NamingException ne = new LdapNameAlreadyBoundException();
91              ne.setResolvedName( new LdapName( upName ) );
92              throw ne;
93          }
94  
95          Name parentDn = new LdapName( upName );
96          parentDn = parentDn.getSuffix( 1 );
97  
98          // check if we don't have the parent to add to
99          assertHasEntry( "Attempt to add under non-existant parent: ", parentDn );
100 
101         // check if we're trying to add to a parent that is an alias
102         Attributes attrs = nexus.lookup( normName.getSuffix( 1 ) );
103         Attribute objectClass = attrs.get( "objectClass" );
104         if ( objectClass.contains( "alias" ) )
105         {
106             String msg = "Attempt to add entry to alias '" + upName
107                     + "' not allowed.";
108             ResultCodeEnum rc = ResultCodeEnum.ALIASPROBLEM;
109             NamingException e = new LdapNamingException( msg, rc );
110             e.setResolvedName( parentDn );
111             throw e;
112         }
113 
114         nextInterceptor.add( upName, normName, entry );
115     }
116 
117 
118     /***
119      * Checks to make sure the entry being deleted exists, and has no children, otherwise throws the appropriate
120      * LdapException.
121      */
122     public void delete( NextInterceptor nextInterceptor, Name name ) throws NamingException
123     {
124         // check if entry to delete exists
125         String msg = "Attempt to delete non-existant entry: ";
126         assertHasEntry( msg, name );
127 
128         // check if entry to delete has children (only leaves can be deleted)
129         boolean hasChildren = false;
130         NamingEnumeration list = nexus.list( name );
131         if ( list.hasMore() )
132         {
133             hasChildren = true;
134         }
135 
136         list.close();
137         if ( hasChildren )
138         {
139             LdapContextNotEmptyException e = new LdapContextNotEmptyException();
140             e.setResolvedName( name );
141             throw e;
142         }
143 
144         nextInterceptor.delete( name );
145     }
146 
147 
148     /***
149      * Checks to see the base being searched exists, otherwise throws the appropriate LdapException.
150      */
151     public NamingEnumeration list( NextInterceptor nextInterceptor, Name baseName ) throws NamingException
152     {
153         // check if entry to search exists
154         String msg = "Attempt to search under non-existant entry: ";
155         assertHasEntry( msg, baseName );
156 
157         return nextInterceptor.list( baseName );
158     }
159 
160 
161     /***
162      * Checks to make sure the entry being looked up exists other wise throws the appropriate LdapException.
163      */
164     public Attributes lookup( NextInterceptor nextInterceptor, Name name ) throws NamingException
165     {
166         String msg = "Attempt to lookup non-existant entry: ";
167         assertHasEntry( msg, name );
168 
169         return nextInterceptor.lookup( name );
170     }
171 
172 
173     /***
174      * Checks to see the base being searched exists, otherwise throws the appropriate LdapException.
175      */
176     public Attributes lookup( NextInterceptor nextInterceptor, Name name, String[] attrIds ) throws NamingException
177     {
178         // check if entry to lookup exists
179         String msg = "Attempt to lookup non-existant entry: ";
180         assertHasEntry( msg, name );
181 
182         return nextInterceptor.lookup( name, attrIds );
183     }
184 
185 
186     /***
187      * Checks to see the entry being modified exists, otherwise throws the appropriate LdapException.
188      */
189     public void modify( NextInterceptor nextInterceptor, Name name, int modOp, Attributes attrs ) throws NamingException
190     {
191         // check if entry to modify exists
192         String msg = "Attempt to modify non-existant entry: ";
193         assertHasEntry( msg, name );
194 
195         nextInterceptor.modify( name, modOp, attrs );
196     }
197 
198 
199     /***
200      * Checks to see the entry being modified exists, otherwise throws the appropriate LdapException.
201      */
202     public void modify( NextInterceptor nextInterceptor, Name name, ModificationItem[] items ) throws NamingException
203     {
204         // check if entry to modify exists
205         String msg = "Attempt to modify non-existant entry: ";
206         assertHasEntry( msg, name );
207 
208         nextInterceptor.modify( name, items );
209     }
210 
211 
212     /***
213      * Checks to see the entry being renamed exists, otherwise throws the appropriate LdapException.
214      */
215     public void modifyRn( NextInterceptor nextInterceptor, Name dn, String newRn, boolean deleteOldRn ) throws NamingException
216     {
217         // check if entry to rename exists
218         String msg = "Attempt to rename non-existant entry: ";
219         assertHasEntry( msg, dn );
220 
221         // check to see if target entry exists
222         Name target = dn.getSuffix( 1 ).add( newRn );
223         if ( nexus.hasEntry( target ) )
224         {
225             LdapNameAlreadyBoundException e = null;
226             e = new LdapNameAlreadyBoundException( "target entry " + target
227                     + " already exists!" );
228             e.setResolvedName( target );
229             throw e;
230         }
231 
232         nextInterceptor.modifyRn( dn, newRn, deleteOldRn );
233     }
234 
235 
236     /***
237      * Checks to see the entry being moved exists, and so does its parent, otherwise throws the appropriate
238      * LdapException.
239      */
240     public void move( NextInterceptor nextInterceptor, Name oriChildName, Name newParentName ) throws NamingException
241     {
242         // check if child to move exists
243         String msg = "Attempt to move to non-existant parent: ";
244         assertHasEntry( msg, oriChildName );
245 
246         // check if parent to move to exists
247         msg = "Attempt to move to non-existant parent: ";
248         assertHasEntry( msg, newParentName );
249 
250         // check to see if target entry exists
251         String rdn = oriChildName.get( oriChildName.size() - 1 );
252         Name target = ( Name ) newParentName.clone();
253         target.add( rdn );
254         if ( nexus.hasEntry( target ) )
255         {
256             LdapNameAlreadyBoundException e = null;
257             e = new LdapNameAlreadyBoundException( "target entry " + target
258                     + " already exists!" );
259             e.setResolvedName( target );
260             throw e;
261         }
262 
263         nextInterceptor.move( oriChildName, newParentName );
264     }
265 
266 
267     /***
268      * Checks to see the entry being moved exists, and so does its parent, otherwise throws the appropriate
269      * LdapException.
270      */
271     public void move( NextInterceptor nextInterceptor,
272             Name oriChildName, Name newParentName, String newRn,
273             boolean deleteOldRn ) throws NamingException
274     {
275         // check if child to move exists
276         String msg = "Attempt to move to non-existant parent: ";
277         assertHasEntry( msg, oriChildName );
278 
279         // check if parent to move to exists
280         msg = "Attempt to move to non-existant parent: ";
281         assertHasEntry( msg, newParentName );
282 
283         // check to see if target entry exists
284         Name target = ( Name ) newParentName.clone();
285         target.add( newRn );
286         if ( nexus.hasEntry( target ) )
287         {
288             LdapNameAlreadyBoundException e = null;
289             e = new LdapNameAlreadyBoundException( "target entry " + target
290                     + " already exists!" );
291             e.setResolvedName( target );
292             throw e;
293         }
294 
295         nextInterceptor.move( oriChildName, newParentName, newRn, deleteOldRn );
296     }
297 
298 
299     /***
300      * Checks to see the entry being searched exists, otherwise throws the appropriate LdapException.
301      */
302     public NamingEnumeration search( NextInterceptor nextInterceptor, 
303             Name base, Map env, ExprNode filter,
304             SearchControls searchCtls ) throws NamingException
305     {
306         String msg = "Attempt to search under non-existant entry: ";
307 
308         if ( base.size() == 0 )
309         {
310             return nextInterceptor.search( base, env, filter, searchCtls );
311         }
312 
313         Attribute attr = nexus.getRootDSE().get( "subschemaSubentry" );
314         if ( ( ( String ) attr.get() ).equalsIgnoreCase( base.toString() ) )
315         {
316             return nextInterceptor.search( base, env, filter, searchCtls );
317         }
318 
319         assertHasEntry( msg, base );
320 
321         return nextInterceptor.search( base, env, filter, searchCtls );
322     }
323 
324 
325     /***
326      * Asserts that an entry is present and as a side effect if it is not, creates a LdapNameNotFoundException, which is
327      * used to set the before exception on the invocation - eventually the exception is thrown.
328      *
329      * @param msg        the message to prefix to the distinguished name for explanation
330      * @param dn         the distinguished name of the entry that is asserted
331      * @throws NamingException if the entry does not exist
332      */
333     private void assertHasEntry( String msg, Name dn ) throws NamingException
334     {
335         if ( !nexus.hasEntry( dn ) )
336         {
337             LdapNameNotFoundException e = null;
338 
339             if ( msg != null )
340             {
341                 e = new LdapNameNotFoundException( msg + dn );
342             }
343             else
344             {
345                 e = new LdapNameNotFoundException( dn.toString() );
346             }
347 
348             e.setResolvedName( nexus.getMatchedName( dn, false ) );
349             throw e;
350         }
351     }
352 }