001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS.
026 */
027package org.opends.server.types;
028
029import java.util.Iterator;
030import java.util.LinkedHashMap;
031import java.util.LinkedHashSet;
032import java.util.List;
033import java.util.Map;
034import java.util.Set;
035
036import org.forgerock.i18n.slf4j.LocalizedLogger;
037
038import static org.forgerock.util.Reject.*;
039import static org.opends.server.util.ServerConstants.*;
040
041/**
042 * This class defines a DIT content rule, which defines the set of
043 * allowed, required, and prohibited attributes for entries with a
044 * given structural objectclass, and also indicates which auxiliary
045 * classes that may be included in the entry.
046 */
047@org.opends.server.types.PublicAPI(
048     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
049     mayInstantiate=false,
050     mayExtend=false,
051     mayInvoke=true)
052public final class DITContentRule
053       implements SchemaFileElement
054{
055  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
056
057  /** Indicates whether this content rule is declared "obsolete". */
058  private final boolean isObsolete;
059
060  /**
061   * The set of additional name-value pairs associated with this
062   * content rule definition.
063   */
064  private final Map<String,List<String>> extraProperties;
065
066  /**
067   * The set of names for this DIT content rule, in a mapping between
068   * the all-lowercase form and the user-defined form.
069   */
070  private final Map<String,String> names;
071
072  /** The structural objectclass for this DIT content rule. */
073  private final ObjectClass structuralClass;
074
075  /**
076   * The set of auxiliary objectclasses that entries with this content
077   * rule may contain, in a mapping between the objectclass and the
078   * user-defined name for that class.
079   */
080  private final Set<ObjectClass> auxiliaryClasses;
081
082  /** The set of optional attribute types for this DIT content rule. */
083  private final Set<AttributeType> optionalAttributes;
084
085  /** The set of prohibited attribute types for this DIT content rule. */
086  private final Set<AttributeType> prohibitedAttributes;
087
088  /** The set of required attribute types for this DIT content rule. */
089  private final Set<AttributeType> requiredAttributes;
090
091  /** The definition string used to create this DIT content rule. */
092  private final String definition;
093
094  /** The description for this DIT content rule. */
095  private final String description;
096
097
098
099  /**
100   * Creates a new DIT content rule definition with the provided
101   * information.
102   *
103   * @param  definition            The definition string used to
104   *                               create this DIT content rule.  It
105   *                               must not be {@code null}.
106   * @param  structuralClass       The structural objectclass for this
107   *                               DIT content rule.  It must not be
108   *                               {@code null}.
109   * @param  names                 The set of names that may be used
110   *                               to reference this DIT content rule.
111   * @param  description           The description for this DIT
112   *                               content rule.
113   * @param  auxiliaryClasses      The set of auxiliary classes for
114   *                               this DIT content rule
115   * @param  requiredAttributes    The set of required attribute types
116   *                               for this DIT content rule.
117   * @param  optionalAttributes    The set of optional attribute types
118   *                               for this DIT content rule.
119   * @param  prohibitedAttributes  The set of prohibited attribute
120   *                               types for this DIT content rule.
121   * @param  isObsolete            Indicates whether this DIT content
122   *                               rule is declared "obsolete".
123   * @param  extraProperties       A set of extra properties for this
124   *                               DIT content rule.
125   */
126  public DITContentRule(String definition,
127                        ObjectClass structuralClass,
128                        Map<String,String> names, String description,
129                        Set<ObjectClass> auxiliaryClasses,
130                        Set<AttributeType> requiredAttributes,
131                        Set<AttributeType> optionalAttributes,
132                        Set<AttributeType> prohibitedAttributes,
133                        boolean isObsolete,
134                        Map<String,List<String>> extraProperties)
135  {
136    ifNull(definition, structuralClass);
137
138    this.structuralClass = structuralClass;
139    this.description     = description;
140    this.isObsolete      = isObsolete;
141
142    int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME);
143    if (schemaFilePos > 0)
144    {
145      String defStr;
146      try
147      {
148        int firstQuotePos = definition.indexOf('\'', schemaFilePos);
149        int secondQuotePos = definition.indexOf('\'',
150                                                firstQuotePos+1);
151
152        defStr = definition.substring(0, schemaFilePos).trim() + " " +
153                 definition.substring(secondQuotePos+1).trim();
154      }
155      catch (Exception e)
156      {
157        logger.traceException(e);
158
159        defStr = definition;
160      }
161
162      this.definition = defStr;
163    }
164    else
165    {
166      this.definition = definition;
167    }
168
169    if (names == null || names.isEmpty())
170    {
171      this.names = new LinkedHashMap<>(0);
172    }
173    else
174    {
175      this.names = new LinkedHashMap<>(names);
176    }
177
178    if (auxiliaryClasses == null || auxiliaryClasses.isEmpty())
179    {
180      this.auxiliaryClasses = new LinkedHashSet<>(0);
181    }
182    else
183    {
184      this.auxiliaryClasses = new LinkedHashSet<>(auxiliaryClasses);
185    }
186
187    if (requiredAttributes == null || requiredAttributes.isEmpty())
188    {
189      this.requiredAttributes = new LinkedHashSet<>(0);
190    }
191    else
192    {
193      this.requiredAttributes = new LinkedHashSet<>(requiredAttributes);
194    }
195
196    if (optionalAttributes == null || optionalAttributes.isEmpty())
197    {
198      this.optionalAttributes = new LinkedHashSet<>(0);
199    }
200    else
201    {
202      this.optionalAttributes = new LinkedHashSet<>(optionalAttributes);
203    }
204
205    if (prohibitedAttributes == null || prohibitedAttributes.isEmpty())
206    {
207      this.prohibitedAttributes = new LinkedHashSet<>(0);
208    }
209    else
210    {
211      this.prohibitedAttributes = new LinkedHashSet<>(prohibitedAttributes);
212    }
213
214    if (extraProperties == null || extraProperties.isEmpty())
215    {
216      this.extraProperties = new LinkedHashMap<>(0);
217    }
218    else
219    {
220      this.extraProperties = new LinkedHashMap<>(extraProperties);
221    }
222  }
223
224
225
226  /**
227   * Retrieves the structural objectclass for this DIT content rule.
228   *
229   * @return  The structural objectclass for this DIT content rule.
230   */
231  public ObjectClass getStructuralClass()
232  {
233    return structuralClass;
234  }
235
236
237
238  /**
239   * Retrieves the set of names that may be used to reference this DIT
240   * content rule.  The returned object will be a mapping between each
241   * name in all lowercase characters and that name in a user-defined
242   * form (which may include mixed capitalization).
243   *
244   * @return  The set of names that may be used to reference this DIT
245   *          content rule.
246   */
247  public Map<String,String> getNames()
248  {
249    return names;
250  }
251
252
253
254  /**
255   * Retrieves the primary name to use to reference this DIT content
256   * rule.
257   *
258   * @return  The primary name to use to reference this DIT content
259   *          rule, or {@code null} if there is none.
260   */
261  public String getNameOrOID()
262  {
263    if (names.isEmpty())
264    {
265      return null;
266    }
267    else
268    {
269      return names.values().iterator().next();
270    }
271  }
272
273
274
275  /**
276   * Indicates whether the provided lowercase name may be used to
277   * reference this DIT content rule.
278   *
279   * @param  lowerName  The name for which to make the determination,
280   *                    in all lowercase characters.
281   *
282   * @return  {@code true} if the provided lowercase name may be used
283   *          to reference this DIT content rule, or {@code false} if
284   *          not.
285   */
286  public boolean hasName(String lowerName)
287  {
288    return names.containsKey(lowerName);
289  }
290
291
292
293  /**
294   * Retrieves the set of auxiliary objectclasses that may be used for
295   * entries associated with this DIT content rule.
296   *
297   * @return  The set of auxiliary objectclasses that may be used for
298   *          entries associated with this DIT content rule.
299   */
300  public Set<ObjectClass> getAuxiliaryClasses()
301  {
302    return auxiliaryClasses;
303  }
304
305
306
307  /**
308   * Retrieves the set of required attributes for this DIT content
309   * rule.
310   *
311   * @return  The set of required attributes for this DIT content
312   *          rule.
313   */
314  public Set<AttributeType> getRequiredAttributes()
315  {
316    return requiredAttributes;
317  }
318
319
320
321  /**
322   * Indicates whether the provided attribute type is included in the
323   * required attribute list for this DIT content rule.
324   *
325   * @param  attributeType  The attribute type for which to make the
326   *                        determination.
327   *
328   * @return  {@code true} if the provided attribute type is required
329   *          by this DIT content rule, or {@code false} if not.
330   */
331  public boolean isRequired(AttributeType attributeType)
332  {
333    return requiredAttributes.contains(attributeType);
334  }
335
336
337
338  /**
339   * Retrieves the set of optional attributes for this DIT content
340   * rule.
341   *
342   * @return  The set of optional attributes for this DIT content
343   *          rule.
344   */
345  public Set<AttributeType> getOptionalAttributes()
346  {
347    return optionalAttributes;
348  }
349
350
351
352  /**
353   * Indicates whether the provided attribute type is included in the
354   * optional attribute list for this DIT content rule.
355   *
356   * @param  attributeType  The attribute type for which to make the
357   *                        determination.
358   *
359   * @return  {@code true} if the provided attribute type is optional
360   *          for this DIT content rule, or {@code false} if not.
361   */
362  public boolean isOptional(AttributeType attributeType)
363  {
364    return optionalAttributes.contains(attributeType);
365  }
366
367
368
369  /**
370   * Indicates whether the provided attribute type is in the list of
371   * required or optional attributes for this DIT content rule.
372   *
373   * @param  attributeType  The attribute type for which to make the
374   *                        determination.
375   *
376   * @return  {@code true} if the provided attribute type is required
377   *          or allowed for this DIT content rule, or {@code false}
378   *          if it is not.
379   */
380  public boolean isRequiredOrOptional(AttributeType attributeType)
381  {
382    return requiredAttributes.contains(attributeType) ||
383            optionalAttributes.contains(attributeType);
384  }
385
386
387
388  /**
389   * Retrieves the set of prohibited attributes for this DIT content
390   * rule.
391   *
392   * @return  The set of prohibited attributes for this DIT content
393   *          rule.
394   */
395  public Set<AttributeType> getProhibitedAttributes()
396  {
397    return prohibitedAttributes;
398  }
399
400
401  /**
402   * Indicates whether this DIT content rule is declared "obsolete".
403   *
404   * @return  {@code true} if this DIT content rule is declared
405   *          "obsolete", or {@code false} if it is not.
406   */
407  public boolean isObsolete()
408  {
409    return isObsolete;
410  }
411
412
413
414  /**
415   * Retrieves a mapping between the names of any extra non-standard
416   * properties that may be associated with this DIT content rule and
417   * the value for that property.
418   *
419   * @return  A mapping between the names of any extra non-standard
420   *          properties that may be associated with this DIT content
421   *          rule and the value for that property.
422   */
423  @Override
424  public Map<String,List<String>> getExtraProperties()
425  {
426    return extraProperties;
427  }
428
429
430
431  /**
432   * Indicates whether the provided object is equal to this DIT
433   * content rule.  The object will be considered equal if it is a DIT
434   * content rule for the same structural objectclass and the same
435   * sets of names.  For performance reasons, the set of auxiliary
436   * classes, and the sets of required, optional, and prohibited
437   * attribute types will not be checked, so that should be done
438   * manually if a more thorough equality comparison is required.
439   *
440   * @param  o  The object for which to make the determination.
441   *
442   * @return  {@code true} if the provided object is equal to
443   *          this DIT content rule, or {@code false} if not.
444   */
445  @Override
446  public boolean equals(Object o)
447  {
448    if (this == o)
449    {
450      return true;
451    }
452    if (!(o instanceof DITContentRule))
453    {
454      return false;
455    }
456
457    DITContentRule dcr = (DITContentRule) o;
458    if (!structuralClass.equals(dcr.structuralClass))
459    {
460      return false;
461    }
462
463    if (names.size() != dcr.names.size())
464    {
465      return false;
466    }
467
468    Iterator<String> iterator = names.keySet().iterator();
469    while (iterator.hasNext())
470    {
471      if (! dcr.names.containsKey(iterator.next()))
472      {
473        return false;
474      }
475    }
476
477    return true;
478  }
479
480
481
482  /**
483   * Retrieves the hash code for this DIT content rule.  It will be
484   * equal to the hash code for the associated structural objectclass.
485   *
486   * @return  The hash code for this DIT content rule.
487   */
488  @Override
489  public int hashCode()
490  {
491    return structuralClass.hashCode();
492  }
493
494
495
496  /**
497   * Retrieves the string representation of this DIT content rule in
498   * the form specified in RFC 2252.
499   *
500   * @return  The string representation of this DIT content rule in
501   *          the form specified in RFC 2252.
502   */
503  @Override
504  public String toString()
505  {
506    return definition;
507  }
508
509}