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