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.shared.ldap.subtree; 021 022 023 import org.apache.directory.shared.ldap.filter.ExprNode; 024 import org.apache.directory.shared.ldap.name.DN; 025 026 import java.util.Iterator; 027 import java.util.Set; 028 import java.util.Collections; 029 030 031 /** 032 * A simple implementation of the SubtreeSpecification interface. 033 * 034 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 035 * @version $Rev: 918756 $ 036 */ 037 public class BaseSubtreeSpecification implements SubtreeSpecification 038 { 039 /** the subtree base relative to the administration point */ 040 private final DN base; 041 042 /** the set of subordinates entries and their subordinates to exclude */ 043 private final Set<DN> chopBefore; 044 045 /** the set of subordinates entries whose subordinates are to be excluded */ 046 private final Set<DN> chopAfter; 047 048 /** the minimum distance below base to start including entries */ 049 private final int minBaseDistance; 050 051 /** the maximum distance from base past which entries are excluded */ 052 private final int maxBaseDistance; 053 054 /** 055 * a filter using only assertions on objectClass attributes for subtree 056 * refinement 057 */ 058 private final ExprNode refinement; 059 060 061 // ----------------------------------------------------------------------- 062 // C O N S T R U C T O R S 063 // ----------------------------------------------------------------------- 064 065 /** 066 * Creates a simple subtree whose administrative point is necessarily the 067 * base and all subordinates underneath (excluding those that are part of 068 * inner areas) are part of the the subtree. 069 */ 070 @SuppressWarnings("unchecked") 071 public BaseSubtreeSpecification() 072 { 073 this.base = new DN(); 074 this.minBaseDistance = 0; 075 this.maxBaseDistance = UNBOUNDED_MAX; 076 this.chopAfter = Collections.EMPTY_SET; 077 this.chopBefore = Collections.EMPTY_SET; 078 this.refinement = null; 079 } 080 081 082 /** 083 * Creates a simple subtree refinement whose administrative point is 084 * necessarily the base and only those subordinates selected by the 085 * refinement filter are included. 086 * 087 * @param refinement 088 * the filter expression only composed of objectClass attribute 089 * value assertions 090 */ 091 @SuppressWarnings("unchecked") 092 public BaseSubtreeSpecification(ExprNode refinement) 093 { 094 this.base = new DN(); 095 this.minBaseDistance = 0; 096 this.maxBaseDistance = UNBOUNDED_MAX; 097 this.chopAfter = Collections.EMPTY_SET; 098 this.chopBefore = Collections.EMPTY_SET; 099 this.refinement = refinement; 100 } 101 102 103 /** 104 * Creates a simple subtree whose administrative point above the base and 105 * all subordinates underneath the base (excluding those that are part of 106 * inner areas) are part of the the subtree. 107 * 108 * @param base 109 * the base of the subtree relative to the administrative point 110 */ 111 @SuppressWarnings("unchecked") 112 public BaseSubtreeSpecification( DN base ) 113 { 114 this.base = base; 115 this.minBaseDistance = 0; 116 this.maxBaseDistance = UNBOUNDED_MAX; 117 this.chopAfter = Collections.EMPTY_SET; 118 this.chopBefore = Collections.EMPTY_SET; 119 this.refinement = null; 120 } 121 122 123 /** 124 * Creates a subtree without a refinement filter where all other aspects can 125 * be varied. 126 * 127 * @param base 128 * the base of the subtree relative to the administrative point 129 * @param minBaseDistance 130 * the minimum distance below base to start including entries 131 * @param maxBaseDistance 132 * the maximum distance from base past which entries are excluded 133 * @param chopAfter 134 * the set of subordinates entries whose subordinates are to be 135 * excluded 136 * @param chopBefore 137 * the set of subordinates entries and their subordinates to 138 * exclude 139 */ 140 public BaseSubtreeSpecification( DN base, int minBaseDistance, int maxBaseDistance, 141 Set<DN> chopAfter, Set<DN> chopBefore ) 142 { 143 this( base, minBaseDistance, maxBaseDistance, chopAfter, chopBefore, null ); 144 } 145 146 147 /** 148 * Creates a subtree which may be a refinement filter where all aspects of 149 * the specification can be set. If the refinement filter is null this 150 * defaults to {@link #BaseSubtreeSpecification(DN, int, int, Set, Set)}. 151 * 152 * @param base 153 * the base of the subtree relative to the administrative point 154 * @param minBaseDistance 155 * the minimum distance below base to start including entries 156 * @param maxBaseDistance 157 * the maximum distance from base past which entries are excluded 158 * @param chopAfter 159 * the set of subordinates entries whose subordinates are to be 160 * excluded 161 * @param chopBefore 162 * the set of subordinates entries and their subordinates to 163 * exclude 164 * @param refinement 165 * the filter expression only composed of objectClass attribute 166 * value assertions 167 */ 168 public BaseSubtreeSpecification( DN base, int minBaseDistance, int maxBaseDistance, 169 Set<DN> chopAfter, Set<DN> chopBefore, ExprNode refinement ) 170 { 171 this.base = base; 172 this.minBaseDistance = minBaseDistance; 173 174 if ( maxBaseDistance < 0 ) 175 { 176 this.maxBaseDistance = UNBOUNDED_MAX; 177 } 178 else 179 { 180 this.maxBaseDistance = maxBaseDistance; 181 } 182 183 this.chopAfter = chopAfter; 184 this.chopBefore = chopBefore; 185 this.refinement = refinement; 186 } 187 188 189 // ----------------------------------------------------------------------- 190 // A C C E S S O R S 191 // ----------------------------------------------------------------------- 192 193 194 public DN getBase() 195 { 196 return this.base; 197 } 198 199 200 public Set<DN> getChopBeforeExclusions() 201 { 202 return this.chopBefore; 203 } 204 205 206 public Set<DN> getChopAfterExclusions() 207 { 208 return this.chopAfter; 209 } 210 211 212 public int getMinBaseDistance() 213 { 214 return this.minBaseDistance; 215 } 216 217 218 public int getMaxBaseDistance() 219 { 220 return this.maxBaseDistance; 221 } 222 223 224 public ExprNode getRefinement() 225 { 226 return this.refinement; 227 } 228 229 230 /** 231 * Converts this item into its string representation as stored 232 * in directory. 233 * 234 * @param buffer the string buffer 235 */ 236 public void printToBuffer( StringBuilder buffer ) 237 { 238 buffer.append( '{' ); 239 240 if(!base.isEmpty()) { 241 buffer.append( ' ' ); 242 buffer.append( "base" ); 243 buffer.append( ' ' ); 244 buffer.append( '"' ); 245 buffer.append( base.getName() ); 246 buffer.append( '"' ); 247 buffer.append( ',' ); 248 } 249 250 if(minBaseDistance > 0) { 251 buffer.append( ' ' ); 252 buffer.append( "minimum" ); 253 buffer.append( ' ' ); 254 buffer.append( minBaseDistance ); 255 buffer.append( ',' ); 256 } 257 258 if(maxBaseDistance > UNBOUNDED_MAX) { 259 buffer.append( ' ' ); 260 buffer.append( "maximum" ); 261 buffer.append( ' ' ); 262 buffer.append( maxBaseDistance ); 263 buffer.append( ',' ); 264 } 265 266 if ( !chopBefore.isEmpty() || !chopAfter.isEmpty() ) 267 { 268 buffer.append( ' ' ); 269 buffer.append( "specificExclusions" ); 270 buffer.append( ' ' ); 271 buffer.append( '{' ); 272 273 for ( Iterator<DN> it = chopBefore.iterator(); it.hasNext(); ) 274 { 275 DN dn = it.next(); 276 buffer.append( ' ' ); 277 buffer.append( "chopBefore" ); 278 buffer.append( ':' ); 279 buffer.append( ' ' ); 280 buffer.append( '"' ); 281 buffer.append( dn.getName() ); 282 buffer.append( '"' ); 283 284 if(it.hasNext()) 285 { 286 buffer.append( ',' ); 287 buffer.append( ' ' ); 288 } 289 } 290 291 if ( !chopBefore.isEmpty() && !chopAfter.isEmpty() ) 292 { 293 buffer.append( ',' ); 294 buffer.append( ' ' ); 295 } 296 297 for ( Iterator<DN> it = chopAfter.iterator(); it.hasNext(); ) 298 { 299 DN dn = it.next(); 300 buffer.append( ' ' ); 301 buffer.append( "chopAfter" ); 302 buffer.append( ':' ); 303 buffer.append( ' ' ); 304 buffer.append( '"' ); 305 buffer.append( dn.getName() ); 306 buffer.append( '"' ); 307 308 if(it.hasNext()) 309 { 310 buffer.append( ',' ); 311 buffer.append( ' ' ); 312 } 313 } 314 315 buffer.append( ' ' ); 316 buffer.append( '}' ); 317 318 buffer.append( ',' ); 319 } 320 321 if ( refinement != null ) 322 { 323 buffer.append( ' ' ); 324 buffer.append( "specificationFilter" ); 325 buffer.append( ' ' ); 326 327 // The ExprNode could represent both, a refinement 328 // or a filter. First we try to print the ExprNode 329 // as refinement. If that fails it is printed as 330 // LDAP filter. 331 try 332 { 333 // Must use a tempBuffer here because the 334 // exception could occur after some characters 335 // were added to the buffer. 336 StringBuilder tempBuffer = new StringBuilder(); 337 refinement.printRefinementToBuffer( tempBuffer ); 338 buffer.append( tempBuffer ); 339 } 340 catch ( UnsupportedOperationException e ) 341 { 342 buffer.append( refinement.toString() ); 343 } 344 345 buffer.append( ',' ); 346 } 347 348 if(buffer.charAt( buffer.length()-1 ) == ',') { 349 buffer.deleteCharAt( buffer.length()-1 ); 350 } 351 352 buffer.append( ' ' ); 353 buffer.append( '}' ); 354 } 355 356 357 }