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 2008-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.guitools.controlpanel.ui; 018 019import static org.opends.messages.AdminToolMessages.*; 020import static org.opends.server.types.CommonSchemaElements.*; 021import static org.opends.server.util.CollectionUtils.*; 022import static org.opends.server.util.SchemaUtils.*; 023 024import java.awt.Component; 025import java.awt.Container; 026import java.awt.GridBagConstraints; 027import java.awt.GridBagLayout; 028import java.awt.Insets; 029import java.awt.event.ActionEvent; 030import java.awt.event.ActionListener; 031import java.io.File; 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.Collections; 035import java.util.Comparator; 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.swing.DefaultComboBoxModel; 044import javax.swing.JButton; 045import javax.swing.JCheckBox; 046import javax.swing.JComboBox; 047import javax.swing.JLabel; 048import javax.swing.JList; 049import javax.swing.JPanel; 050import javax.swing.JScrollPane; 051import javax.swing.JTextField; 052import javax.swing.ListCellRenderer; 053import javax.swing.SwingUtilities; 054import javax.swing.event.ChangeEvent; 055import javax.swing.event.ChangeListener; 056import javax.swing.event.DocumentEvent; 057import javax.swing.event.DocumentListener; 058import javax.swing.event.ListDataEvent; 059import javax.swing.event.ListDataListener; 060 061import org.forgerock.i18n.LocalizableMessage; 062import org.forgerock.i18n.LocalizableMessageBuilder; 063import org.forgerock.opendj.ldap.schema.AttributeType; 064import org.forgerock.opendj.ldap.schema.ObjectClass; 065import org.forgerock.opendj.ldap.schema.ObjectClassType; 066import org.forgerock.opendj.ldap.schema.SchemaBuilder; 067import org.opends.guitools.controlpanel.datamodel.ServerDescriptor; 068import org.opends.guitools.controlpanel.datamodel.SomeSchemaElement; 069import org.opends.guitools.controlpanel.datamodel.SortableListModel; 070import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 071import org.opends.guitools.controlpanel.event.ConfigurationElementCreatedListener; 072import org.opends.guitools.controlpanel.event.ScrollPaneBorderListener; 073import org.opends.guitools.controlpanel.event.SuperiorObjectClassesChangedEvent; 074import org.opends.guitools.controlpanel.event.SuperiorObjectClassesChangedListener; 075import org.opends.guitools.controlpanel.task.DeleteSchemaElementsTask; 076import org.opends.guitools.controlpanel.task.ModifyObjectClassTask; 077import org.opends.guitools.controlpanel.task.Task; 078import org.opends.guitools.controlpanel.ui.components.BasicExpander; 079import org.opends.guitools.controlpanel.ui.components.DoubleAddRemovePanel; 080import org.opends.guitools.controlpanel.ui.components.SuperiorObjectClassesEditor; 081import org.opends.guitools.controlpanel.ui.components.TitlePanel; 082import org.opends.guitools.controlpanel.ui.renderer.SchemaElementComboBoxCellRenderer; 083import org.opends.guitools.controlpanel.util.Utilities; 084import org.opends.server.types.Schema; 085import org.opends.server.util.ServerConstants; 086import org.opends.server.util.StaticUtils; 087 088/** The panel that displays a custom object class definition. */ 089public class CustomObjectClassPanel extends SchemaElementPanel 090{ 091 private static final long serialVersionUID = 2105520588901380L; 092 private JButton delete; 093 private JButton saveChanges; 094 private ObjectClass objectClass; 095 private String ocName; 096 private ScrollPaneBorderListener scrollListener; 097 098 private TitlePanel titlePanel = new TitlePanel(LocalizableMessage.EMPTY, LocalizableMessage.EMPTY); 099 private JLabel lName = Utilities.createPrimaryLabel( 100 INFO_CTRL_PANEL_OBJECTCLASS_NAME_LABEL.get()); 101 private JLabel lSuperior = Utilities.createPrimaryLabel( 102 INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get()); 103 private JLabel lOID = Utilities.createPrimaryLabel( 104 INFO_CTRL_PANEL_OBJECTCLASS_OID_LABEL.get()); 105 private JLabel lAliases = Utilities.createPrimaryLabel( 106 INFO_CTRL_PANEL_OBJECTCLASS_ALIASES_LABEL.get()); 107 private JLabel lOrigin = Utilities.createPrimaryLabel( 108 INFO_CTRL_PANEL_OBJECTCLASS_ORIGIN_LABEL.get()); 109 private JLabel lFile = Utilities.createPrimaryLabel( 110 INFO_CTRL_PANEL_OBJECTCLASS_FILE_LABEL.get()); 111 private JTextField aliases = Utilities.createLongTextField(); 112 private JLabel lDescription = Utilities.createPrimaryLabel( 113 INFO_CTRL_PANEL_OBJECTCLASS_DESCRIPTION_LABEL.get()); 114 private JLabel lType = Utilities.createPrimaryLabel( 115 INFO_CTRL_PANEL_OBJECTCLASS_TYPE_LABEL.get()); 116 private JLabel lAttributes = Utilities.createPrimaryLabel( 117 INFO_CTRL_PANEL_OBJECTCLASS_ATTRIBUTES_LABEL.get()); 118 119 private Set<AttributeType> inheritedOptionalAttributes = new HashSet<>(); 120 private Set<AttributeType> inheritedRequiredAttributes = new HashSet<>(); 121 122 private JLabel[] labels = {lName, lSuperior, lOID, lAliases, lOrigin, lFile, 123 lDescription, lType, lAttributes 124 }; 125 126 private JTextField name = Utilities.createMediumTextField(); 127 private SuperiorObjectClassesEditor superiors = 128 new SuperiorObjectClassesEditor(); 129 private JComboBox type = Utilities.createComboBox(); 130 private JTextField oid = Utilities.createMediumTextField(); 131 private JTextField description = Utilities.createLongTextField(); 132 private JTextField origin = Utilities.createLongTextField(); 133 private JTextField file = Utilities.createLongTextField(); 134 private JCheckBox obsolete = Utilities.createCheckBox( 135 INFO_CTRL_PANEL_OBJECTCLASS_OBSOLETE_LABEL.get()); 136 private DoubleAddRemovePanel<AttributeType> attributes; 137 138 private Schema schema; 139 private Set<String> lastAliases = new LinkedHashSet<>(); 140 141 private boolean ignoreChangeEvents; 142 143 /** Default constructor of the panel. */ 144 public CustomObjectClassPanel() 145 { 146 super(); 147 createLayout(); 148 } 149 150 @Override 151 public LocalizableMessage getTitle() 152 { 153 return INFO_CTRL_PANEL_CUSTOM_OBJECTCLASS_TITLE.get(); 154 } 155 156 /** Creates the layout of the panel (but the contents are not populated here). */ 157 private void createLayout() 158 { 159 JPanel p = new JPanel(new GridBagLayout()); 160 GridBagConstraints gbc = new GridBagConstraints(); 161 p.setOpaque(false); 162 p.setBorder(PANEL_BORDER); 163 createBasicLayout(p, gbc); 164 gbc = new GridBagConstraints(); 165 gbc.weightx = 1.0; 166 gbc.weighty = 1.0; 167 gbc.gridwidth = 2; 168 gbc.fill = GridBagConstraints.BOTH; 169 gbc.gridx = 0; 170 gbc.gridy = 0; 171 JScrollPane scroll = Utilities.createBorderLessScrollBar(p); 172 scrollListener = 173 ScrollPaneBorderListener.createBottomBorderListener(scroll); 174 add(scroll, gbc); 175 176 gbc.gridy ++; 177 gbc.weighty = 0.0; 178 gbc.anchor = GridBagConstraints.WEST; 179 gbc.fill = GridBagConstraints.NONE; 180 gbc.insets = new Insets(10, 10, 10, 10); 181 gbc.gridwidth = 1; 182 delete = Utilities.createButton( 183 INFO_CTRL_PANEL_DELETE_OBJECTCLASS_BUTTON.get()); 184 delete.setOpaque(false); 185 add(delete, gbc); 186 delete.addActionListener(new ActionListener() 187 { 188 @Override 189 public void actionPerformed(ActionEvent ev) 190 { 191 deleteObjectclass(); 192 } 193 }); 194 195 gbc.anchor = GridBagConstraints.EAST; 196 gbc.gridx ++; 197 saveChanges = 198 Utilities.createButton(INFO_CTRL_PANEL_SAVE_CHANGES_LABEL.get()); 199 saveChanges.setOpaque(false); 200 add(saveChanges, gbc); 201 saveChanges.addActionListener(new ActionListener() 202 { 203 @Override 204 public void actionPerformed(ActionEvent ev) 205 { 206 ArrayList<LocalizableMessage> errors = new ArrayList<>(); 207 saveChanges(errors); 208 } 209 }); 210 } 211 212 /** 213 * Creates the basic layout of the panel. 214 * @param c the container where all the components will be layed out. 215 * @param gbc the grid bag constraints. 216 */ 217 private void createBasicLayout(Container c, GridBagConstraints gbc) 218 { 219 SuperiorObjectClassesChangedListener listener = 220 new SuperiorObjectClassesChangedListener() 221 { 222 @Override 223 public void parentObjectClassesChanged( 224 SuperiorObjectClassesChangedEvent ev) 225 { 226 if (ignoreChangeEvents) 227 { 228 return; 229 } 230 updateAttributesWithParent(true); 231 checkEnableSaveChanges(); 232 if (ev.getNewObjectClasses().size() > 1) 233 { 234 lSuperior.setText( 235 INFO_CTRL_PANEL_OBJECTCLASS_PARENTS_LABEL.get().toString()); 236 } 237 else 238 { 239 lSuperior.setText( 240 INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString()); 241 } 242 } 243 }; 244 superiors.addParentObjectClassesChangedListener(listener); 245 246 DefaultComboBoxModel model = new DefaultComboBoxModel(); 247 for (ObjectClassType t : ObjectClassType.values()) 248 { 249 model.addElement(t); 250 } 251 type.setModel(model); 252 type.setSelectedItem(ObjectClassType.STRUCTURAL); 253 SchemaElementComboBoxCellRenderer renderer = new 254 SchemaElementComboBoxCellRenderer(type); 255 type.setRenderer(renderer); 256 257 attributes = new DoubleAddRemovePanel<>(0, AttributeType.class); 258 Comparator<AttributeType> comparator = new Comparator<AttributeType>() 259 { 260 @Override 261 public int compare(AttributeType attr1, AttributeType attr2) 262 { 263 return attr1.getNameOrOID().toLowerCase().compareTo( 264 attr2.getNameOrOID().toLowerCase()); 265 } 266 }; 267 attributes.getAvailableListModel().setComparator(comparator); 268 attributes.getSelectedListModel1().setComparator(comparator); 269 attributes.getSelectedListModel2().setComparator(comparator); 270 271 gbc.gridy = 0; 272 gbc.gridwidth = 2; 273 addErrorPane(c, gbc); 274 gbc.gridy ++; 275 276 gbc.anchor = GridBagConstraints.WEST; 277 titlePanel.setTitle(INFO_CTRL_PANEL_OBJECTCLASS_DETAILS.get()); 278 gbc.fill = GridBagConstraints.NONE; 279 gbc.insets.top = 5; 280 gbc.insets.bottom = 7; 281 c.add(titlePanel, gbc); 282 283 gbc.insets.bottom = 0; 284 gbc.insets.top = 8; 285 gbc.gridy ++; 286 gbc.gridwidth = 1; 287 gbc.fill = GridBagConstraints.HORIZONTAL; 288 289 Component[] basicComps = {name, oid, description, superiors}; 290 JLabel[] basicLabels = {lName, lOID, lDescription, lSuperior}; 291 JLabel[] basicInlineHelp = new JLabel[] {null, null, null, null}; 292 add(basicLabels, basicComps, basicInlineHelp, c, gbc); 293 294 gbc.gridx = 0; 295 gbc.weightx = 0.0; 296 gbc.insets.left = 0; 297 gbc.fill = GridBagConstraints.HORIZONTAL; 298 gbc.anchor = GridBagConstraints.NORTHWEST; 299 c.add(lAttributes, gbc); 300 301 gbc.gridx ++; 302 gbc.fill = GridBagConstraints.BOTH; 303 gbc.weightx = 1.0; 304 gbc.weighty = 1.0; 305 gbc.insets.left = 10; 306 c.add(attributes, gbc); 307 attributes.getAvailableLabel().setText( 308 INFO_CTRL_PANEL_ADDREMOVE_AVAILABLE_ATTRIBUTES.get().toString()); 309 attributes.getSelectedLabel1().setText( 310 INFO_CTRL_PANEL_ADDREMOVE_REQUIRED_ATTRIBUTES.get().toString()); 311 attributes.getSelectedLabel2().setText( 312 INFO_CTRL_PANEL_ADDREMOVE_OPTIONAL_ATTRIBUTES.get().toString()); 313 AttributeTypeCellRenderer listRenderer = new AttributeTypeCellRenderer(); 314 attributes.getAvailableList().setCellRenderer(listRenderer); 315 attributes.getSelectedList1().setCellRenderer(listRenderer); 316 attributes.getSelectedList2().setCellRenderer(listRenderer); 317 318 gbc.gridy ++; 319 gbc.weighty = 0.0; 320 gbc.insets.top = 3; 321 JLabel explanation = Utilities.createInlineHelpLabel( 322 INFO_CTRL_PANEL_INHERITED_ATTRIBUTES_HELP.get()); 323 gbc.insets.top = 3; 324 c.add(explanation, gbc); 325 326 final BasicExpander expander = new BasicExpander( 327 INFO_CTRL_PANEL_EXTRA_OPTIONS_EXPANDER.get()); 328 329 obsolete.setText("Obsolete"); 330 331 Component[] comps = {aliases, origin, file, type, obsolete}; 332 JLabel[] labels = {lAliases, lOrigin, lFile, lType, null}; 333 JLabel[] inlineHelps = { 334 Utilities.createInlineHelpLabel( 335 INFO_CTRL_PANEL_SEPARATED_WITH_COMMAS_HELP.get()), null, 336 Utilities.createInlineHelpLabel( 337 INFO_CTRL_PANEL_SCHEMA_FILE_OBJECTCLASS_HELP.get(File.separator)), 338 null, null}; 339 gbc.gridwidth = 2; 340 gbc.gridx = 0; 341 gbc.weighty = 0.0; 342 gbc.insets.left = 0; 343 gbc.gridy ++; 344 c.add(expander, gbc); 345 final JPanel p = new JPanel(new GridBagLayout()); 346 gbc.insets.left = 15; 347 gbc.gridy ++; 348 c.add(p, gbc); 349 gbc.gridy ++; 350 p.setOpaque(false); 351 352 GridBagConstraints gbc1 = new GridBagConstraints(); 353 gbc1.fill = GridBagConstraints.HORIZONTAL; 354 gbc1.gridy = 0; 355 356 add(labels, comps, inlineHelps, p, gbc1); 357 ChangeListener changeListener = new ChangeListener() 358 { 359 @Override 360 public void stateChanged(ChangeEvent e) 361 { 362 p.setVisible(expander.isSelected()); 363 } 364 }; 365 expander.addChangeListener(changeListener); 366 expander.setSelected(false); 367 changeListener.stateChanged(null); 368 369 DocumentListener docListener = new DocumentListener() 370 { 371 @Override 372 public void insertUpdate(DocumentEvent ev) 373 { 374 checkEnableSaveChanges(); 375 } 376 377 @Override 378 public void removeUpdate(DocumentEvent ev) 379 { 380 checkEnableSaveChanges(); 381 } 382 383 @Override 384 public void changedUpdate(DocumentEvent arg0) 385 { 386 checkEnableSaveChanges(); 387 } 388 }; 389 JTextField[] tfs = {name, description, oid, aliases, origin, file}; 390 for (JTextField tf : tfs) 391 { 392 tf.getDocument().addDocumentListener(docListener); 393 } 394 395 ActionListener actionListener = new ActionListener() 396 { 397 @Override 398 public void actionPerformed(ActionEvent ev) 399 { 400 checkEnableSaveChanges(); 401 } 402 }; 403 404 type.addActionListener(actionListener); 405 406 ListDataListener dataListener = new ListDataListener() 407 { 408 @Override 409 public void contentsChanged(ListDataEvent e) 410 { 411 checkEnableSaveChanges(); 412 } 413 @Override 414 public void intervalAdded(ListDataEvent e) 415 { 416 checkEnableSaveChanges(); 417 } 418 @Override 419 public void intervalRemoved(ListDataEvent e) 420 { 421 checkEnableSaveChanges(); 422 } 423 }; 424 SortableListModel<AttributeType> list1 = attributes.getSelectedListModel1(); 425 SortableListModel<AttributeType> list2 = attributes.getSelectedListModel2(); 426 list1.addListDataListener(dataListener); 427 list2.addListDataListener(dataListener); 428 429 obsolete.addActionListener(actionListener); 430 } 431 432 /** 433 * Updates the contents of the panel with the provided object class. 434 * @param oc the object class. 435 * @param schema the schema. 436 */ 437 public void update(ObjectClass oc, Schema schema) 438 { 439 ignoreChangeEvents = true; 440 441 objectClass = oc; 442 if (oc == null || schema == null) 443 { 444 // Ignore: this is called to get an initial panel size. 445 return; 446 } 447 String n = oc.getNameOrOID(); 448 if (n == null) 449 { 450 n = NOT_APPLICABLE.toString(); 451 } 452 titlePanel.setDetails(LocalizableMessage.raw(n)); 453 name.setText(n); 454 455 SortableListModel<AttributeType> modelRequired = attributes.getSelectedListModel1(); 456 SortableListModel<AttributeType> modelAvailable = attributes.getSelectedListModel2(); 457 SortableListModel<AttributeType> availableModel = attributes.getAvailableListModel(); 458 availableModel.addAll(modelRequired.getData()); 459 availableModel.addAll(modelAvailable.getData()); 460 modelRequired.clear(); 461 modelAvailable.clear(); 462 463 superiors.setSelectedSuperiors(oc.getSuperiorClasses()); 464 superiors.setObjectClassesToExclude(Collections.singleton(oc)); 465 if (oc.getSuperiorClasses().size() > 1) 466 { 467 lSuperior.setText( 468 INFO_CTRL_PANEL_OBJECTCLASS_PARENTS_LABEL.get().toString()); 469 } 470 else 471 { 472 lSuperior.setText( 473 INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString()); 474 } 475 476 updateAttributesWithParent(false); 477 478 for (AttributeType attr : oc.getDeclaredRequiredAttributes()) 479 { 480 availableModel.remove(attr); 481 modelRequired.add(attr); 482 } 483 for (AttributeType attr : oc.getDeclaredOptionalAttributes()) 484 { 485 availableModel.remove(attr); 486 modelAvailable.add(attr); 487 } 488 notifyAttributesChanged(); 489 490 oid.setText(oc.getOID()); 491 n = oc.getDescription(); 492 if (n == null) 493 { 494 n = ""; 495 } 496 description.setText(n); 497 498 Set<String> aliases = getAliases(oc); 499 lastAliases.clear(); 500 lastAliases.addAll(aliases); 501 this.aliases.setText(Utilities.getStringFromCollection(aliases, ", ")); 502 503 String sOrigin = new SomeSchemaElement(oc).getOrigin(); 504 if (sOrigin == null) 505 { 506 sOrigin = ""; 507 } 508 origin.setText(sOrigin); 509 510 String sFile = getSchemaFile(oc); 511 if (sFile == null) 512 { 513 sFile = ""; 514 } 515 file.setText(sFile); 516 517 type.setSelectedItem(oc.getObjectClassType()); 518 519 obsolete.setSelected(oc.isObsolete()); 520 521 ocName = objectClass.getNameOrOID(); 522 scrollListener.updateBorder(); 523 for (JLabel label : labels) 524 { 525 setPrimaryValid(label); 526 } 527 saveChanges.setEnabled(false); 528 ignoreChangeEvents = false; 529 } 530 531 @Override 532 public void configurationChanged(ConfigurationChangeEvent ev) 533 { 534 final ServerDescriptor desc = ev.getNewDescriptor(); 535 Schema s = desc.getSchema(); 536 final boolean schemaChanged = schemaChanged(s); 537 if (schemaChanged) 538 { 539 schema = s; 540 541 updateErrorPaneIfAuthRequired(desc, isLocal() 542 ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_OBJECTCLASS_EDIT.get() 543 : INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname())); 544 } 545 else if (schema == null) 546 { 547 updateErrorPane(errorPane, 548 ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_SUMMARY.get(), 549 ColorAndFontConstants.errorTitleFont, 550 ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get(), 551 ColorAndFontConstants.defaultFont); 552 } 553 SwingUtilities.invokeLater(new Runnable() 554 { 555 @Override 556 public void run() 557 { 558 final boolean enabled = !authenticationRequired(desc) && schema != null; 559 delete.setEnabled(enabled); 560 checkEnableSaveChanges(); 561 saveChanges.setEnabled(enabled && saveChanges.isEnabled()); 562 if (schemaChanged && schema != null) 563 { 564 superiors.setSchema(schema); 565 updateAttributes(); 566 } 567 } 568 }); 569 } 570 571 private boolean schemaChanged(Schema s) 572 { 573 if (s != null) 574 { 575 return schema == null || !ServerDescriptor.areSchemasEqual(s, schema); 576 } 577 return false; 578 } 579 580 @Override 581 public boolean mustCheckUnsavedChanges() 582 { 583 return saveChanges.isEnabled(); 584 } 585 586 @Override 587 public UnsavedChangesDialog.Result checkUnsavedChanges() 588 { 589 UnsavedChangesDialog.Result result; 590 UnsavedChangesDialog unsavedChangesDlg = new UnsavedChangesDialog( 591 Utilities.getParentDialog(this), getInfo()); 592 unsavedChangesDlg.setMessage(INFO_CTRL_PANEL_UNSAVED_CHANGES_SUMMARY.get(), 593 INFO_CTRL_PANEL_UNSAVED_OBJECTCLASS_CHANGES_DETAILS.get( 594 objectClass.getNameOrOID())); 595 Utilities.centerGoldenMean(unsavedChangesDlg, 596 Utilities.getParentDialog(this)); 597 unsavedChangesDlg.setVisible(true); 598 result = unsavedChangesDlg.getResult(); 599 if (result == UnsavedChangesDialog.Result.SAVE) 600 { 601 List<LocalizableMessage> errors = new ArrayList<>(); 602 saveChanges(errors); 603 if (!errors.isEmpty()) 604 { 605 result = UnsavedChangesDialog.Result.CANCEL; 606 } 607 } 608 609 return result; 610 } 611 612 @Override 613 public Component getPreferredFocusComponent() 614 { 615 return name; 616 } 617 618 @Override 619 public void okClicked() 620 { 621 } 622 623 private void deleteObjectclass() 624 { 625 ArrayList<LocalizableMessage> errors = new ArrayList<>(); 626 ProgressDialog dlg = new ProgressDialog( 627 Utilities.createFrame(), 628 Utilities.getParentDialog(this), 629 INFO_CTRL_PANEL_DELETE_OBJECTCLASS_TITLE.get(), getInfo()); 630 LinkedHashSet<ObjectClass> ocsToDelete = new LinkedHashSet<>(); 631 ocsToDelete.add(objectClass); 632 LinkedHashSet<AttributeType> attrsToDelete = new LinkedHashSet<>(0); 633 634 DeleteSchemaElementsTask newTask = new DeleteSchemaElementsTask(getInfo(), 635 dlg, ocsToDelete, attrsToDelete); 636 for (Task task : getInfo().getTasks()) 637 { 638 task.canLaunch(newTask, errors); 639 } 640 Schema schema = getInfo().getServerDescriptor().getSchema(); 641 ArrayList<String> childClasses = new ArrayList<>(); 642 if (schema != null) 643 { 644 for (ObjectClass o : schema.getObjectClasses()) 645 { 646 for (ObjectClass superior : o.getSuperiorClasses()) 647 { 648 if (objectClass.equals(superior)) 649 { 650 childClasses.add(o.getNameOrOID()); 651 } 652 } 653 } 654 } 655 else 656 { 657 errors.add(ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get()); 658 } 659 if (errors.isEmpty()) 660 { 661 LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 662 663 if (!childClasses.isEmpty()) 664 { 665 mb.append(INFO_OBJECTCLASS_IS_SUPERIOR.get( 666 ocName, 667 Utilities.getStringFromCollection(childClasses, ", "))); 668 mb.append("<br>"); 669 } 670 LocalizableMessage confirmationMessage = 671 INFO_CTRL_PANEL_CONFIRMATION_DELETE_OBJECTCLASS_DETAILS.get( 672 ocName); 673 mb.append(confirmationMessage); 674 if (displayConfirmationDialog( 675 INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(), 676 confirmationMessage)) 677 { 678 launchOperation(newTask, 679 INFO_CTRL_PANEL_DELETING_OBJECTCLASS_SUMMARY.get(ocName), 680 INFO_CTRL_PANEL_DELETING_OBJECTCLASS_COMPLETE.get(), 681 INFO_CTRL_PANEL_DELETING_OBJECTCLASS_SUCCESSFUL.get(ocName), 682 ERR_CTRL_PANEL_DELETING_OBJECTCLASS_ERROR_SUMMARY.get(), 683 ERR_CTRL_PANEL_DELETING_OBJECTCLASS_ERROR_DETAILS.get(ocName), 684 null, 685 dlg); 686 dlg.setVisible(true); 687 } 688 } 689 else 690 { 691 displayErrorDialog(errors); 692 } 693 } 694 695 private void saveChanges(List<LocalizableMessage> errors) 696 { 697 for (JLabel label : labels) 698 { 699 setPrimaryValid(label); 700 } 701 String n = getObjectClassName(); 702 LocalizableMessageBuilder err = new LocalizableMessageBuilder(); 703 if (n.length() == 0) 704 { 705 errors.add(ERR_CTRL_PANEL_OBJECTCLASS_NAME_REQUIRED.get()); 706 setPrimaryInvalid(lName); 707 } 708 else if (!n.equalsIgnoreCase(objectClass.getNameOrOID())) 709 { 710 if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err)) 711 { 712 errors.add(ERR_CTRL_PANEL_INVALID_OBJECTCLASS_NAME.get(err)); 713 setPrimaryInvalid(lName); 714 err = new LocalizableMessageBuilder(); 715 } 716 else 717 { 718 LocalizableMessage elementType = NewAttributePanel.getSchemaElementType(n, schema); 719 if (elementType != null) 720 { 721 errors.add(ERR_CTRL_PANEL_OBJECTCLASS_NAME_ALREADY_IN_USE.get(n, elementType)); 722 setPrimaryInvalid(lName); 723 } 724 } 725 } 726 n = oid.getText().trim(); 727 if (n.length() > 0 && !n.equalsIgnoreCase(objectClass.getOID())) 728 { 729 if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err)) 730 { 731 errors.add(ERR_CTRL_PANEL_OID_NOT_VALID.get(err)); 732 setPrimaryInvalid(lOID); 733 err = new LocalizableMessageBuilder(); 734 } 735 else 736 { 737 LocalizableMessage elementType = NewAttributePanel.getSchemaElementType(n, schema); 738 if (elementType != null) 739 { 740 errors.add(ERR_CTRL_PANEL_OID_ALREADY_IN_USE.get(n, elementType)); 741 setPrimaryInvalid(lOID); 742 } 743 } 744 } 745 746 Collection<String> aliases = getAliases(); 747 Collection<String> oldAliases = getAliases(objectClass); 748 749 if (!aliases.equals(oldAliases)) 750 { 751 for (String alias : aliases) 752 { 753 if (alias.trim().length() == 0) 754 { 755 errors.add(ERR_CTRL_PANEL_EMPTY_ALIAS.get()); 756 setPrimaryInvalid(lAliases); 757 } 758 else 759 { 760 boolean notPreviouslyDefined = !containsIgnoreCase(oldAliases, alias); 761 if (notPreviouslyDefined) 762 { 763 LocalizableMessage elementType = 764 NewAttributePanel.getSchemaElementType(alias, schema); 765 if (elementType != null) 766 { 767 errors.add(ERR_CTRL_PANEL_ALIAS_ALREADY_IN_USE.get(n, elementType)); 768 setPrimaryInvalid(lAliases); 769 } 770 } 771 } 772 } 773 } 774 775 //validate the superiority. 776 for(ObjectClass superior : getObjectClassSuperiors()) 777 { 778 validateSuperiority(superior, errors); 779 } 780 checkCompatibleSuperiors(getObjectClassSuperiors(), getObjectClassType(), 781 errors); 782 783 if (errors.isEmpty()) 784 { 785 ProgressDialog dlg = new ProgressDialog( 786 Utilities.createFrame(), 787 Utilities.getParentDialog(this), 788 INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TITLE.get(), getInfo()); 789 790 ModifyObjectClassTask newTask = new ModifyObjectClassTask(getInfo(), 791 dlg, objectClass, getNewObjectClass()); 792 for (ConfigurationElementCreatedListener listener : 793 getConfigurationElementCreatedListeners()) 794 { 795 newTask.addConfigurationElementCreatedListener(listener); 796 } 797 for (Task task : getInfo().getTasks()) 798 { 799 task.canLaunch(newTask, errors); 800 } 801 if (errors.isEmpty()) 802 { 803 launchOperation(newTask, 804 INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_SUMMARY.get(ocName), 805 INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_COMPLETE.get(), 806 INFO_CTRL_PANEL_MODIFYING_OBJECTCLASS_SUCCESSFUL.get(ocName), 807 ERR_CTRL_PANEL_MODIFYING_OBJECTCLASS_ERROR_SUMMARY.get(), 808 ERR_CTRL_PANEL_MODIFYING_OBJECTCLASS_ERROR_DETAILS.get(ocName), 809 null, 810 dlg); 811 dlg.setVisible(true); 812 } 813 } 814 815 if (!errors.isEmpty()) 816 { 817 displayErrorDialog(errors); 818 } 819 } 820 821 private boolean containsIgnoreCase(Collection<String> col, String toFind) 822 { 823 for (String s : col) 824 { 825 if (s.equalsIgnoreCase(toFind)) 826 { 827 return true; 828 } 829 } 830 return false; 831 } 832 833 private void validateSuperiority(ObjectClass superior, List<LocalizableMessage> errors) 834 { 835 if(superior.getNameOrOID().equalsIgnoreCase(objectClass.getNameOrOID())) 836 { 837 errors.add(ERR_CTRL_PANEL_OBJECTCLASS_CANNOT_BE_ITS_SUPERIOR.get()); 838 setPrimaryInvalid(lSuperior); 839 return; 840 } 841 for (ObjectClass obj : superior.getSuperiorClasses()) 842 { 843 if (superior.getNameOrOID().equalsIgnoreCase(obj.getNameOrOID())) 844 { 845 errors.add( 846 ERR_CTRL_PANEL_OBJECTCLASS_IS_SUPERIOR_OF_SUPERIOR.get( 847 obj.getNameOrOID())); 848 setPrimaryInvalid(lSuperior); 849 return; 850 } 851 validateSuperiority(obj,errors); 852 } 853 } 854 855 private void checkEnableSaveChanges() 856 { 857 if (!ignoreChangeEvents) 858 { 859 saveChanges.setEnabled(hasChanged()); 860 } 861 } 862 863 private boolean hasChanged() 864 { 865 if (objectClass != null) 866 { 867 try 868 { 869 return !objectClass.toString().equals(getNewObjectClass().toString()); 870 } 871 catch (Throwable t) 872 { 873 return true; 874 } 875 } 876 return false; 877 } 878 879 private Set<String> getAliases() 880 { 881 Set<String> al = new LinkedHashSet<>(); 882 String s = aliases.getText().trim(); 883 if (s.length() > 0) 884 { 885 String[] a = s.split(","); 886 for (String alias : a) 887 { 888 al.add(alias.trim()); 889 } 890 } 891 return al; 892 } 893 894 private String getObjectClassName() 895 { 896 return name.getText().trim(); 897 } 898 899 private String getOID() 900 { 901 String o = oid.getText().trim(); 902 if (o.length() == 0) 903 { 904 o = getObjectClassName()+"-oid"; 905 } 906 return o; 907 } 908 909 private Map<String, List<String>> getExtraProperties() 910 { 911 Map<String, List<String>> map = new HashMap<>(); 912 String f = file.getText().trim(); 913 if (f.length() > 0) 914 { 915 map.put(ServerConstants.SCHEMA_PROPERTY_FILENAME, newArrayList(f)); 916 } 917 String or = origin.getText().trim(); 918 if (or.length() > 0) 919 { 920 map.put(ServerConstants.SCHEMA_PROPERTY_ORIGIN, newArrayList(or)); 921 } 922 return map; 923 } 924 925 private ArrayList<String> getAllNames() 926 { 927 ArrayList<String> al = new ArrayList<>(); 928 al.add(getObjectClassName()); 929 al.addAll(getAliases()); 930 return al; 931 } 932 933 private String getDescription() 934 { 935 return description.getText().trim(); 936 } 937 938 private Set<ObjectClass> getObjectClassSuperiors() 939 { 940 return superiors.getSelectedSuperiors(); 941 } 942 943 private ObjectClassType getObjectClassType() 944 { 945 return (ObjectClassType)type.getSelectedItem(); 946 } 947 948 private Set<AttributeType> getRequiredAttributes() 949 { 950 return intersect(attributes.getSelectedListModel1().getData(), inheritedRequiredAttributes); 951 } 952 953 private Set<AttributeType> getOptionalAttributes() 954 { 955 return intersect(attributes.getSelectedListModel2().getData(), inheritedOptionalAttributes); 956 } 957 958 private Set<AttributeType> intersect(Set<AttributeType> set1, Set<AttributeType> set2) 959 { 960 HashSet<AttributeType> attrs = new HashSet<>(set1); 961 attrs.removeAll(set2); 962 return attrs; 963 } 964 965 private ObjectClass getNewObjectClass() 966 { 967 return new SchemaBuilder(schema.getSchemaNG()).buildObjectClass(getOID()) 968 .names(getAllNames()) 969 .description(getDescription()) 970 .superiorObjectClasses(getNameOrOIDsForOCs(getObjectClassSuperiors())) 971 .requiredAttributes(getNameOrOIDsForATs(getRequiredAttributes())) 972 .optionalAttributes(getNameOrOIDsForATs(getOptionalAttributes())) 973 .type(getObjectClassType()) 974 .obsolete(obsolete.isSelected()) 975 .extraProperties(getExtraProperties()) 976 .addToSchema() 977 .toSchema() 978 .getObjectClass(getOID()); 979 } 980 981 private void updateAttributes() 982 { 983 int[][] selected = 984 { 985 attributes.getAvailableList().getSelectedIndices(), 986 attributes.getSelectedList1().getSelectedIndices(), 987 attributes.getSelectedList2().getSelectedIndices() 988 }; 989 JList[] lists = 990 { 991 attributes.getAvailableList(), 992 attributes.getSelectedList1(), 993 attributes.getSelectedList2() 994 }; 995 attributes.getAvailableListModel().clear(); 996 Collection<AttributeType> allAttrs = schema.getAttributeTypes(); 997 attributes.getAvailableListModel().addAll(allAttrs); 998 999 HashSet<AttributeType> toDelete = new HashSet<>(); 1000 for (AttributeType attr : attributes.getSelectedListModel1().getData()) 1001 { 1002 if (!allAttrs.contains(attr)) 1003 { 1004 toDelete.add(attr); 1005 } 1006 else 1007 { 1008 attributes.getAvailableListModel().remove(attr); 1009 } 1010 } 1011 for (AttributeType attr : toDelete) 1012 { 1013 attributes.getSelectedListModel1().remove(attr); 1014 } 1015 1016 toDelete = new HashSet<>(); 1017 for (AttributeType attr : attributes.getSelectedListModel2().getData()) 1018 { 1019 if (!allAttrs.contains(attr)) 1020 { 1021 toDelete.add(attr); 1022 } 1023 else 1024 { 1025 attributes.getAvailableListModel().remove(attr); 1026 } 1027 } 1028 for (AttributeType attr : toDelete) 1029 { 1030 attributes.getSelectedListModel1().remove(attr); 1031 } 1032 1033 int i = 0; 1034 for (int[] sel : selected) 1035 { 1036 if (sel != null) 1037 { 1038 ArrayList<Integer> indexes = new ArrayList<>(); 1039 for (int element : sel) 1040 { 1041 if (element < lists[i].getModel().getSize()) 1042 { 1043 indexes.add(element); 1044 } 1045 } 1046 int[] newSelection = new int[indexes.size()]; 1047 for (int j=0; j<newSelection.length; j++) 1048 { 1049 newSelection[j] = indexes.get(j); 1050 } 1051 lists[i].setSelectedIndices(newSelection); 1052 } 1053 i++; 1054 } 1055 } 1056 1057 private void updateAttributesWithParent(boolean notify) 1058 { 1059 // Remove the previous inherited attributes. 1060 for (AttributeType attr : inheritedRequiredAttributes) 1061 { 1062 attributes.getAvailableListModel().add(attr); 1063 attributes.getSelectedListModel1().remove(attr); 1064 } 1065 for (AttributeType attr : inheritedOptionalAttributes) 1066 { 1067 attributes.getAvailableListModel().add(attr); 1068 attributes.getSelectedListModel2().remove(attr); 1069 } 1070 1071 inheritedOptionalAttributes.clear(); 1072 inheritedRequiredAttributes.clear(); 1073 for (ObjectClass p : getObjectClassSuperiors()) 1074 { 1075 inheritedRequiredAttributes.addAll(p.getRequiredAttributes()); 1076 inheritedOptionalAttributes.addAll(p.getOptionalAttributes()); 1077 } 1078 for (AttributeType attr : inheritedRequiredAttributes) 1079 { 1080 attributes.getAvailableListModel().remove(attr); 1081 attributes.getSelectedListModel1().add(attr); 1082 } 1083 for (AttributeType attr : inheritedOptionalAttributes) 1084 { 1085 attributes.getAvailableListModel().remove(attr); 1086 attributes.getSelectedListModel2().add(attr); 1087 } 1088 1089 Collection<AttributeType> unmovableItems = new ArrayList<>(inheritedRequiredAttributes); 1090 unmovableItems.addAll(inheritedOptionalAttributes); 1091 attributes.setUnmovableItems(unmovableItems); 1092 1093 if (notify) 1094 { 1095 notifyAttributesChanged(); 1096 } 1097 } 1098 1099 private void notifyAttributesChanged() 1100 { 1101 attributes.getAvailableListModel().fireContentsChanged( 1102 attributes.getAvailableList(), 0, 1103 attributes.getAvailableListModel().getSize() - 1); 1104 attributes.getSelectedListModel1().fireContentsChanged( 1105 attributes.getSelectedList1(), 0, 1106 attributes.getSelectedListModel1().getSize() - 1); 1107 attributes.getSelectedListModel2().fireContentsChanged( 1108 attributes.getSelectedList2(), 0, 1109 attributes.getSelectedListModel2().getSize() - 1); 1110 } 1111 1112 /** 1113 * A renderer for the attribute lists. The renderer basically marks the 1114 * inherited attributes with an asterisk. 1115 */ 1116 private class AttributeTypeCellRenderer implements ListCellRenderer 1117 { 1118 private ListCellRenderer defaultRenderer; 1119 1120 /** Renderer constructor. */ 1121 public AttributeTypeCellRenderer() 1122 { 1123 defaultRenderer = attributes.getAvailableList().getCellRenderer(); 1124 } 1125 1126 @Override 1127 public Component getListCellRendererComponent(JList list, Object value, 1128 int index, boolean isSelected, boolean cellHasFocus) 1129 { 1130 if (value instanceof AttributeType) 1131 { 1132 AttributeType attr = (AttributeType)value; 1133 if (inheritedOptionalAttributes.contains(value) || 1134 inheritedRequiredAttributes.contains(value)) 1135 { 1136 value = attr.getNameOrOID()+ " (*)"; 1137 } 1138 else 1139 { 1140 value = attr.getNameOrOID(); 1141 } 1142 } 1143 return defaultRenderer.getListCellRendererComponent(list, value, index, 1144 isSelected, cellHasFocus); 1145 } 1146 } 1147}