View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.server.core.shared;
21  
22  
23  import java.io.IOException;
24  import java.util.Set;
25  import java.util.concurrent.locks.ReentrantReadWriteLock;
26  
27  import javax.naming.directory.SearchControls;
28  
29  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
30  import org.apache.directory.api.ldap.model.entry.Entry;
31  import org.apache.directory.api.ldap.model.entry.Value;
32  import org.apache.directory.api.ldap.model.exception.LdapException;
33  import org.apache.directory.api.ldap.model.exception.LdapOperationException;
34  import org.apache.directory.api.ldap.model.exception.LdapOtherException;
35  import org.apache.directory.api.ldap.model.filter.EqualityNode;
36  import org.apache.directory.api.ldap.model.filter.ExprNode;
37  import org.apache.directory.api.ldap.model.message.AliasDerefMode;
38  import org.apache.directory.api.ldap.model.name.Dn;
39  import org.apache.directory.api.ldap.model.schema.AttributeType;
40  import org.apache.directory.api.ldap.util.tree.DnNode;
41  import org.apache.directory.server.core.api.CoreSession;
42  import org.apache.directory.server.core.api.DirectoryService;
43  import org.apache.directory.server.core.api.ReferralManager;
44  import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
45  import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
46  import org.apache.directory.server.core.api.partition.Partition;
47  import org.apache.directory.server.core.api.partition.PartitionNexus;
48  import org.apache.directory.server.core.api.partition.PartitionTxn;
49  
50  
51  /**
52   * Implement a referral Manager, handling the requests from the LDAP protocol.
53   * <br>
54   * Referrals are stored in a tree, where leaves are the referrals. We are using
55   * the very same structure than for the partition manager.
56   *
57   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
58   */
59  public class ReferralManagerImpl implements ReferralManager
60  {
61      /** The referrals tree */
62      private DnNode<Entry> referrals;
63  
64      /** A lock to guarantee the manager consistency */
65      private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
66  
67      /** A storage for the ObjectClass attributeType */
68      private AttributeType objectClassAT;
69  
70  
71      /**
72       *
73       * Creates a new instance of ReferralManagerImpl.
74       *
75       * @param directoryService The directory service
76       * @throws LdapException If we can't initialize the manager
77       */
78      public ReferralManagerImpl( DirectoryService directoryService ) throws LdapException
79      {
80          lockWrite();
81  
82          try
83          {
84              referrals = new DnNode<>();
85              PartitionNexus nexus = directoryService.getPartitionNexus();
86      
87              Set<String> suffixes = nexus.listSuffixes();
88              objectClassAT = directoryService.getSchemaManager().getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
89      
90              init( directoryService, suffixes.toArray( new String[]
91                  {} ) );
92          }
93          finally
94          {
95              unlock();
96          }
97      }
98  
99  
100     /**
101      * Get a read-lock on the referralManager.
102      * No read operation can be done on the referralManager if this
103      * method is not called before.
104      */
105     @Override
106     public void lockRead()
107     {
108         mutex.readLock().lock();
109     }
110 
111 
112     /**
113      * Get a write-lock on the referralManager.
114      * No write operation can be done on the referralManager if this
115      * method is not called before.
116      */
117     @Override
118     public void lockWrite()
119     {
120         mutex.writeLock().lock();
121     }
122 
123 
124     /**
125      * Release the read-write lock on the referralManager.
126      * This method must be called after having read or modified the
127      * ReferralManager
128      */
129     @Override
130     public void unlock()
131     {
132         if ( mutex.isWriteLockedByCurrentThread() )
133         {
134             mutex.writeLock().unlock();
135         }
136         else
137         {
138             mutex.readLock().unlock();
139         }
140     }
141 
142 
143     /**
144      * {@inheritDoc}
145      */
146     @Override
147     public void addReferral( Entry entry )
148     {
149         try
150         {
151             referrals.add( entry.getDn(), entry );
152         }
153         catch ( LdapException ne )
154         {
155             // Do nothing
156         }
157     }
158 
159 
160     /**
161      * {@inheritDoc}
162      */
163     @Override
164     public void init( DirectoryService directoryService, String... suffixes ) throws LdapException
165     {
166         ExprNode referralFilter = new EqualityNode<String>( objectClassAT,
167             new Value( objectClassAT, SchemaConstants.REFERRAL_OC ) );
168 
169         // Lookup for each entry with the ObjectClass = Referral value
170         SearchControls searchControl = new SearchControls();
171         searchControl.setReturningObjFlag( false );
172         searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
173 
174         CoreSession adminSession = directoryService.getAdminSession();
175         PartitionNexus nexus = directoryService.getPartitionNexus();
176 
177         for ( String suffix : suffixes )
178         {
179             // We will store each entry's Dn into the Referral tree
180             Dn suffixDn = directoryService.getDnFactory().create( suffix );
181 
182             SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, suffixDn,
183                 referralFilter, searchControl );
184             
185             Partition partition = nexus.getPartition( suffixDn );
186             
187             try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
188             {
189                 searchOperationContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
190                 searchOperationContext.setTransaction( partitionTxn );
191                 searchOperationContext.setPartition( partition );
192                 EntryFilteringCursor cursor = nexus.search( searchOperationContext );
193     
194                 try
195                 {
196                     // Move to the first entry in the cursor
197                     cursor.beforeFirst();
198     
199                     while ( cursor.next() )
200                     {
201                         Entry entry = cursor.get();
202     
203                         // Lock the referralManager
204                         lockWrite();
205     
206                         try
207                         {
208                             // Add it at the right place
209                             addReferral( entry );
210                         }
211                         finally
212                         { 
213                             // Unlock the referralManager
214                             unlock();
215                         }
216                     }
217     
218                     cursor.close();
219                 }
220                 catch ( Exception e )
221                 {
222                     throw new LdapOperationException( e.getMessage(), e );
223                 }
224             }
225             catch ( IOException ioe )
226             {
227                 throw new LdapOtherException( ioe.getMessage(), ioe );
228             }
229         }
230     }
231 
232 
233     /**
234      * {@inheritDoc}
235      */
236     @Override
237     public void remove( DirectoryService directoryService, Dn suffix ) throws Exception
238     {
239         ExprNode referralFilter = new EqualityNode<String>( objectClassAT,
240             new Value( objectClassAT, SchemaConstants.REFERRAL_OC ) );
241 
242         // Lookup for each entry with the ObjectClass = Referral value
243         SearchControls searchControl = new SearchControls();
244         searchControl.setReturningObjFlag( false );
245         searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
246 
247         CoreSession adminSession = directoryService.getAdminSession();
248         PartitionNexus nexus = directoryService.getPartitionNexus();
249 
250         // We will store each entry's Dn into the Referral tree
251         SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, suffix,
252             referralFilter, searchControl );
253         Partition partition = nexus.getPartition( suffix ); 
254         searchOperationContext.setPartition( partition );
255         searchOperationContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
256         
257         try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
258         {
259             searchOperationContext.setTransaction( partitionTxn );
260             EntryFilteringCursor cursor = nexus.search( searchOperationContext );
261     
262             // Move to the first entry in the cursor
263             cursor.beforeFirst();
264     
265             while ( cursor.next() )
266             {
267                 Entry entry = cursor.get();
268     
269                 // Add it at the right place
270                 removeReferral( entry );
271             }
272         } 
273     }
274 
275 
276     /**
277      * {@inheritDoc}
278      */
279     @Override
280     public boolean hasParentReferral( Dn dn )
281     {
282         DnNode<Entry> referral = referrals.getNode( dn );
283 
284         return ( referral != null ) && referral.isLeaf();
285     }
286 
287 
288     /**
289      * {@inheritDoc}
290      */
291     @Override
292     public Entry getParentReferral( Dn dn )
293     {
294         if ( !hasParentReferral( dn ) )
295         {
296             return null;
297         }
298 
299         return referrals.getElement( dn );
300     }
301 
302 
303     /**
304      * {@inheritDoc}
305      */
306     @Override
307     public boolean isReferral( Dn dn )
308     {
309         Entry parent = referrals.getElement( dn );
310 
311         if ( parent != null )
312         {
313             return dn.equals( parent.getDn() );
314         }
315         else
316         {
317             return false;
318         }
319     }
320 
321 
322     /**
323      * {@inheritDoc}
324      */
325     @Override
326     public void removeReferral( Entry entry ) throws LdapException
327     {
328         referrals.remove( entry.getDn() );
329     }
330 }