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 2009-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027package org.opends.server.types;
028
029import java.util.ArrayList;
030import java.util.LinkedHashSet;
031import java.util.List;
032import java.util.Set;
033
034import org.forgerock.i18n.LocalizableMessage;
035import org.forgerock.opendj.ldap.ByteString;
036import org.forgerock.opendj.ldap.ResultCode;
037import org.opends.server.core.DirectoryServer;
038
039import static org.opends.messages.SchemaMessages.*;
040import static org.opends.server.util.ServerConstants.*;
041
042/**
043 * This class represents RFC 3672 subentries and RFC 3671
044 * collective attribute subentries objects.
045 */
046public class SubEntry {
047  /**
048   * Defines the set of permissible values for the conflict behavior.
049   * Specifies the behavior that the server is to exhibit for entries
050   * that already contain one or more real values for the associated
051   * collective attribute.
052   */
053  public static enum CollectiveConflictBehavior {
054    /**
055     * Indicates that the virtual attribute provider is to preserve
056     * any real values contained in the entry and merge them with the
057     * set of generated virtual values so that both the real and
058     * virtual values are used.
059     */
060    MERGE_REAL_AND_VIRTUAL("merge-real-and-virtual"),
061
062    /**
063     * Indicates that any real values contained in the entry are
064     * preserved and used, and virtual values are not generated.
065     */
066    REAL_OVERRIDES_VIRTUAL("real-overrides-virtual"),
067
068    /**
069     * Indicates that the virtual attribute provider suppresses any
070     * real values contained in the entry and generates virtual values
071     * and uses them.
072     */
073    VIRTUAL_OVERRIDES_REAL("virtual-overrides-real");
074
075    /** String representation of the value. */
076    private final String name;
077
078    /**
079     * Private constructor.
080     * @param name for this conflict behavior.
081     */
082    private CollectiveConflictBehavior(String name)
083    {
084      this.name = name;
085    }
086
087    /** {@inheritDoc} */
088    @Override
089    public String toString()
090    {
091      return name;
092    }
093  }
094
095  /**
096   * The name of the "collectiveConflictBehavior" attribute type,
097   * formatted in all lowercase characters.
098   */
099  public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR =
100          "collectiveconflictbehavior";
101
102  /**
103   * The name of the "inheritFromDNAttribute" attribute type,
104   * formatted in all lowercase characters.
105   */
106  public static final String ATTR_INHERIT_COLLECTIVE_FROM_DN =
107          "inheritfromdnattribute";
108
109  /**
110   * The name of the "inheritFromRDNAttribute" attribute type,
111   * formatted in all lowercase characters.
112   */
113  public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN =
114          "inheritfromrdnattribute";
115
116  /**
117   * The name of the "inheritFromRDNType" attribute type,
118   * formatted in all lowercase characters.
119   */
120  public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE =
121          "inheritfromrdntype";
122
123  /**
124   * The name of the "inheritFromBaseRDN" attribute type,
125   * formatted in all lowercase characters.
126   */
127  public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE =
128          "inheritfrombaserdn";
129
130  /**
131   * The name of the "inheritAttribute" attribute type,
132   * formatted in all lowercase characters.
133   */
134  public static final String ATTR_INHERIT_COLLECTIVE_ATTR =
135          "inheritattribute";
136
137  /** Attribute option to mark attributes collective. */
138  private static final String ATTR_OPTION_COLLECTIVE =
139          "collective";
140
141  /** Entry object. */
142  private Entry entry;
143
144  /** Subtree specification. */
145  private SubtreeSpecification subTreeSpec;
146
147  /** Collective subentry flag. */
148  private boolean isCollective;
149  /** Inherited collective subentry flag. */
150  private boolean isInheritedCollective;
151  /** Inherited collective from DN subentry flag. */
152  private boolean isInheritedFromDNCollective;
153  /** Inherited collective from RDN subentry flag. */
154  private boolean isInheritedFromRDNCollective;
155
156  /** Inherited collective DN attribute type. */
157  private AttributeType inheritFromDNType;
158  /** Inherited collective RDN attribute type. */
159  private AttributeType inheritFromRDNAttrType;
160  /** Inherited collective RDN type attribute type. */
161  private AttributeType inheritFromRDNType;
162
163  /** Inherited collective RDN attribute value. */
164  private ByteString inheritFromRDNAttrValue;
165  /** Inherited collective from DN value. */
166  private ByteString inheritFromDNAttrValue;
167
168  /** Inherited collective from base DN. */
169  private DN inheritFromBaseDN;
170
171  /** Collective attributes. */
172  private List<Attribute> collectiveAttributes;
173
174  /** Conflict behavior. */
175  private CollectiveConflictBehavior conflictBehavior =
176          CollectiveConflictBehavior.REAL_OVERRIDES_VIRTUAL;
177
178  /**
179   * Constructs a subentry object from a given entry object.
180   * @param  entry LDAP subentry to construct from.
181   * @throws DirectoryException if there is a problem with
182   *         constructing a subentry from a given entry.
183   */
184  public SubEntry(Entry entry) throws DirectoryException
185  {
186    this.entry = entry;
187
188    // Process subtree specification.
189    this.subTreeSpec = null;
190    String specString = null;
191    boolean isValidSpec = true;
192    AttributeType specAttrType = DirectoryServer.getAttributeTypeOrDefault(ATTR_SUBTREE_SPEC_LC);
193    List<Attribute> specAttrList = entry.getAttribute(specAttrType);
194    if (specAttrList != null)
195    {
196      for (Attribute attr : specAttrList)
197      {
198        for (ByteString value : attr)
199        {
200          specString = value.toString();
201          try
202          {
203            this.subTreeSpec = SubtreeSpecification.valueOf(
204                    entry.getName().parent(), specString);
205            isValidSpec = true;
206          }
207          catch (DirectoryException de)
208          {
209            isValidSpec = false;
210          }
211          if (this.subTreeSpec != null)
212          {
213            break;
214          }
215        }
216        if (this.subTreeSpec != null)
217        {
218          break;
219        }
220      }
221    }
222
223    // Check that the subtree spec is flagged as valid. If it is not
224    // that means all parsers have failed and it is invalid syntax.
225    if (!isValidSpec)
226    {
227      LocalizableMessage message =
228        ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
229          specString);
230      throw new DirectoryException(
231              ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
232    }
233
234    // Subentry has to to have a subtree specification.
235    if (this.subTreeSpec == null)
236    {
237      // There is none for some reason eg this could be
238      // old Draft based ldapSubEntry so create a dummy.
239      this.subTreeSpec = new SubtreeSpecification(entry.getName().parent(),
240          null, -1, -1, null, null, null);
241    }
242
243    // Determine if this subentry is collective attribute subentry.
244    this.isCollective = entry.isCollectiveAttributeSubentry();
245
246    // Determine if this subentry is inherited collective
247    // attribute subentry and if so what kind.
248    this.isInheritedCollective =
249            entry.isInheritedCollectiveAttributeSubentry();
250    if (this.isInheritedCollective)
251    {
252      this.isInheritedFromDNCollective =
253              entry.isInheritedFromDNCollectiveAttributeSubentry();
254      this.isInheritedFromRDNCollective =
255              entry.isInheritedFromRDNCollectiveAttributeSubentry();
256    }
257
258    // Process collective attributes.
259    this.collectiveAttributes = new ArrayList<>();
260    if (this.isCollective)
261    {
262      List<Attribute> subAttrList = entry.getAttributes();
263      for (Attribute subAttr : subAttrList)
264      {
265        AttributeType attrType = subAttr.getAttributeType();
266        if (attrType.isCollective())
267        {
268          CollectiveVirtualAttribute collectiveAttr =
269                  new CollectiveVirtualAttribute(subAttr);
270          this.collectiveAttributes.add(collectiveAttr);
271        }
272        else if (subAttr.hasOption(ATTR_OPTION_COLLECTIVE))
273        {
274          AttributeBuilder builder = new AttributeBuilder(subAttr.getAttributeType());
275          builder.addAll(subAttr);
276          Set<String> options = new LinkedHashSet<>(subAttr.getOptions());
277          options.remove(ATTR_OPTION_COLLECTIVE);
278          builder.setOptions(options);
279          Attribute attr = builder.toAttribute();
280          CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(attr);
281          this.collectiveAttributes.add(collectiveAttr);
282        }
283      }
284    }
285
286    // Process inherited collective attributes.
287    if (this.isInheritedCollective)
288    {
289      if (this.isInheritedFromDNCollective)
290      {
291        List<Attribute> attrList = entry.getAttribute(
292                ATTR_INHERIT_COLLECTIVE_FROM_DN);
293        if (attrList != null && !attrList.isEmpty())
294        {
295          for (Attribute attr : attrList)
296          {
297            for (ByteString value : attr)
298            {
299              this.inheritFromDNType = DirectoryServer.getAttributeTypeOrDefault(value.toString().toLowerCase());
300              this.inheritFromDNAttrValue = value;
301              break;
302            }
303          }
304        }
305      }
306
307      if (this.isInheritedFromRDNCollective)
308      {
309        List<Attribute> attrList = entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN);
310        if (attrList != null && !attrList.isEmpty())
311        {
312          for (Attribute attr : attrList)
313          {
314            for (ByteString value : attr)
315            {
316              this.inheritFromRDNAttrType = DirectoryServer.getAttributeTypeOrDefault(value.toString().toLowerCase());
317              this.inheritFromRDNAttrValue = value;
318              break;
319            }
320          }
321        }
322        attrList = entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE);
323        if (attrList != null && !attrList.isEmpty())
324        {
325          for (Attribute attr : attrList)
326          {
327            for (ByteString value : attr)
328            {
329              this.inheritFromRDNType = DirectoryServer.getAttributeTypeOrDefault(value.toString().toLowerCase());
330              break;
331            }
332          }
333        }
334        attrList = entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE);
335        if (attrList != null && !attrList.isEmpty())
336        {
337          for (Attribute attr : attrList)
338          {
339            for (ByteString value : attr)
340            {
341              // Has to have a parent since subentry itself
342              // cannot be a suffix entry within the server.
343              this.inheritFromBaseDN = getDN().parent().child(DN.decode(value));
344              break;
345            }
346          }
347        }
348      }
349
350      List<Attribute> attrList = entry.getAttribute(
351              ATTR_INHERIT_COLLECTIVE_ATTR);
352      if (attrList != null && !attrList.isEmpty())
353      {
354        for (Attribute attr : attrList)
355        {
356          for (ByteString value : attr)
357          {
358            CollectiveVirtualAttribute collectiveAttr =
359              new CollectiveVirtualAttribute(
360                Attributes.empty(value.toString()));
361            this.collectiveAttributes.add(collectiveAttr);
362          }
363        }
364      }
365    }
366
367    // Establish collective attribute conflict behavior.
368    if (this.isCollective || this.isInheritedCollective)
369    {
370      List<Attribute> attrList = entry.getAttribute(
371              ATTR_COLLECTIVE_CONFLICT_BEHAVIOR);
372      if (attrList != null && !attrList.isEmpty())
373      {
374        for (Attribute attr : attrList)
375        {
376          for (ByteString value : attr)
377          {
378            for (CollectiveConflictBehavior behavior :
379              CollectiveConflictBehavior.values())
380            {
381              if (behavior.toString().equals(value.toString()))
382              {
383                this.conflictBehavior = behavior;
384                break;
385              }
386            }
387          }
388        }
389      }
390    }
391  }
392
393  /**
394   * Retrieves the distinguished name for this subentry.
395   * @return  The distinguished name for this subentry.
396   */
397  public final DN getDN()
398  {
399    return this.entry.getName();
400  }
401
402  /**
403   * Getter to retrieve the actual entry object
404   * for this subentry.
405   * @return entry object for this subentry.
406   */
407  public final Entry getEntry()
408  {
409    return this.entry;
410  }
411
412  /**
413   * Indicates whether or not this subentry is
414   * a collective attribute subentry.
415   * @return <code>true</code> if collective,
416   *         <code>false</code> otherwise.
417   */
418  public boolean isCollective()
419  {
420    return this.isCollective;
421  }
422
423  /**
424   * Indicates whether or not this subentry is
425   * an inherited collective attribute subentry.
426   * @return <code>true</code> if inherited
427   *         collective, <code>false</code>
428   *         otherwise.
429   */
430  public boolean isInheritedCollective()
431  {
432    return this.isInheritedCollective;
433  }
434
435  /**
436   * Indicates whether or not this subentry is
437   * an inherited from DN collective attribute
438   * subentry.
439   * @return <code>true</code> if inherited
440   *         from DN collective,
441   *         <code>false</code> otherwise.
442   */
443  public boolean isInheritedFromDNCollective()
444  {
445    return this.isInheritedFromDNCollective;
446  }
447
448  /**
449   * Indicates whether or not this subentry is
450   * an inherited from RDN collective attribute
451   * subentry.
452   * @return <code>true</code> if inherited
453   *         from RDN collective,
454   *         <code>false</code> otherwise.
455   */
456  public boolean isInheritedFromRDNCollective()
457  {
458    return this.isInheritedFromRDNCollective;
459  }
460
461  /**
462   * Getter to retrieve inheritFromDNAttribute type
463   * for inherited collective attribute subentry.
464   * @return Type of inheritFromDNAttribute or,
465   *         <code>null</code> if there is none.
466   */
467  public AttributeType getInheritFromDNType()
468  {
469    return this.inheritFromDNType;
470  }
471
472  /**
473   * Getter to retrieve inheritFromRDNAttribute type
474   * for inherited collective attribute subentry.
475   * @return Type of inheritFromRDNAttribute or,
476   *         <code>null</code> if there is none.
477   */
478  public AttributeType getInheritFromRDNAttrType()
479  {
480    return this.inheritFromRDNAttrType;
481  }
482
483  /**
484   * Getter to retrieve inheritFromRDNAttribute value
485   * for inherited collective attribute subentry.
486   * @return ByteString of inheritFromRDNAttribute
487   *         or, <code>null</code> if there is none.
488   */
489  public ByteString getInheritFromRDNAttrValue()
490  {
491    return this.inheritFromRDNAttrValue;
492  }
493
494  /**
495   * Getter to retrieve RDN type of inheritFromRDNType
496   * for inherited collective attribute subentry.
497   * @return RDN Type of inheritFromRDNAttribute or,
498   *         <code>null</code> if there is none.
499   */
500  public AttributeType getInheritFromRDNType()
501  {
502    return this.inheritFromRDNType;
503  }
504
505  /**
506   * Getter to retrieve inheritFromDNAttribute value
507   * for inherited collective attribute subentry.
508   * @return ByteString of inheritFromDNAttribute
509   *         or, <code>null</code> if there is none.
510   */
511  public ByteString getInheritFromDNAttrValue()
512  {
513    return this.inheritFromDNAttrValue;
514  }
515
516  /**
517   * Getter to retrieve inheritFromBaseRDN DN
518   * for inherited collective attribute subentry.
519   * @return DN of inheritFromBaseRDN or,
520   *         <code>null</code> if there is none.
521   */
522  public DN getInheritFromBaseDN()
523  {
524    return this.inheritFromBaseDN;
525  }
526
527  /**
528   * Getter for subentry subtree specification.
529   * @return subtree specification for this subentry.
530   */
531  public SubtreeSpecification getSubTreeSpecification()
532  {
533    return this.subTreeSpec;
534  }
535
536  /**
537   * Getter for collective attributes contained within this subentry.
538   * @return collective attributes contained within this subentry.
539   */
540  public List<Attribute> getCollectiveAttributes()
541  {
542    return this.collectiveAttributes;
543  }
544
545  /**
546   * Getter for collective conflict behavior defined for this
547   * collective attributes subentry.
548   * @return conflict behavior for this collective attributes
549   *         subentry.
550   */
551  public CollectiveConflictBehavior getConflictBehavior()
552  {
553    return this.conflictBehavior;
554  }
555}