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 2008-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.guitools.controlpanel.task; 028 029import static org.opends.messages.AdminToolMessages.*; 030 031import java.io.File; 032import java.io.IOException; 033import java.util.ArrayList; 034import java.util.Collection; 035import java.util.Collections; 036import java.util.HashMap; 037import java.util.HashSet; 038import java.util.LinkedHashSet; 039import java.util.List; 040import java.util.Map; 041import java.util.Set; 042 043import javax.naming.NamingException; 044import javax.naming.directory.BasicAttribute; 045import javax.naming.directory.DirContext; 046import javax.naming.directory.ModificationItem; 047import javax.swing.SwingUtilities; 048 049import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 050import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 051import org.opends.guitools.controlpanel.ui.ProgressDialog; 052import org.opends.guitools.controlpanel.util.Utilities; 053import org.forgerock.i18n.LocalizableMessage; 054import org.opends.server.config.ConfigConstants; 055import org.opends.server.core.DirectoryServer; 056import org.opends.server.types.Attributes; 057import org.opends.server.types.AttributeType; 058import org.opends.server.types.CommonSchemaElements; 059import org.opends.server.types.Entry; 060import org.opends.server.types.ExistingFileBehavior; 061import org.opends.server.types.LDIFExportConfig; 062import org.opends.server.types.LDIFImportConfig; 063import org.opends.server.types.Modification; 064import org.forgerock.opendj.ldap.ModificationType; 065import org.opends.server.types.ObjectClass; 066import org.opends.server.types.OpenDsException; 067import org.opends.server.types.Schema; 068import org.opends.server.types.SchemaFileElement; 069import org.opends.server.util.LDIFReader; 070import org.opends.server.util.LDIFWriter; 071import org.opends.server.util.StaticUtils; 072 073/** The task that is launched when a schema element must be deleted. */ 074public class DeleteSchemaElementsTask extends Task 075{ 076 /** The list of object classes that the user asked to delete. */ 077 private Set<ObjectClass> providedOcsToDelete = new LinkedHashSet<>(); 078 /** The list of attributes that the user asked to delete. */ 079 private Set<AttributeType> providedAttrsToDelete = new LinkedHashSet<>(); 080 /** The list of object classes that will be actually deleted (some might be recreated). */ 081 private Set<ObjectClass> ocsToDelete = new LinkedHashSet<>(); 082 /** The list of attributes that will be actually deleted (some might be recreated). */ 083 private Set<AttributeType> attrsToDelete = new LinkedHashSet<>(); 084 /** The list of object classes that will be recreated. */ 085 private Set<ObjectClass> ocsToAdd = new LinkedHashSet<>(); 086 /** The list of attributes that will be recreated. */ 087 private Set<AttributeType> attrsToAdd = new LinkedHashSet<>(); 088 089 /** 090 * Constructor of the task. 091 * @param info the control panel information. 092 * @param dlg the progress dialog where the task progress will be displayed. 093 * @param ocsToDelete the object classes that must be deleted (ordered). 094 * @param attrsToDelete the attributes that must be deleted (ordered). 095 */ 096 public DeleteSchemaElementsTask(ControlPanelInfo info, ProgressDialog dlg, 097 Set<ObjectClass> ocsToDelete, Set<AttributeType> attrsToDelete) 098 { 099 super(info, dlg); 100 101 this.providedOcsToDelete.addAll(ocsToDelete); 102 this.providedAttrsToDelete.addAll(attrsToDelete); 103 104 Schema schema = info.getServerDescriptor().getSchema(); 105 LinkedHashSet<AttributeType> allAttrsToDelete = 106 DeleteSchemaElementsTask.getOrderedAttributesToDelete(attrsToDelete, 107 schema); 108 LinkedHashSet<ObjectClass> allOcsToDelete = null; 109 if (!attrsToDelete.isEmpty()) 110 { 111 allOcsToDelete = 112 DeleteSchemaElementsTask.getOrderedObjectClassesToDeleteFromAttrs( 113 attrsToDelete, schema); 114 } 115 if (!ocsToDelete.isEmpty()) 116 { 117 LinkedHashSet<ObjectClass> orderedOCs = 118 DeleteSchemaElementsTask.getOrderedObjectClassesToDelete(ocsToDelete, schema); 119 if (allOcsToDelete == null) 120 { 121 allOcsToDelete = orderedOCs; 122 } 123 else 124 { 125 allOcsToDelete.addAll(orderedOCs); 126 } 127 } 128 ArrayList<AttributeType> lAttrsToDelete = new ArrayList<>(allAttrsToDelete); 129 for (int i = lAttrsToDelete.size() - 1; i >= 0; i--) 130 { 131 AttributeType attrToDelete = lAttrsToDelete.get(i); 132 if (!attrsToDelete.contains(attrToDelete)) 133 { 134 AttributeType attrToAdd = getAttributeToAdd(attrToDelete); 135 if (attrToAdd != null) 136 { 137 attrsToAdd.add(attrToAdd); 138 } 139 } 140 } 141 142 assert allOcsToDelete != null; 143 ArrayList<ObjectClass> lOcsToDelete = new ArrayList<>(allOcsToDelete); 144 for (int i = lOcsToDelete.size() - 1; i >= 0; i--) 145 { 146 ObjectClass ocToDelete = lOcsToDelete.get(i); 147 if (!ocsToDelete.contains(ocToDelete)) 148 { 149 ocsToAdd.add(getObjectClassToAdd(lOcsToDelete.get(i))); 150 } 151 } 152 153 this.ocsToDelete.addAll(allOcsToDelete); 154 this.attrsToDelete.addAll(allAttrsToDelete); 155 } 156 157 /** {@inheritDoc} */ 158 @Override 159 public Set<String> getBackends() 160 { 161 return Collections.emptySet(); 162 } 163 164 /** {@inheritDoc} */ 165 @Override 166 public boolean canLaunch(Task taskToBeLaunched, 167 Collection<LocalizableMessage> incompatibilityReasons) 168 { 169 boolean canLaunch = true; 170 if (state == State.RUNNING && 171 (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT || 172 taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT || 173 taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT)) 174 { 175 incompatibilityReasons.add(getIncompatibilityMessage(this, 176 taskToBeLaunched)); 177 canLaunch = false; 178 } 179 return canLaunch; 180 } 181 182 /** {@inheritDoc} */ 183 @Override 184 public Type getType() 185 { 186 return Type.NEW_SCHEMA_ELEMENT; 187 } 188 189 /** {@inheritDoc} */ 190 @Override 191 public void runTask() 192 { 193 state = State.RUNNING; 194 lastException = null; 195 196 try 197 { 198 updateSchema(); 199 state = State.FINISHED_SUCCESSFULLY; 200 } 201 catch (Throwable t) 202 { 203 lastException = t; 204 state = State.FINISHED_WITH_ERROR; 205 } 206 } 207 208 /** {@inheritDoc} */ 209 @Override 210 protected String getCommandLinePath() 211 { 212 return null; 213 } 214 215 /** {@inheritDoc} */ 216 @Override 217 protected List<String> getCommandLineArguments() 218 { 219 return Collections.emptyList(); 220 } 221 222 /** {@inheritDoc} */ 223 @Override 224 public LocalizableMessage getTaskDescription() 225 { 226 return INFO_CTRL_PANEL_DELETE_SCHEMA_ELEMENT_TASK_DESCRIPTION.get(); 227 } 228 229 /** 230 * Updates the schema. 231 * @throws OpenDsException if an error occurs. 232 */ 233 private void updateSchema() throws OpenDsException 234 { 235 final boolean[] isFirst = {true}; 236 final int totalNumber = ocsToDelete.size() + attrsToDelete.size(); 237 int numberDeleted = 0; 238 for (ObjectClass objectClass : ocsToDelete) 239 { 240 final ObjectClass fObjectclass = objectClass; 241 SwingUtilities.invokeLater(new Runnable() 242 { 243 @Override 244 public void run() 245 { 246 if (!isFirst[0]) 247 { 248 getProgressDialog().appendProgressHtml("<br><br>"); 249 } 250 isFirst[0] = false; 251 printEquivalentCommandToDelete(fObjectclass); 252 getProgressDialog().appendProgressHtml( 253 Utilities.getProgressWithPoints( 254 INFO_CTRL_PANEL_DELETING_OBJECTCLASS.get( 255 fObjectclass.getNameOrOID()), 256 ColorAndFontConstants.progressFont)); 257 } 258 }); 259 260 if (isServerRunning()) 261 { 262 try 263 { 264 BasicAttribute attr = new BasicAttribute( 265 getSchemaFileAttributeName(objectClass)); 266 attr.add(getSchemaFileAttributeValue(objectClass)); 267 ModificationItem mod = 268 new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr); 269 getInfo().getDirContext().modifyAttributes( 270 ConfigConstants.DN_DEFAULT_SCHEMA_ROOT, 271 new ModificationItem[] { mod }); 272 } 273 catch (NamingException ne) 274 { 275 throw new OnlineUpdateException( 276 ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne), ne); 277 } 278 } 279 else 280 { 281 updateSchemaFile(objectClass); 282 } 283 numberDeleted ++; 284 final int fNumberDeleted = numberDeleted; 285 SwingUtilities.invokeLater(new Runnable() 286 { 287 @Override 288 public void run() 289 { 290 getProgressDialog().getProgressBar().setIndeterminate(false); 291 getProgressDialog().getProgressBar().setValue( 292 (fNumberDeleted * 100) / totalNumber); 293 getProgressDialog().appendProgressHtml( 294 Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 295 } 296 }); 297 } 298 299 for (AttributeType attribute : attrsToDelete) 300 { 301 final AttributeType fAttribute = attribute; 302 SwingUtilities.invokeLater(new Runnable() 303 { 304 @Override 305 public void run() 306 { 307 if (!isFirst[0]) 308 { 309 getProgressDialog().appendProgressHtml("<br><br>"); 310 } 311 isFirst[0] = false; 312 printEquivalentCommandToDelete(fAttribute); 313 getProgressDialog().appendProgressHtml( 314 Utilities.getProgressWithPoints( 315 INFO_CTRL_PANEL_DELETING_ATTRIBUTE.get( 316 fAttribute.getNameOrOID()), 317 ColorAndFontConstants.progressFont)); 318 } 319 }); 320 321 if (isServerRunning()) 322 { 323 try 324 { 325 BasicAttribute attr = new BasicAttribute( 326 getSchemaFileAttributeName(attribute)); 327 attr.add(getSchemaFileAttributeValue(attribute)); 328 ModificationItem mod = new ModificationItem( 329 DirContext.REMOVE_ATTRIBUTE, 330 attr); 331 getInfo().getDirContext().modifyAttributes( 332 ConfigConstants.DN_DEFAULT_SCHEMA_ROOT, 333 new ModificationItem[] { mod }); 334 } 335 catch (NamingException ne) 336 { 337 throw new OnlineUpdateException( 338 ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(ne), ne); 339 } 340 } 341 else 342 { 343 updateSchemaFile(attribute); 344 } 345 346 numberDeleted ++; 347 final int fNumberDeleted = numberDeleted; 348 SwingUtilities.invokeLater(new Runnable() 349 { 350 @Override 351 public void run() 352 { 353 getProgressDialog().getProgressBar().setIndeterminate(false); 354 getProgressDialog().getProgressBar().setValue( 355 (fNumberDeleted * 100) / totalNumber); 356 getProgressDialog().appendProgressHtml( 357 Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 358 } 359 }); 360 } 361 362 if (!ocsToAdd.isEmpty() || !attrsToAdd.isEmpty()) 363 { 364 SwingUtilities.invokeLater(new Runnable() 365 { 366 @Override 367 public void run() 368 { 369 getProgressDialog().appendProgressHtml(Utilities.applyFont( 370 "<br><br>"+ 371 INFO_CTRL_PANEL_EXPLANATION_TO_DELETE_REFERENCED_ELEMENTS.get()+ 372 "<br><br>", 373 ColorAndFontConstants.progressFont)); 374 } 375 }); 376 377 NewSchemaElementsTask createTask = 378 new NewSchemaElementsTask(getInfo(), getProgressDialog(), ocsToAdd, 379 attrsToAdd); 380 createTask.runTask(); 381 } 382 } 383 384 /** 385 * Updates the schema file by deleting the provided schema element. 386 * @param schemaElement the schema element to be deleted. 387 * @throws OpenDsException if an error occurs. 388 */ 389 private void updateSchemaFile(CommonSchemaElements schemaElement) 390 throws OpenDsException 391 { 392 String schemaFile = getSchemaFile(schemaElement); 393 LDIFExportConfig exportConfig = 394 new LDIFExportConfig(schemaFile, 395 ExistingFileBehavior.OVERWRITE); 396 LDIFReader reader = null; 397 LDIFWriter writer = null; 398 try 399 { 400 reader = new LDIFReader(new LDIFImportConfig(schemaFile)); 401 Entry schemaEntry = reader.readEntry(); 402 403 Modification mod = new Modification(ModificationType.DELETE, 404 Attributes.create( 405 getSchemaFileAttributeName(schemaElement).toLowerCase(), 406 getSchemaFileAttributeValue(schemaElement))); 407 schemaEntry.applyModification(mod); 408 writer = new LDIFWriter(exportConfig); 409 writer.writeEntry(schemaEntry); 410 exportConfig.getWriter().newLine(); 411 } 412 catch (IOException e) 413 { 414 throw new OfflineUpdateException( 415 ERR_CTRL_PANEL_ERROR_UPDATING_SCHEMA.get(e), e); 416 } 417 finally 418 { 419 StaticUtils.close(reader, exportConfig, writer); 420 } 421 } 422 423 /** 424 * Returns the schema file for a given schema element. 425 * @param element the schema element. 426 * @return the schema file for a given schema element. 427 */ 428 private String getSchemaFile(SchemaFileElement element) 429 { 430 String schemaFile = CommonSchemaElements.getSchemaFile(element); 431 if (schemaFile == null) 432 { 433 schemaFile = ConfigConstants.FILE_USER_SCHEMA_ELEMENTS; 434 } 435 File f = new File(schemaFile); 436 if (!f.isAbsolute()) 437 { 438 f = new File( 439 DirectoryServer.getEnvironmentConfig().getSchemaDirectory(), 440 schemaFile); 441 } 442 return f.getAbsolutePath(); 443 } 444 445 /** 446 * Returns the attribute name in the schema entry that corresponds to the 447 * provided schema element. 448 * @param element the schema element. 449 * @return the attribute name in the schema entry that corresponds to the 450 * provided schema element. 451 */ 452 private String getSchemaFileAttributeName(CommonSchemaElements element) 453 { 454 if (element instanceof AttributeType) 455 { 456 return "attributeTypes"; 457 } 458 else 459 { 460 return "objectClasses"; 461 } 462 } 463 464 /** 465 * Returns the value in the schema file for the provided element. 466 * @param element the schema element. 467 * @return the value in the schema file for the provided element. 468 */ 469 private String getSchemaFileAttributeValue(CommonSchemaElements element) 470 { 471 return element.toString(); 472 } 473 474 /** 475 * Prints the equivalent command-line to delete the schema element in the 476 * progress dialog. 477 * @param element the schema element to be deleted. 478 */ 479 private void printEquivalentCommandToDelete(CommonSchemaElements element) 480 { 481 String schemaFile = getSchemaFile(element); 482 String attrName = getSchemaFileAttributeName(element); 483 String attrValue = getSchemaFileAttributeValue(element); 484 if (!isServerRunning()) 485 { 486 LocalizableMessage msg; 487 if (element instanceof AttributeType) 488 { 489 msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_ATTRIBUTE_OFFLINE.get( 490 element.getNameOrOID(), schemaFile); 491 } 492 else 493 { 494 msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_OBJECTCLASS_OFFLINE.get( 495 element.getNameOrOID(), schemaFile); 496 } 497 getProgressDialog().appendProgressHtml(Utilities.applyFont( 498 msg+"<br><b>"+ 499 attrName+": "+attrValue+"</b><br><br>", 500 ColorAndFontConstants.progressFont)); 501 } 502 else 503 { 504 ArrayList<String> args = new ArrayList<>(); 505 args.add("-a"); 506 args.addAll(getObfuscatedCommandLineArguments( 507 getConnectionCommandLineArguments(true, true))); 508 args.add(getNoPropertiesFileArgument()); 509 String equiv = getEquivalentCommandLine(getCommandLinePath("ldapmodify"), 510 args); 511 512 LocalizableMessage msg; 513 if (element instanceof AttributeType) 514 { 515 msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_ATTRIBUTE_ONLINE.get( 516 element.getNameOrOID()); 517 } 518 else 519 { 520 msg = INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_OBJECTCLASS_ONLINE.get( 521 element.getNameOrOID()); 522 } 523 524 StringBuilder sb = new StringBuilder(); 525 sb.append(msg).append("<br><b>"); 526 sb.append(equiv); 527 sb.append("<br>"); 528 sb.append("dn: cn=schema<br>"); 529 sb.append("changetype: modify<br>"); 530 sb.append("delete: ").append(attrName).append("<br>"); 531 sb.append(attrName).append(": ").append(attrValue); 532 sb.append("</b><br><br>"); 533 getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(), 534 ColorAndFontConstants.progressFont)); 535 } 536 } 537 538 private AttributeType getAttributeToAdd(AttributeType attrToDelete) 539 { 540 boolean isSuperior = false; 541 for (AttributeType attr : providedAttrsToDelete) 542 { 543 if (attr.equals(attrToDelete.getSuperiorType())) 544 { 545 isSuperior = true; 546 AttributeType newSuperior = attr.getSuperiorType(); 547 while (newSuperior != null && 548 providedAttrsToDelete.contains(newSuperior)) 549 { 550 newSuperior = newSuperior.getSuperiorType(); 551 } 552 break; 553 } 554 } 555 if (isSuperior) 556 { 557 ArrayList<String> allNames = new ArrayList<>(attrToDelete.getNormalizedNames()); 558 Map<String, List<String>> extraProperties = 559 cloneExtraProperties(attrToDelete); 560 return new AttributeType( 561 "", 562 attrToDelete.getPrimaryName(), 563 allNames, 564 attrToDelete.getOID(), 565 attrToDelete.getDescription(), 566 null, 567 attrToDelete.getSyntax(), 568 attrToDelete.getApproximateMatchingRule(), 569 attrToDelete.getEqualityMatchingRule(), 570 attrToDelete.getOrderingMatchingRule(), 571 attrToDelete.getSubstringMatchingRule(), 572 attrToDelete.getUsage(), 573 attrToDelete.isCollective(), 574 attrToDelete.isNoUserModification(), 575 attrToDelete.isObsolete(), 576 attrToDelete.isSingleValue(), 577 extraProperties); 578 } 579 else 580 { 581 // Nothing to be changed in the definition of the attribute itself. 582 return attrToDelete; 583 } 584 } 585 586 private ObjectClass getObjectClassToAdd(ObjectClass ocToDelete) 587 { 588 boolean containsAttribute = false; 589 for (AttributeType attr : providedAttrsToDelete) 590 { 591 if(ocToDelete.getRequiredAttributeChain().contains(attr) || 592 ocToDelete.getOptionalAttributeChain().contains(attr)) 593 { 594 containsAttribute = true; 595 break; 596 } 597 } 598 boolean hasSuperior = false; 599 Set<ObjectClass> newSuperiors = new LinkedHashSet<>(); 600 for (ObjectClass sup : ocToDelete.getSuperiorClasses()) 601 { 602 boolean isFound = false; 603 for (ObjectClass oc: providedOcsToDelete) 604 { 605 if(sup.equals(oc)) 606 { 607 hasSuperior = true; 608 isFound = true; 609 newSuperiors.addAll(getNewSuperiors(oc)); 610 break; 611 } 612 } 613 if (!isFound) 614 { 615 //Use the same super if not found in the list. 616 newSuperiors.add(sup); 617 } 618 } 619 620 if (containsAttribute || hasSuperior) 621 { 622 ArrayList<String> allNames = new ArrayList<>(ocToDelete.getNormalizedNames()); 623 Map<String, List<String>> extraProperties = 624 cloneExtraProperties(ocToDelete); 625 Set<AttributeType> required; 626 Set<AttributeType> optional; 627 if (containsAttribute) 628 { 629 required = new HashSet<>(ocToDelete.getRequiredAttributes()); 630 optional = new HashSet<>(ocToDelete.getOptionalAttributes()); 631 required.removeAll(providedAttrsToDelete); 632 optional.removeAll(providedAttrsToDelete); 633 } 634 else 635 { 636 required = ocToDelete.getRequiredAttributes(); 637 optional = ocToDelete.getOptionalAttributes(); 638 } 639 return new ObjectClass("", 640 ocToDelete.getPrimaryName(), 641 allNames, 642 ocToDelete.getOID(), 643 ocToDelete.getDescription(), 644 newSuperiors, 645 required, 646 optional, 647 ocToDelete.getObjectClassType(), 648 ocToDelete.isObsolete(), 649 extraProperties); 650 } 651 else 652 { 653 // Nothing to be changed in the definition of the object class itself. 654 return ocToDelete; 655 } 656 } 657 658 private Set<ObjectClass> getNewSuperiors(ObjectClass currentSup) 659 { 660 Set<ObjectClass> newSuperiors = new LinkedHashSet<>(); 661 if (currentSup.getSuperiorClasses() != null && 662 !currentSup.getSuperiorClasses().isEmpty()) 663 { 664 for (ObjectClass o : currentSup.getSuperiorClasses()) 665 { 666 if (providedOcsToDelete.contains(o)) 667 { 668 newSuperiors.addAll(getNewSuperiors(o)); 669 } 670 else 671 { 672 newSuperiors.add(o); 673 } 674 } 675 } 676 return newSuperiors; 677 } 678 679 /** 680 * Returns an ordered set of the attributes that must be deleted. 681 * @param attrsToDelete the attributes to be deleted. 682 * @param schema the server schema. 683 * @return an ordered list of the attributes that must be deleted. 684 */ 685 public static LinkedHashSet<AttributeType> getOrderedAttributesToDelete( 686 Collection<AttributeType> attrsToDelete, Schema schema) 687 { 688 LinkedHashSet<AttributeType> orderedAttributes = new LinkedHashSet<>(); 689 for (AttributeType attribute : attrsToDelete) 690 { 691 orderedAttributes.addAll(getOrderedChildrenToDelete(attribute, schema)); 692 orderedAttributes.add(attribute); 693 } 694 return orderedAttributes; 695 } 696 697 /** 698 * Returns an ordered list of the object classes that must be deleted. 699 * @param ocsToDelete the object classes to be deleted. 700 * @param schema the server schema. 701 * @return an ordered list of the object classes that must be deleted. 702 */ 703 public static LinkedHashSet<ObjectClass> getOrderedObjectClassesToDelete( 704 Collection<ObjectClass> ocsToDelete, Schema schema) 705 { 706 LinkedHashSet<ObjectClass> orderedOcs = new LinkedHashSet<>(); 707 for (ObjectClass oc : ocsToDelete) 708 { 709 orderedOcs.addAll(getOrderedChildrenToDelete(oc, schema)); 710 orderedOcs.add(oc); 711 } 712 return orderedOcs; 713 } 714 715 /** 716 * Returns an ordered list of the object classes that must be deleted when 717 * deleting a list of attributes that must be deleted. 718 * @param attrsToDelete the attributes to be deleted. 719 * @param schema the server schema. 720 * @return an ordered list of the object classes that must be deleted when 721 * deleting a list of attributes that must be deleted. 722 */ 723 public static LinkedHashSet<ObjectClass> 724 getOrderedObjectClassesToDeleteFromAttrs( 725 Collection<AttributeType> attrsToDelete, Schema schema) 726 { 727 LinkedHashSet<ObjectClass> orderedOcs = new LinkedHashSet<>(); 728 ArrayList<ObjectClass> dependentClasses = new ArrayList<>(); 729 for (AttributeType attr : attrsToDelete) 730 { 731 for (ObjectClass oc : schema.getObjectClasses().values()) 732 { 733 if (oc.getRequiredAttributeChain().contains(attr)) 734 { 735 dependentClasses.add(oc); 736 } 737 else if (oc.getOptionalAttributeChain().contains(attr)) 738 { 739 dependentClasses.add(oc); 740 } 741 } 742 } 743 for (ObjectClass oc : dependentClasses) 744 { 745 orderedOcs.addAll(getOrderedChildrenToDelete(oc, schema)); 746 orderedOcs.add(oc); 747 } 748 return orderedOcs; 749 } 750 751 /** 752 * Clones the extra properties of the provided schema element. This can 753 * be used when copying schema elements. 754 * @param element the schema element. 755 * @return the extra properties of the provided schema element. 756 */ 757 public static Map<String, List<String>> cloneExtraProperties( 758 CommonSchemaElements element) 759 { 760 Map<String, List<String>> extraProperties = new HashMap<>(); 761 Map<String, List<String>> props = element.getExtraProperties(); 762 for (String name : props.keySet()) 763 { 764 List<String> values = new ArrayList<>(props.get(name)); 765 extraProperties.put(name, values); 766 } 767 return extraProperties; 768 } 769 770 private static LinkedHashSet<AttributeType> getOrderedChildrenToDelete( 771 AttributeType attribute, Schema schema) 772 { 773 LinkedHashSet<AttributeType> children = new LinkedHashSet<>(); 774 for (AttributeType attr : schema.getAttributeTypes().values()) 775 { 776 if (attribute.equals(attr.getSuperiorType())) 777 { 778 children.addAll(getOrderedChildrenToDelete(attr, schema)); 779 children.add(attr); 780 } 781 } 782 return children; 783 } 784 785 private static LinkedHashSet<ObjectClass> getOrderedChildrenToDelete( 786 ObjectClass objectClass, Schema schema) 787 { 788 LinkedHashSet<ObjectClass> children = new LinkedHashSet<>(); 789 for (ObjectClass oc : schema.getObjectClasses().values()) 790 { 791 if (oc.getSuperiorClasses().contains(objectClass)) 792 { 793 children.addAll(getOrderedChildrenToDelete(oc, schema)); 794 children.add(oc); 795 } 796 } 797 return children; 798 } 799}