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.LdapDN;
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: 664290 $
036 */
037 public class BaseSubtreeSpecification implements SubtreeSpecification
038 {
039 /** the subtree base relative to the administration point */
040 private final LdapDN base;
041
042 /** the set of subordinates entries and their subordinates to exclude */
043 private final Set<LdapDN> chopBefore;
044
045 /** the set of subordinates entries whose subordinates are to be excluded */
046 private final Set<LdapDN> 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 LdapDN();
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 LdapDN();
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( LdapDN 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( LdapDN base, int minBaseDistance, int maxBaseDistance,
141 Set<LdapDN> chopAfter, Set<LdapDN> 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(LdapDN, 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( LdapDN base, int minBaseDistance, int maxBaseDistance,
169 Set<LdapDN> chopAfter, Set<LdapDN> 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 LdapDN getBase()
195 {
196 return this.base;
197 }
198
199
200 public Set<LdapDN> getChopBeforeExclusions()
201 {
202 return this.chopBefore;
203 }
204
205
206 public Set<LdapDN> 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.getUpName() );
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<LdapDN> it = chopBefore.iterator(); it.hasNext(); )
274 {
275 LdapDN dn = it.next();
276 buffer.append( ' ' );
277 buffer.append( "chopBefore" );
278 buffer.append( ':' );
279 buffer.append( ' ' );
280 buffer.append( '"' );
281 buffer.append( dn.getUpName() );
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<LdapDN> it = chopAfter.iterator(); it.hasNext(); )
298 {
299 LdapDN dn = it.next();
300 buffer.append( ' ' );
301 buffer.append( "chopAfter" );
302 buffer.append( ':' );
303 buffer.append( ' ' );
304 buffer.append( '"' );
305 buffer.append( dn.getUpName() );
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 }