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 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2015 ForgeRock AS.
026 */
027
028package org.opends.server.admin;
029
030
031
032import java.util.Arrays;
033import java.util.HashSet;
034import java.util.LinkedList;
035import java.util.List;
036import java.util.MissingResourceException;
037import java.util.NoSuchElementException;
038import java.util.Set;
039
040
041
042/**
043 * This class is used to map configuration elements to their LDAP
044 * schema names.
045 * <p>
046 * It is possible to augment the core LDAP profile with additional
047 * profile mappings at run-time using instances of {@link Wrapper}.
048 * This is useful for unit tests which need to add and remove mock
049 * components.
050 */
051public final class LDAPProfile {
052
053  /**
054   * LDAP profile wrappers can be used to provide temporary LDAP
055   * profile information for components which do not have LDAP profile
056   * property files. These components are typically "mock" components
057   * used in unit-tests.
058   */
059  public static abstract class Wrapper {
060
061    /**
062     * Default constructor.
063     */
064    protected Wrapper() {
065      // No implementation required.
066    }
067
068
069
070    /**
071     * Get the name of the LDAP attribute associated with the
072     * specified property definition.
073     * <p>
074     * The default implementation of this method is to return
075     * <code>null</code>.
076     *
077     * @param d
078     *          The managed object definition.
079     * @param pd
080     *          The property definition.
081     * @return Returns the name of the LDAP attribute associated with
082     *         the specified property definition, or <code>null</code>
083     *         if the property definition is not handled by this LDAP
084     *         profile wrapper.
085     */
086    public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
087        PropertyDefinition<?> pd) {
088      return null;
089    }
090
091
092
093    /**
094     * Gets the LDAP RDN attribute type for child entries of an
095     * instantiable relation.
096     * <p>
097     * The default implementation of this method is to return
098     * <code>null</code>.
099     *
100     * @param r
101     *          The instantiable relation.
102     * @return Returns the LDAP RDN attribute type for child entries
103     *         of an instantiable relation, or <code>null</code> if
104     *         the instantiable relation is not handled by this LDAP
105     *         profile wrapper.
106     */
107    public String getRelationChildRDNType(
108        InstantiableRelationDefinition<?, ?> r) {
109      return null;
110    }
111
112
113
114    /**
115     * Gets the LDAP RDN attribute type for child entries of an set
116     * relation.
117     * <p>
118     * The default implementation of this method is to return
119     * <code>null</code>.
120     *
121     * @param r
122     *          The set relation.
123     * @return Returns the LDAP RDN attribute type for child entries of
124     *         an set relation, or <code>null</code> if the set relation
125     *         is not handled by this LDAP profile wrapper.
126     */
127    public String getRelationChildRDNType(SetRelationDefinition<?, ?> r)
128    {
129      return null;
130    }
131
132
133
134    /**
135     * Get the principle object class associated with the specified
136     * definition.
137     * <p>
138     * The default implementation of this method is to return
139     * <code>null</code>.
140     *
141     * @param d
142     *          The managed object definition.
143     * @return Returns the principle object class associated with the
144     *         specified definition, or <code>null</code> if the
145     *         managed object definition is not handled by this LDAP
146     *         profile wrapper.
147     */
148    public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d) {
149      return null;
150    }
151
152
153
154    /**
155     * Get an LDAP RDN sequence associatied with a relation.
156     * <p>
157     * The default implementation of this method is to return
158     * <code>null</code>.
159     *
160     * @param r
161     *          The relation.
162     * @return Returns the LDAP RDN sequence associatied with a
163     *         relation, or <code>null</code> if the relation is not
164     *         handled by this LDAP profile wrapper.
165     */
166    public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
167      return null;
168    }
169  }
170
171  /** The singleton instance. */
172  private static final LDAPProfile INSTANCE = new LDAPProfile();
173
174
175
176  /**
177   * Get the global LDAP profile instance.
178   *
179   * @return Returns the global LDAP profile instance.
180   */
181  public static LDAPProfile getInstance() {
182    return INSTANCE;
183  }
184
185  /** The list of profile wrappers. */
186  private final LinkedList<Wrapper> profiles = new LinkedList<>();
187
188  /** The LDAP profile property table. */
189  private final ManagedObjectDefinitionResource resource =
190    ManagedObjectDefinitionResource.createForProfile("ldap");
191
192
193
194  /** Prevent construction. */
195  private LDAPProfile() {
196    // No implementation required.
197  }
198
199
200
201  /**
202   * Get the name of the LDAP attribute associated with the specified
203   * property definition.
204   *
205   * @param d
206   *          The managed object definition.
207   * @param pd
208   *          The property definition.
209   * @return Returns the name of the LDAP attribute associated with
210   *         the specified property definition.
211   * @throws MissingResourceException
212   *           If the LDAP profile properties file associated with the
213   *           provided managed object definition could not be loaded.
214   */
215  public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
216      PropertyDefinition<?> pd) throws MissingResourceException {
217    for (Wrapper profile : profiles) {
218      String attributeName = profile.getAttributeName(d, pd);
219      if (attributeName != null) {
220        return attributeName;
221      }
222    }
223    return resource.getString(d, "attribute." + pd.getName());
224  }
225
226
227
228  /**
229   * Gets the LDAP RDN attribute type for child entries of an
230   * instantiable relation.
231   *
232   * @param r
233   *          The instantiable relation.
234   * @return Returns the LDAP RDN attribute type for child entries of
235   *         an instantiable relation.
236   * @throws MissingResourceException
237   *           If the LDAP profile properties file associated with the
238   *           provided managed object definition could not be loaded.
239   */
240  public String getRelationChildRDNType(
241      InstantiableRelationDefinition<?, ?> r) throws MissingResourceException {
242    if (r.getNamingPropertyDefinition() != null) {
243      // Use the attribute associated with the naming property.
244      return getAttributeName(r.getChildDefinition(), r
245          .getNamingPropertyDefinition());
246    } else {
247      for (Wrapper profile : profiles) {
248        String rdnType = profile.getRelationChildRDNType(r);
249        if (rdnType != null) {
250          return rdnType;
251        }
252      }
253      return resource.getString(r.getParentDefinition(), "naming-attribute."
254          + r.getName());
255    }
256  }
257
258
259
260  /**
261   * Gets the LDAP object classes associated with an instantiable or set
262   * relation branch. The branch is the parent entry of child managed
263   * objects.
264   *
265   * @param r
266   *          The instantiable or set relation.
267   * @return Returns the LDAP object classes associated with an
268   *         instantiable or set relation branch.
269   */
270  public List<String> getRelationObjectClasses(
271      RelationDefinition<?, ?> r) {
272    return Arrays.asList(new String[] { "top", "ds-cfg-branch" });
273  }
274
275
276
277  /**
278   * Gets the LDAP RDN attribute type for child entries of an set
279   * relation.
280   *
281   * @param r
282   *          The set relation.
283   * @return Returns the LDAP RDN attribute type for child entries of an
284   *         set relation.
285   * @throws MissingResourceException
286   *           If the LDAP profile properties file associated with the
287   *           provided managed object definition could not be loaded.
288   */
289  public String getRelationChildRDNType(SetRelationDefinition<?, ?> r)
290      throws MissingResourceException
291  {
292    for (Wrapper profile : profiles)
293    {
294      String rdnType = profile.getRelationChildRDNType(r);
295      if (rdnType != null)
296      {
297        return rdnType;
298      }
299    }
300    return resource.getString(r.getParentDefinition(),
301        "naming-attribute." + r.getName());
302  }
303
304
305
306  /**
307   * Get the principle object class associated with the specified
308   * definition.
309   *
310   * @param d
311   *          The managed object definition.
312   * @return Returns the principle object class associated with the
313   *         specified definition.
314   * @throws MissingResourceException
315   *           If the LDAP profile properties file associated with the
316   *           provided managed object definition could not be loaded.
317   */
318  public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d)
319      throws MissingResourceException {
320    if (d.isTop()) {
321      return "top";
322    }
323
324    for (Wrapper profile : profiles) {
325      String objectClass = profile.getObjectClass(d);
326      if (objectClass != null) {
327        return objectClass;
328      }
329    }
330    return resource.getString(d, "objectclass");
331  }
332
333
334
335  /**
336   * Get all the object classes associated with the specified
337   * definition.
338   * <p>
339   * The returned list is ordered such that the uppermost object
340   * classes appear first (e.g. top).
341   *
342   * @param d
343   *          The managed object definition.
344   * @return Returns all the object classes associated with the
345   *         specified definition.
346   * @throws MissingResourceException
347   *           If the LDAP profile properties file associated with the
348   *           provided managed object definition could not be loaded.
349   */
350  public List<String> getObjectClasses(AbstractManagedObjectDefinition<?, ?> d)
351      throws MissingResourceException {
352    LinkedList<String> objectClasses = new LinkedList<>();
353    Set<String> s = new HashSet<>();
354
355    // Add the object classes from the parent hierarchy.
356    while (d != null) {
357      String oc = getObjectClass(d);
358      if (!s.contains(oc)) {
359        objectClasses.addFirst(oc);
360        s.add(oc);
361      }
362      d = d.getParent();
363    }
364
365    if (!s.contains("top")) {
366      objectClasses.addFirst("top");
367    }
368
369    return objectClasses;
370  }
371
372
373
374  /**
375   * Get an LDAP RDN sequence associated with a relation.
376   *
377   * @param r
378   *          The relation.
379   * @return Returns the LDAP RDN sequence associated with a
380   *         relation.
381   * @throws MissingResourceException
382   *           If the LDAP profile properties file associated with the
383   *           provided managed object definition could not be loaded.
384   */
385  public String getRelationRDNSequence(RelationDefinition<?, ?> r)
386      throws MissingResourceException {
387    for (Wrapper profile : profiles) {
388      String rdnSequence = profile.getRelationRDNSequence(r);
389      if (rdnSequence != null) {
390        return rdnSequence;
391      }
392    }
393    return resource.getString(r.getParentDefinition(), "rdn." + r.getName());
394  }
395
396
397
398  /**
399   * Removes the last LDAP profile wrapper added using
400   * {@link #pushWrapper(org.opends.server.admin.LDAPProfile.Wrapper)}.
401   *
402   * @throws NoSuchElementException
403   *           If there are no LDAP profile wrappers.
404   */
405  public void popWrapper() throws NoSuchElementException {
406    profiles.removeFirst();
407  }
408
409
410
411  /**
412   * Decorates the core LDAP profile with the provided LDAP profile
413   * wrapper. All profile requests will be directed to the provided
414   * wrapper before being forwarded onto the core profile if the
415   * request could not be satisfied.
416   *
417   * @param wrapper
418   *          The LDAP profile wrapper.
419   */
420  public void pushWrapper(Wrapper wrapper) {
421    profiles.addFirst(wrapper);
422  }
423}