001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.server.core;
021
022
023 import java.util.Set;
024 import java.util.concurrent.locks.ReentrantReadWriteLock;
025
026 import javax.naming.directory.SearchControls;
027
028 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
029 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
030 import org.apache.directory.server.core.partition.PartitionNexus;
031 import org.apache.directory.shared.ldap.constants.SchemaConstants;
032 import org.apache.directory.shared.ldap.entry.StringValue;
033 import org.apache.directory.shared.ldap.entry.ServerEntry;
034 import org.apache.directory.shared.ldap.exception.LdapException;
035 import org.apache.directory.shared.ldap.filter.EqualityNode;
036 import org.apache.directory.shared.ldap.filter.ExprNode;
037 import org.apache.directory.shared.ldap.message.AliasDerefMode;
038 import org.apache.directory.shared.ldap.name.DN;
039 import org.apache.directory.shared.ldap.util.tree.DnBranchNode;
040
041
042 /**
043 * Implement a referral Manager, handling the requests from the LDAP protocol.
044 * <br>
045 * Referrals are stored in a tree, where leaves are the referrals. We are using
046 * the very same structure than for the partition manager.
047 *
048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049 * @version $Rev$, $Date$
050 */
051 public class ReferralManagerImpl implements ReferralManager
052 {
053 /** The referrals tree */
054 private DnBranchNode<ServerEntry> referrals;
055
056 /** A lock to guarantee the manager consistency */
057 private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
058
059
060 /**
061 *
062 * Creates a new instance of ReferralManagerImpl.
063 *
064 * @param directoryService The directory service
065 * @throws Exception If we can't initialize the manager
066 */
067 public ReferralManagerImpl( DirectoryService directoryService ) throws Exception
068 {
069 lockWrite();
070
071 referrals = new DnBranchNode<ServerEntry>();
072 PartitionNexus nexus = directoryService.getPartitionNexus();
073
074 Set<String> suffixes = nexus.listSuffixes( null );
075
076 init( directoryService, suffixes.toArray( new String[]{} ) );
077
078 unlock();
079 }
080
081
082 /**
083 * Get a read-lock on the referralManager.
084 * No read operation can be done on the referralManager if this
085 * method is not called before.
086 */
087 public void lockRead()
088 {
089 mutex.readLock().lock();
090 }
091
092
093 /**
094 * Get a write-lock on the referralManager.
095 * No write operation can be done on the referralManager if this
096 * method is not called before.
097 */
098 public void lockWrite()
099 {
100 mutex.writeLock().lock();
101 }
102
103
104 /**
105 * Release the read-write lock on the referralManager.
106 * This method must be called after having read or modified the
107 * ReferralManager
108 */
109 public void unlock()
110 {
111 if ( mutex.isWriteLockedByCurrentThread() )
112 {
113 mutex.writeLock().unlock();
114 }
115 else
116 {
117 mutex.readLock().unlock();
118 }
119 }
120
121
122 /**
123 * {@inheritDoc}
124 */
125 public void addReferral( ServerEntry entry )
126 {
127 try
128 {
129 ((DnBranchNode<ServerEntry>)referrals).add( entry.getDn(), entry );
130 }
131 catch ( LdapException ne )
132 {
133 // Do nothing
134 }
135 }
136
137
138 /**
139 * {@inheritDoc}
140 */
141 public void init( DirectoryService directoryService, String... suffixes ) throws Exception
142 {
143 ExprNode referralFilter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT,
144 new StringValue( SchemaConstants.REFERRAL_OC ) );
145
146 // Lookup for each entry with the ObjectClass = Referral value
147 SearchControls searchControl = new SearchControls();
148 searchControl.setReturningObjFlag( false );
149 searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
150
151 CoreSession adminSession = directoryService.getAdminSession();
152 PartitionNexus nexus = directoryService.getPartitionNexus();
153
154 for ( String suffix:suffixes )
155 {
156 // We will store each entry's DN into the Referral tree
157 DN suffixDn = new DN( suffix );
158 suffixDn.normalize( directoryService.getSchemaManager().getNormalizerMapping() );
159
160 SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, suffixDn, referralFilter, searchControl );
161 searchOperationContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
162 EntryFilteringCursor cursor = nexus.search( searchOperationContext );
163
164 // Move to the first entry in the cursor
165 cursor.beforeFirst();
166
167 while ( cursor.next() )
168 {
169 ServerEntry entry = cursor.get();
170
171 // Lock the referralManager
172 lockWrite();
173
174 // Add it at the right place
175 addReferral( entry );
176
177 // Unlock the referralManager
178 unlock();
179 }
180 }
181 }
182
183
184 /**
185 * {@inheritDoc}
186 */
187 public void remove( DirectoryService directoryService, DN suffix ) throws Exception
188 {
189 ExprNode referralFilter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT,
190 new StringValue( SchemaConstants.REFERRAL_OC ) );
191
192 // Lookup for each entry with the ObjectClass = Referral value
193 SearchControls searchControl = new SearchControls();
194 searchControl.setReturningObjFlag( false );
195 searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
196
197 CoreSession adminSession = directoryService.getAdminSession();
198 PartitionNexus nexus = directoryService.getPartitionNexus();
199
200 // We will store each entry's DN into the Referral tree
201 SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, suffix,
202 referralFilter, searchControl );
203 searchOperationContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
204 EntryFilteringCursor cursor = nexus.search( searchOperationContext );
205
206 // Move to the first entry in the cursor
207 cursor.beforeFirst();
208
209 while ( cursor.next() )
210 {
211 ServerEntry entry = cursor.get();
212
213 // Add it at the right place
214 removeReferral( entry );
215 }
216 }
217
218
219 /**
220 * {@inheritDoc}
221 */
222 public boolean hasParentReferral( DN dn )
223 {
224 return referrals.hasParentElement( dn );
225 }
226
227
228 /**
229 * {@inheritDoc}
230 */
231 public ServerEntry getParentReferral( DN dn )
232 {
233 if ( !hasParentReferral( dn ) )
234 {
235 return null;
236 }
237
238 return referrals.getParentElement( dn );
239 }
240
241
242 /**
243 * {@inheritDoc}
244 */
245 public boolean isReferral( DN dn )
246 {
247 ServerEntry parent = referrals.getParentElement( dn );
248
249 if ( parent != null )
250 {
251 return dn.equals( parent.getDn() );
252 }
253 else
254 {
255 return false;
256 }
257 }
258
259
260 /**
261 * {@inheritDoc}
262 */
263 public void removeReferral( ServerEntry entry )
264 {
265 referrals.remove( entry );
266 }
267 }