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 }