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