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