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.LinkedHashMap;
030import java.util.LinkedHashSet;
031import java.util.List;
032import java.util.Map;
033import java.util.Set;
034
035import org.forgerock.i18n.slf4j.LocalizedLogger;
036
037import static org.forgerock.util.Reject.*;
038import static org.opends.server.util.ServerConstants.*;
039
040/**
041 * This class defines a data structure for storing and interacting
042 * with a name form, which defines the attribute type(s) that must
043 * and/or may be used in the RDN of an entry with a given structural
044 * objectclass.
045 */
046@org.opends.server.types.PublicAPI(
047     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
048     mayInstantiate=false,
049     mayExtend=false,
050     mayInvoke=true)
051public final class NameForm
052       implements SchemaFileElement
053{
054  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
055
056  /** Indicates whether this name form is declared "obsolete". */
057  private final boolean isObsolete;
058
059  /**
060   * The set of additional name-value pairs associated with this name
061   * form definition.
062   */
063  private final Map<String,List<String>> extraProperties;
064
065  /**
066   * The mapping between the lowercase names and the user-provided
067   * names for this name form.
068   */
069  private final Map<String,String> names;
070
071  /** The reference to the structural objectclass for this name form. */
072  private final ObjectClass structuralClass;
073
074  /** The set of optional attribute types for this name form. */
075  private final Set<AttributeType> optionalAttributes;
076
077  /** The set of required attribute types for this name form. */
078  private final Set<AttributeType> requiredAttributes;
079
080  /** The definition string used to create this name form. */
081  private final String definition;
082
083  /** The description for this name form. */
084  private final String description;
085
086  /** The OID for this name form. */
087  private final String oid;
088
089
090
091  /**
092   * Creates a new name form definition with the provided information.
093   *
094   * @param  definition          The definition string used to create
095   *                             this name form.  It must not be
096   *                             {@code null}.
097   * @param  names               The set of names that may be used to
098   *                             reference this name form.
099   * @param  oid                 The OID for this name form.  It must
100   *                             not be {@code null}.
101   * @param  description         The description for this name form.
102   * @param  isObsolete          Indicates whether this name form is
103   *                             declared "obsolete".
104   * @param  structuralClass     The structural objectclass with which
105   *                             this name form is associated.  It
106   *                             must not be {@code null}.
107   * @param  requiredAttributes  The set of required attribute types
108   *                             for this name form.
109   * @param  optionalAttributes  The set of optional attribute types
110   *                             for this name form.
111   * @param  extraProperties     A set of extra properties for this
112   *                             name form.
113   */
114  public NameForm(String definition, Map<String,String> names,
115                  String oid, String description, boolean isObsolete,
116                  ObjectClass structuralClass,
117                  Set<AttributeType> requiredAttributes,
118                  Set<AttributeType> optionalAttributes,
119                  Map<String,List<String>> extraProperties)
120  {
121    ifNull(definition, oid, structuralClass);
122
123    this.oid             = oid;
124    this.description     = description;
125    this.isObsolete      = isObsolete;
126    this.structuralClass = structuralClass;
127
128    int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME);
129    if (schemaFilePos > 0)
130    {
131      String defStr;
132      try
133      {
134        int firstQuotePos = definition.indexOf('\'', schemaFilePos);
135        int secondQuotePos = definition.indexOf('\'',
136                                                firstQuotePos+1);
137
138        defStr = definition.substring(0, schemaFilePos).trim() + " " +
139                 definition.substring(secondQuotePos+1).trim();
140      }
141      catch (Exception e)
142      {
143        logger.traceException(e);
144
145        defStr = definition;
146      }
147
148      this.definition = defStr;
149    }
150    else
151    {
152      this.definition = definition;
153    }
154
155    if (names == null || names.isEmpty())
156    {
157      this.names = new LinkedHashMap<>(0);
158    }
159    else
160    {
161      this.names = new LinkedHashMap<>(names);
162    }
163
164    if (requiredAttributes == null || requiredAttributes.isEmpty())
165    {
166      this.requiredAttributes = new LinkedHashSet<>(0);
167    }
168    else
169    {
170      this.requiredAttributes = new LinkedHashSet<>(requiredAttributes);
171    }
172
173    if (optionalAttributes == null || optionalAttributes.isEmpty())
174    {
175      this.optionalAttributes = new LinkedHashSet<>(0);
176    }
177    else
178    {
179      this.optionalAttributes = new LinkedHashSet<>(optionalAttributes);
180    }
181
182    if (extraProperties == null || extraProperties.isEmpty())
183    {
184      this.extraProperties = new LinkedHashMap<>(0);
185    }
186    else
187    {
188      this.extraProperties = new LinkedHashMap<>(extraProperties);
189    }
190  }
191
192
193
194  /**
195   * Retrieves the set of names that may be used to reference this
196   * name form.  The returned object will be a mapping between each
197   * name in all lowercase characters and that name in a user-defined
198   * form (which may include mixed capitalization).
199   *
200   * @return  The set of names that may be used to reference this
201   *          name form.
202   */
203  public Map<String,String> getNames()
204  {
205    return names;
206  }
207
208
209
210  /**
211   * Indicates whether the provided lowercase name may be used to
212   * reference this name form.
213   *
214   * @param  lowerName  The name for which to make the determination,
215   *                    in all lowercase characters.
216   *
217   * @return  {@code true} if the provided lowercase name may be used
218   *          to reference this name form, or {@code false} if not.
219   */
220  public boolean hasName(String lowerName)
221  {
222    return names.containsKey(lowerName);
223  }
224
225
226
227  /**
228   * Retrieves the OID for this name form.
229   *
230   * @return  The OID for this name form.
231   */
232  public String getOID()
233  {
234    return oid;
235  }
236
237
238
239  /**
240   * Retrieves the name or OID that should be used to reference this
241   * name form.  If at least one name is defined, then the first will
242   * be returned.  Otherwise, the OID will be returned.
243   *
244   * @return  The name or OID that should be used to reference this
245   *          name form.
246   */
247  public String getNameOrOID()
248  {
249    if (names.isEmpty())
250    {
251      return oid;
252    }
253    else
254    {
255      return names.values().iterator().next();
256    }
257  }
258
259
260
261  /**
262   * Indicates whether the provided lowercase value is equal to the
263   * OID or any of the names that may be used to reference this name
264   * form.
265   *
266   * @param  lowerValue  The value, in all lowercase characters, that
267   *                     may be used to make the determination.
268   *
269   * @return  {@code true} if the provided lowercase value is one of
270   *          the names or the OID of this name form, or {@code false}
271   *          if it is not.
272   */
273  public boolean hasNameOrOID(String lowerValue)
274  {
275    return names.containsKey(lowerValue) || lowerValue.equals(oid);
276  }
277
278
279
280  /**
281   * Retrieves the description for this name form.
282   *
283   * @return  The description for this name form, or {@code true} if
284   *          there is none.
285   */
286  public String getDescription()
287  {
288    return description;
289  }
290
291
292
293  /**
294   * Retrieves the reference to the structural objectclass for this
295   * name form.
296   *
297   * @return  The reference to the structural objectclass for this
298   *          name form.
299   */
300  public ObjectClass getStructuralClass()
301  {
302    return structuralClass;
303  }
304
305
306
307  /**
308   * Retrieves the set of required attributes for this name form.
309   *
310   * @return  The set of required attributes for this name form.
311   */
312  public Set<AttributeType> getRequiredAttributes()
313  {
314    return requiredAttributes;
315  }
316
317
318
319  /**
320   * Indicates whether the provided attribute type is included in the
321   * required attribute list for this name form.
322   *
323   * @param  attributeType  The attribute type for which to make the
324   *                        determination.
325   *
326   * @return  {@code true} if the provided attribute type is required
327   *          by this name form, or {@code false} if not.
328   */
329  public boolean isRequired(AttributeType attributeType)
330  {
331    return requiredAttributes.contains(attributeType);
332  }
333
334
335
336  /**
337   * Retrieves the set of optional attributes for this name form.
338   *
339   * @return  The set of optional attributes for this name form.
340   */
341  public Set<AttributeType> getOptionalAttributes()
342  {
343    return optionalAttributes;
344  }
345
346
347
348  /**
349   * Indicates whether the provided attribute type is included in the
350   * optional attribute list for this name form.
351   *
352   * @param  attributeType  The attribute type for which to make the
353   *                        determination.
354   *
355   * @return  {@code true} if the provided attribute type is optional
356   *          for this name form, or {@code false} if not.
357   */
358  public boolean isOptional(AttributeType attributeType)
359  {
360    return optionalAttributes.contains(attributeType);
361  }
362
363
364
365  /**
366   * Indicates whether the provided attribute type is in the list of
367   * required or optional attributes for this name form.
368   *
369   * @param  attributeType  The attribute type for which to make the
370   *                        determination.
371   *
372   * @return  {@code true} if the provided attribute type is required
373   *          or optional for this name form, or {@code false} if it
374   *          is not.
375   */
376  public boolean isRequiredOrOptional(AttributeType attributeType)
377  {
378    return requiredAttributes.contains(attributeType) ||
379            optionalAttributes.contains(attributeType);
380  }
381
382
383
384  /**
385   * Indicates whether this name form is declared "obsolete".
386   *
387   * @return  {@code true} if this name form is declared
388   *          "obsolete", or {@code false} if it is not.
389   */
390  public boolean isObsolete()
391  {
392    return isObsolete;
393  }
394
395
396
397  /**
398   * Retrieves a mapping between the names of any extra non-standard
399   * properties that may be associated with this name form and the
400   * value for that property.
401   *
402   * @return  A mapping between the names of any extra non-standard
403   *          properties that may be associated with this name form
404   *          and the value for that property.
405   */
406  @Override
407  public Map<String,List<String>> getExtraProperties()
408  {
409    return extraProperties;
410  }
411
412
413
414  /**
415   * Indicates whether the provided object is equal to this name form.
416   * The object will be considered equal if it is a name form with the
417   * same OID as the current name form.
418   *
419   * @param  o  The object for which to make the determination.
420   *
421   * @return  {@code true} if the provided object is equal to this
422   *          name form, or {@code true} if not.
423   */
424  @Override
425  public boolean equals(Object o)
426  {
427    if (this == o)
428    {
429      return true;
430    }
431    if (!(o instanceof NameForm))
432    {
433      return false;
434    }
435    return oid.equals(((NameForm) o).oid);
436  }
437
438
439
440  /**
441   * Retrieves the hash code for this name form.  It will be based on
442   * the sum of the bytes of the OID.
443   *
444   * @return  The hash code for this name form.
445   */
446  @Override
447  public int hashCode()
448  {
449    int oidLength = oid.length();
450    int hashCode  = 0;
451    for (int i=0; i < oidLength; i++)
452    {
453      hashCode += oid.charAt(i);
454    }
455
456    return hashCode;
457  }
458
459
460
461  /**
462   * Retrieves the string representation of this name form in the form
463   * specified in RFC 2252.
464   *
465   * @return  The string representation of this name form in the form
466   *          specified in RFC 2252.
467   */
468  @Override
469  public String toString()
470  {
471    return definition;
472  }
473
474}