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 */ 017 018package org.opends.guitools.controlpanel.ui; 019 020import static org.opends.messages.AdminToolMessages.*; 021 022import java.awt.Component; 023import java.awt.Container; 024import java.awt.GridBagConstraints; 025import java.awt.event.KeyAdapter; 026import java.awt.event.KeyEvent; 027import java.awt.event.MouseAdapter; 028import java.awt.event.MouseEvent; 029import java.util.ArrayList; 030import java.util.Comparator; 031import java.util.HashMap; 032import java.util.HashSet; 033import java.util.Map; 034import java.util.Set; 035import java.util.SortedSet; 036import java.util.TreeSet; 037 038import javax.swing.DefaultListModel; 039import javax.swing.JLabel; 040import javax.swing.JList; 041 042import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 043import org.opends.guitools.controlpanel.ui.components.TitlePanel; 044import org.opends.guitools.controlpanel.util.LowerCaseComparator; 045import org.opends.guitools.controlpanel.util.Utilities; 046import org.forgerock.i18n.LocalizableMessage; 047import org.forgerock.i18n.LocalizableMessageBuilder; 048import org.forgerock.opendj.ldap.schema.AttributeType; 049import org.opends.server.schema.SomeSchemaElement; 050import org.opends.server.types.ObjectClass; 051import org.opends.server.types.Schema; 052 053/** 054 * The panel that displays a standard object class definition. 055 * 056 */ 057public class StandardObjectClassPanel extends SchemaElementPanel 058{ 059 private static final long serialVersionUID = 5561268287795223026L; 060 private TitlePanel titlePanel = new TitlePanel(LocalizableMessage.EMPTY, LocalizableMessage.EMPTY); 061 062 private JLabel lParent; 063 064 private JLabel name = Utilities.createDefaultLabel(); 065 private JLabel parent = Utilities.createDefaultLabel(); 066 private JLabel oid = Utilities.createDefaultLabel(); 067 private JLabel origin = Utilities.createDefaultLabel(); 068 private JLabel description = Utilities.createDefaultLabel(); 069 private JLabel aliases = Utilities.createDefaultLabel(); 070 private JLabel type = Utilities.createDefaultLabel(); 071 private JList requiredAttributes = new JList(new DefaultListModel()); 072 private JList optionalAttributes = new JList(new DefaultListModel()); 073 074 private static LocalizableMessage ABSTRACT_VALUE = 075 INFO_CTRL_PANEL_OBJECTCLASS_ABSTRACT_LABEL.get(); 076 private static LocalizableMessage STRUCTURAL_VALUE = 077 INFO_CTRL_PANEL_OBJECTCLASS_STRUCTURAL_LABEL.get(); 078 private static LocalizableMessage AUXILIARY_VALUE = 079 INFO_CTRL_PANEL_OBJECTCLASS_AUXILIARY_LABEL.get(); 080 private static LocalizableMessage OBSOLETE_VALUE = 081 INFO_CTRL_PANEL_OBJECTCLASS_OBSOLETE_LABEL.get(); 082 083 private Map<String, AttributeType> hmAttrs = new HashMap<>(); 084 085 /** Default constructor of the panel. */ 086 public StandardObjectClassPanel() 087 { 088 createLayout(); 089 } 090 091 /** {@inheritDoc} */ 092 @Override 093 public LocalizableMessage getTitle() 094 { 095 return INFO_CTRL_PANEL_STANDARD_OBJECTCLASS_TITLE.get(); 096 } 097 098 /** {@inheritDoc} */ 099 @Override 100 public Component getPreferredFocusComponent() 101 { 102 return requiredAttributes; 103 } 104 105 /** {@inheritDoc} */ 106 @Override 107 public void configurationChanged(ConfigurationChangeEvent ev) 108 { 109 } 110 111 /** {@inheritDoc} */ 112 @Override 113 public void okClicked() 114 { 115 } 116 117 /** 118 * Creates the layout of the panel (but the contents are not populated here). 119 */ 120 protected void createLayout() 121 { 122 createBasicLayout(this, new GridBagConstraints()); 123 setBorder(PANEL_BORDER); 124 } 125 126 /** 127 * Creates the basic layout of the panel. 128 * @param c the container where all the components will be layed out. 129 * @param gbc the grid bag constraints. 130 */ 131 protected void createBasicLayout(Container c, GridBagConstraints gbc) 132 { 133 134 requiredAttributes.setVisibleRowCount(5); 135 optionalAttributes.setVisibleRowCount(9); 136 137 LocalizableMessage[] labels = { 138 INFO_CTRL_PANEL_OBJECTCLASS_NAME_LABEL.get(), 139 INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get(), 140 INFO_CTRL_PANEL_OBJECTCLASS_OID_LABEL.get(), 141 INFO_CTRL_PANEL_OBJECTCLASS_ALIASES_LABEL.get(), 142 INFO_CTRL_PANEL_OBJECTCLASS_ORIGIN_LABEL.get(), 143 INFO_CTRL_PANEL_OBJECTCLASS_DESCRIPTION_LABEL.get(), 144 INFO_CTRL_PANEL_OBJECTCLASS_TYPE_LABEL.get() 145 }; 146 147 JLabel[] values = {name, parent, oid, aliases, origin, description, type}; 148 gbc.gridy = 0; 149 gbc.gridwidth = 2; 150 addErrorPane(c, gbc); 151 gbc.gridy ++; 152 titlePanel.setTitle(INFO_CTRL_PANEL_OBJECTCLASS_DETAILS.get()); 153 gbc.fill = GridBagConstraints.NONE; 154 gbc.anchor = GridBagConstraints.WEST; 155 gbc.insets.top = 5; 156 gbc.insets.bottom = 7; 157 c.add(titlePanel, gbc); 158 159 gbc.insets.bottom = 0; 160 gbc.insets.top = 8; 161 gbc.gridy ++; 162 gbc.gridwidth = 1; 163 gbc.fill = GridBagConstraints.HORIZONTAL; 164 for (int i=0; i < labels.length; i++) 165 { 166 gbc.insets.left = 0; 167 gbc.gridx = 0; 168 JLabel l = Utilities.createPrimaryLabel(labels[i]); 169 if (i == 1) 170 { 171 lParent = l; 172 } 173 c.add(l, gbc); 174 gbc.insets.left = 10; 175 gbc.gridx = 1; 176 c.add(values[i], gbc); 177 gbc.gridy ++; 178 } 179 labels = new LocalizableMessage[] { 180 INFO_CTRL_PANEL_REQUIRED_ATTRIBUTES_LABEL.get(), 181 INFO_CTRL_PANEL_OPTIONAL_ATTRIBUTES_LABEL.get() 182 }; 183 JList[] lists = {requiredAttributes, optionalAttributes}; 184 gbc.anchor = GridBagConstraints.NORTHWEST; 185 for (int i=0; i<2; i++) 186 { 187 gbc.insets.left = 0; 188 gbc.gridx = 0; 189 JLabel l = Utilities.createPrimaryLabel(labels[i]); 190 gbc.weightx = 0.0; 191 gbc.fill = GridBagConstraints.HORIZONTAL; 192 c.add(l, gbc); 193 gbc.insets.left = 10; 194 gbc.gridx = 1; 195 if (i == 0) 196 { 197 gbc.weighty = 0.35; 198 } 199 else 200 { 201 gbc.weighty = 0.65; 202 } 203 gbc.weightx = 1.0; 204 gbc.fill = GridBagConstraints.BOTH; 205 gbc.insets.top = 10; 206 c.add(Utilities.createScrollPane(lists[i]), gbc); 207 gbc.gridy ++; 208 gbc.weighty = 0.0; 209 JLabel explanation = Utilities.createInlineHelpLabel( 210 INFO_CTRL_PANEL_INHERITED_ATTRIBUTES_HELP.get()); 211 gbc.insets.top = 3; 212 c.add(explanation, gbc); 213 gbc.gridy ++; 214 215 final JList list = lists[i]; 216 MouseAdapter clickListener = new MouseAdapter() 217 { 218 /** {@inheritDoc} */ 219 @Override 220 public void mouseClicked(MouseEvent ev) 221 { 222 if (ev.getClickCount() == 1) 223 { 224 attrSelected(list); 225 } 226 } 227 }; 228 list.addMouseListener(clickListener); 229 230 KeyAdapter keyListener = new KeyAdapter() 231 { 232 /** {@inheritDoc} */ 233 @Override 234 public void keyTyped(KeyEvent ev) 235 { 236 if (ev.getKeyChar() == KeyEvent.VK_SPACE || 237 ev.getKeyChar() == KeyEvent.VK_ENTER) 238 { 239 attrSelected(list); 240 } 241 } 242 }; 243 list.addKeyListener(keyListener); 244 } 245 } 246 247 /** 248 * Returns the message describing the schema element origin (file, RFC, etc.). 249 * @param element the schema element. 250 * @return the message describing the schema element origin (file, RFC, etc.). 251 */ 252 static LocalizableMessage getOrigin(SomeSchemaElement element) 253 { 254 LocalizableMessageBuilder returnValue = new LocalizableMessageBuilder(); 255 String fileName = element.getSchemaFile(); 256 String xOrigin = Utilities.getOrigin(element); 257 if (xOrigin != null) 258 { 259 returnValue.append(xOrigin); 260 if (fileName != null) 261 { 262 returnValue.append(" -"); 263 returnValue.append( 264 INFO_CTRL_PANEL_DEFINED_IN_SCHEMA_FILE.get(fileName)); 265 } 266 } 267 else if (fileName != null) 268 { 269 returnValue.append(INFO_CTRL_PANEL_DEFINED_IN_SCHEMA_FILE.get(fileName)); 270 } 271 else 272 { 273 returnValue.append(NOT_APPLICABLE); 274 } 275 return returnValue.toMessage(); 276 } 277 278 /** 279 * Updates the contents of the panel with the provided object class. 280 * @param oc the object class. 281 * @param schema the schema. 282 */ 283 public void update(ObjectClass oc, Schema schema) 284 { 285 if (oc == null || schema == null) 286 { 287 // Ignore: this is called to get an initial panel size. 288 return; 289 } 290 hmAttrs.clear(); 291 String n = oc.getPrimaryName(); 292 if (n == null) 293 { 294 n = NOT_APPLICABLE.toString(); 295 } 296 titlePanel.setDetails(LocalizableMessage.raw(n)); 297 name.setText(n); 298 parent.setText(getSuperiorText(oc)); 299 oid.setText(oc.getOID()); 300 origin.setText(getOrigin(new SomeSchemaElement(oc)).toString()); 301 n = oc.getDescription(); 302 if (n == null) 303 { 304 n = NOT_APPLICABLE.toString(); 305 } 306 description.setText(n); 307 ArrayList<String> otherNames = new ArrayList<>(); 308 Iterable<String> ocNames = oc.getNormalizedNames(); 309 String primaryName = oc.getPrimaryName(); 310 if (primaryName == null) 311 { 312 primaryName = ""; 313 } 314 for (String name : ocNames) 315 { 316 if (!name.equalsIgnoreCase(primaryName)) 317 { 318 otherNames.add(name); 319 } 320 } 321 if (!otherNames.isEmpty()) 322 { 323 n = Utilities.getStringFromCollection(otherNames, ", "); 324 } 325 else 326 { 327 n = NOT_APPLICABLE.toString(); 328 } 329 aliases.setText(n); 330 331 type.setText(getTypeValue(oc).toString()); 332 333 Comparator<String> lowerCaseComparator = new LowerCaseComparator(); 334 SortedSet<String> requiredAttrs = new TreeSet<>(lowerCaseComparator); 335 Set<String> inheritedAttrs = new HashSet<>(); 336 for (AttributeType attr : oc.getRequiredAttributeChain()) 337 { 338 requiredAttrs.add(attr.getNameOrOID()); 339 } 340 Set<ObjectClass> parents = oc.getSuperiorClasses(); 341 if (parents != null) 342 { 343 if (parents.size() > 1) 344 { 345 lParent.setText( 346 INFO_CTRL_PANEL_OBJECTCLASS_PARENTS_LABEL.get().toString()); 347 } 348 else 349 { 350 lParent.setText( 351 INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString()); 352 } 353 for (ObjectClass parent : parents) 354 { 355 for (AttributeType attr : parent.getRequiredAttributeChain()) 356 { 357 inheritedAttrs.add(attr.getNameOrOID()); 358 } 359 } 360 } 361 else 362 { 363 lParent.setText( 364 INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString()); 365 } 366 367 DefaultListModel model = (DefaultListModel)requiredAttributes.getModel(); 368 model.clear(); 369 for (String attr : requiredAttrs) 370 { 371 String v; 372 if (inheritedAttrs.contains(attr)) 373 { 374 v = attr+" (*)"; 375 } 376 else 377 { 378 v = attr; 379 } 380 model.addElement(v); 381 hmAttrs.put(v, schema.getAttributeType(attr.toLowerCase())); 382 } 383 384 SortedSet<String> optionalAttrs = new TreeSet<>(lowerCaseComparator); 385 inheritedAttrs = new HashSet<>(); 386 for (AttributeType attr : oc.getOptionalAttributeChain()) 387 { 388 optionalAttrs.add(attr.getNameOrOID()); 389 } 390 if (parents != null) 391 { 392 for (ObjectClass parent : parents) 393 { 394 for (AttributeType attr : parent.getOptionalAttributeChain()) 395 { 396 inheritedAttrs.add(attr.getNameOrOID()); 397 } 398 } 399 } 400 model = (DefaultListModel)optionalAttributes.getModel(); 401 model.clear(); 402 for (String attr : optionalAttrs) 403 { 404 String v; 405 if (inheritedAttrs.contains(attr)) 406 { 407 v = attr+" (*)"; 408 } 409 else 410 { 411 v = attr; 412 } 413 model.addElement(v); 414 hmAttrs.put(v, schema.getAttributeType(attr.toLowerCase())); 415 } 416 } 417 418 private String getSuperiorText(ObjectClass oc) 419 { 420 String n; 421 Set<ObjectClass> superiors = oc.getSuperiorClasses(); 422 if (superiors == null) 423 { 424 n = null; 425 } 426 else 427 { 428 if (superiors.isEmpty()) 429 { 430 n = NOT_APPLICABLE.toString(); 431 } 432 else if (superiors.size() == 1) 433 { 434 n = superiors.iterator().next().getPrimaryName(); 435 } 436 else 437 { 438 SortedSet<String> names = new TreeSet<>(); 439 for (ObjectClass superior : superiors) 440 { 441 names.add(superior.getPrimaryName()); 442 } 443 n = Utilities.getStringFromCollection(names, ", "); 444 } 445 } 446 if (n == null) 447 { 448 n = NOT_APPLICABLE.toString(); 449 } 450 return n; 451 } 452 453 /** 454 * Returns the message describing the object class type (structural, obsolete, 455 * etc.) of a given object class. 456 * @param oc the object class. 457 * @return the message describing the object class type (structural, obsolete, 458 * etc.) of the provided object class. 459 */ 460 static LocalizableMessage getTypeValue(ObjectClass oc) 461 { 462 LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 463 switch (oc.getObjectClassType()) 464 { 465 case ABSTRACT: 466 mb.append(ABSTRACT_VALUE); 467 break; 468 case STRUCTURAL: 469 mb.append(STRUCTURAL_VALUE); 470 break; 471 case AUXILIARY: 472 mb.append(AUXILIARY_VALUE); 473 break; 474 } 475 if (oc.isObsolete()) 476 { 477 if (mb.length() > 0) 478 { 479 mb.append(", "); 480 } 481 mb.append(OBSOLETE_VALUE); 482 } 483 return mb.toMessage(); 484 } 485 486 private void attrSelected(JList list) 487 { 488 String o = (String)list.getSelectedValue(); 489 if (o != null) 490 { 491 AttributeType attr = hmAttrs.get(o); 492 if (attr != null) 493 { 494 notifySchemaSelectionListeners(attr); 495 } 496 } 497 } 498}