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