001/*
002 * Copyright 2017-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2017-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2017-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.controls;
037
038
039
040import java.io.Serializable;
041import java.util.Collection;
042import java.util.Collections;
043import java.util.Iterator;
044import java.util.LinkedHashSet;
045import java.util.Set;
046
047import com.unboundid.ldap.sdk.Filter;
048import com.unboundid.util.Mutable;
049import com.unboundid.util.NotNull;
050import com.unboundid.util.Nullable;
051import com.unboundid.util.StaticUtils;
052import com.unboundid.util.ThreadSafety;
053import com.unboundid.util.ThreadSafetyLevel;
054import com.unboundid.util.Validator;
055
056
057
058/**
059 * This class provides a data structure that holds a set of properties for use
060 * in conjunction with the {@link UniquenessRequestControl}.
061 * <BR>
062 * <BLOCKQUOTE>
063 *   <B>NOTE:</B>  This class, and other classes within the
064 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
065 *   supported for use against Ping Identity, UnboundID, and
066 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
067 *   for proprietary functionality or for external specifications that are not
068 *   considered stable or mature enough to be guaranteed to work in an
069 *   interoperable way with other types of LDAP servers.
070 * </BLOCKQUOTE>
071 * <BR>
072 * The control must be created with either a set of attribute types or a filter
073 * (or both).  See the {@link UniquenessRequestControl} class-level
074 * documentation for details about how the server will behave if either or both
075 * of these values are provided.
076 * <BR><BR>
077 * The following default values will be used for properties that are not
078 * specified:
079 * <UL>
080 *   <LI>
081 *     An empty set of attribute types.
082 *   </LI>
083 *   <LI>
084 *     A multiple attribute behavior of
085 *     {@link UniquenessMultipleAttributeBehavior#UNIQUE_WITHIN_EACH_ATTRIBUTE}.
086 *   </LI>
087 *   <LI>
088 *     No base DN.
089 *   </LI>
090 *   <LI>
091 *     No filter.
092 *   </LI>
093 *   <LI>
094 *     The control will not prevent conflicts with soft-deleted entries.
095 *   </LI>
096 *   <LI>
097 *     A pre-commit validation level of
098 *     {@link UniquenessValidationLevel#ALL_SUBTREE_VIEWS}.
099 *   </LI>
100 *   <LI>
101 *     A post-commit validation level of
102 *     {@link UniquenessValidationLevel#ALL_SUBTREE_VIEWS}.
103 *   </LI>
104 *   <LI>
105 *     Do alert on conflicts detected during post-commit validation.
106 *   </LI>
107 *   <LI>
108 *     Do not create a conflict prevention details entry.
109 *   </LI>
110 * </UL>
111 */
112@Mutable()
113@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
114public final class UniquenessRequestControlProperties
115       implements Serializable
116{
117  /**
118   * The serial version UID for this serializable class.
119   */
120  private static final long serialVersionUID = 4330352906527176309L;
121
122
123
124  // Indicates whether the server should raise an administrative alert if a
125  // conflict is detected during post-commit validation.
126  private boolean alertOnPostCommitConflictDetection = true;
127
128  // Indicates whether the server should create a conflict prevention details
129  // entry before pre-commit validation as a means of helping to avoid
130  // conflicts.
131  private boolean createConflictPreventionDetailsEntry = false;
132
133  // Indicates whether to prevent conflicts with soft-deleted entries.
134  private boolean preventConflictsWithSoftDeletedEntries = false;
135
136  // An optional filter that should be used in the course of identifying
137  // uniqueness conflicts.
138  @Nullable private Filter filter = null;
139
140  // A potentially-empty set of attribute types that should be checked for
141  // uniqueness conflicts.
142  @NotNull private Set<String> attributeTypes = Collections.emptySet();
143
144  // An optional base DN to use when checking for conflicts.
145  @Nullable private String baseDN = null;
146
147  // The behavior that the server should exhibit if multiple attribute types
148  // are configured.
149  @NotNull private
150       UniquenessMultipleAttributeBehavior multipleAttributeBehavior =
151            UniquenessMultipleAttributeBehavior.UNIQUE_WITHIN_EACH_ATTRIBUTE;
152
153  // The level of validation that the server should perform before processing
154  // the associated change.
155  @NotNull private UniquenessValidationLevel postCommitValidationLevel =
156       UniquenessValidationLevel.ALL_SUBTREE_VIEWS;
157
158  // The level of validation that the server should perform after processing the
159  // associated change.
160  @NotNull private UniquenessValidationLevel preCommitValidationLevel =
161       UniquenessValidationLevel.ALL_SUBTREE_VIEWS;
162
163
164
165  /**
166   * Creates a new instance of this uniqueness request control properties object
167   * with no attribute types and all default values.  This is primarily intended
168   * for supporting deserialization, since it will not include any .
169   */
170  private UniquenessRequestControlProperties()
171  {
172    // No implementation is required.
173  }
174
175
176
177  /**
178   * Creates a new instance of this uniqueness request control properties object
179   * with the provided set of attribute types and default values for all other
180   * properties as specified in the class-level javadoc documentation.
181   *
182   * @param  attributeTypes  The set of attribute types that the server will
183   *                         check for uniqueness conflicts.  It must not be
184   *                         {@code null} or empty.  The server should be
185   *                         configured with equality indexes for each of these
186   *                         attribute types.
187   */
188  public UniquenessRequestControlProperties(
189              @NotNull final String... attributeTypes)
190  {
191    this();
192
193    Validator.ensureTrue(
194         ((attributeTypes != null) && (attributeTypes.length > 0)),
195         "The set of attribute types must not be null or empty.");
196    this.attributeTypes = Collections.unmodifiableSet(new LinkedHashSet<>(
197         StaticUtils.toList(attributeTypes)));
198  }
199
200
201
202  /**
203   * Creates a new instance of this uniqueness request control properties object
204   * with the provided set of attribute types and default values for all other
205   * properties as specified in the class-level javadoc documentation.
206   *
207   * @param  attributeTypes  The set of attribute types that the server will
208   *                         check for uniqueness conflicts.  It must not be
209   *                         {@code null} or empty.  The server should be
210   *                         configured with equality indexes for each of these
211   *                         attribute types.
212   */
213  public UniquenessRequestControlProperties(
214              @NotNull final Collection<String> attributeTypes)
215  {
216    this();
217
218    Validator.ensureTrue(
219         ((attributeTypes != null) && (! attributeTypes.isEmpty())),
220         "The set of attribute types must not be null or empty.");
221    this.attributeTypes =
222         Collections.unmodifiableSet(new LinkedHashSet<>(attributeTypes));
223  }
224
225
226
227  /**
228   * Creates a new instance of this uniqueness request control properties object
229   * with the provided filter and default values for all other properties as
230   * specified in the class-level javadoc documentation.
231   *
232   * @param  filter  The filter that the server will use to check for uniqueness
233   *                 conflicts.  It must not be {@code null}.
234   */
235  public UniquenessRequestControlProperties(@NotNull final Filter filter)
236  {
237    this();
238
239    Validator.ensureNotNull(filter);
240    this.filter = filter;
241  }
242
243
244
245  /**
246   * Retrieves the set of attribute types that the server will check for
247   * uniqueness conflicts.
248   *
249   * @return  The set of attribute types that the server will check for
250   *          uniqueness conflicts, or an empty set if only a filter should be
251   *          used to identify conflicts.
252   */
253  @NotNull()
254  public Set<String> getAttributeTypes()
255  {
256    return attributeTypes;
257  }
258
259
260
261  /**
262   * Specifies the set of attribute types that the server will check for
263   * uniqueness conflicts.
264   *
265   * @param  attributeTypes  The set of attribute types that the server will
266   *                         check for uniqueness conflicts.  It must not be
267   *                         {@code null} or empty if no filter is configured.
268   *                         It may optionally be {@code null} or empty if
269   *                         a filter is provided.  The server should be
270   *                         configured with an equality index for each of the
271   *                         provided attribute types.
272   */
273  public void setAttributeTypes(@Nullable final String... attributeTypes)
274  {
275    if (attributeTypes == null)
276    {
277      this.attributeTypes = Collections.emptySet();
278    }
279    else
280    {
281      this.attributeTypes = Collections.unmodifiableSet(new LinkedHashSet<>(
282           StaticUtils.toList(attributeTypes)));
283    }
284  }
285
286
287
288  /**
289   * Specifies the set of attribute types that the server will check for
290   * uniqueness conflicts.
291   *
292   * @param  attributeTypes  The set of attribute types that the server will
293   *                         check for uniqueness conflicts.  It must not be
294   *                         {@code null} or empty if no filter is configured.
295   *                         It may optionally be {@code null} or empty if
296   *                         a filter is provided.  The server should be
297   *                         configured with an equality index for each of the
298   *                         provided attribute types.
299   */
300  public void setAttributeTypes(
301                   @Nullable final Collection<String> attributeTypes)
302  {
303    if (attributeTypes == null)
304    {
305      this.attributeTypes = Collections.emptySet();
306    }
307    else
308    {
309      this.attributeTypes =
310           Collections.unmodifiableSet(new LinkedHashSet<>(attributeTypes));
311    }
312  }
313
314
315
316  /**
317   * Retrieves the behavior that the server should exhibit if multiple attribute
318   * types are configured.
319   *
320   * @return  The behavior that the server should exhibit if multiple attribute
321   *          types are configured.
322   */
323  @NotNull()
324  public UniquenessMultipleAttributeBehavior getMultipleAttributeBehavior()
325  {
326    return multipleAttributeBehavior;
327  }
328
329
330
331  /**
332   * Specifies the behavior that the server should exhibit if multiple attribute
333   * types are configured.
334   *
335   * @param  multipleAttributeBehavior  The behavior that the server should
336   *                                    exhibit if multiple attribute types are
337   *                                    configured.  This must not be
338   *                                    {@code null}.
339   */
340  public void setMultipleAttributeBehavior(
341       @NotNull
342       final UniquenessMultipleAttributeBehavior multipleAttributeBehavior)
343  {
344    Validator.ensureNotNull(multipleAttributeBehavior);
345    this.multipleAttributeBehavior = multipleAttributeBehavior;
346  }
347
348
349
350  /**
351   * Retrieves the base DN that will be used for searches used to identify
352   * uniqueness conflicts, if defined.
353   *
354   * @return  The base DN that will be used for searches used to identify
355   *          uniqueness conflicts, or {@code null} if the server should search
356   *          below all public naming contexts.
357   */
358  @Nullable()
359  public String getBaseDN()
360  {
361    return baseDN;
362  }
363
364
365
366  /**
367   * Specifies the base DN that will be used for searches used to identify
368   * uniqueness conflicts.
369   *
370   * @param  baseDN  The base DN that will be used for searches used to identify
371   *                 uniqueness conflicts.  It may be {@code null} to indicate
372   *                 that the server should search below all public naming
373   *                 contexts.
374   */
375  public void setBaseDN(@Nullable final String baseDN)
376  {
377    this.baseDN = baseDN;
378  }
379
380
381
382  /**
383   * Retrieves a filter that will be used to identify uniqueness conflicts, if
384   * defined.
385   *
386   * @return  A filter that will be used to identify uniqueness conflicts, or
387   *          {@code null} if no filter has been defined.
388   */
389  @Nullable()
390  public Filter getFilter()
391  {
392    return filter;
393  }
394
395
396
397  /**
398   * Specifies a filter that will be used to identify uniqueness conflicts.
399   *
400   * @param  filter  A filter that will be used to identify uniqueness
401   *                 conflicts.  It must not be {@code null} if no set of
402   *                 attribute types has been configured.  It may optionally be
403   *                 {@code null} if a set of attribute types has been
404   *                 configured.  If no attribute types are provided, then this
405   *                 filter should be indexed within the server.
406   */
407  public void setFilter(@Nullable final Filter filter)
408  {
409    this.filter = filter;
410  }
411
412
413
414  /**
415   * Indicates whether the server should attempt to identify conflicts with
416   * soft-deleted entries.
417   *
418   * @return  {@code true} if the server should identify conflicts with both
419   *          regular entries and soft-deleted entries, or {@code false} if the
420   *          server should only identify conflicts with regular entries.
421   */
422  public boolean preventConflictsWithSoftDeletedEntries()
423  {
424    return preventConflictsWithSoftDeletedEntries;
425  }
426
427
428
429  /**
430   * Specifies whether the server should attempt to identify conflicts with
431   * soft-deleted entries.
432   *
433   * @param  preventConflictsWithSoftDeletedEntries  Indicates whether the
434   *                                                 server should attempt to
435   *                                                 identify conflicts with
436   *                                                 soft-deleted entries.
437   */
438  public void setPreventConflictsWithSoftDeletedEntries(
439                   final boolean preventConflictsWithSoftDeletedEntries)
440  {
441    this.preventConflictsWithSoftDeletedEntries =
442         preventConflictsWithSoftDeletedEntries;
443  }
444
445
446
447  /**
448   * Retrieves the pre-commit validation level, which will be used to identify
449   * any conflicts before the associated request is processed.
450   *
451   * @return  The pre-commit validation level.
452   */
453  @NotNull()
454  public UniquenessValidationLevel getPreCommitValidationLevel()
455  {
456    return preCommitValidationLevel;
457  }
458
459
460
461  /**
462   * Specifies the pre-commit validation level, which will be used to identify
463   * any conflicts before the associated request is processed.
464   *
465   * @param  preCommitValidationLevel  The pre-commit validation level.  It must
466   *                                   not be {@code null}.
467   */
468  public void setPreCommitValidationLevel(
469       @NotNull final UniquenessValidationLevel preCommitValidationLevel)
470  {
471    Validator.ensureNotNull(preCommitValidationLevel);
472    this.preCommitValidationLevel = preCommitValidationLevel;
473  }
474
475
476
477  /**
478   * Retrieves the post-commit validation level, which will be used to identify
479   * any conflicts that were introduced by the request with which the control is
480   * associated, or by some other concurrent changed processed in the server.
481   *
482   * @return  The post-commit validation level.
483   */
484  @NotNull()
485  public UniquenessValidationLevel getPostCommitValidationLevel()
486  {
487    return postCommitValidationLevel;
488  }
489
490
491
492  /**
493   * Specifies the post-commit validation level, which will be used to identify
494   * any conflicts that were introduced by the request with which the control is
495   * associated, or by some other concurrent changed processed in the server.
496   *
497   * @param  postCommitValidationLevel  The post-commit validation level.  It
498   *                                    must not be {@code null}.
499   */
500  public void setPostCommitValidationLevel(
501       @NotNull final UniquenessValidationLevel postCommitValidationLevel)
502  {
503    Validator.ensureNotNull(postCommitValidationLevel);
504    this.postCommitValidationLevel = postCommitValidationLevel;
505  }
506
507
508
509  /**
510   * Indicates whether the server should raise an administrative alert if a
511   * conflict is detected during post-commit validation processing.
512   *
513   * @return  {@code true} if the server should raise an administrative alert if
514   *          a conflict is detected during post-commit validation processing,
515   *          or {@code false} if not.
516   */
517  public boolean alertOnPostCommitConflictDetection()
518  {
519    return alertOnPostCommitConflictDetection;
520  }
521
522
523
524  /**
525   * Specifies whether the server should raise an administrative alert if a
526   * conflict is detected during post-commit validation processing.
527   *
528   * @param  alertOnPostCommitConflictDetection  Indicates whether the server
529   *                                             should raise an administrative
530   *                                             alert if a conflict is detected
531   *                                             during post-commit validation
532   *                                             processing.
533   */
534  public void setAlertOnPostCommitConflictDetection(
535                   final boolean alertOnPostCommitConflictDetection)
536  {
537    this.alertOnPostCommitConflictDetection =
538         alertOnPostCommitConflictDetection;
539  }
540
541
542
543  /**
544   * Indicates whether the server should create a temporary conflict prevention
545   * details entry before beginning pre-commit validation to provide better
546   * support for preventing conflicts.  If created, the entry will be removed
547   * after post-commit validation processing has completed.
548   *
549   * @return  {@code true} if the server should create a temporary conflict
550   *          prevention details entry before beginning pre-commit validation,
551   *          or {@code false} if not.
552   */
553  public boolean createConflictPreventionDetailsEntry()
554  {
555    return createConflictPreventionDetailsEntry;
556  }
557
558
559
560  /**
561   * Specifies whether the server should create a temporary conflict prevention
562   * details entry before beginning pre-commit validation to provide better
563   * support for preventing conflicts.  If created, the entry will be removed
564   * after post-commit validation processing has completed.
565   *
566   * @param  createConflictPreventionDetailsEntry  Indicates whether the server
567   *                                               should create a temporary
568   *                                               conflict prevention details
569   *                                               entry before beginning
570   *                                               pre-commit validation.
571   */
572  public void setCreateConflictPreventionDetailsEntry(
573                   final boolean createConflictPreventionDetailsEntry)
574  {
575    this.createConflictPreventionDetailsEntry =
576         createConflictPreventionDetailsEntry;
577  }
578
579
580
581  /**
582   * Retrieves a string representation of this uniqueness request control
583   * properties object.
584   *
585   * @return  A string representation of this uniqueness request control
586   *          properties object.
587   */
588  @Override()
589  @NotNull()
590  public String toString()
591  {
592    final StringBuilder buffer = new StringBuilder();
593    toString(buffer);
594    return buffer.toString();
595  }
596
597
598
599  /**
600   * Appends a string representation of this uniqueness request control
601   * properties object to the provided buffer.
602   *
603   * @param  buffer  The buffer to which the information should be appended.
604   */
605  public void toString(@NotNull final StringBuilder buffer)
606  {
607    buffer.append("UniquenessRequestControlProperties(attributeTypes={");
608
609    final Iterator<String> attributeTypesIterator = attributeTypes.iterator();
610    while (attributeTypesIterator.hasNext())
611    {
612      buffer.append('\'');
613      buffer.append(attributeTypesIterator.next());
614      buffer.append('\'');
615
616      if (attributeTypesIterator.hasNext())
617      {
618        buffer.append(", ");
619      }
620    }
621
622    buffer.append("}, multipleAttributeBehavior=");
623    buffer.append(multipleAttributeBehavior);
624
625    if (baseDN != null)
626    {
627      buffer.append(", baseDN='");
628      buffer.append(baseDN);
629      buffer.append('\'');
630    }
631
632    if (filter != null)
633    {
634      buffer.append(", filter='");
635      buffer.append(filter);
636      buffer.append('\'');
637    }
638
639    buffer.append(", preventConflictsWithSoftDeletedEntries=");
640    buffer.append(preventConflictsWithSoftDeletedEntries);
641    buffer.append(", preCommitValidationLevel=");
642    buffer.append(preCommitValidationLevel);
643    buffer.append(", postCommitValidationLevel=");
644    buffer.append(postCommitValidationLevel);
645    buffer.append(", alertOnPostCommitConflictDetection=");
646    buffer.append(alertOnPostCommitConflictDetection);
647    buffer.append(", createConflictPreventionDetailsEntry=");
648    buffer.append(createConflictPreventionDetailsEntry);
649    buffer.append(')');
650  }
651}