KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ldap > server > jndi > ServerContext


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.jndi;
18
19
20 import org.apache.ldap.common.exception.LdapNoPermissionException;
21 import org.apache.ldap.common.filter.PresenceNode;
22 import org.apache.ldap.common.message.LockableAttributesImpl;
23 import org.apache.ldap.common.name.LdapName;
24 import org.apache.ldap.common.util.NamespaceTools;
25 import org.apache.ldap.server.PartitionNexus;
26 import org.apache.ldap.server.authn.AuthenticationService;
27 import org.apache.ldap.server.authn.LdapPrincipal;
28
29 import javax.naming.*;
30 import javax.naming.directory.Attribute JavaDoc;
31 import javax.naming.directory.Attributes JavaDoc;
32 import javax.naming.directory.DirContext JavaDoc;
33 import javax.naming.directory.SearchControls JavaDoc;
34 import javax.naming.ldap.Control JavaDoc;
35 import javax.naming.spi.DirStateFactory JavaDoc;
36 import javax.naming.spi.DirectoryManager JavaDoc;
37 import java.io.Serializable JavaDoc;
38 import java.util.Hashtable JavaDoc;
39
40
41 /**
42  * A non-federated abstract Context implementation.
43  *
44  * @author <a HREF="mailto:dev@directory.apache.org">Apache Directory Project</a>
45  * @version $Rev: 169198 $
46  */

47 public abstract class ServerContext implements Context JavaDoc
48 {
49     /** property key used for deleting the old RDN on a rename */
50     public static final String JavaDoc DELETE_OLD_RDN_PROP = "java.naming.ldap.deleteRDN";
51
52     /** The interceptor proxy to the backend nexus */
53     private final PartitionNexus nexusProxy;
54
55     /** The cloned environment used by this Context */
56     private final Hashtable JavaDoc env;
57
58     /** The distinguished name of this Context */
59     private final LdapName dn;
60
61     /** The Principal associated with this context */
62     private LdapPrincipal principal;
63
64     // ------------------------------------------------------------------------
65
// Constructors
66
// ------------------------------------------------------------------------
67

68
69     /**
70      * Must be called by all subclasses to initialize the nexus proxy and the
71      * environment settings to be used by this Context implementation. This
72      * specific contstructor relies on the presence of the {@link
73      * Context#PROVIDER_URL} key and value to determine the distinguished name
74      * of the newly created context. It also checks to make sure the
75      * referenced name actually exists within the system. This constructor
76      * is used for all InitialContext requests.
77      *
78      * @param nexusProxy the intercepting proxy to the nexus.
79      * @param env the environment properties used by this context.
80      * @throws NamingException if the environment parameters are not set
81      * correctly.
82      */

83     protected ServerContext( PartitionNexus nexusProxy, Hashtable JavaDoc env ) throws NamingException
84     {
85         String JavaDoc url;
86
87         // set references to cloned env and the proxy
88
this.nexusProxy = nexusProxy;
89
90         this.env = ( Hashtable JavaDoc ) env.clone();
91
92         /* --------------------------------------------------------------------
93          * check for the provider URL property and make sure it exists
94          * as a valid value or else we need to throw a configuration error
95          * ------------------------------------------------------------------ */

96         if ( ! env.containsKey( Context.PROVIDER_URL ) )
97         {
98             String JavaDoc msg = "Expected property " + Context.PROVIDER_URL;
99
100             msg += " but could not find it in env!";
101
102             throw new ConfigurationException( msg );
103         }
104
105         url = ( String JavaDoc ) env.get( Context.PROVIDER_URL );
106
107         if ( url == null )
108         {
109             String JavaDoc msg = "Expected value for property " + Context.PROVIDER_URL;
110
111             msg += " but it was set to null in env!";
112
113             throw new ConfigurationException( msg );
114         }
115
116         dn = new LdapName( url );
117
118         if ( ! nexusProxy.hasEntry( dn ) )
119         {
120             throw new NameNotFoundException( dn + " does not exist" );
121         }
122     }
123
124
125     /**
126      * Must be called by all subclasses to initialize the nexus proxy and the
127      * environment settings to be used by this Context implementation. This
128      * constructor is used to propagate new contexts from existing contexts.
129      *
130      * @param principal the directory user principal that is propagated
131      * @param nexusProxy the intercepting proxy to the nexus
132      * @param env the environment properties used by this context
133      * @param dn the distinguished name of this context
134      */

135     protected ServerContext( LdapPrincipal principal, PartitionNexus nexusProxy, Hashtable JavaDoc env, Name dn )
136     {
137         this.dn = ( LdapName ) dn.clone();
138
139         this.env = ( Hashtable JavaDoc ) env.clone();
140
141         this.env.put( PROVIDER_URL, dn.toString() );
142
143         this.nexusProxy = nexusProxy;
144
145         this.principal = principal;
146     }
147
148
149     // ------------------------------------------------------------------------
150
// New Impl Specific Public Methods
151
// ------------------------------------------------------------------------
152

153
154     /**
155      * Gets the principal of the authenticated user which also happens to own
156      */

157     public LdapPrincipal getPrincipal()
158     {
159         return principal;
160     }
161
162
163     /**
164      * Sets the principal of the authenticated user which also happens to own.
165      * This method can be invoked only once to keep this property safe. This
166      * method has been changed to be public but it can only be set by the
167      * AuthenticationService to prevent malicious code from changing the
168      * effective principal.
169      */

170     public void setPrincipal( AuthenticationService.TrustedPrincipalWrapper wrapper )
171     {
172         this.principal = wrapper.getPrincipal();
173     }
174
175
176     // ------------------------------------------------------------------------
177
// Protected Accessor Methods
178
// ------------------------------------------------------------------------
179

180
181     /**
182      * Gets the RootNexus proxy.
183      *
184      * @return the proxy to the backend nexus.
185      */

186     protected PartitionNexus getNexusProxy()
187     {
188        return nexusProxy ;
189     }
190     
191     
192     /**
193      * Gets the distinguished name of the entry associated with this Context.
194      *
195      * @return the distinguished name of this Context's entry.
196      */

197     protected Name getDn()
198     {
199         return dn;
200     }
201
202
203     // ------------------------------------------------------------------------
204
// JNDI Context Interface Methods
205
// ------------------------------------------------------------------------
206

207
208     /**
209      * @see javax.naming.Context#close()
210      */

211     public void close() throws NamingException
212     {
213         // Does nothing yet?
214
}
215
216
217     /**
218      * @see javax.naming.Context#getNameInNamespace()
219      */

220     public String JavaDoc getNameInNamespace() throws NamingException
221     {
222         return dn.toString();
223     }
224
225
226     /**
227      * @see javax.naming.Context#getEnvironment()
228      */

229     public Hashtable JavaDoc getEnvironment()
230     {
231         return env;
232     }
233
234
235     /**
236      * @see javax.naming.Context#addToEnvironment(java.lang.String,
237      * java.lang.Object)
238      */

239     public Object JavaDoc addToEnvironment( String JavaDoc propName, Object JavaDoc propVal ) throws NamingException
240     {
241         return env.put( propName, propVal );
242     }
243
244
245     /**
246      * @see javax.naming.Context#removeFromEnvironment(java.lang.String)
247      */

248     public Object JavaDoc removeFromEnvironment( String JavaDoc propName ) throws NamingException
249     {
250         return env.remove( propName );
251     }
252
253
254     /**
255      * @see javax.naming.Context#createSubcontext(java.lang.String)
256      */

257     public Context JavaDoc createSubcontext( String JavaDoc name ) throws NamingException
258     {
259         return createSubcontext( new LdapName( name ) );
260     }
261
262
263     /**
264      * @see javax.naming.Context#createSubcontext(javax.naming.Name)
265      */

266     public Context JavaDoc createSubcontext( Name name ) throws NamingException
267     {
268         Attributes JavaDoc attributes = new LockableAttributesImpl();
269
270         LdapName target = buildTarget( name );
271
272         String JavaDoc rdn = name.get( name.size() - 1 );
273
274         String JavaDoc rdnAttribute = NamespaceTools.getRdnAttribute( rdn );
275
276         String JavaDoc rdnValue = NamespaceTools.getRdnValue( rdn );
277
278         attributes.put( rdnAttribute, rdnValue );
279
280         attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.JCONTAINER_ATTR );
281
282         attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.TOP_ATTR );
283         
284         /*
285          * Add the new context to the server which as a side effect adds
286          * operational attributes to the attributes refering instance which
287          * can them be used to initialize a new ServerLdapContext. Remember
288          * we need to copy over the controls as well to propagate the complete
289          * environment besides whats in the hashtable for env.
290          */

291         nexusProxy.add( target.toString(), target, attributes );
292         
293         ServerLdapContext ctx = new ServerLdapContext( principal, nexusProxy, env, target );
294
295         Control JavaDoc [] controls = ( Control JavaDoc [] ) ( ( ServerLdapContext ) this ).getRequestControls().clone();
296
297         ctx.setRequestControls( controls );
298
299         return ctx;
300     }
301
302
303     /**
304      * @see javax.naming.Context#destroySubcontext(java.lang.String)
305      */

306     public void destroySubcontext( String JavaDoc name ) throws NamingException
307     {
308         destroySubcontext( new LdapName( name ) );
309     }
310
311
312     /**
313      * @see javax.naming.Context#destroySubcontext(javax.naming.Name)
314      */

315     public void destroySubcontext( Name name ) throws NamingException
316     {
317         Name target = buildTarget( name );
318
319         if ( target.size() == 0 )
320         {
321             throw new LdapNoPermissionException( "can't delete the rootDSE" );
322         }
323
324         nexusProxy.delete( target );
325     }
326
327
328     /**
329      * @see javax.naming.Context#bind(java.lang.String, java.lang.Object)
330      */

331     public void bind( String JavaDoc name, Object JavaDoc obj ) throws NamingException
332     {
333         bind( new LdapName( name ), obj );
334     }
335     
336
337     /**
338      * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object)
339      */

340     public void bind( Name name, Object JavaDoc obj ) throws NamingException
341     {
342         // First, use state factories to do a transformation
343
DirStateFactory.Result JavaDoc res = DirectoryManager.getStateToBind( obj, name, this, env, null );
344
345         Attributes JavaDoc outAttrs = res.getAttributes();
346
347         if ( outAttrs != null )
348         {
349             Name target = buildTarget( name );
350
351             nexusProxy.add( target.toString(), target, outAttrs );
352
353             return;
354         }
355
356         // Check for Referenceable
357
if ( obj instanceof Referenceable )
358         {
359             obj = ( ( Referenceable ) obj ).getReference();
360
361             throw new NamingException( "Do not know how to store Referenceables yet!" );
362         }
363
364         // Store different formats
365
if ( obj instanceof Reference )
366         {
367             // Store as ref and add outAttrs
368

369             throw new NamingException( "Do not know how to store References yet!" );
370         }
371         else if ( obj instanceof Serializable JavaDoc )
372         {
373             // Serialize and add outAttrs
374

375             Attributes JavaDoc attributes = new LockableAttributesImpl();
376
377             if ( outAttrs != null && outAttrs.size() > 0 )
378             {
379                 NamingEnumeration list = outAttrs.getAll();
380
381                 while ( list.hasMore() )
382                 {
383                     attributes.put( ( Attribute JavaDoc ) list.next() );
384                 }
385             }
386
387             Name target = buildTarget( name );
388
389             // Serialize object into entry attributes and add it.
390

391             JavaLdapSupport.serialize( attributes, obj );
392
393             nexusProxy.add( target.toString(), target, attributes );
394         }
395         else if ( obj instanceof DirContext JavaDoc )
396         {
397             // Grab attributes and merge with outAttrs
398

399             Attributes JavaDoc attributes = ( ( DirContext JavaDoc ) obj ).getAttributes( "" );
400
401             if ( outAttrs != null && outAttrs.size() > 0 )
402             {
403                 NamingEnumeration list = outAttrs.getAll();
404
405                 while ( list.hasMore() )
406                 {
407                     attributes.put( ( Attribute JavaDoc ) list.next() );
408                 }
409             }
410
411             Name target = buildTarget( name );
412
413             nexusProxy.add( target.toString(), target, attributes );
414         }
415         else
416         {
417             throw new NamingException( "Can't find a way to bind: " + obj );
418         }
419     }
420
421
422     /**
423      * @see javax.naming.Context#rename(java.lang.String, java.lang.String)
424      */

425     public void rename( String JavaDoc oldName, String JavaDoc newName ) throws NamingException
426     {
427         rename( new LdapName( oldName ), new LdapName( newName ) );
428     }
429
430
431     /**
432      * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name)
433      */

434     public void rename( Name oldName, Name newName ) throws NamingException
435     {
436         Name oldDn = buildTarget( oldName );
437
438         Name newDn = buildTarget( newName );
439
440         if ( oldDn.size() == 0 )
441         {
442             throw new LdapNoPermissionException( "can't rename the rootDSE" );
443         }
444
445         Name oldBase = oldName.getSuffix( 1 );
446
447         Name newBase = newName.getSuffix( 1 );
448
449         String JavaDoc newRdn = newName.get( newName.size() - 1 );
450
451         String JavaDoc oldRdn = oldName.get( oldName.size() - 1 );
452                 
453         boolean delOldRdn = true;
454             
455         /*
456          * Attempt to use the java.naming.ldap.deleteRDN environment property
457          * to get an override for the deleteOldRdn option to modifyRdn.
458          */

459         if ( null != env.get( DELETE_OLD_RDN_PROP ) )
460         {
461             String JavaDoc delOldRdnStr = ( String JavaDoc ) env.get( DELETE_OLD_RDN_PROP );
462
463             delOldRdn = ! delOldRdnStr.equals( "false" );
464
465             delOldRdn = delOldRdn || delOldRdnStr.equals( "no" );
466
467             delOldRdn = delOldRdn || delOldRdnStr.equals( "0" );
468         }
469
470         /*
471          * We need to determine if this rename operation corresponds to a simple
472          * RDN name change or a move operation. If the two names are the same
473          * except for the RDN then it is a simple modifyRdn operation. If the
474          * names differ in size or have a different baseDN then the operation is
475          * a move operation. Furthermore if the RDN in the move operation
476          * changes it is both an RDN change and a move operation.
477          */

478         if ( oldName.size() == newName.size() && oldBase.equals( newBase ) )
479         {
480             nexusProxy.modifyRn( oldDn, newRdn, delOldRdn );
481         }
482         else
483         {
484             Name parent = newDn.getSuffix( 1 );
485             
486             if ( newRdn.equalsIgnoreCase( oldRdn ) )
487             {
488                 nexusProxy.move( oldDn, parent );
489             }
490             else
491             {
492                 nexusProxy.move( oldDn, parent, newRdn, delOldRdn );
493             }
494         }
495     }
496
497
498     /**
499      * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object)
500      */

501     public void rebind( String JavaDoc name, Object JavaDoc obj ) throws NamingException
502     {
503         rebind( new LdapName( name ), obj );
504     }
505
506
507     /**
508      * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object)
509      */

510     public void rebind( Name name, Object JavaDoc obj ) throws NamingException
511     {
512         Name target = buildTarget( name );
513
514         if ( nexusProxy.hasEntry( target ) )
515         {
516             nexusProxy.delete( target );
517         }
518
519         bind( name, obj );
520     }
521
522
523     /**
524      * @see javax.naming.Context#unbind(java.lang.String)
525      */

526     public void unbind( String JavaDoc name ) throws NamingException
527     {
528         unbind( new LdapName( name ) );
529     }
530
531
532     /**
533      * @see javax.naming.Context#unbind(javax.naming.Name)
534      */

535     public void unbind( Name name ) throws NamingException
536     {
537         nexusProxy.delete( buildTarget( name ) );
538     }
539
540
541     /**
542      * @see javax.naming.Context#lookup(java.lang.String)
543      */

544     public Object JavaDoc lookup( String JavaDoc name ) throws NamingException
545     {
546         return lookup( new LdapName( name ) );
547     }
548
549
550     /**
551      * @see javax.naming.Context#lookup(javax.naming.Name)
552      */

553     public Object JavaDoc lookup( Name name ) throws NamingException
554     {
555         Object JavaDoc obj = null;
556
557         LdapName target = buildTarget( name );
558
559         Attributes JavaDoc attributes = nexusProxy.lookup( target );
560
561         try
562         {
563             obj = DirectoryManager.getObjectInstance( null, name, this, env, attributes );
564         }
565         catch ( Exception JavaDoc e )
566         {
567             throw new NamingException( e.getMessage() );
568         }
569
570         if ( obj != null )
571         {
572             return obj;
573         }
574
575         // First lets test and see if the entry is a serialized java object
576
if ( attributes.get( JavaLdapSupport.JCLASSNAME_ATTR ) != null )
577         {
578             // Give back serialized object and not a context
579
return JavaLdapSupport.deserialize( attributes );
580         }
581         
582         // Initialize and return a context since the entry is not a java object
583
ServerLdapContext ctx = new ServerLdapContext( principal, nexusProxy, env, target );
584             
585         // Need to add controls to propagate extended ldap operational env
586
Control JavaDoc [] controls = ( ( ServerLdapContext ) this ).getRequestControls();
587
588         if ( null != controls )
589         {
590             ctx.setRequestControls( ( Control JavaDoc [] ) controls.clone() );
591         }
592         
593         return ctx;
594     }
595
596
597     /**
598      * @see javax.naming.Context#lookupLink(java.lang.String)
599      */

600     public Object JavaDoc lookupLink( String JavaDoc name ) throws NamingException
601     {
602         throw new UnsupportedOperationException JavaDoc();
603     }
604
605
606     /**
607      * @see javax.naming.Context#lookupLink(javax.naming.Name)
608      */

609     public Object JavaDoc lookupLink( Name name ) throws NamingException
610     {
611         throw new UnsupportedOperationException JavaDoc();
612     }
613
614
615     /**
616      * Non-federated implementation presuming the name argument is not a
617      * composite name spanning multiple namespaces but a compound name in
618      * the same LDAP namespace. Hence the parser returned is always the
619      * same as calling this method with the empty String.
620      *
621      * @see javax.naming.Context#getNameParser(java.lang.String)
622      */

623     public NameParser getNameParser( String JavaDoc name ) throws NamingException
624     {
625         return LdapName.getNameParser();
626     }
627
628
629     /**
630      * Non-federated implementation presuming the name argument is not a
631      * composite name spanning multiple namespaces but a compound name in
632      * the same LDAP namespace. Hence the parser returned is always the
633      * same as calling this method with the empty String Name.
634      *
635      * @see javax.naming.Context#getNameParser(javax.naming.Name)
636      */

637     public NameParser getNameParser( Name name ) throws NamingException
638     {
639         return LdapName.getNameParser();
640     }
641
642
643     /**
644      * @see javax.naming.Context#list(java.lang.String)
645      */

646     public NamingEnumeration list( String JavaDoc name ) throws NamingException
647     {
648         return list( new LdapName( name ) );
649     }
650
651
652     /**
653      * @see javax.naming.Context#list(javax.naming.Name)
654      */

655     public NamingEnumeration list( Name name ) throws NamingException
656     {
657         return nexusProxy.list( buildTarget( name ) );
658     }
659
660
661     /**
662      * @see javax.naming.Context#listBindings(java.lang.String)
663      */

664     public NamingEnumeration listBindings( String JavaDoc name ) throws NamingException
665     {
666         return listBindings( new LdapName( name ) );
667     }
668
669
670     /**
671      * @see javax.naming.Context#listBindings(javax.naming.Name)
672      */

673     public NamingEnumeration listBindings( Name name ) throws NamingException
674     {
675         // Conduct a special one level search at base for all objects
676
Name base = buildTarget( name );
677
678         PresenceNode filter = new PresenceNode( "objectClass" );
679
680         SearchControls JavaDoc ctls = new SearchControls JavaDoc();
681
682         ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
683
684         return nexusProxy.search( base , getEnvironment(), filter, ctls );
685     }
686
687
688     /**
689      * @see javax.naming.Context#composeName(java.lang.String, java.lang.String)
690      */

691     public String JavaDoc composeName( String JavaDoc name, String JavaDoc prefix ) throws NamingException
692     {
693         return composeName( new LdapName( name ), new LdapName( prefix ) ).toString();
694     }
695
696
697     /**
698      * @see javax.naming.Context#composeName(javax.naming.Name,
699      * javax.naming.Name)
700      */

701     public Name composeName( Name name, Name prefix ) throws NamingException
702     {
703         // No prefix reduces to name, or the name relative to this context
704
if ( prefix == null || prefix.size() == 0 )
705         {
706             return name;
707         }
708
709         /*
710          * Example: This context is ou=people and say name is the relative
711          * name of uid=jwalker and the prefix is dc=domain. Then we must
712          * compose the name relative to prefix which would be:
713          *
714          * uid=jwalker,ou=people,dc=domain.
715          *
716          * The following general algorithm generates the right name:
717          * 1). Find the Dn for name and walk it from the head to tail
718          * trying to match for the head of prefix.
719          * 2). Remove name components from the Dn until a match for the
720          * head of the prefix is found.
721          * 3). Return the remainder of the fqn or Dn after chewing off some
722          */

723          
724         // 1). Find the Dn for name and walk it from the head to tail
725
Name fqn = buildTarget( name );
726
727         String JavaDoc head = prefix.get( 0 );
728         
729         // 2). Walk the fqn trying to match for the head of the prefix
730
while ( fqn.size() > 0 )
731         {
732             // match found end loop
733
if ( fqn.get( 0 ).equalsIgnoreCase( head ) )
734             {
735                 return fqn;
736             }
737             else // 2). Remove name components from the Dn until a match
738
{
739                 fqn.remove( 0 );
740             }
741         }
742
743         String JavaDoc msg = "The prefix '" + prefix + "' is not an ancestor of this ";
744
745         msg += "entry '" + dn + "'";
746
747         throw new NamingException( msg );
748     }
749     
750     
751     // ------------------------------------------------------------------------
752
// Utility Methods to Reduce Code
753
// ------------------------------------------------------------------------
754

755     
756     /**
757      * Clones this context's DN and adds the components of the name relative to
758      * this context to the left hand side of this context's cloned DN.
759      *
760      * @param relativeName a name relative to this context.
761      * @return the name of the target
762      * @throws InvalidNameException if relativeName is not a valid name in
763      * the LDAP namespace.
764      */

765     LdapName buildTarget( Name relativeName ) throws InvalidNameException
766     {
767         // Clone our DN or absolute path
768
LdapName target = ( LdapName ) dn.clone();
769         
770         // Add to left hand side of cloned DN the relative name arg
771
target.addAll( target.size(), relativeName );
772
773         return target;
774     }
775 }
776
Popular Tags