/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS
*/
package org.opends.server.types;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.core.DirectoryServer;
import static org.opends.messages.SchemaMessages.*;
import static org.opends.server.util.ServerConstants.*;
/**
* This class represents RFC 3672 subentries and RFC 3671
* collective attribute subentries objects.
*/
public class SubEntry {
/**
* Defines the set of permissible values for the conflict behavior.
* Specifies the behavior that the server is to exhibit for entries
* that already contain one or more real values for the associated
* collective attribute.
*/
public static enum CollectiveConflictBehavior {
/**
* Indicates that the virtual attribute provider is to preserve
* any real values contained in the entry and merge them with the
* set of generated virtual values so that both the real and
* virtual values are used.
*/
MERGE_REAL_AND_VIRTUAL("merge-real-and-virtual"),
/**
* Indicates that any real values contained in the entry are
* preserved and used, and virtual values are not generated.
*/
REAL_OVERRIDES_VIRTUAL("real-overrides-virtual"),
/**
* Indicates that the virtual attribute provider suppresses any
* real values contained in the entry and generates virtual values
* and uses them.
*/
VIRTUAL_OVERRIDES_REAL("virtual-overrides-real");
/** String representation of the value. */
private final String name;
/**
* Private constructor.
* @param name for this conflict behavior.
*/
private CollectiveConflictBehavior(String name)
{
this.name = name;
}
/** {@inheritDoc} */
@Override
public String toString()
{
return name;
}
}
/**
* The name of the "collectiveConflictBehavior" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR =
"collectiveconflictbehavior";
/**
* The name of the "inheritFromDNAttribute" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_INHERIT_COLLECTIVE_FROM_DN =
"inheritfromdnattribute";
/**
* The name of the "inheritFromRDNAttribute" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN =
"inheritfromrdnattribute";
/**
* The name of the "inheritFromRDNType" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE =
"inheritfromrdntype";
/**
* The name of the "inheritFromBaseRDN" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE =
"inheritfrombaserdn";
/**
* The name of the "inheritAttribute" attribute type,
* formatted in all lowercase characters.
*/
public static final String ATTR_INHERIT_COLLECTIVE_ATTR =
"inheritattribute";
/** Attribute option to mark attributes collective. */
private static final String ATTR_OPTION_COLLECTIVE =
"collective";
/** Entry object. */
private Entry entry;
/** Subtree specification. */
private SubtreeSpecification subTreeSpec;
/** Collective subentry flag. */
private boolean isCollective;
/** Inherited collective subentry flag. */
private boolean isInheritedCollective;
/** Inherited collective from DN subentry flag. */
private boolean isInheritedFromDNCollective;
/** Inherited collective from RDN subentry flag. */
private boolean isInheritedFromRDNCollective;
/** Inherited collective DN attribute type. */
private AttributeType inheritFromDNType;
/** Inherited collective RDN attribute type. */
private AttributeType inheritFromRDNAttrType;
/** Inherited collective RDN type attribute type. */
private AttributeType inheritFromRDNType;
/** Inherited collective RDN attribute value. */
private ByteString inheritFromRDNAttrValue;
/** Inherited collective from DN value. */
private ByteString inheritFromDNAttrValue;
/** Inherited collective from base DN. */
private DN inheritFromBaseDN;
/** Collective attributes. */
private List<Attribute> collectiveAttributes;
/** Conflict behavior. */
private CollectiveConflictBehavior conflictBehavior =
CollectiveConflictBehavior.REAL_OVERRIDES_VIRTUAL;
/**
* Constructs a subentry object from a given entry object.
* @param entry LDAP subentry to construct from.
* @throws DirectoryException if there is a problem with
* constructing a subentry from a given entry.
*/
public SubEntry(Entry entry) throws DirectoryException
{
this.entry = entry;
// Process subtree specification.
this.subTreeSpec = null;
String specString = null;
boolean isValidSpec = true;
AttributeType specAttrType = DirectoryServer.getAttributeTypeOrDefault(ATTR_SUBTREE_SPEC_LC);
List<Attribute> specAttrList = entry.getAttribute(specAttrType);
if (specAttrList != null)
{
for (Attribute attr : specAttrList)
{
for (ByteString value : attr)
{
specString = value.toString();
try
{
this.subTreeSpec = SubtreeSpecification.valueOf(
entry.getName().parent(), specString);
isValidSpec = true;
}
catch (DirectoryException de)
{
isValidSpec = false;
}
if (this.subTreeSpec != null)
{
break;
}
}
if (this.subTreeSpec != null)
{
break;
}
}
}
// Check that the subtree spec is flagged as valid. If it is not
// that means all parsers have failed and it is invalid syntax.
if (!isValidSpec)
{
LocalizableMessage message =
ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
specString);
throw new DirectoryException(
ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
}
// Subentry has to to have a subtree specification.
if (this.subTreeSpec == null)
{
// There is none for some reason eg this could be
// old Draft based ldapSubEntry so create a dummy.
this.subTreeSpec = new SubtreeSpecification(entry.getName().parent(),
null, -1, -1, null, null, null);
}
// Determine if this subentry is collective attribute subentry.
this.isCollective = entry.isCollectiveAttributeSubentry();
// Determine if this subentry is inherited collective
// attribute subentry and if so what kind.
this.isInheritedCollective =
entry.isInheritedCollectiveAttributeSubentry();
if (this.isInheritedCollective)
{
this.isInheritedFromDNCollective =
entry.isInheritedFromDNCollectiveAttributeSubentry();
this.isInheritedFromRDNCollective =
entry.isInheritedFromRDNCollectiveAttributeSubentry();
}
// Process collective attributes.
this.collectiveAttributes = new ArrayList<>();
if (this.isCollective)
{
List<Attribute> subAttrList = entry.getAttributes();
for (Attribute subAttr : subAttrList)
{
AttributeType attrType = subAttr.getAttributeType();
if (attrType.isCollective())
{
CollectiveVirtualAttribute collectiveAttr =
new CollectiveVirtualAttribute(subAttr);
this.collectiveAttributes.add(collectiveAttr);
}
else if (subAttr.hasOption(ATTR_OPTION_COLLECTIVE))
{
AttributeBuilder builder = new AttributeBuilder(subAttr.getAttributeType());
builder.addAll(subAttr);
Set<String> options = new LinkedHashSet<>(subAttr.getOptions());
options.remove(ATTR_OPTION_COLLECTIVE);
builder.setOptions(options);
Attribute attr = builder.toAttribute();
CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(attr);
this.collectiveAttributes.add(collectiveAttr);
}
}
}
// Process inherited collective attributes.
if (this.isInheritedCollective)
{
if (this.isInheritedFromDNCollective)
{
List<Attribute> attrList = entry.getAttribute(
ATTR_INHERIT_COLLECTIVE_FROM_DN);
if (attrList != null && !attrList.isEmpty())
{
for (Attribute attr : attrList)
{
for (ByteString value : attr)
{
this.inheritFromDNType = DirectoryServer.getAttributeTypeOrDefault(value.toString().toLowerCase());
this.inheritFromDNAttrValue = value;
break;
}
}
}
}
if (this.isInheritedFromRDNCollective)
{
List<Attribute> attrList = entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN);
if (attrList != null && !attrList.isEmpty())
{
for (Attribute attr : attrList)
{
for (ByteString value : attr)
{
this.inheritFromRDNAttrType = DirectoryServer.getAttributeTypeOrDefault(value.toString().toLowerCase());
this.inheritFromRDNAttrValue = value;
break;
}
}
}
attrList = entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE);
if (attrList != null && !attrList.isEmpty())
{
for (Attribute attr : attrList)
{
for (ByteString value : attr)
{
this.inheritFromRDNType = DirectoryServer.getAttributeTypeOrDefault(value.toString().toLowerCase());
break;
}
}
}
attrList = entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE);
if (attrList != null && !attrList.isEmpty())
{
for (Attribute attr : attrList)
{
for (ByteString value : attr)
{
// Has to have a parent since subentry itself
// cannot be a suffix entry within the server.
this.inheritFromBaseDN = getDN().parent().child(DN.decode(value));
break;
}
}
}
}
List<Attribute> attrList = entry.getAttribute(
ATTR_INHERIT_COLLECTIVE_ATTR);
if (attrList != null && !attrList.isEmpty())
{
for (Attribute attr : attrList)
{
for (ByteString value : attr)
{
CollectiveVirtualAttribute collectiveAttr =
new CollectiveVirtualAttribute(
Attributes.empty(value.toString()));
this.collectiveAttributes.add(collectiveAttr);
}
}
}
}
// Establish collective attribute conflict behavior.
if (this.isCollective || this.isInheritedCollective)
{
List<Attribute> attrList = entry.getAttribute(
ATTR_COLLECTIVE_CONFLICT_BEHAVIOR);
if (attrList != null && !attrList.isEmpty())
{
for (Attribute attr : attrList)
{
for (ByteString value : attr)
{
for (CollectiveConflictBehavior behavior :
CollectiveConflictBehavior.values())
{
if (behavior.toString().equals(value.toString()))
{
this.conflictBehavior = behavior;
break;
}
}
}
}
}
}
}
/**
* Retrieves the distinguished name for this subentry.
* @return The distinguished name for this subentry.
*/
public final DN getDN()
{
return this.entry.getName();
}
/**
* Getter to retrieve the actual entry object
* for this subentry.
* @return entry object for this subentry.
*/
public final Entry getEntry()
{
return this.entry;
}
/**
* Indicates whether or not this subentry is
* a collective attribute subentry.
* @return <code>true</code> if collective,
* <code>false</code> otherwise.
*/
public boolean isCollective()
{
return this.isCollective;
}
/**
* Indicates whether or not this subentry is
* an inherited collective attribute subentry.
* @return <code>true</code> if inherited
* collective, <code>false</code>
* otherwise.
*/
public boolean isInheritedCollective()
{
return this.isInheritedCollective;
}
/**
* Indicates whether or not this subentry is
* an inherited from DN collective attribute
* subentry.
* @return <code>true</code> if inherited
* from DN collective,
* <code>false</code> otherwise.
*/
public boolean isInheritedFromDNCollective()
{
return this.isInheritedFromDNCollective;
}
/**
* Indicates whether or not this subentry is
* an inherited from RDN collective attribute
* subentry.
* @return <code>true</code> if inherited
* from RDN collective,
* <code>false</code> otherwise.
*/
public boolean isInheritedFromRDNCollective()
{
return this.isInheritedFromRDNCollective;
}
/**
* Getter to retrieve inheritFromDNAttribute type
* for inherited collective attribute subentry.
* @return Type of inheritFromDNAttribute or,
* <code>null</code> if there is none.
*/
public AttributeType getInheritFromDNType()
{
return this.inheritFromDNType;
}
/**
* Getter to retrieve inheritFromRDNAttribute type
* for inherited collective attribute subentry.
* @return Type of inheritFromRDNAttribute or,
* <code>null</code> if there is none.
*/
public AttributeType getInheritFromRDNAttrType()
{
return this.inheritFromRDNAttrType;
}
/**
* Getter to retrieve inheritFromRDNAttribute value
* for inherited collective attribute subentry.
* @return ByteString of inheritFromRDNAttribute
* or, <code>null</code> if there is none.
*/
public ByteString getInheritFromRDNAttrValue()
{
return this.inheritFromRDNAttrValue;
}
/**
* Getter to retrieve RDN type of inheritFromRDNType
* for inherited collective attribute subentry.
* @return RDN Type of inheritFromRDNAttribute or,
* <code>null</code> if there is none.
*/
public AttributeType getInheritFromRDNType()
{
return this.inheritFromRDNType;
}
/**
* Getter to retrieve inheritFromDNAttribute value
* for inherited collective attribute subentry.
* @return ByteString of inheritFromDNAttribute
* or, <code>null</code> if there is none.
*/
public ByteString getInheritFromDNAttrValue()
{
return this.inheritFromDNAttrValue;
}
/**
* Getter to retrieve inheritFromBaseRDN DN
* for inherited collective attribute subentry.
* @return DN of inheritFromBaseRDN or,
* <code>null</code> if there is none.
*/
public DN getInheritFromBaseDN()
{
return this.inheritFromBaseDN;
}
/**
* Getter for subentry subtree specification.
* @return subtree specification for this subentry.
*/
public SubtreeSpecification getSubTreeSpecification()
{
return this.subTreeSpec;
}
/**
* Getter for collective attributes contained within this subentry.
* @return collective attributes contained within this subentry.
*/
public List<Attribute> getCollectiveAttributes()
{
return this.collectiveAttributes;
}
/**
* Getter for collective conflict behavior defined for this
* collective attributes subentry.
* @return conflict behavior for this collective attributes
* subentry.
*/
public CollectiveConflictBehavior getConflictBehavior()
{
return this.conflictBehavior;
}
}