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