1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.*;
26
27 import org.apache.ldap.common.exception.*;
28 import org.apache.ldap.common.filter.ExprNode;
29 import org.apache.ldap.common.message.ResultCodeEnum;
30 import org.apache.ldap.common.name.LdapName;
31 import org.apache.ldap.server.DirectoryServiceConfiguration;
32 import org.apache.ldap.server.invocation.Invocation;
33 import org.apache.ldap.server.invocation.InvocationStack;
34 import org.apache.ldap.server.configuration.InterceptorConfiguration;
35 import org.apache.ldap.server.interceptor.BaseInterceptor;
36 import org.apache.ldap.server.interceptor.NextInterceptor;
37 import org.apache.ldap.server.partition.DirectoryPartition;
38 import org.apache.ldap.server.partition.DirectoryPartitionNexus;
39 import org.apache.ldap.server.partition.DirectoryPartitionNexusProxy;
40
41
42 /***
43 * An {@link org.apache.ldap.server.interceptor.Interceptor} that detects any operations that breaks integrity
44 * of {@link DirectoryPartition} and terminates the current invocation chain by
45 * throwing a {@link NamingException}. Those operations include when an entry
46 * already exists at a DN and is added once again to the same DN.
47 *
48 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
49 * @version $Rev: 326825 $
50 */
51 public class ExceptionService extends BaseInterceptor
52 {
53 private DirectoryPartitionNexus nexus;
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( DirectoryServiceConfiguration factoryCfg, InterceptorConfiguration cfg )
64 {
65 nexus = factoryCfg.getPartitionNexus();
66 }
67
68
69 public void destroy()
70 {
71 }
72
73
74 /***
75 * In the pre-invocation state this interceptor method checks to see if the entry to be added already exists. If it
76 * does an exception is raised.
77 */
78 public void add( NextInterceptor nextInterceptor, String upName, Name normName, Attributes entry ) throws NamingException
79 {
80
81 if ( nextInterceptor.hasEntry( normName ) )
82 {
83 NamingException ne = new LdapNameAlreadyBoundException( normName.toString() + " already exists!" );
84 ne.setResolvedName( new LdapName( upName ) );
85 throw ne;
86 }
87
88 Name parentDn = normName.getPrefix( 1 );
89
90
91 assertHasEntry( nextInterceptor, "Attempt to add under non-existant parent: ", parentDn );
92
93
94 Attributes attrs = nextInterceptor.lookup( normName.getPrefix( 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
117 String msg = "Attempt to delete non-existant entry: ";
118 assertHasEntry( nextInterceptor, msg, name );
119
120
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
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
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
184 String msg = "Attempt to modify non-existant entry: ";
185 assertHasEntry( nextInterceptor, msg, name );
186
187 Attributes entry = nexus.lookup( name );
188 NamingEnumeration attrIds = attrs.getIDs();
189 while ( attrIds.hasMore() )
190 {
191 String attrId = ( String ) attrIds.next();
192 Attribute modAttr = attrs.get( attrId );
193 Attribute entryAttr = entry.get( attrId );
194
195 if ( modOp == DirContext.ADD_ATTRIBUTE )
196 {
197 if ( entryAttr != null )
198 {
199 for ( int ii = 0; ii < modAttr.size(); ii++ )
200 {
201 if ( entryAttr.contains( modAttr.get( ii ) ) )
202 {
203 throw new LdapAttributeInUseException( "Trying to add existing value '"
204 + modAttr.get( ii ) + "' to attribute " + attrId );
205 }
206 }
207 }
208 }
209 }
210 nextInterceptor.modify( name, modOp, attrs );
211 }
212
213
214 /***
215 * Checks to see the entry being modified exists, otherwise throws the appropriate LdapException.
216 */
217 public void modify( NextInterceptor nextInterceptor, Name name, ModificationItem[] items ) throws NamingException
218 {
219
220 String msg = "Attempt to modify non-existant entry: ";
221 assertHasEntry( nextInterceptor, msg, name );
222
223 Attributes entry = nexus.lookup( name );
224 for ( int ii = 0; ii < items.length; ii++ )
225 {
226 if ( items[ii].getModificationOp() == DirContext.ADD_ATTRIBUTE )
227 {
228 Attribute modAttr = items[ii].getAttribute();
229 Attribute entryAttr = entry.get( modAttr.getID() );
230
231 if ( entryAttr != null )
232 {
233 for ( int jj = 0; jj < modAttr.size(); jj++ )
234 {
235 if ( entryAttr.contains( modAttr.get( jj ) ) )
236 {
237 throw new LdapAttributeInUseException( "Trying to add existing value '"
238 + modAttr.get( ii ) + "' to attribute " + modAttr.getID() );
239 }
240 }
241 }
242 }
243 }
244 nextInterceptor.modify( name, items );
245 }
246
247
248 /***
249 * Checks to see the entry being renamed exists, otherwise throws the appropriate LdapException.
250 */
251 public void modifyRn( NextInterceptor nextInterceptor, Name dn, String newRn, boolean deleteOldRn ) throws NamingException
252 {
253
254 String msg = "Attempt to rename non-existant entry: ";
255 assertHasEntry( nextInterceptor, msg, dn );
256
257
258 Name target = dn.getPrefix( 1 ).add( newRn );
259 if ( nextInterceptor.hasEntry( target ) )
260 {
261 LdapNameAlreadyBoundException e = null;
262 e = new LdapNameAlreadyBoundException( "target entry " + target
263 + " already exists!" );
264 e.setResolvedName( target );
265 throw e;
266 }
267
268 nextInterceptor.modifyRn( dn, newRn, deleteOldRn );
269 }
270
271
272 /***
273 * Checks to see the entry being moved exists, and so does its parent, otherwise throws the appropriate
274 * LdapException.
275 */
276 public void move( NextInterceptor nextInterceptor, Name oriChildName, Name newParentName ) throws NamingException
277 {
278
279 String msg = "Attempt to move to non-existant parent: ";
280 assertHasEntry( nextInterceptor, msg, oriChildName );
281
282
283 msg = "Attempt to move to non-existant parent: ";
284 assertHasEntry( nextInterceptor, msg, newParentName );
285
286
287 String rdn = oriChildName.get( oriChildName.size() - 1 );
288 Name target = ( Name ) newParentName.clone();
289 target.add( rdn );
290 if ( nextInterceptor.hasEntry( target ) )
291 {
292 LdapNameAlreadyBoundException e = null;
293 e = new LdapNameAlreadyBoundException( "target entry " + target
294 + " already exists!" );
295 e.setResolvedName( target );
296 throw e;
297 }
298
299 nextInterceptor.move( oriChildName, newParentName );
300 }
301
302
303 /***
304 * Checks to see the entry being moved exists, and so does its parent, otherwise throws the appropriate
305 * LdapException.
306 */
307 public void move( NextInterceptor nextInterceptor,
308 Name oriChildName, Name newParentName, String newRn,
309 boolean deleteOldRn ) throws NamingException
310 {
311
312 String msg = "Attempt to move to non-existant parent: ";
313 assertHasEntry( nextInterceptor, msg, oriChildName );
314
315
316 msg = "Attempt to move to non-existant parent: ";
317 assertHasEntry( nextInterceptor, msg, newParentName );
318
319
320 Name target = ( Name ) newParentName.clone();
321 target.add( newRn );
322 if ( nextInterceptor.hasEntry( target ) )
323 {
324 LdapNameAlreadyBoundException e = null;
325 e = new LdapNameAlreadyBoundException( "target entry " + target
326 + " already exists!" );
327 e.setResolvedName( target );
328 throw e;
329 }
330
331 nextInterceptor.move( oriChildName, newParentName, newRn, deleteOldRn );
332 }
333
334
335 /***
336 * Checks to see the entry being searched exists, otherwise throws the appropriate LdapException.
337 */
338 public NamingEnumeration search( NextInterceptor nextInterceptor,
339 Name base, Map env, ExprNode filter,
340 SearchControls searchCtls ) throws NamingException
341 {
342 String msg = "Attempt to search under non-existant entry: ";
343
344 if ( base.size() == 0 )
345 {
346 return nextInterceptor.search( base, env, filter, searchCtls );
347 }
348
349 Attribute attr = nextInterceptor.getRootDSE().get( "subschemaSubentry" );
350 if ( ( ( String ) attr.get() ).equalsIgnoreCase( base.toString() ) )
351 {
352 return nextInterceptor.search( base, env, filter, searchCtls );
353 }
354
355 assertHasEntry( nextInterceptor, msg, base );
356
357 return nextInterceptor.search( base, env, filter, searchCtls );
358 }
359
360
361 /***
362 * Asserts that an entry is present and as a side effect if it is not, creates a LdapNameNotFoundException, which is
363 * used to set the before exception on the invocation - eventually the exception is thrown.
364 *
365 * @param msg the message to prefix to the distinguished name for explanation
366 * @param dn the distinguished name of the entry that is asserted
367 * @throws NamingException if the entry does not exist
368 */
369 private void assertHasEntry( NextInterceptor nextInterceptor, String msg, Name dn ) throws NamingException
370 {
371 Invocation invocation = InvocationStack.getInstance().peek();
372 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
373 if ( !nextInterceptor.hasEntry( dn ) )
374 {
375 LdapNameNotFoundException e = null;
376
377 if ( msg != null )
378 {
379 e = new LdapNameNotFoundException( msg + dn );
380 }
381 else
382 {
383 e = new LdapNameNotFoundException( dn.toString() );
384 }
385
386 e.setResolvedName( proxy.getMatchedName( dn, false ) );
387 throw e;
388 }
389 }
390 }