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