001/*
002 * Copyright 2007-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-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) 2007-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.schema;
037
038
039
040import java.util.ArrayList;
041import java.util.Collection;
042import java.util.Collections;
043import java.util.Map;
044import java.util.LinkedHashMap;
045
046import com.unboundid.ldap.sdk.LDAPException;
047import com.unboundid.ldap.sdk.ResultCode;
048import com.unboundid.util.NotMutable;
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
056import static com.unboundid.ldap.sdk.schema.SchemaMessages.*;
057
058
059
060/**
061 * This class provides a data structure that describes an LDAP DIT content rule
062 * schema element.
063 */
064@NotMutable()
065@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
066public final class DITContentRuleDefinition
067       extends SchemaElement
068{
069  /**
070   * The serial version UID for this serializable class.
071   */
072  private static final long serialVersionUID = 3224440505307817586L;
073
074
075
076  // Indicates whether this DIT content rule is declared obsolete.
077  private final boolean isObsolete;
078
079  // The set of extensions for this DIT content rule.
080  @NotNull private final Map<String,String[]> extensions;
081
082  // The description for this DIT content rule.
083  @Nullable private final String description;
084
085  // The string representation of this DIT content rule.
086  @NotNull private final String ditContentRuleString;
087
088  // The OID of the structural object class with which this DIT content rule is
089  // associated.
090  @NotNull private final String oid;
091
092  // The names/OIDs of the allowed auxiliary classes.
093  @NotNull private final String[] auxiliaryClasses;
094
095  // The set of names for this DIT content rule.
096  @NotNull private final String[] names;
097
098  // The names/OIDs of the optional attributes.
099  @NotNull private final String[] optionalAttributes;
100
101  // The names/OIDs of the prohibited attributes.
102  @NotNull private final String[] prohibitedAttributes;
103
104  // The names/OIDs of the required attributes.
105  @NotNull private final String[] requiredAttributes;
106
107
108
109  /**
110   * Creates a new DIT content rule from the provided string representation.
111   *
112   * @param  s  The string representation of the DIT content rule to create,
113   *            using the syntax described in RFC 4512 section 4.1.6.  It must
114   *            not be {@code null}.
115   *
116   * @throws  LDAPException  If the provided string cannot be decoded as a DIT
117   *                         content rule definition.
118   */
119  public DITContentRuleDefinition(@NotNull final String s)
120         throws LDAPException
121  {
122    Validator.ensureNotNull(s);
123
124    ditContentRuleString = s.trim();
125
126    // The first character must be an opening parenthesis.
127    final int length = ditContentRuleString.length();
128    if (length == 0)
129    {
130      throw new LDAPException(ResultCode.DECODING_ERROR,
131                              ERR_DCR_DECODE_EMPTY.get());
132    }
133    else if (ditContentRuleString.charAt(0) != '(')
134    {
135      throw new LDAPException(ResultCode.DECODING_ERROR,
136                              ERR_DCR_DECODE_NO_OPENING_PAREN.get(
137                                   ditContentRuleString));
138    }
139
140
141    // Skip over any spaces until we reach the start of the OID, then read the
142    // OID until we find the next space.
143    int pos = skipSpaces(ditContentRuleString, 1, length);
144
145    StringBuilder buffer = new StringBuilder();
146    pos = readOID(ditContentRuleString, pos, length, buffer);
147    oid = buffer.toString();
148
149
150    // Technically, DIT content elements are supposed to appear in a specific
151    // order, but we'll be lenient and allow remaining elements to come in any
152    // order.
153    final ArrayList<String> nameList = new ArrayList<>(5);
154    final ArrayList<String> reqAttrs = new ArrayList<>(10);
155    final ArrayList<String> optAttrs = new ArrayList<>(10);
156    final ArrayList<String> notAttrs = new ArrayList<>(10);
157    final ArrayList<String> auxOCs = new ArrayList<>(10);
158    final Map<String,String[]> exts =
159         new LinkedHashMap<>(StaticUtils.computeMapCapacity(5));
160    Boolean obsolete = null;
161    String descr = null;
162
163    while (true)
164    {
165      // Skip over any spaces until we find the next element.
166      pos = skipSpaces(ditContentRuleString, pos, length);
167
168      // Read until we find the next space or the end of the string.  Use that
169      // token to figure out what to do next.
170      final int tokenStartPos = pos;
171      while ((pos < length) && (ditContentRuleString.charAt(pos) != ' '))
172      {
173        pos++;
174      }
175
176      // It's possible that the token could be smashed right up against the
177      // closing parenthesis.  If that's the case, then extract just the token
178      // and handle the closing parenthesis the next time through.
179      String token = ditContentRuleString.substring(tokenStartPos, pos);
180      if ((token.length() > 1) && (token.endsWith(")")))
181      {
182        token = token.substring(0, token.length() - 1);
183        pos--;
184      }
185
186      final String lowerToken = StaticUtils.toLowerCase(token);
187      if (lowerToken.equals(")"))
188      {
189        // This indicates that we're at the end of the value.  There should not
190        // be any more closing characters.
191        if (pos < length)
192        {
193          throw new LDAPException(ResultCode.DECODING_ERROR,
194                                  ERR_DCR_DECODE_CLOSE_NOT_AT_END.get(
195                                       ditContentRuleString));
196        }
197        break;
198      }
199      else if (lowerToken.equals("name"))
200      {
201        if (nameList.isEmpty())
202        {
203          pos = skipSpaces(ditContentRuleString, pos, length);
204          pos = readQDStrings(ditContentRuleString, pos, length, token,
205               nameList);
206        }
207        else
208        {
209          throw new LDAPException(ResultCode.DECODING_ERROR,
210                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
211                                       ditContentRuleString, "NAME"));
212        }
213      }
214      else if (lowerToken.equals("desc"))
215      {
216        if (descr == null)
217        {
218          pos = skipSpaces(ditContentRuleString, pos, length);
219
220          buffer = new StringBuilder();
221          pos = readQDString(ditContentRuleString, pos, length, token, buffer);
222          descr = buffer.toString();
223        }
224        else
225        {
226          throw new LDAPException(ResultCode.DECODING_ERROR,
227                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
228                                       ditContentRuleString, "DESC"));
229        }
230      }
231      else if (lowerToken.equals("obsolete"))
232      {
233        if (obsolete == null)
234        {
235          obsolete = true;
236        }
237        else
238        {
239          throw new LDAPException(ResultCode.DECODING_ERROR,
240                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
241                                       ditContentRuleString, "OBSOLETE"));
242        }
243      }
244      else if (lowerToken.equals("aux"))
245      {
246        if (auxOCs.isEmpty())
247        {
248          pos = skipSpaces(ditContentRuleString, pos, length);
249          pos = readOIDs(ditContentRuleString, pos, length, token, auxOCs);
250        }
251        else
252        {
253          throw new LDAPException(ResultCode.DECODING_ERROR,
254                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
255                                       ditContentRuleString, "AUX"));
256        }
257      }
258      else if (lowerToken.equals("must"))
259      {
260        if (reqAttrs.isEmpty())
261        {
262          pos = skipSpaces(ditContentRuleString, pos, length);
263          pos = readOIDs(ditContentRuleString, pos, length, token, reqAttrs);
264        }
265        else
266        {
267          throw new LDAPException(ResultCode.DECODING_ERROR,
268                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
269                                       ditContentRuleString, "MUST"));
270        }
271      }
272      else if (lowerToken.equals("may"))
273      {
274        if (optAttrs.isEmpty())
275        {
276          pos = skipSpaces(ditContentRuleString, pos, length);
277          pos = readOIDs(ditContentRuleString, pos, length, token, optAttrs);
278        }
279        else
280        {
281          throw new LDAPException(ResultCode.DECODING_ERROR,
282                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
283                                       ditContentRuleString, "MAY"));
284        }
285      }
286      else if (lowerToken.equals("not"))
287      {
288        if (notAttrs.isEmpty())
289        {
290          pos = skipSpaces(ditContentRuleString, pos, length);
291          pos = readOIDs(ditContentRuleString, pos, length, token, notAttrs);
292        }
293        else
294        {
295          throw new LDAPException(ResultCode.DECODING_ERROR,
296                                  ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get(
297                                       ditContentRuleString, "NOT"));
298        }
299      }
300      else if (lowerToken.startsWith("x-"))
301      {
302        pos = skipSpaces(ditContentRuleString, pos, length);
303
304        final ArrayList<String> valueList = new ArrayList<>(5);
305        pos = readQDStrings(ditContentRuleString, pos, length, token,
306             valueList);
307
308        final String[] values = new String[valueList.size()];
309        valueList.toArray(values);
310
311        if (exts.containsKey(token))
312        {
313          throw new LDAPException(ResultCode.DECODING_ERROR,
314                                  ERR_DCR_DECODE_DUP_EXT.get(
315                                       ditContentRuleString, token));
316        }
317
318        exts.put(token, values);
319      }
320      else
321      {
322        throw new LDAPException(ResultCode.DECODING_ERROR,
323                                ERR_DCR_DECODE_DUP_EXT.get(
324                                     ditContentRuleString, token));
325      }
326    }
327
328    description = descr;
329
330    names = new String[nameList.size()];
331    nameList.toArray(names);
332
333    auxiliaryClasses = new String[auxOCs.size()];
334    auxOCs.toArray(auxiliaryClasses);
335
336    requiredAttributes = new String[reqAttrs.size()];
337    reqAttrs.toArray(requiredAttributes);
338
339    optionalAttributes = new String[optAttrs.size()];
340    optAttrs.toArray(optionalAttributes);
341
342    prohibitedAttributes = new String[notAttrs.size()];
343    notAttrs.toArray(prohibitedAttributes);
344
345    isObsolete = (obsolete != null);
346
347    extensions = Collections.unmodifiableMap(exts);
348  }
349
350
351
352  /**
353   * Creates a new DIT content rule with the provided information.
354   *
355   * @param  oid                   The OID for the structural object class with
356   *                               which this DIT content rule is associated.
357   *                               It must not be {@code null}.
358   * @param  name                  The name for this DIT content rule.  It may
359   *                               be {@code null} if the DIT content rule
360   *                               should only be referenced by OID.
361   * @param  description           The description for this DIT content rule.
362   *                               It may be {@code null} if there is no
363   *                               description.
364   * @param  auxiliaryClasses      The names/OIDs of the auxiliary object
365   *                               classes that may be present in entries
366   *                               containing this DIT content rule.
367   * @param  requiredAttributes    The names/OIDs of the attributes which must
368   *                               be present in entries containing this DIT
369   *                               content rule.
370   * @param  optionalAttributes    The names/OIDs of the attributes which may be
371   *                               present in entries containing this DIT
372   *                               content rule.
373   * @param  prohibitedAttributes  The names/OIDs of the attributes which may
374   *                               not be present in entries containing this DIT
375   *                               content rule.
376   * @param  extensions            The set of extensions for this DIT content
377   *                               rule.  It may be {@code null} or empty if
378   *                               there should not be any extensions.
379   */
380  public DITContentRuleDefinition(@NotNull final String oid,
381              @Nullable final String name,
382              @Nullable final String description,
383              @Nullable final String[] auxiliaryClasses,
384              @Nullable final String[] requiredAttributes,
385              @Nullable final String[] optionalAttributes,
386              @Nullable final String[] prohibitedAttributes,
387              @Nullable final Map<String,String[]> extensions)
388  {
389    this(oid, ((name == null) ? null : new String[] { name }), description,
390         false, auxiliaryClasses, requiredAttributes, optionalAttributes,
391         prohibitedAttributes, extensions);
392  }
393
394
395
396  /**
397   * Creates a new DIT content rule with the provided information.
398   *
399   * @param  oid                   The OID for the structural object class with
400   *                               which this DIT content rule is associated.
401   *                               It must not be {@code null}.
402   * @param  name                  The name for this DIT content rule.  It may
403   *                               be {@code null} if the DIT content rule
404   *                               should only be referenced by OID.
405   * @param  description           The description for this DIT content rule.
406   *                               It may be {@code null} if there is no
407   *                               description.
408   * @param  auxiliaryClasses      The names/OIDs of the auxiliary object
409   *                               classes that may be present in entries
410   *                               containing this DIT content rule.
411   * @param  requiredAttributes    The names/OIDs of the attributes which must
412   *                               be present in entries containing this DIT
413   *                               content rule.
414   * @param  optionalAttributes    The names/OIDs of the attributes which may be
415   *                               present in entries containing this DIT
416   *                               content rule.
417   * @param  prohibitedAttributes  The names/OIDs of the attributes which may
418   *                               not be present in entries containing this DIT
419   *                               content rule.
420   * @param  extensions            The set of extensions for this DIT content
421   *                               rule.  It may be {@code null} or empty if
422   *                               there should not be any extensions.
423   */
424  public DITContentRuleDefinition(@NotNull final String oid,
425              @Nullable final String name,
426              @Nullable final String description,
427              @Nullable final Collection<String> auxiliaryClasses,
428              @Nullable final Collection<String> requiredAttributes,
429              @Nullable final Collection<String> optionalAttributes,
430              @Nullable final Collection<String> prohibitedAttributes,
431              @Nullable final Map<String,String[]> extensions)
432  {
433    this(oid, ((name == null) ? null : new String[] { name }), description,
434         false, toArray(auxiliaryClasses), toArray(requiredAttributes),
435         toArray(optionalAttributes), toArray(prohibitedAttributes),
436         extensions);
437  }
438
439
440
441  /**
442   * Creates a new DIT content rule with the provided information.
443   *
444   * @param  oid                   The OID for the structural object class with
445   *                               which this DIT content rule is associated.
446   *                               It must not be {@code null}.
447   * @param  names                 The set of names for this DIT content rule.
448   *                               It may be {@code null} or empty if the DIT
449   *                               content rule should only be referenced by
450   *                               OID.
451   * @param  description           The description for this DIT content rule.
452   *                               It may be {@code null} if there is no
453   *                               description.
454   * @param  isObsolete            Indicates whether this DIT content rule is
455   *                               declared obsolete.
456   * @param  auxiliaryClasses      The names/OIDs of the auxiliary object
457   *                               classes that may be present in entries
458   *                               containing this DIT content rule.
459   * @param  requiredAttributes    The names/OIDs of the attributes which must
460   *                               be present in entries containing this DIT
461   *                               content rule.
462   * @param  optionalAttributes    The names/OIDs of the attributes which may be
463   *                               present in entries containing this DIT
464   *                               content rule.
465   * @param  prohibitedAttributes  The names/OIDs of the attributes which may
466   *                               not be present in entries containing this DIT
467   *                               content rule.
468   * @param  extensions            The set of extensions for this DIT content
469   *                               rule.  It may be {@code null} or empty if
470   *                               there should not be any extensions.
471   */
472  public DITContentRuleDefinition(@NotNull final String oid,
473              @Nullable final String[] names,
474              @Nullable final String description,
475              final boolean isObsolete,
476              @Nullable final String[] auxiliaryClasses,
477              @Nullable final String[] requiredAttributes,
478              @Nullable final String[] optionalAttributes,
479              @Nullable final String[] prohibitedAttributes,
480              @Nullable final Map<String,String[]> extensions)
481  {
482    Validator.ensureNotNull(oid);
483
484    this.oid             = oid;
485    this.isObsolete      = isObsolete;
486    this.description     = description;
487
488    if (names == null)
489    {
490      this.names = StaticUtils.NO_STRINGS;
491    }
492    else
493    {
494      this.names = names;
495    }
496
497    if (auxiliaryClasses == null)
498    {
499      this.auxiliaryClasses = StaticUtils.NO_STRINGS;
500    }
501    else
502    {
503      this.auxiliaryClasses  = auxiliaryClasses;
504    }
505
506    if (requiredAttributes == null)
507    {
508      this.requiredAttributes = StaticUtils.NO_STRINGS;
509    }
510    else
511    {
512      this.requiredAttributes = requiredAttributes;
513    }
514
515    if (optionalAttributes == null)
516    {
517      this.optionalAttributes = StaticUtils.NO_STRINGS;
518    }
519    else
520    {
521      this.optionalAttributes = optionalAttributes;
522    }
523
524    if (prohibitedAttributes == null)
525    {
526      this.prohibitedAttributes = StaticUtils.NO_STRINGS;
527    }
528    else
529    {
530      this.prohibitedAttributes = prohibitedAttributes;
531    }
532
533    if (extensions == null)
534    {
535      this.extensions = Collections.emptyMap();
536    }
537    else
538    {
539      this.extensions = Collections.unmodifiableMap(extensions);
540    }
541
542    final StringBuilder buffer = new StringBuilder();
543    createDefinitionString(buffer);
544    ditContentRuleString = buffer.toString();
545  }
546
547
548
549  /**
550   * Constructs a string representation of this DIT content rule definition in
551   * the provided buffer.
552   *
553   * @param  buffer  The buffer in which to construct a string representation of
554   *                 this DIT content rule definition.
555   */
556  private void createDefinitionString(@NotNull final StringBuilder buffer)
557  {
558    buffer.append("( ");
559    buffer.append(oid);
560
561    if (names.length == 1)
562    {
563      buffer.append(" NAME '");
564      buffer.append(names[0]);
565      buffer.append('\'');
566    }
567    else if (names.length > 1)
568    {
569      buffer.append(" NAME (");
570      for (final String name : names)
571      {
572        buffer.append(" '");
573        buffer.append(name);
574        buffer.append('\'');
575      }
576      buffer.append(" )");
577    }
578
579    if (description != null)
580    {
581      buffer.append(" DESC '");
582      encodeValue(description, buffer);
583      buffer.append('\'');
584    }
585
586    if (isObsolete)
587    {
588      buffer.append(" OBSOLETE");
589    }
590
591    if (auxiliaryClasses.length == 1)
592    {
593      buffer.append(" AUX ");
594      buffer.append(auxiliaryClasses[0]);
595    }
596    else if (auxiliaryClasses.length > 1)
597    {
598      buffer.append(" AUX (");
599      for (int i=0; i < auxiliaryClasses.length; i++)
600      {
601        if (i >0)
602        {
603          buffer.append(" $ ");
604        }
605        else
606        {
607          buffer.append(' ');
608        }
609        buffer.append(auxiliaryClasses[i]);
610      }
611      buffer.append(" )");
612    }
613
614    if (requiredAttributes.length == 1)
615    {
616      buffer.append(" MUST ");
617      buffer.append(requiredAttributes[0]);
618    }
619    else if (requiredAttributes.length > 1)
620    {
621      buffer.append(" MUST (");
622      for (int i=0; i < requiredAttributes.length; i++)
623      {
624        if (i >0)
625        {
626          buffer.append(" $ ");
627        }
628        else
629        {
630          buffer.append(' ');
631        }
632        buffer.append(requiredAttributes[i]);
633      }
634      buffer.append(" )");
635    }
636
637    if (optionalAttributes.length == 1)
638    {
639      buffer.append(" MAY ");
640      buffer.append(optionalAttributes[0]);
641    }
642    else if (optionalAttributes.length > 1)
643    {
644      buffer.append(" MAY (");
645      for (int i=0; i < optionalAttributes.length; i++)
646      {
647        if (i > 0)
648        {
649          buffer.append(" $ ");
650        }
651        else
652        {
653          buffer.append(' ');
654        }
655        buffer.append(optionalAttributes[i]);
656      }
657      buffer.append(" )");
658    }
659
660    if (prohibitedAttributes.length == 1)
661    {
662      buffer.append(" NOT ");
663      buffer.append(prohibitedAttributes[0]);
664    }
665    else if (prohibitedAttributes.length > 1)
666    {
667      buffer.append(" NOT (");
668      for (int i=0; i < prohibitedAttributes.length; i++)
669      {
670        if (i > 0)
671        {
672          buffer.append(" $ ");
673        }
674        else
675        {
676          buffer.append(' ');
677        }
678        buffer.append(prohibitedAttributes[i]);
679      }
680      buffer.append(" )");
681    }
682
683    for (final Map.Entry<String,String[]> e : extensions.entrySet())
684    {
685      final String   name   = e.getKey();
686      final String[] values = e.getValue();
687      if (values.length == 1)
688      {
689        buffer.append(' ');
690        buffer.append(name);
691        buffer.append(" '");
692        encodeValue(values[0], buffer);
693        buffer.append('\'');
694      }
695      else
696      {
697        buffer.append(' ');
698        buffer.append(name);
699        buffer.append(" (");
700        for (final String value : values)
701        {
702          buffer.append(" '");
703          encodeValue(value, buffer);
704          buffer.append('\'');
705        }
706        buffer.append(" )");
707      }
708    }
709
710    buffer.append(" )");
711  }
712
713
714
715  /**
716   * Retrieves the OID for the structural object class associated with this
717   * DIT content rule.
718   *
719   * @return  The OID for the structural object class associated with this DIT
720   *          content rule.
721   */
722  @NotNull()
723  public String getOID()
724  {
725    return oid;
726  }
727
728
729
730  /**
731   * Retrieves the set of names for this DIT content rule.
732   *
733   * @return  The set of names for this DIT content rule, or an empty array if
734   *          it does not have any names.
735   */
736  @NotNull()
737  public String[] getNames()
738  {
739    return names;
740  }
741
742
743
744  /**
745   * Retrieves the primary name that can be used to reference this DIT content
746   * rule.  If one or more names are defined, then the first name will be used.
747   * Otherwise, the structural object class OID will be returned.
748   *
749   * @return  The primary name that can be used to reference this DIT content
750   *          rule.
751   */
752  @NotNull()
753  public String getNameOrOID()
754  {
755    if (names.length == 0)
756    {
757      return oid;
758    }
759    else
760    {
761      return names[0];
762    }
763  }
764
765
766
767  /**
768   * Indicates whether the provided string matches the OID or any of the names
769   * for this DIT content rule.
770   *
771   * @param  s  The string for which to make the determination.  It must not be
772   *            {@code null}.
773   *
774   * @return  {@code true} if the provided string matches the OID or any of the
775   *          names for this DIT content rule, or {@code false} if not.
776   */
777  public boolean hasNameOrOID(@NotNull final String s)
778  {
779    for (final String name : names)
780    {
781      if (s.equalsIgnoreCase(name))
782      {
783        return true;
784      }
785    }
786
787    return s.equalsIgnoreCase(oid);
788  }
789
790
791
792  /**
793   * Retrieves the description for this DIT content rule, if available.
794   *
795   * @return  The description for this DIT content rule, or {@code null} if
796   *          there is no description defined.
797   */
798  @Nullable()
799  public String getDescription()
800  {
801    return description;
802  }
803
804
805
806  /**
807   * Indicates whether this DIT content rule is declared obsolete.
808   *
809   * @return  {@code true} if this DIT content rule is declared obsolete, or
810   *          {@code false} if it is not.
811   */
812  public boolean isObsolete()
813  {
814    return isObsolete;
815  }
816
817
818
819  /**
820   * Retrieves the names or OIDs of the auxiliary object classes that may be
821   * present in entries containing the structural class for this DIT content
822   * rule.
823   *
824   * @return  The names or OIDs of the auxiliary object classes that may be
825   *          present in entries containing the structural class for this DIT
826   *          content rule.
827   */
828  @NotNull()
829  public String[] getAuxiliaryClasses()
830  {
831    return auxiliaryClasses;
832  }
833
834
835
836  /**
837   * Retrieves the names or OIDs of the attributes that are required to be
838   * present in entries containing the structural object class for this DIT
839   * content rule.
840   *
841   * @return  The names or OIDs of the attributes that are required to be
842   *          present in entries containing the structural object class for this
843   *          DIT content rule, or an empty array if there are no required
844   *          attributes.
845   */
846  @NotNull()
847  public String[] getRequiredAttributes()
848  {
849    return requiredAttributes;
850  }
851
852
853
854  /**
855   * Retrieves the names or OIDs of the attributes that are optionally allowed
856   * to be present in entries containing the structural object class for this
857   * DIT content rule.
858   *
859   * @return  The names or OIDs of the attributes that are optionally allowed to
860   *          be present in entries containing the structural object class for
861   *          this DIT content rule, or an empty array if there are no required
862   *          attributes.
863   */
864  @NotNull()
865  public String[] getOptionalAttributes()
866  {
867    return optionalAttributes;
868  }
869
870
871
872  /**
873   * Retrieves the names or OIDs of the attributes that are not allowed to be
874   * present in entries containing the structural object class for this DIT
875   * content rule.
876   *
877   * @return  The names or OIDs of the attributes that are not allowed to be
878   *          present in entries containing the structural object class for this
879   *          DIT content rule, or an empty array if there are no required
880   *          attributes.
881   */
882  @NotNull()
883  public String[] getProhibitedAttributes()
884  {
885    return prohibitedAttributes;
886  }
887
888
889
890  /**
891   * Retrieves the set of extensions for this DIT content rule.  They will be
892   * mapped from the extension name (which should start with "X-") to the set of
893   * values for that extension.
894   *
895   * @return  The set of extensions for this DIT content rule.
896   */
897  @NotNull()
898  public Map<String,String[]> getExtensions()
899  {
900    return extensions;
901  }
902
903
904
905  /**
906   * {@inheritDoc}
907   */
908  @Override()
909  @NotNull()
910  public SchemaElementType getSchemaElementType()
911  {
912    return SchemaElementType.DIT_CONTENT_RULE;
913  }
914
915
916
917  /**
918   * {@inheritDoc}
919   */
920  @Override()
921  public int hashCode()
922  {
923    return oid.hashCode();
924  }
925
926
927
928  /**
929   * {@inheritDoc}
930   */
931  @Override()
932  public boolean equals(@Nullable final Object o)
933  {
934    if (o == null)
935    {
936      return false;
937    }
938
939    if (o == this)
940    {
941      return true;
942    }
943
944    if (! (o instanceof DITContentRuleDefinition))
945    {
946      return false;
947    }
948
949    final DITContentRuleDefinition d = (DITContentRuleDefinition) o;
950    return (oid.equals(d.oid) &&
951         StaticUtils.stringsEqualIgnoreCaseOrderIndependent(names, d.names) &&
952         StaticUtils.stringsEqualIgnoreCaseOrderIndependent(auxiliaryClasses,
953              d.auxiliaryClasses) &&
954         StaticUtils.stringsEqualIgnoreCaseOrderIndependent(requiredAttributes,
955              d.requiredAttributes) &&
956         StaticUtils.stringsEqualIgnoreCaseOrderIndependent(optionalAttributes,
957              d.optionalAttributes) &&
958         StaticUtils.stringsEqualIgnoreCaseOrderIndependent(
959              prohibitedAttributes, d.prohibitedAttributes) &&
960         StaticUtils.bothNullOrEqualIgnoreCase(description, d.description) &&
961         (isObsolete == d.isObsolete) &&
962         extensionsEqual(extensions, d.extensions));
963  }
964
965
966
967  /**
968   * Retrieves a string representation of this DIT content rule definition, in
969   * the format described in RFC 4512 section 4.1.6.
970   *
971   * @return  A string representation of this DIT content rule definition.
972   */
973  @Override()
974  @NotNull()
975  public String toString()
976  {
977    return ditContentRuleString;
978  }
979}