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