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 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  private static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR_LC = "collectiveconflictbehavior";
087  /** The lowercased name of the "inheritFromDNAttribute" attribute type. */
088  private static final String ATTR_INHERIT_COLLECTIVE_FROM_DN_LC = "inheritfromdnattribute";
089  /** The lowercased name of the "inheritFromRDNAttribute" attribute type. */
090  private static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_LC = "inheritfromrdnattribute";
091  /** The lowercased name of the "inheritFromRDNType" attribute type. */
092  private static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE_LC = "inheritfromrdntype";
093  /** The lowercased name of the "inheritFromBaseRDN" attribute type. */
094  private static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE_LC = "inheritfrombaserdn";
095  /** The lowercased name of the "inheritAttribute" attribute type. */
096  private 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 final Entry entry;
102
103  /** Subtree specification. */
104  private final SubtreeSpecification subTreeSpec;
105
106  /** Collective subentry flag. */
107  private final boolean isCollective;
108  /** Inherited collective subentry flag. */
109  private final boolean isInheritedCollective;
110  /** Inherited collective from DN subentry flag. */
111  private final boolean isInheritedFromDNCollective;
112  /** Inherited collective from RDN subentry flag. */
113  private final 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  /** Inherited collective RDN attribute value. */
122  private ByteString inheritFromRDNAttrValue;
123  /** Inherited collective from DN value. */
124  private ByteString inheritFromDNAttrValue;
125
126  /** Inherited collective from base DN. */
127  private DN inheritFromBaseDN;
128
129  /** Collective attributes. */
130  private final List<Attribute> collectiveAttributes = new ArrayList<>();
131
132  /** Conflict behavior. */
133  private CollectiveConflictBehavior conflictBehavior = REAL_OVERRIDES_VIRTUAL;
134
135  /**
136   * Constructs a subentry object from a given entry object.
137   * @param  entry LDAP subentry to construct from.
138   * @throws DirectoryException if there is a problem with
139   *         constructing a subentry from a given entry.
140   */
141  public SubEntry(Entry entry) throws DirectoryException
142  {
143    this.entry = entry;
144
145    this.subTreeSpec = buildSubTreeSpecification(entry);
146    this.isCollective = entry.isCollectiveAttributeSubentry();
147
148    this.isInheritedCollective = entry.isInheritedCollectiveAttributeSubentry();
149    if (this.isInheritedCollective)
150    {
151      this.isInheritedFromDNCollective = entry.isInheritedFromDNCollectiveAttributeSubentry();
152      this.isInheritedFromRDNCollective = entry.isInheritedFromRDNCollectiveAttributeSubentry();
153    }
154    else
155    {
156      this.isInheritedFromDNCollective = false;
157      this.isInheritedFromRDNCollective = false;
158    }
159
160    // Process collective attributes.
161    if (this.isCollective)
162    {
163      List<Attribute> subAttrList = entry.getAttributes();
164      for (Attribute subAttr : subAttrList)
165      {
166        AttributeType attrType = subAttr.getAttributeDescription().getAttributeType();
167        if (attrType.isCollective())
168        {
169          this.collectiveAttributes.add(new CollectiveVirtualAttribute(subAttr));
170        }
171        else if (subAttr.getAttributeDescription().hasOption(ATTR_OPTION_COLLECTIVE))
172        {
173          AttributeBuilder builder = new AttributeBuilder(subAttr.getAttributeDescription().getAttributeType());
174          builder.addAll(subAttr);
175          for (String option : subAttr.getAttributeDescription().getOptions())
176          {
177            if (!ATTR_OPTION_COLLECTIVE.equals(option))
178            {
179              builder.setOption(option);
180            }
181          }
182          Attribute attr = builder.toAttribute();
183          this.collectiveAttributes.add(new CollectiveVirtualAttribute(attr));
184        }
185      }
186    }
187
188    // Process inherited collective attributes.
189    if (this.isInheritedCollective)
190    {
191      if (this.isInheritedFromDNCollective)
192      {
193        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_DN_LC))
194        {
195          for (ByteString value : attr)
196          {
197            this.inheritFromDNType = DirectoryServer.getSchema().getAttributeType(value.toString());
198            this.inheritFromDNAttrValue = value;
199            break;
200          }
201        }
202      }
203
204      if (this.isInheritedFromRDNCollective)
205      {
206        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_LC))
207        {
208          for (ByteString value : attr)
209          {
210            this.inheritFromRDNAttrType = DirectoryServer.getSchema().getAttributeType(value.toString());
211            this.inheritFromRDNAttrValue = value;
212            break;
213          }
214        }
215        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE_LC))
216        {
217          for (ByteString value : attr)
218          {
219            this.inheritFromRDNType = DirectoryServer.getSchema().getAttributeType(value.toString());
220            break;
221          }
222        }
223        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE_LC))
224        {
225          for (ByteString value : attr)
226          {
227            // Has to have a parent since subentry itself
228            // cannot be a suffix entry within the server.
229            this.inheritFromBaseDN = getDN().parent().child(DN.valueOf(value));
230            break;
231          }
232        }
233      }
234
235      for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_ATTR_LC))
236      {
237        for (ByteString value : attr)
238        {
239          Attribute collectiveAttr = Attributes.empty(value.toString());
240          this.collectiveAttributes.add(new CollectiveVirtualAttribute(collectiveAttr));
241        }
242      }
243    }
244
245    // Establish collective attribute conflict behavior.
246    if (this.isCollective || this.isInheritedCollective)
247    {
248      for (Attribute attr : entry.getAttribute(ATTR_COLLECTIVE_CONFLICT_BEHAVIOR_LC))
249      {
250        for (ByteString value : attr)
251        {
252          for (CollectiveConflictBehavior behavior : CollectiveConflictBehavior.values())
253          {
254            if (behavior.toString().equals(value.toString()))
255            {
256              this.conflictBehavior = behavior;
257              break;
258            }
259          }
260        }
261      }
262    }
263  }
264
265  private SubtreeSpecification buildSubTreeSpecification(Entry entry) throws DirectoryException
266  {
267    String specString = null;
268    boolean isValidSpec = true;
269    AttributeType specAttrType = DirectoryServer.getSchema().getAttributeType(ATTR_SUBTREE_SPEC_LC);
270    for (Attribute attr : entry.getAttribute(specAttrType))
271    {
272      for (ByteString value : attr)
273      {
274        specString = value.toString();
275        try
276        {
277          SubtreeSpecification subTreeSpec = SubtreeSpecification.valueOf(entry.getName().parent(), specString);
278          if (subTreeSpec != null)
279          {
280            return subTreeSpec;
281          }
282          isValidSpec = true;
283        }
284        catch (DirectoryException ignored)
285        {
286          isValidSpec = false;
287        }
288      }
289    }
290
291    // Check that the subtree spec is flagged as valid. If it is not
292    // that means all parsers have failed and it is invalid syntax.
293    if (!isValidSpec)
294    {
295      LocalizableMessage message = ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(specString);
296      throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
297    }
298
299    // Subentry has to have a subtree specification.
300    // There is none for some reason eg this could be
301    // old Draft based ldapSubEntry so create a dummy.
302    return new SubtreeSpecification(entry.getName().parent(), null, -1, -1, null, null, null);
303  }
304
305  /**
306   * Retrieves the distinguished name for this subentry.
307   * @return  The distinguished name for this subentry.
308   */
309  public final DN getDN()
310  {
311    return this.entry.getName();
312  }
313
314  /**
315   * Getter to retrieve the actual entry object for this subentry.
316   * @return entry object for this subentry.
317   */
318  public final Entry getEntry()
319  {
320    return this.entry;
321  }
322
323  /**
324   * Indicates whether this subentry is a collective attribute subentry.
325   * @return {@code true} if collective, {@code false} otherwise.
326   */
327  public boolean isCollective()
328  {
329    return this.isCollective;
330  }
331
332  /**
333   * Indicates whether this subentry is inherited collective attribute subentry.
334   * @return {@code true} if inherited collective, {@code false} otherwise.
335   */
336  public boolean isInheritedCollective()
337  {
338    return this.isInheritedCollective;
339  }
340
341  /**
342   * Indicates whether this subentry is inherited from DN collective attribute subentry.
343   * @return {@code true} if inherited from DN collective, {@code false} otherwise.
344   */
345  public boolean isInheritedFromDNCollective()
346  {
347    return this.isInheritedFromDNCollective;
348  }
349
350  /**
351   * Indicates whether this subentry is inherited from RDN collective attribute subentry.
352   * @return {@code true} if inherited from RDN collective, {@code false} otherwise.
353   */
354  public boolean isInheritedFromRDNCollective()
355  {
356    return this.isInheritedFromRDNCollective;
357  }
358
359  /**
360   * Getter to retrieve inheritFromDNAttribute type for inherited collective attribute subentry.
361   * @return Type of inheritFromDNAttribute, or {@code null} if there is none.
362   */
363  public AttributeType getInheritFromDNType()
364  {
365    return this.inheritFromDNType;
366  }
367
368  /**
369   * Getter to retrieve inheritFromRDNAttribute type for inherited collective attribute subentry.
370   * @return Type of inheritFromRDNAttribute, or {@code null} if there is none.
371   */
372  public AttributeType getInheritFromRDNAttrType()
373  {
374    return this.inheritFromRDNAttrType;
375  }
376
377  /**
378   * Getter to retrieve inheritFromRDNAttribute value for inherited collective attribute subentry.
379   * @return ByteString of inheritFromRDNAttribute, or {@code null} if there is none.
380   */
381  public ByteString getInheritFromRDNAttrValue()
382  {
383    return this.inheritFromRDNAttrValue;
384  }
385
386  /**
387   * Getter to retrieve RDN type of inheritFromRDNType for inherited collective attribute subentry.
388   * @return RDN Type of inheritFromRDNAttribute, or {@code null} if there is none.
389   */
390  public AttributeType getInheritFromRDNType()
391  {
392    return this.inheritFromRDNType;
393  }
394
395  /**
396   * Getter to retrieve inheritFromDNAttribute value for inherited collective attribute subentry.
397   * @return ByteString of inheritFromDNAttribute, or {@code null} if there is none.
398   */
399  public ByteString getInheritFromDNAttrValue()
400  {
401    return this.inheritFromDNAttrValue;
402  }
403
404  /**
405   * Getter to retrieve inheritFromBaseRDN DN for inherited collective attribute subentry.
406   * @return DN of inheritFromBaseRDN, or {@code null} if there is none.
407   */
408  public DN getInheritFromBaseDN()
409  {
410    return this.inheritFromBaseDN;
411  }
412
413  /**
414   * Getter for subentry subtree specification.
415   * @return subtree specification for this subentry.
416   */
417  public SubtreeSpecification getSubTreeSpecification()
418  {
419    return this.subTreeSpec;
420  }
421
422  /**
423   * Getter for collective attributes contained within this subentry.
424   * @return collective attributes contained within this subentry.
425   */
426  public List<Attribute> getCollectiveAttributes()
427  {
428    return this.collectiveAttributes;
429  }
430
431  /**
432   * Getter for collective conflict behavior defined for this collective attributes subentry.
433   * @return conflict behavior for this collective attributes subentry.
434   */
435  public CollectiveConflictBehavior getConflictBehavior()
436  {
437    return this.conflictBehavior;
438  }
439
440  @Override
441  public String toString()
442  {
443    return getClass().getSimpleName() + "(" + this.entry.getName() + ")";
444  }
445}