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