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 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.guitools.controlpanel.task; 018 019import static org.forgerock.util.Utils.*; 020import static org.opends.messages.AdminToolMessages.*; 021 022import java.io.File; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.LinkedHashMap; 029import java.util.LinkedHashSet; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033 034import javax.naming.NamingException; 035import javax.naming.directory.BasicAttribute; 036import javax.naming.directory.DirContext; 037import javax.naming.directory.ModificationItem; 038import javax.swing.SwingUtilities; 039 040import org.forgerock.i18n.LocalizableMessage; 041import org.forgerock.opendj.ldap.ModificationType; 042import org.forgerock.opendj.ldap.schema.AttributeType; 043import org.forgerock.opendj.ldap.schema.MatchingRule; 044import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 045import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 046import org.opends.guitools.controlpanel.ui.ProgressDialog; 047import org.opends.guitools.controlpanel.util.Utilities; 048import org.opends.server.config.ConfigConstants; 049import org.opends.server.core.DirectoryServer; 050import org.opends.server.schema.SomeSchemaElement; 051import org.opends.server.types.Attributes; 052import org.opends.server.types.DirectoryException; 053import org.opends.server.types.Entry; 054import org.opends.server.types.ExistingFileBehavior; 055import org.opends.server.types.LDIFExportConfig; 056import org.opends.server.types.LDIFImportConfig; 057import org.opends.server.types.Modification; 058import org.opends.server.types.ObjectClass; 059import org.opends.server.types.OpenDsException; 060import org.opends.server.util.LDIFReader; 061import org.opends.server.util.LDIFWriter; 062import org.opends.server.util.ServerConstants; 063import org.opends.server.util.StaticUtils; 064 065/** 066 * An abstract class used to re-factor some code between the different tasks 067 * that create elements in the schema. 068 */ 069public class NewSchemaElementsTask extends Task 070{ 071 private final Set<ObjectClass> ocsToAdd = new LinkedHashSet<>(); 072 private final Set<AttributeType> attrsToAdd = new LinkedHashSet<>(); 073 074 /** 075 * Constructor of the task. 076 * 077 * @param info 078 * the control panel information. 079 * @param dlg 080 * the progress dialog where the task progress will be displayed. 081 * @param ocsToAdd 082 * the object classes that must be created in order. 083 * @param attrsToAdd 084 * the attributes that must be created in order. 085 */ 086 public NewSchemaElementsTask( 087 ControlPanelInfo info, ProgressDialog dlg, Set<ObjectClass> ocsToAdd, Set<AttributeType> attrsToAdd) 088 { 089 super(info, dlg); 090 this.ocsToAdd.addAll(ocsToAdd); 091 this.attrsToAdd.addAll(attrsToAdd); 092 } 093 094 @Override 095 public Set<String> getBackends() 096 { 097 return Collections.emptySet(); 098 } 099 100 @Override 101 public boolean canLaunch(Task taskToBeLaunched, Collection<LocalizableMessage> incompatibilityReasons) 102 { 103 if (state == State.RUNNING && 104 (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT || 105 taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT || 106 taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT)) 107 { 108 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 109 return false; 110 } 111 return true; 112 } 113 114 @Override 115 public void runTask() 116 { 117 state = State.RUNNING; 118 lastException = null; 119 120 try 121 { 122 updateSchema(); 123 state = State.FINISHED_SUCCESSFULLY; 124 } 125 catch (Throwable t) 126 { 127 lastException = t; 128 state = State.FINISHED_WITH_ERROR; 129 } 130 } 131 132 @Override 133 public Type getType() 134 { 135 return Type.NEW_SCHEMA_ELEMENT; 136 } 137 138 @Override 139 public LocalizableMessage getTaskDescription() 140 { 141 if (attrsToAdd.size() == 1 && ocsToAdd.isEmpty()) 142 { 143 return INFO_CTRL_PANEL_NEW_ATTRIBUTE_TASK_DESCRIPTION.get(attrsToAdd.iterator().next().getNameOrOID()); 144 } 145 else if (ocsToAdd.size() == 1 && attrsToAdd.isEmpty()) 146 { 147 return INFO_CTRL_PANEL_NEW_OBJECTCLASS_TASK_DESCRIPTION.get(ocsToAdd.iterator().next().getNameOrOID()); 148 } 149 else 150 { 151 final List<String> attrNames = getElementsNameOrOID(attributeTypesToSchemaElements(attrsToAdd)); 152 final List<String> ocNames = getElementsNameOrOID(objectClassesToSchemaElements(ocsToAdd)); 153 if (ocNames.isEmpty()) 154 { 155 return INFO_CTRL_PANEL_NEW_ATTRIBUTES_TASK_DESCRIPTION.get(joinAsString(", ", attrNames)); 156 } 157 else if (attrNames.isEmpty()) 158 { 159 return INFO_CTRL_PANEL_NEW_OBJECTCLASSES_TASK_DESCRIPTION.get(joinAsString(", ", ocNames)); 160 } 161 else 162 { 163 return INFO_CTRL_PANEL_NEW_SCHEMA_ELEMENTS_TASK_DESCRIPTION.get( 164 joinAsString(", ", attrNames), joinAsString(", ", ocNames)); 165 } 166 } 167 } 168 169 private List<String> getElementsNameOrOID(final Collection<SomeSchemaElement> schemaElements) 170 { 171 final List<String> nameOrOIDs = new ArrayList<>(); 172 for (SomeSchemaElement schemaElement : schemaElements) 173 { 174 nameOrOIDs.add(schemaElement.getNameOrOID()); 175 } 176 return nameOrOIDs; 177 } 178 179 /** 180 * Update the schema. 181 * 182 * @throws OpenDsException 183 * if an error occurs. 184 */ 185 private void updateSchema() throws OpenDsException 186 { 187 if (isServerRunning()) 188 { 189 updateSchemaOnline(); 190 } 191 else 192 { 193 updateSchemaOffline(); 194 } 195 } 196 197 @Override 198 protected String getCommandLinePath() 199 { 200 return null; 201 } 202 203 @Override 204 protected List<String> getCommandLineArguments() 205 { 206 return Collections.emptyList(); 207 } 208 209 /** 210 * Add the schema elements one by one: we are not sure that the server will 211 * handle the adds sequentially if we only send one modification. 212 * 213 * @throws OpenDsException 214 */ 215 private void updateSchemaOnline() throws OpenDsException 216 { 217 for (AttributeType attr : attrsToAdd) 218 { 219 addAttributeOnline(attr); 220 appendNewLinesToProgress(); 221 } 222 223 for (ObjectClass oc : ocsToAdd) 224 { 225 addObjectClassOnline(oc); 226 appendNewLinesToProgress(); 227 } 228 } 229 230 private void appendNewLinesToProgress() 231 { 232 SwingUtilities.invokeLater(new Runnable() 233 { 234 @Override 235 public void run() 236 { 237 getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>", ColorAndFontConstants.progressFont)); 238 } 239 }); 240 } 241 242 private void updateSchemaOffline() throws OpenDsException 243 { 244 // Group the changes in the same schema file. 245 final Map<String, List<SomeSchemaElement>> mapAttrs = copy(attributeTypesToSchemaElements(attrsToAdd)); 246 final Map<String, List<SomeSchemaElement>> mapClasses = copy(objectClassesToSchemaElements(ocsToAdd)); 247 final Set<String> allFileNames = new LinkedHashSet<>(mapAttrs.keySet()); 248 allFileNames.addAll(mapClasses.keySet()); 249 250 for (String fileName : allFileNames) 251 { 252 List<AttributeType> attrs = schemaElementsToAttributeTypes(get(mapAttrs, fileName)); 253 List<ObjectClass> ocs = schemaElementsToObjectClasses(get(mapClasses, fileName)); 254 255 if ("".equals(fileName)) 256 { 257 fileName = null; 258 } 259 updateSchemaOffline(fileName, attrs, ocs); 260 appendNewLinesToProgress(); 261 } 262 } 263 264 private List<SomeSchemaElement> get(Map<String, List<SomeSchemaElement>> hmElems, String fileName) 265 { 266 List<SomeSchemaElement> elems = hmElems.get(fileName); 267 if (elems != null) 268 { 269 return elems; 270 } 271 return Collections.emptyList(); 272 } 273 274 private Map<String, List<SomeSchemaElement>> copy(Set<SomeSchemaElement> elemsToAdd) 275 { 276 Map<String, List<SomeSchemaElement>> hmElems = new LinkedHashMap<>(); 277 for (SomeSchemaElement elem : elemsToAdd) 278 { 279 String fileName = elem.getSchemaFile(); 280 if (fileName == null) 281 { 282 fileName = ""; 283 } 284 List<SomeSchemaElement> elems = hmElems.get(fileName); 285 if (elems == null) 286 { 287 elems = new ArrayList<>(); 288 hmElems.put(fileName, elems); 289 } 290 elems.add(elem); 291 } 292 return hmElems; 293 } 294 295 private void addAttributeOnline(final AttributeType attribute) throws OpenDsException 296 { 297 addSchemaElementOnline(new SomeSchemaElement(attribute), 298 INFO_CTRL_PANEL_CREATING_ATTRIBUTE_PROGRESS.get(attribute.getNameOrOID())); 299 } 300 301 private void addObjectClassOnline(final ObjectClass objectClass) throws OpenDsException 302 { 303 addSchemaElementOnline(new SomeSchemaElement(objectClass), 304 INFO_CTRL_PANEL_CREATING_OBJECTCLASS_PROGRESS.get(objectClass.getNameOrOID())); 305 } 306 307 private void addSchemaElementOnline(final SomeSchemaElement schemaElement, final LocalizableMessage progressMsg) 308 throws OpenDsException 309 { 310 SwingUtilities.invokeLater(new Runnable() 311 { 312 @Override 313 public void run() 314 { 315 printEquivalentCommandLineToAddOnline(schemaElement); 316 getProgressDialog().appendProgressHtml( 317 Utilities.getProgressWithPoints(progressMsg, ColorAndFontConstants.progressFont)); 318 } 319 }); 320 try 321 { 322 final BasicAttribute attr = new BasicAttribute(schemaElement.getAttributeName()); 323 attr.add(getElementDefinition(schemaElement)); 324 final ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr); 325 getInfo().getDirContext().modifyAttributes( 326 ConfigConstants.DN_DEFAULT_SCHEMA_ROOT, new ModificationItem[] { mod }); 327 } 328 catch (NamingException ne) 329 { 330 throw new OnlineUpdateException(ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne), ne); 331 } 332 notifyConfigurationElementCreated(schemaElement); 333 SwingUtilities.invokeLater(new Runnable() 334 { 335 @Override 336 public void run() 337 { 338 getProgressDialog().appendProgressHtml(Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 339 } 340 }); 341 } 342 343 private String getValueOffline(SomeSchemaElement element) 344 { 345 final Map<String, List<String>> props = element.getExtraProperties(); 346 List<String> previousValues = props.get(ServerConstants.SCHEMA_PROPERTY_FILENAME); 347 element.setExtraPropertySingleValue(null, ServerConstants.SCHEMA_PROPERTY_FILENAME, null); 348 String attributeWithoutFileDefinition = getElementDefinition(element); 349 350 if (previousValues != null && !previousValues.isEmpty()) 351 { 352 element.setExtraPropertyMultipleValues(null, 353 ServerConstants.SCHEMA_PROPERTY_FILENAME, new ArrayList<String>(previousValues)); 354 } 355 return attributeWithoutFileDefinition; 356 } 357 358 private String getElementDefinition(SomeSchemaElement element) 359 { 360 final List<String> names = new ArrayList<>(); 361 for (final String name : element.getNames()) 362 { 363 names.add(StaticUtils.toLowerCase(name)); 364 } 365 return element.isAttributeType() 366 ? getAttributeTypeDefinition(element.getAttributeType(), names) 367 : getObjectClassDefinition(element.getObjectClass(), names); 368 } 369 370 private String getAttributeTypeDefinition(final AttributeType attributeType, final List<String> names) 371 { 372 final StringBuilder buffer = new StringBuilder(); 373 buffer.append("( ").append(attributeType.getOID()); 374 appendCollection(buffer, "NAME", names); 375 appendDescription(buffer, attributeType.getDescription()); 376 appendIfTrue(buffer, " OBSOLETE", attributeType.isObsolete()); 377 378 final AttributeType superiorType = attributeType.getSuperiorType(); 379 final String superiorTypeOID = superiorType != null ? superiorType.getOID() : null; 380 appendIfNotNull(buffer, " SUP ", superiorTypeOID); 381 addMatchingRuleIfNotNull(buffer, " EQUALITY ", attributeType.getEqualityMatchingRule()); 382 addMatchingRuleIfNotNull(buffer, " ORDERING ", attributeType.getOrderingMatchingRule()); 383 addMatchingRuleIfNotNull(buffer, " SUBSTR ", attributeType.getSubstringMatchingRule()); 384 appendIfNotNull(buffer, " SYNTAX ", attributeType.getSyntax().getOID()); 385 appendIfTrue(buffer, " SINGLE-VALUE", attributeType.isSingleValue()); 386 appendIfTrue(buffer, " COLLECTIVE", attributeType.isCollective()); 387 appendIfTrue(buffer, " NO-USER-MODIFICATION", attributeType.isNoUserModification()); 388 appendIfNotNull(buffer, " USAGE ", attributeType.getUsage()); 389 390 final MatchingRule approximateMatchingRule = attributeType.getApproximateMatchingRule(); 391 if (approximateMatchingRule != null) 392 { 393 buffer.append(" ").append(ServerConstants.SCHEMA_PROPERTY_APPROX_RULE).append(" '") 394 .append(approximateMatchingRule.getOID()).append("'"); 395 } 396 appendExtraProperties(buffer, attributeType.getExtraProperties()); 397 buffer.append(")"); 398 399 return buffer.toString(); 400 } 401 402 private void addMatchingRuleIfNotNull(final StringBuilder buffer, final String label, final MatchingRule matchingRule) 403 { 404 if (matchingRule != null) 405 { 406 append(buffer, label, matchingRule.getOID()); 407 } 408 } 409 410 private String getObjectClassDefinition(final ObjectClass objectClass, final List<String> names) 411 { 412 final StringBuilder buffer = new StringBuilder(); 413 buffer.append("( "); 414 buffer.append(objectClass.getOID()); 415 appendCollection(buffer, "NAME", names); 416 appendDescription(buffer, objectClass.getDescription()); 417 appendIfTrue(buffer, " OBSOLETE", objectClass.isObsolete()); 418 appendOIDs(buffer, "SUP", objectClassesToSchemaElements(objectClass.getSuperiorClasses())); 419 appendIfNotNull(buffer, " ", objectClass.getObjectClassType()); 420 appendOIDs(buffer, "MUST", attributeTypesToSchemaElements(objectClass.getRequiredAttributes())); 421 appendOIDs(buffer, "MAY", attributeTypesToSchemaElements(objectClass.getOptionalAttributes())); 422 appendExtraProperties(buffer, objectClass.getExtraProperties()); 423 buffer.append(")"); 424 425 return buffer.toString(); 426 } 427 428 private void appendOIDs(final StringBuilder buffer, final String label, 429 final Collection<SomeSchemaElement> schemaElements) 430 { 431 if (!schemaElements.isEmpty()) 432 { 433 final Iterator<SomeSchemaElement> iterator = schemaElements.iterator(); 434 final String firstOID = iterator.next().getOID(); 435 buffer.append(" ").append(label).append(" ( ").append(firstOID); 436 while (iterator.hasNext()) 437 { 438 buffer.append(" $ ").append(iterator.next().getOID()); 439 } 440 buffer.append(" )"); 441 } 442 } 443 444 private Set<SomeSchemaElement> objectClassesToSchemaElements(final Collection<ObjectClass> classes) 445 { 446 Set<SomeSchemaElement> elements = new HashSet<>(); 447 for (ObjectClass objectClass : classes) 448 { 449 elements.add(new SomeSchemaElement(objectClass)); 450 } 451 return elements; 452 } 453 454 private Set<SomeSchemaElement> attributeTypesToSchemaElements(final Collection<AttributeType> types) 455 { 456 Set<SomeSchemaElement> elements = new HashSet<>(); 457 for (AttributeType type : types) 458 { 459 elements.add(new SomeSchemaElement(type)); 460 } 461 return elements; 462 } 463 464 private List<AttributeType> schemaElementsToAttributeTypes(final Collection<SomeSchemaElement> elements) 465 { 466 List<AttributeType> types = new ArrayList<>(); 467 for (SomeSchemaElement element : elements) 468 { 469 types.add(element.getAttributeType()); 470 } 471 return types; 472 } 473 474 private List<ObjectClass> schemaElementsToObjectClasses(final Collection<SomeSchemaElement> elements) 475 { 476 List<ObjectClass> classes = new ArrayList<>(); 477 for (SomeSchemaElement element : elements) 478 { 479 classes.add(element.getObjectClass()); 480 } 481 return classes; 482 } 483 484 private void appendIfTrue(final StringBuilder buffer, final String label, final boolean labelIsActive) 485 { 486 if (labelIsActive) 487 { 488 buffer.append(label); 489 } 490 } 491 492 private void appendIfNotNull(final StringBuilder buffer, final String label, final Object value) 493 { 494 if (value != null) 495 { 496 append(buffer, label, value.toString()); 497 } 498 } 499 500 private void append(final StringBuilder buffer, final String label, final String value) 501 { 502 buffer.append(label).append(value); 503 } 504 505 private void appendDescription(final StringBuilder buffer, final String description) 506 { 507 if (description != null && !description.isEmpty()) 508 { 509 buffer.append(" DESC '"); 510 buffer.append(description); 511 buffer.append("'"); 512 } 513 } 514 515 private void appendExtraProperties( 516 final StringBuilder buffer, final Map<String, List<String>> extraProperties) 517 { 518 for (final Map.Entry<String, List<String>> e : extraProperties.entrySet()) 519 { 520 appendCollection(buffer, e.getKey(), e.getValue()); 521 } 522 } 523 524 private void appendCollection(final StringBuilder buffer, final String property, final Collection<String> values) 525 { 526 final Iterator<String> iterator = values.iterator(); 527 final boolean isMultiValued = values.size() > 1; 528 if (iterator.hasNext()) 529 { 530 final String first = iterator.next(); 531 buffer.append(" ").append(property); 532 buffer.append(isMultiValued ? " ( '" : " '").append(first).append("' "); 533 while (iterator.hasNext()) 534 { 535 buffer.append("'").append(iterator.next()).append("' "); 536 } 537 if (isMultiValued) 538 { 539 buffer.append(")"); 540 } 541 } 542 } 543 544 private void printEquivalentCommandLineToAddOnline(SomeSchemaElement element) 545 { 546 List<String> args = new ArrayList<>(); 547 args.add("-a"); 548 args.addAll(getObfuscatedCommandLineArguments(getConnectionCommandLineArguments(true, true))); 549 args.add(getNoPropertiesFileArgument()); 550 551 final String equivalentCmdLine = getEquivalentCommandLine(getCommandLinePath("ldapmodify"), args); 552 final StringBuilder sb = new StringBuilder(); 553 final String attName = element.getAttributeName(); 554 final String elementId = element.getNameOrOID(); 555 final LocalizableMessage message = element.isAttributeType() 556 ? INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_ATTRIBUTE_ONLINE.get(elementId) 557 : INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_OBJECTCLASS_ONLINE.get(elementId); 558 sb.append(message).append("<br><b>") 559 .append(equivalentCmdLine).append("<br>") 560 .append("dn: cn=schema<br>") 561 .append("changetype: modify<br>") 562 .append("add: ").append(attName).append("<br>") 563 .append(attName).append(": ").append(getElementDefinition(element)).append("</b><br><br>"); 564 getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(), ColorAndFontConstants.progressFont)); 565 } 566 567 private void updateSchemaOffline( 568 String file, final List<AttributeType> attributes, final List<ObjectClass> objectClasses) throws OpenDsException 569 { 570 final List<SomeSchemaElement> schemaElements = 571 new ArrayList<SomeSchemaElement>(attributeTypesToSchemaElements(attributes)); 572 schemaElements.addAll(objectClassesToSchemaElements(objectClasses)); 573 if (file == null) 574 { 575 file = ConfigConstants.FILE_USER_SCHEMA_ELEMENTS; 576 } 577 File f = new File(file); 578 if (!f.isAbsolute()) 579 { 580 f = new File(DirectoryServer.getEnvironmentConfig().getSchemaDirectory(), file); 581 } 582 final String fileName = f.getAbsolutePath(); 583 final boolean isSchemaFileDefined = isSchemaFileDefined(fileName); 584 SwingUtilities.invokeLater(new Runnable() 585 { 586 @Override 587 public void run() 588 { 589 final ProgressDialog progressDialog = getProgressDialog(); 590 final String command = equivalentCommandToAddOffline(fileName, isSchemaFileDefined, schemaElements); 591 progressDialog.appendProgressHtml(Utilities.applyFont(command, ColorAndFontConstants.progressFont)); 592 593 if (attributes.size() == 1 && objectClasses.isEmpty()) 594 { 595 String attributeName = attributes.get(0).getNameOrOID(); 596 progressDialog.appendProgressHtml(Utilities.getProgressWithPoints( 597 INFO_CTRL_PANEL_CREATING_ATTRIBUTE_PROGRESS.get(attributeName), ColorAndFontConstants.progressFont)); 598 } 599 else if (objectClasses.size() == 1 && attributes.isEmpty()) 600 { 601 String ocName = objectClasses.get(0).getNameOrOID(); 602 progressDialog.appendProgressHtml(Utilities.getProgressWithPoints( 603 INFO_CTRL_PANEL_CREATING_OBJECTCLASS_PROGRESS.get(ocName), ColorAndFontConstants.progressFont)); 604 } 605 else 606 { 607 progressDialog.appendProgressHtml(Utilities.getProgressWithPoints( 608 INFO_CTRL_PANEL_UPDATING_SCHEMA_FILE_PROGRESS.get(fileName), ColorAndFontConstants.progressFont)); 609 } 610 } 611 }); 612 613 if (isSchemaFileDefined) 614 { 615 updateSchemaFile(fileName, schemaElements); 616 } 617 else 618 { 619 updateSchemaUndefinedFile(fileName, schemaElements); 620 } 621 622 for (SomeSchemaElement schemaElement : schemaElements) 623 { 624 notifyConfigurationElementCreated(schemaElement); 625 } 626 SwingUtilities.invokeLater(new Runnable() 627 { 628 @Override 629 public void run() 630 { 631 getProgressDialog().appendProgressHtml(Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 632 } 633 }); 634 } 635 636 private String equivalentCommandToAddOffline( 637 String schemaFile, boolean isSchemaFileDefined, List<SomeSchemaElement> schemaElements) 638 { 639 List<String> names = getElementsNameOrOID(schemaElements); 640 641 final String namesString = joinAsString(", ", names); 642 final StringBuilder sb = new StringBuilder(); 643 if (isSchemaFileDefined) 644 { 645 sb.append(INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ELEMENT_OFFLINE.get(namesString, schemaFile)) 646 .append("<br><b>"); 647 } 648 else 649 { 650 sb.append(INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_ADD_SCHEMA_ENTRY_OFFLINE.get(namesString, schemaFile)) 651 .append("<br><b>"); 652 for (String line : getSchemaEntryLines()) 653 { 654 sb.append(line); 655 sb.append("<br>"); 656 } 657 } 658 659 for (SomeSchemaElement schemaElement : schemaElements) 660 { 661 sb.append(schemaElement.getAttributeName()).append(": ").append(getValueOffline(schemaElement)).append("<br>"); 662 } 663 sb.append("</b><br><br>"); 664 665 return sb.toString(); 666 } 667 668 /** 669 * Returns whether the file defined in the schema element exists or not. 670 * 671 * @param schemaFile 672 * the path to the schema file. 673 * @return <CODE>true</CODE> if the schema file is defined and 674 * <CODE>false</CODE> otherwise. 675 */ 676 private boolean isSchemaFileDefined(String schemaFile) 677 { 678 try (LDIFReader reader = new LDIFReader(new LDIFImportConfig(schemaFile))) 679 { 680 return reader.readEntry() != null; 681 } 682 catch (Throwable t) 683 { 684 return false; 685 } 686 } 687 688 /** 689 * Returns the list of LDIF lines that are enough to create the entry 690 * containing only the schema element associated with this task. 691 * 692 * @return the list of LDIF lines that are enough to create the entry 693 * containing only the schema element associated with this task. 694 */ 695 private List<String> getSchemaEntryLines() 696 { 697 List<String> lines = new ArrayList<>(); 698 lines.add("dn: cn=schema"); 699 lines.add("objectClass: top"); 700 lines.add("objectClass: ldapSubentry"); 701 lines.add("objectClass: subschema"); 702 return lines; 703 } 704 705 /** 706 * Updates the contents of the schema file. 707 * 708 * @param schemaFile 709 * the schema file. 710 * @param isSchemaFileDefined 711 * whether the schema is defined or not. 712 * @param attributes 713 * the attributes to add. 714 * @param objectClasses 715 * the object classes to add. 716 * @throws OpenDsException 717 * if an error occurs updating the schema file. 718 */ 719 private void updateSchemaFile(String schemaFile, List<SomeSchemaElement> schemaElements) 720 throws OpenDsException 721 { 722 try (final LDIFExportConfig exportConfig = new LDIFExportConfig(schemaFile, ExistingFileBehavior.OVERWRITE)) 723 { 724 try (final LDIFReader reader = new LDIFReader(new LDIFImportConfig(schemaFile))) 725 { 726 final Entry schemaEntry = reader.readEntry(); 727 addElementsToEntry(schemaElements, schemaEntry); 728 try (final LDIFWriter writer = new LDIFWriter(exportConfig)) 729 { 730 writer.writeEntry(schemaEntry); 731 exportConfig.getWriter().newLine(); 732 } 733 } 734 catch (Throwable t) 735 { 736 throw new OfflineUpdateException(ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(t), t); 737 } 738 } 739 } 740 741 private void addElementsToEntry(List<SomeSchemaElement> schemaElements, Entry schemaEntry) 742 throws DirectoryException 743 { 744 for (SomeSchemaElement schemaElement : schemaElements) 745 { 746 final Modification mod = new Modification(ModificationType.ADD, 747 Attributes.create(schemaElement.getAttributeName().toLowerCase(), getValueOffline(schemaElement))); 748 schemaEntry.applyModification(mod); 749 } 750 } 751 752 private void updateSchemaUndefinedFile(String schemaFile, List<SomeSchemaElement> schemaElements) 753 throws OfflineUpdateException 754 { 755 try (LDIFExportConfig exportConfig = new LDIFExportConfig(schemaFile, ExistingFileBehavior.FAIL)) 756 { 757 List<String> lines = getSchemaEntryLines(); 758 for (final SomeSchemaElement schemaElement : schemaElements) 759 { 760 lines.add(schemaElement.getAttributeName() + ": " + getValueOffline(schemaElement)); 761 } 762 for (String line : lines) 763 { 764 final boolean wrapLines = exportConfig.getWrapColumn() > 1; 765 LDIFWriter.writeLDIFLine( 766 new StringBuilder(line), exportConfig.getWriter(), wrapLines, exportConfig.getWrapColumn()); 767 } 768 exportConfig.getWriter().newLine(); 769 } 770 catch (Throwable t) 771 { 772 throw new OfflineUpdateException(ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(t), t); 773 } 774 } 775}