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 @Override 181 public Dn getBase() 182 { 183 return this.base; 184 } 185 186 187 /** 188 * @return The set of ChopBefore exclusions 189 */ 190 @Override 191 public Set<Dn> getChopBeforeExclusions() 192 { 193 return this.chopBefore; 194 } 195 196 197 /** 198 * @return The set of ChopAfter exclusions 199 */ 200 @Override 201 public Set<Dn> getChopAfterExclusions() 202 { 203 return this.chopAfter; 204 } 205 206 207 /** 208 * @return The mimimum distance from the base 209 */ 210 @Override 211 public int getMinBaseDistance() 212 { 213 return this.minBaseDistance; 214 } 215 216 217 /** 218 * @return The maximum distance from the base 219 */ 220 @Override 221 public int getMaxBaseDistance() 222 { 223 return this.maxBaseDistance; 224 } 225 226 227 /** 228 * @return The refinement 229 */ 230 @Override 231 public ExprNode getRefinement() 232 { 233 return this.refinement; 234 } 235 236 237 /** 238 * Converts this item into its string representation as stored 239 * in directory. 240 * 241 * @param buffer the string buffer 242 */ 243 @Override 244 public void toString( StringBuilder buffer ) 245 { 246 buffer.append( toString() ); 247 } 248 249 250 /** 251 * @see Object#toString() 252 */ 253 @Override 254 public String toString() 255 { 256 StringBuilder buffer = new StringBuilder(); 257 boolean isFirst = true; 258 buffer.append( '{' ); 259 260 // The base 261 if ( !base.isEmpty() ) 262 { 263 buffer.append( " base \"" ); 264 buffer.append( base.getName() ); 265 buffer.append( '"' ); 266 isFirst = false; 267 } 268 269 // The minimum 270 if ( minBaseDistance > 0 ) 271 { 272 if ( isFirst ) 273 { 274 isFirst = false; 275 buffer.append( " " ); 276 } 277 else 278 { 279 buffer.append( ", " ); 280 } 281 282 buffer.append( "minimum " ); 283 buffer.append( minBaseDistance ); 284 } 285 286 // The maximum 287 if ( maxBaseDistance > UNBOUNDED_MAX ) 288 { 289 if ( isFirst ) 290 { 291 isFirst = false; 292 buffer.append( " " ); 293 } 294 else 295 { 296 buffer.append( ", " ); 297 } 298 299 buffer.append( "maximum " ); 300 buffer.append( maxBaseDistance ); 301 } 302 303 // The chopBefore exclusions 304 if ( ( ( chopBefore != null ) && !chopBefore.isEmpty() ) || ( ( chopAfter != null ) && !chopAfter.isEmpty() ) ) 305 { 306 if ( isFirst ) 307 { 308 isFirst = false; 309 buffer.append( " " ); 310 } 311 else 312 { 313 buffer.append( ", " ); 314 } 315 316 buffer.append( "specificExclusions { " ); 317 318 boolean isFirstExclusion = true; 319 320 if ( chopBefore != null ) 321 { 322 for ( Dn exclusion : chopBefore ) 323 { 324 if ( isFirstExclusion ) 325 { 326 isFirstExclusion = false; 327 } 328 else 329 { 330 buffer.append( ", " ); 331 } 332 333 buffer.append( "chopBefore: \"" ); 334 buffer.append( exclusion.getName() ); 335 buffer.append( '"' ); 336 } 337 } 338 339 if ( chopAfter != null ) 340 { 341 for ( Dn exclusion : chopAfter ) 342 { 343 if ( isFirstExclusion ) 344 { 345 isFirstExclusion = false; 346 } 347 else 348 { 349 buffer.append( ", " ); 350 } 351 352 buffer.append( "chopAfter: \"" ); 353 buffer.append( exclusion.getName() ); 354 buffer.append( '"' ); 355 } 356 } 357 358 buffer.append( " }" ); 359 } 360 361 if ( refinement != null ) 362 { 363 if ( isFirst ) 364 { 365 buffer.append( " " ); 366 } 367 else 368 { 369 buffer.append( ", " ); 370 } 371 372 buffer.append( "specificationFilter " ); 373 buffer.append( refinement.toString() ); 374 } 375 376 buffer.append( " }" ); 377 378 return buffer.toString(); 379 } 380}