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