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.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
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
99 assertHasEntry( "Attempt to add under non-existant parent: ", parentDn );
100
101
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
125 String msg = "Attempt to delete non-existant entry: ";
126 assertHasEntry( msg, name );
127
128
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
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
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
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
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
218 String msg = "Attempt to rename non-existant entry: ";
219 assertHasEntry( msg, dn );
220
221
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
243 String msg = "Attempt to move to non-existant parent: ";
244 assertHasEntry( msg, oriChildName );
245
246
247 msg = "Attempt to move to non-existant parent: ";
248 assertHasEntry( msg, newParentName );
249
250
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
276 String msg = "Attempt to move to non-existant parent: ";
277 assertHasEntry( msg, oriChildName );
278
279
280 msg = "Attempt to move to non-existant parent: ";
281 assertHasEntry( msg, newParentName );
282
283
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 }