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-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027package org.opends.server.types;
028
029import java.util.Collection;
030import java.util.List;
031import java.util.Map;
032
033import org.forgerock.i18n.slf4j.LocalizedLogger;
034import org.forgerock.opendj.ldap.schema.AttributeUsage;
035import org.forgerock.opendj.ldap.schema.Syntax;
036import org.forgerock.opendj.ldap.schema.MatchingRule;
037import org.opends.server.core.DirectoryServer;
038
039import static org.forgerock.util.Reject.*;
040import static org.opends.server.util.ServerConstants.*;
041
042/**
043 * This class defines a data structure for storing and interacting
044 * with an attribute type, which contains information about the format
045 * of an attribute and the syntax and matching rules that should be
046 * used when interacting with it.
047 * <p>
048 * Any methods which accesses the set of names associated with this
049 * attribute type, will retrieve the primary name as the first name,
050 * regardless of whether or not it was contained in the original set
051 * of <code>names</code> passed to the constructor.
052 * <p>
053 * Where ordered sets of names, or extra properties are provided, the
054 * ordering will be preserved when the associated fields are accessed
055 * via their getters or via the {@link #toString()} methods.
056 */
057@org.opends.server.types.PublicAPI(
058     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
059     mayInstantiate=false,
060     mayExtend=false,
061     mayInvoke=true)
062public final class AttributeType
063       extends CommonSchemaElements
064       implements Comparable<AttributeType>
065{
066  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
067
068  /** The approximate matching rule for this attribute type. */
069  private final MatchingRule approximateMatchingRule;
070
071  /** The syntax for this attribute type. */
072  private final Syntax syntax;
073
074  /** The superior attribute type from which this attribute type inherits. */
075  private final AttributeType superiorType;
076
077  /** The attribute usage for this attribute type. */
078  private final AttributeUsage attributeUsage;
079
080  /** Indicates whether this attribute type is declared "collective". */
081  private final boolean isCollective;
082
083  /**
084   * Indicates whether this attribute type is declared
085   * "no-user-modification".
086   */
087  private final boolean isNoUserModification;
088
089  /** Indicates whether this attribute type is the objectclass type. */
090  private final boolean isObjectClassType;
091
092  /** Indicates whether this attribute type is operational. */
093  private final boolean isOperational;
094
095  /** Indicates whether this attribute type is declared "single-value". */
096  private final boolean isSingleValue;
097
098  /**
099   * Indicates whether there is a possibility that this attribute type
100   * may have one or more subtypes that list this type or one of its
101   * subtypes as a superior.  Note that this variable is intentional
102   * not declared "final", but if it ever gets set to "true", then it
103   * should never be unset back to "false".
104   */
105  private boolean mayHaveSubordinateTypes;
106  /** The definition string used to create this attribute type. */
107  private final String definition;
108
109  /** The equality matching rule for this attribute type. */
110  private final MatchingRule equalityMatchingRule;
111  /** The ordering matching rule for this attribute type. */
112  private final MatchingRule orderingMatchingRule;
113  /** The substring matching rule for this attribute type. */
114  private final MatchingRule substringMatchingRule;
115
116  /** True once this attribute type has been removed from the schema. */
117  private volatile boolean isDirty;
118
119
120
121  /**
122   * Creates a new attribute type with the provided information.
123   * <p>
124   * If no <code>primaryName</code> is specified, but a set of
125   * <code>names</code> is specified, then the first name retrieved
126   * from the set of <code>names</code> will be used as the primary
127   * name.
128   *
129   * @param definition
130   *          The definition string used to create this attribute
131   *          type.  It must not be {@code null}.
132   * @param primaryName
133   *          The primary name for this attribute type, or
134   *          <code>null</code> if there is no primary name.
135   * @param typeNames
136   *          The full set of names for this attribute type, or
137   *          <code>null</code> if there are no names.
138   * @param oid
139   *          The OID for this attribute type.  It must not be
140   *          {@code null}.
141   * @param description
142   *          The description for the attribute type, or
143   *          <code>null</code> if there is no description.
144   * @param superiorType
145   *          The reference to the superior type for this attribute
146   *          type, or <code>null</code> if there is no superior
147   *          type.
148   * @param syntax
149   *          The syntax for this attribute type, or <code>null</code>
150   *          if there is no syntax.
151   * @param attributeUsage
152   *          The attribute usage for this attribute type, or
153   *          <code>null</code> to default to user applications.
154   * @param isCollective
155   *          Indicates whether this attribute type is declared
156   *          "collective".
157   * @param isNoUserModification
158   *          Indicates whether this attribute type is declared
159   *          "no-user-modification".
160   * @param isObsolete
161   *          Indicates whether this attribute type is declared
162   *          "obsolete".
163   * @param isSingleValue
164   *          Indicates whether this attribute type is declared
165   *          "single-value".
166   */
167  public AttributeType(String definition, String primaryName,
168                       Collection<String> typeNames,
169                       String oid, String description,
170                       AttributeType superiorType,
171                       Syntax syntax,
172                       AttributeUsage attributeUsage,
173                       boolean isCollective,
174                       boolean isNoUserModification,
175                       boolean isObsolete, boolean isSingleValue)
176  {
177    this(definition, primaryName, typeNames, oid, description,
178        superiorType, syntax, null, null, null,
179        null, attributeUsage, isCollective,
180        isNoUserModification, isObsolete, isSingleValue, null);
181  }
182
183
184
185  /**
186   * Creates a new attribute type with the provided information.
187   * <p>
188   * If no <code>primaryName</code> is specified, but a set of
189   * <code>names</code> is specified, then the first name retrieved
190   * from the set of <code>names</code> will be used as the primary
191   * name.
192   *
193   * @param definition
194   *          The definition string used to create this attribute
195   *          type.  It must not be {@code null}.
196   * @param primaryName
197   *          The primary name for this attribute type, or
198   *          <code>null</code> if there is no primary name.
199   * @param typeNames
200   *          The full set of names for this attribute type, or
201   *          <code>null</code> if there are no names.
202   * @param oid
203   *          The OID for this attribute type.  It must not be
204   *          {@code null}.
205   * @param description
206   *          The description for the attribute type, or
207   *          <code>null</code> if there is no description.
208   * @param superiorType
209   *          The reference to the superior type for this attribute
210   *          type, or <code>null</code> if there is no superior
211   *          type.
212   * @param syntax
213   *          The syntax for this attribute type, or <code>null</code>
214   *          if there is no syntax.
215   * @param approximateMatchingRule
216   *          The approximate matching rule for this attribute type,
217   *          or <code>null</code> if there is no rule.
218   * @param equalityMatchingRule
219   *          The equality matching rule for this attribute type, or
220   *          <code>null</code> if there is no rule.
221   * @param orderingMatchingRule
222   *          The ordering matching rule for this attribute type, or
223   *          <code>null</code> if there is no rule.
224   * @param substringMatchingRule
225   *          The substring matching rule for this attribute type, or
226   *          <code>null</code> if there is no rule.
227   * @param attributeUsage
228   *          The attribute usage for this attribute type, or
229   *          <code>null</code> to default to user applications.
230   * @param isCollective
231   *          Indicates whether this attribute type is declared
232   *          "collective".
233   * @param isNoUserModification
234   *          Indicates whether this attribute type is declared
235   *          "no-user-modification".
236   * @param isObsolete
237   *          Indicates whether this attribute type is declared
238   *          "obsolete".
239   * @param isSingleValue
240   *          Indicates whether this attribute type is declared
241   *          "single-value".
242   * @param extraProperties
243   *          A set of extra properties for this attribute type, or
244   *          <code>null</code> if there are no extra properties.
245   */
246  public AttributeType(String definition, String primaryName,
247                       Collection<String> typeNames,
248                       String oid, String description,
249                       AttributeType superiorType,
250                       Syntax syntax,
251                       MatchingRule approximateMatchingRule,
252                       MatchingRule equalityMatchingRule,
253                       MatchingRule orderingMatchingRule,
254                       MatchingRule substringMatchingRule,
255                       AttributeUsage attributeUsage,
256                       boolean isCollective,
257                       boolean isNoUserModification,
258                       boolean isObsolete, boolean isSingleValue,
259                       Map<String,List<String>> extraProperties)
260  {
261    super(primaryName, typeNames, oid, description, isObsolete,
262        extraProperties);
263
264
265    ifNull(definition, oid);
266
267    this.superiorType = superiorType;
268    this.isCollective = isCollective;
269    this.isNoUserModification = isNoUserModification;
270    this.isSingleValue = isSingleValue;
271
272    mayHaveSubordinateTypes = false;
273
274    int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME);
275    if (schemaFilePos > 0)
276    {
277      String defStr;
278      try
279      {
280        int firstQuotePos = definition.indexOf('\'', schemaFilePos);
281        int secondQuotePos = definition.indexOf('\'',
282                                                firstQuotePos+1);
283
284        defStr = definition.substring(0, schemaFilePos).trim() + " " +
285                 definition.substring(secondQuotePos+1).trim();
286      }
287      catch (Exception e)
288      {
289        logger.traceException(e);
290
291        defStr = definition;
292      }
293
294      this.definition = defStr;
295    }
296    else
297    {
298      this.definition = definition;
299    }
300
301    if (syntax == null)
302    {
303      if (superiorType != null)
304      {
305        this.syntax = superiorType.getSyntax();
306      }
307      else
308      {
309        this.syntax = DirectoryServer.getDefaultAttributeSyntax();
310      }
311    }
312    else
313    {
314      this.syntax = syntax;
315    }
316
317    if (approximateMatchingRule == null)
318    {
319      this.approximateMatchingRule =
320             this.syntax.getApproximateMatchingRule();
321    }
322    else
323    {
324      this.approximateMatchingRule = approximateMatchingRule;
325    }
326
327
328    if (equalityMatchingRule == null)
329    {
330      this.equalityMatchingRule =
331        this.syntax.getEqualityMatchingRule();
332    }
333    else
334    {
335      this.equalityMatchingRule = equalityMatchingRule;
336    }
337
338
339    if (orderingMatchingRule == null)
340    {
341      this.orderingMatchingRule =
342        this.syntax.getOrderingMatchingRule();
343    }
344    else
345    {
346      this.orderingMatchingRule = orderingMatchingRule;
347    }
348
349
350    if (substringMatchingRule == null)
351    {
352      this.substringMatchingRule =
353        this.syntax.getSubstringMatchingRule();
354    }
355    else
356    {
357      this.substringMatchingRule = substringMatchingRule;
358    }
359
360    if (attributeUsage != null)
361    {
362      this.attributeUsage = attributeUsage;
363    }
364    else
365    {
366      this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
367    }
368
369    if (oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID))
370    {
371      isObjectClassType = true;
372    }
373    else
374    {
375      isObjectClassType = hasName(OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
376    }
377
378    isOperational = this.attributeUsage.isOperational();
379  }
380
381
382
383  /**
384   * Retrieves the superior type for this attribute type.
385   *
386   * @return  The superior type for this attribute type, or
387   *          <CODE>null</CODE> if it does not have one.
388   */
389  public AttributeType getSuperiorType()
390  {
391    return superiorType;
392  }
393
394
395
396  /**
397   * Indicates whether there is a possibility that this attribute type
398   * may have one or more subordinate attribute types defined in the
399   * server schema.  This is only intended for use by the
400   * {@code org.opends.server.types.Entry} class for the purpose of
401   * determining whether to check for subtypes when retrieving
402   * attributes.  Note that it is possible for this method to report
403   * false positives (if an attribute type that previously had one or
404   * more subordinate types no longer has any), but not false
405   * negatives.
406   *
407   * @return  {@code true} if the {@code hasSubordinateTypes} flag has
408   *          been set for this attribute type at any time since
409   *          startup, or {@code false} if not.
410   */
411  boolean mayHaveSubordinateTypes()
412  {
413    return mayHaveSubordinateTypes;
414  }
415
416
417
418  /**
419   * Sets a flag indicating that this attribute type may have one or
420   * more subordinate attribute types defined in the server schema.
421   * This is only intended for use by the
422   * {@code org.opends.server.types.Schema} class.
423   */
424  void setMayHaveSubordinateTypes()
425  {
426    mayHaveSubordinateTypes = true;
427  }
428
429
430
431  /**
432   * Retrieves the syntax for this attribute type.
433   *
434   * @return  The syntax for this attribute type.
435   */
436  public Syntax getSyntax()
437  {
438    return syntax;
439  }
440
441  /**
442   * Retrieves the matching rule that should be used for approximate
443   * matching with this attribute type.
444   *
445   * @return  The matching rule that should be used for approximate
446   *          matching with this attribute type.
447   */
448  public MatchingRule getApproximateMatchingRule()
449  {
450    return approximateMatchingRule;
451  }
452
453
454
455  /**
456   * Retrieves the matching rule that should be used for equality
457   * matching with this attribute type.
458   *
459   * @return  The matching rule that should be used for equality
460   *          matching with this attribute type.
461   */
462  public MatchingRule getEqualityMatchingRule()
463  {
464    return equalityMatchingRule;
465  }
466
467
468
469  /**
470   * Retrieves the matching rule that should be used for ordering with
471   * this attribute type.
472   *
473   * @return  The matching rule that should be used for ordering with
474   *          this attribute type.
475   */
476  public MatchingRule getOrderingMatchingRule()
477  {
478    return orderingMatchingRule;
479  }
480
481
482
483  /**
484   * Retrieves the matching rule that should be used for substring
485   * matching with this attribute type.
486   *
487   * @return  The matching rule that should be used for substring
488   *          matching with this attribute type.
489   */
490  public MatchingRule getSubstringMatchingRule()
491  {
492    return substringMatchingRule;
493  }
494
495
496
497  /**
498   * Retrieves the usage indicator for this attribute type.
499   *
500   * @return  The usage indicator for this attribute type.
501   */
502  public AttributeUsage getUsage()
503  {
504    return attributeUsage;
505  }
506
507
508
509  /**
510   * Indicates whether this is an operational attribute.  An
511   * operational attribute is one with a usage of
512   * "directoryOperation", "distributedOperation", or "dSAOperation"
513   * (i.e., only userApplications is not operational).
514   *
515   * @return  <CODE>true</CODE> if this is an operational attribute,
516   *          or <CODE>false</CODE> if not.
517   */
518  public boolean isOperational()
519  {
520    return isOperational;
521  }
522
523
524
525  /**
526   * Indicates whether this attribute type is declared "collective".
527   *
528   * @return  <CODE>true</CODE> if this attribute type is declared
529   * "collective", or <CODE>false</CODE> if not.
530   */
531  public boolean isCollective()
532  {
533    return isCollective;
534  }
535
536
537
538  /**
539   * Indicates whether this attribute type is declared
540   * "no-user-modification".
541   *
542   * @return  <CODE>true</CODE> if this attribute type is declared
543   *          "no-user-modification", or <CODE>false</CODE> if not.
544   */
545  public boolean isNoUserModification()
546  {
547    return isNoUserModification;
548  }
549
550
551
552  /**
553   * Indicates whether this attribute type is declared "single-value".
554   *
555   * @return  <CODE>true</CODE> if this attribute type is declared
556   *          "single-value", or <CODE>false</CODE> if not.
557   */
558  public boolean isSingleValue()
559  {
560    return isSingleValue;
561  }
562
563
564
565  /**
566   * Indicates whether this attribute type represents the
567   * "objectclass" attribute.  The determination will be made based on
568   * the name and/or OID.
569   *
570   * @return  <CODE>true</CODE> if this attribute type is the
571   *          objectclass type, or <CODE>false</CODE> if not.
572   */
573  public boolean isObjectClass()
574  {
575    return isObjectClassType;
576  }
577
578  /** {@inheritDoc} */
579  @Override
580  public String toString()
581  {
582    return definition;
583  }
584
585  /** {@inheritDoc} */
586  @Override
587  public int compareTo(AttributeType o) {
588    return getNormalizedPrimaryNameOrOID().compareTo(
589      o.getNormalizedPrimaryNameOrOID());
590  }
591
592
593
594  /**
595   * Marks this attribute type as dirty, indicating that it has been removed or
596   * replaced in the schema.
597   *
598   * @return A reference to this attribute type.
599   */
600  public AttributeType setDirty()
601  {
602    isDirty = true;
603    return this;
604  }
605
606
607
608  /**
609   * Returns {@code true} if this attribute type has been removed or replaced in
610   * the schema.
611   *
612   * @return {@code true} if this attribute type has been removed or replaced in
613   *         the schema.
614   */
615  public boolean isDirty()
616  {
617    return isDirty;
618  }
619}
620