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