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