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}