001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.tools.makeldif; 028 029import static org.opends.server.util.LDIFWriter.*; 030import static org.opends.server.util.StaticUtils.*; 031 032import java.io.BufferedWriter; 033import java.io.IOException; 034import java.util.ArrayList; 035import java.util.LinkedHashMap; 036import java.util.List; 037 038import org.forgerock.opendj.ldap.ByteString; 039import org.opends.server.core.DirectoryServer; 040import org.opends.server.types.*; 041import org.opends.server.util.LDIFException; 042 043/** 044 * This class defines an entry that is generated using a MakeLDIF branch or 045 * template. 046 */ 047public class TemplateEntry 048{ 049 /** The branch used to generate this entry (if it is associated with a branch). */ 050 private Branch branch; 051 /** The DN for this template entry, if it is known. */ 052 private DN dn; 053 /** The DN of the parent entry for this template entry, if it is available. */ 054 private DN parentDN; 055 056 /** 057 * The set of attributes associated with this template entry, mapped from the 058 * lowercase name of the attribute to the list of generated values. 059 */ 060 private final LinkedHashMap<AttributeType, ArrayList<TemplateValue>> attributes = new LinkedHashMap<>(); 061 062 /** The template used to generate this entry (if it is associated with a template). */ 063 private Template template; 064 065 066 /** 067 * Creates a new template entry that will be associated with the provided 068 * branch. 069 * 070 * @param branch The branch to use when creating this template entry. 071 */ 072 public TemplateEntry(Branch branch) 073 { 074 this.branch = branch; 075 076 dn = branch.getBranchDN(); 077 } 078 079 080 081 /** 082 * Creates a new template entry that will be associated with the provided 083 * template. 084 * 085 * @param template The template used to generate this entry. 086 * @param parentDN The DN of the parent entry for this template entry. 087 */ 088 public TemplateEntry(Template template, DN parentDN) 089 { 090 this.template = template; 091 this.parentDN = parentDN; 092 } 093 094 095 096 /** 097 * Retrieves the branch used to generate this entry. 098 * 099 * @return The branch used to generate this entry, or <CODE>null</CODE> if it 100 * is associated with a template instead of a branch. 101 */ 102 public Branch getBranch() 103 { 104 return branch; 105 } 106 107 108 109 /** 110 * Retrieves the template used to generate this entry. 111 * 112 * @return The template used to generate this entry, or <CODE>null</CODE> if 113 * it is associated with a branch instead of a template. 114 */ 115 public Template getTemplate() 116 { 117 return template; 118 } 119 120 121 122 /** 123 * Retrieves the DN of the parent entry for this template entry. 124 * 125 * @return The DN of the parent entry for this template entry, or 126 * <CODE>null</CODE> if there is no parent DN. 127 */ 128 public DN getParentDN() 129 { 130 return parentDN; 131 } 132 133 134 135 /** 136 * Retrieves the DN for this template entry, if it is known. 137 * 138 * @return The DN for this template entry if it is known, or 139 * <CODE>null</CODE> if it cannot yet be determined. 140 */ 141 public DN getDN() 142 { 143 if (dn == null) 144 { 145 RDN rdn; 146 AttributeType[] rdnAttrs = template.getRDNAttributes(); 147 if (rdnAttrs.length == 1) 148 { 149 AttributeType t = rdnAttrs[0]; 150 TemplateValue v = getValue(t); 151 if (v == null) 152 { 153 return null; 154 } 155 156 rdn = new RDN(t, ByteString.valueOfUtf8(v.getValue().toString())); 157 } 158 else 159 { 160 String[] names = new String[rdnAttrs.length]; 161 ByteString[] values = new ByteString[rdnAttrs.length]; 162 for (int i=0; i < rdnAttrs.length; i++) 163 { 164 AttributeType t = rdnAttrs[i]; 165 TemplateValue v = getValue(t); 166 if (v == null) 167 { 168 return null; 169 } 170 171 names[i] = t.getPrimaryName(); 172 values[i] = ByteString.valueOfUtf8(v.getValue().toString()); 173 } 174 175 rdn = new RDN(rdnAttrs, names, values); 176 } 177 178 dn = parentDN.child(rdn); 179 } 180 181 return dn; 182 } 183 184 185 186 /** 187 * Indicates whether this entry contains one or more values for the specified 188 * attribute type. 189 * 190 * @param attributeType The attribute type for which to make the 191 * determination. 192 * 193 * @return <CODE>true</CODE> if this entry contains one or more values for 194 * the specified attribute type, or <CODE>false</CODE> if not. 195 */ 196 public boolean hasAttribute(AttributeType attributeType) 197 { 198 return attributes.containsKey(attributeType); 199 } 200 201 202 203 /** 204 * Retrieves the value for the specified attribute, if defined. If the 205 * specified attribute has multiple values, then the first will be returned. 206 * 207 * @param attributeType The attribute type for which to retrieve the value. 208 * 209 * @return The value for the specified attribute, or <CODE>null</CODE> if 210 * there are no values for that attribute type. 211 */ 212 public TemplateValue getValue(AttributeType attributeType) 213 { 214 ArrayList<TemplateValue> valueList = attributes.get(attributeType); 215 if (valueList != null && !valueList.isEmpty()) 216 { 217 return valueList.get(0); 218 } 219 return null; 220 } 221 222 223 224 /** 225 * Retrieves the set of values for the specified attribute, if defined. 226 * 227 * @param attributeType The attribute type for which to retrieve the set of 228 * values. 229 * 230 * @return The set of values for the specified attribute, or 231 * <CODE>null</CODE> if there are no values for that attribute type. 232 */ 233 public List<TemplateValue> getValues(AttributeType attributeType) 234 { 235 return attributes.get(attributeType); 236 } 237 238 239 240 /** 241 * Adds the provided template value to this entry. 242 * 243 * @param value The value to add to this entry. 244 */ 245 public void addValue(TemplateValue value) 246 { 247 ArrayList<TemplateValue> valueList = attributes.get(value.getAttributeType()); 248 if (valueList == null) 249 { 250 valueList = new ArrayList<>(); 251 attributes.put(value.getAttributeType(), valueList); 252 } 253 valueList.add(value); 254 } 255 256 257 /** 258 * Writes this entry in LDIF form. No filtering will be 259 * performed for this entry, nor will any export plugins be invoked. 260 * 261 * @param exportConfig The configuration that specifies how the 262 * entry should be written. 263 * 264 * @return <CODE>true</CODE> if the entry is actually written, or 265 * <CODE>false</CODE> if it is not for some reason. 266 * 267 * @throws IOException If a problem occurs while writing the 268 * information. 269 * 270 * @throws LDIFException If a problem occurs while trying to 271 * determine whether to write the entry. 272 */ 273 public boolean toLDIF(LDIFExportConfig exportConfig) 274 throws IOException, LDIFException 275 { 276 // Process all of the attributes for this entry. 277 LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>(); 278 LinkedHashMap<AttributeType,List<Attribute>> userAttributes = new LinkedHashMap<>(); 279 LinkedHashMap<AttributeType,List<Attribute>> operationalAttributes = new LinkedHashMap<>(); 280 LinkedHashMap<AttributeType, List<Attribute>> urlAttributes = new LinkedHashMap<>(); 281 LinkedHashMap<AttributeType, List<Attribute>> base64Attributes = new LinkedHashMap<>(); 282 283 for (AttributeType t : attributes.keySet()) 284 { 285 ArrayList<TemplateValue> valueList = attributes.get(t); 286 if (t.isObjectClass()) 287 { 288 for (TemplateValue v : valueList) 289 { 290 String ocName = toLowerCase(v.getValue().toString()); 291 ObjectClass oc = DirectoryServer.getObjectClass(ocName, true); 292 objectClasses.put(oc, ocName); 293 } 294 } 295 else if (t.isOperational()) 296 { 297 AttributeBuilder builder = new AttributeBuilder(t, t.getNameOrOID()); 298 for (TemplateValue v : valueList) 299 { 300 builder.add(v.getValue().toString()); 301 } 302 303 operationalAttributes.put(t, builder.toAttributeList()); 304 } 305 else 306 { 307 AttributeBuilder builder = new AttributeBuilder(t, t.getNameOrOID()); 308 AttributeBuilder urlBuilder = null; 309 AttributeBuilder base64Builder = null; 310 for (TemplateValue v : valueList) 311 { 312 ByteString value = ByteString.valueOfUtf8(v.getValue().toString()); 313 builder.add(value); 314 if (v.getTemplateLine().isURL()) 315 { 316 if (urlBuilder == null) 317 { 318 urlBuilder = new AttributeBuilder(t, t.getNameOrOID()); 319 } 320 urlBuilder.add(value); 321 } 322 else if (v.getTemplateLine().isBase64()) 323 { 324 if (base64Builder == null) 325 { 326 base64Builder = new AttributeBuilder(t, t.getNameOrOID()); 327 } 328 base64Builder.add(value); 329 } 330 } 331 332 userAttributes.put(t, builder.toAttributeList()); 333 if (urlBuilder != null) 334 { 335 urlAttributes.put(t, urlBuilder.toAttributeList()); 336 } 337 if (base64Builder != null) 338 { 339 base64Attributes.put(t, base64Builder.toAttributeList()); 340 } 341 } 342 } 343 344 // Get the information necessary to write the LDIF. 345 BufferedWriter writer = exportConfig.getWriter(); 346 int wrapColumn = exportConfig.getWrapColumn(); 347 boolean wrapLines = wrapColumn > 1; 348 349 350 // First, write the DN. It will always be included. 351 StringBuilder dnLine = new StringBuilder("dn"); 352 appendLDIFSeparatorAndValue(dnLine, 353 ByteString.valueOfUtf8(getDN().toString())); 354 writeLDIFLine(dnLine, writer, wrapLines, wrapColumn); 355 356 357 // Next, the set of objectclasses. 358 final boolean typesOnly = exportConfig.typesOnly(); 359 if (exportConfig.includeObjectClasses()) 360 { 361 if (typesOnly) 362 { 363 StringBuilder ocLine = new StringBuilder("objectClass:"); 364 writeLDIFLine(ocLine, writer, wrapLines, wrapColumn); 365 } 366 else 367 { 368 for (String s : objectClasses.values()) 369 { 370 StringBuilder ocLine = new StringBuilder("objectClass: ").append(s); 371 writeLDIFLine(ocLine, writer, wrapLines, wrapColumn); 372 } 373 } 374 } 375 376 377 // Now the set of user attributes. 378 for (AttributeType attrType : userAttributes.keySet()) 379 { 380 if (exportConfig.includeAttribute(attrType)) 381 { 382 for (Attribute a : userAttributes.get(attrType)) 383 { 384 if (a.isVirtual() && !exportConfig.includeVirtualAttributes()) 385 { 386 continue; 387 } 388 389 StringBuilder attrName = attrNameWithOptions(a); 390 if (typesOnly) 391 { 392 attrName.append(":"); 393 394 writeLDIFLine(attrName, writer, wrapLines, wrapColumn); 395 } 396 else 397 { 398 List<Attribute> urlAttrList = urlAttributes.get(attrType); 399 List<Attribute> base64AttrList = base64Attributes.get(attrType); 400 401 for (ByteString v : a) 402 { 403 StringBuilder attrLine = new StringBuilder(attrName); 404 boolean isURLValue = contains(urlAttrList, v); 405 boolean isBase64Value = contains(base64AttrList, v); 406 appendLDIFSeparatorAndValue(attrLine, 407 v, 408 isURLValue, 409 isBase64Value); 410 writeLDIFLine(attrLine, writer, wrapLines, wrapColumn); 411 } 412 } 413 } 414 } 415 } 416 417 418 // Next, the set of operational attributes. 419 if (exportConfig.includeOperationalAttributes()) 420 { 421 for (AttributeType attrType : operationalAttributes.keySet()) 422 { 423 if (exportConfig.includeAttribute(attrType)) 424 { 425 for (Attribute a : operationalAttributes.get(attrType)) 426 { 427 if (a.isVirtual() && !exportConfig.includeVirtualAttributes()) 428 { 429 continue; 430 } 431 432 StringBuilder attrName = attrNameWithOptions(a); 433 if (typesOnly) 434 { 435 attrName.append(":"); 436 437 writeLDIFLine(attrName, writer, wrapLines, wrapColumn); 438 } 439 else 440 { 441 for (ByteString v : a) 442 { 443 StringBuilder attrLine = new StringBuilder(attrName); 444 appendLDIFSeparatorAndValue(attrLine, v); 445 writeLDIFLine(attrLine, writer, wrapLines, wrapColumn); 446 } 447 } 448 } 449 } 450 } 451 } 452 453 // Make sure there is a blank line after the entry. 454 writer.newLine(); 455 456 return true; 457 } 458 459 private StringBuilder attrNameWithOptions(Attribute a) 460 { 461 StringBuilder attrName = new StringBuilder(a.getName()); 462 for (String o : a.getOptions()) 463 { 464 attrName.append(";"); 465 attrName.append(o); 466 } 467 return attrName; 468 } 469 470 private boolean contains(List<Attribute> urlAttrList, ByteString v) 471 { 472 if (urlAttrList != null) 473 { 474 for (Attribute urlAttr : urlAttrList) 475 { 476 for (ByteString urlValue : urlAttr) 477 { 478 if (urlValue.equals(v)) 479 { 480 return true; 481 } 482 } 483 } 484 } 485 return false; 486 } 487}