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