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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.admin;
029    
030    
031    
032    import java.util.Arrays;
033    import java.util.HashSet;
034    import java.util.LinkedList;
035    import java.util.List;
036    import java.util.MissingResourceException;
037    import java.util.NoSuchElementException;
038    import 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     */
051    public 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 getInstantiableRelationChildRDNType(
108            InstantiableRelationDefinition<?, ?> r) {
109          return null;
110        }
111    
112    
113    
114        /**
115         * Get the principle object class associated with the specified
116         * definition.
117         * <p>
118         * The default implementation of this method is to return
119         * <code>null</code>.
120         *
121         * @param d
122         *          The managed object definition.
123         * @return Returns the principle object class associated with the
124         *         specified definition, or <code>null</code> if the
125         *         managed object definition is not handled by this LDAP
126         *         profile wrapper.
127         */
128        public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d) {
129          return null;
130        }
131    
132    
133    
134        /**
135         * Get an LDAP RDN sequence associatied with a relation.
136         * <p>
137         * The default implementation of this method is to return
138         * <code>null</code>.
139         *
140         * @param r
141         *          The relation.
142         * @return Returns the LDAP RDN sequence associatied with a
143         *         relation, or <code>null</code> if the relation is not
144         *         handled by this LDAP profile wrapper.
145         */
146        public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
147          return null;
148        }
149      }
150    
151      // The singleton instance.
152      private static final LDAPProfile INSTANCE = new LDAPProfile();
153    
154    
155    
156      /**
157       * Get the global LDAP profile instance.
158       *
159       * @return Returns the global LDAP profile instance.
160       */
161      public static LDAPProfile getInstance() {
162        return INSTANCE;
163      }
164    
165      // The list of profile wrappers.
166      private final LinkedList<Wrapper> profiles = new LinkedList<Wrapper>();;
167    
168      // The LDAP profile property table.
169      private final ManagedObjectDefinitionResource resource =
170        ManagedObjectDefinitionResource.createForProfile("ldap");
171    
172    
173    
174      // Prevent construction.
175      private LDAPProfile() {
176        // No implementation required.
177      }
178    
179    
180    
181      /**
182       * Get the name of the LDAP attribute associated with the specified
183       * property definition.
184       *
185       * @param d
186       *          The managed object definition.
187       * @param pd
188       *          The property definition.
189       * @return Returns the name of the LDAP attribute associated with
190       *         the specified property definition.
191       * @throws MissingResourceException
192       *           If the LDAP profile properties file associated with the
193       *           provided managed object definition could not be loaded.
194       */
195      public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
196          PropertyDefinition<?> pd) throws MissingResourceException {
197        for (Wrapper profile : profiles) {
198          String attributeName = profile.getAttributeName(d, pd);
199          if (attributeName != null) {
200            return attributeName;
201          }
202        }
203        return resource.getString(d, "attribute." + pd.getName());
204      }
205    
206    
207    
208      /**
209       * Gets the LDAP RDN attribute type for child entries of an
210       * instantiable relation.
211       *
212       * @param r
213       *          The instantiable relation.
214       * @return Returns the LDAP RDN attribute type for child entries of
215       *         an instantiable relation.
216       * @throws MissingResourceException
217       *           If the LDAP profile properties file associated with the
218       *           provided managed object definition could not be loaded.
219       */
220      public String getInstantiableRelationChildRDNType(
221          InstantiableRelationDefinition<?, ?> r) throws MissingResourceException {
222        if (r.getNamingPropertyDefinition() != null) {
223          // Use the attribute associated with the naming property.
224          return getAttributeName(r.getChildDefinition(), r
225              .getNamingPropertyDefinition());
226        } else {
227          for (Wrapper profile : profiles) {
228            String rdnType = profile.getInstantiableRelationChildRDNType(r);
229            if (rdnType != null) {
230              return rdnType;
231            }
232          }
233          return resource.getString(r.getParentDefinition(), "naming-attribute."
234              + r.getName());
235        }
236      }
237    
238    
239    
240      /**
241       * Gets the LDAP object classes associated with an instantiable
242       * relation branch. The branch is the parent entry of child managed
243       * objects.
244       *
245       * @param r
246       *          The instantiable relation.
247       * @return Returns the LDAP object classes associated with an
248       *         instantiable relation branch.
249       */
250      public List<String> getInstantiableRelationObjectClasses(
251          InstantiableRelationDefinition<?, ?> r) {
252        return Arrays.asList(new String[] { "top", "ds-cfg-branch" });
253      }
254    
255    
256    
257      /**
258       * Get the principle object class associated with the specified
259       * definition.
260       *
261       * @param d
262       *          The managed object definition.
263       * @return Returns the principle object class associated with the
264       *         specified definition.
265       * @throws MissingResourceException
266       *           If the LDAP profile properties file associated with the
267       *           provided managed object definition could not be loaded.
268       */
269      public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d)
270          throws MissingResourceException {
271        if (d.isTop()) {
272          return "top";
273        }
274    
275        for (Wrapper profile : profiles) {
276          String objectClass = profile.getObjectClass(d);
277          if (objectClass != null) {
278            return objectClass;
279          }
280        }
281        return resource.getString(d, "objectclass");
282      }
283    
284    
285    
286      /**
287       * Get all the object classes associated with the specified
288       * definition.
289       * <p>
290       * The returned list is ordered such that the uppermost object
291       * classes appear first (e.g. top).
292       *
293       * @param d
294       *          The managed object definition.
295       * @return Returns all the object classes associated with the
296       *         specified definition.
297       * @throws MissingResourceException
298       *           If the LDAP profile properties file associated with the
299       *           provided managed object definition could not be loaded.
300       */
301      public List<String> getObjectClasses(AbstractManagedObjectDefinition<?, ?> d)
302          throws MissingResourceException {
303        LinkedList<String> objectClasses = new LinkedList<String>();
304        Set<String> s = new HashSet<String>();
305    
306        // Add the object classes from the parent hierarchy.
307        while (d != null) {
308          String oc = getObjectClass(d);
309          if (!s.contains(oc)) {
310            objectClasses.addFirst(oc);
311            s.add(oc);
312          }
313          d = d.getParent();
314        }
315    
316        if (!s.contains("top")) {
317          objectClasses.addFirst("top");
318        }
319    
320        return objectClasses;
321      }
322    
323    
324    
325      /**
326       * Get an LDAP RDN sequence associatied with a relation.
327       *
328       * @param r
329       *          The relation.
330       * @return Returns the LDAP RDN sequence associatied with a
331       *         relation.
332       * @throws MissingResourceException
333       *           If the LDAP profile properties file associated with the
334       *           provided managed object definition could not be loaded.
335       */
336      public String getRelationRDNSequence(RelationDefinition<?, ?> r)
337          throws MissingResourceException {
338        for (Wrapper profile : profiles) {
339          String rdnSequence = profile.getRelationRDNSequence(r);
340          if (rdnSequence != null) {
341            return rdnSequence;
342          }
343        }
344        return resource.getString(r.getParentDefinition(), "rdn." + r.getName());
345      }
346    
347    
348    
349      /**
350       * Removes the last LDAP profile wrapper added using
351       * {@link #pushWrapper(org.opends.server.admin.LDAPProfile.Wrapper)}.
352       *
353       * @throws NoSuchElementException
354       *           If there are no LDAP profile wrappers.
355       */
356      public void popWrapper() throws NoSuchElementException {
357        profiles.removeFirst();
358      }
359    
360    
361    
362      /**
363       * Decorates the core LDAP profile with the provided LDAP profile
364       * wrapper. All profile requests will be directed to the provided
365       * wrapper before being forwarded onto the core profile if the
366       * request could not be satisfied.
367       *
368       * @param wrapper
369       *          The LDAP profile wrapper.
370       */
371      public void pushWrapper(Wrapper wrapper) {
372        profiles.addFirst(wrapper);
373      }
374    }