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