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