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}