/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
package org.opends.guitools.controlpanel.ui;
import static org.opends.messages.AdminToolMessages.*;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JList;
import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
import org.opends.guitools.controlpanel.ui.components.TitlePanel;
import org.opends.guitools.controlpanel.util.LowerCaseComparator;
import org.opends.guitools.controlpanel.util.Utilities;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.CommonSchemaElements;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.Schema;
import static org.opends.server.types.CommonSchemaElements.*;
/**
* The panel that displays a standard object class definition.
*
*/
public class StandardObjectClassPanel extends SchemaElementPanel
{
private static final long serialVersionUID = 5561268287795223026L;
private TitlePanel titlePanel = new TitlePanel(LocalizableMessage.EMPTY, LocalizableMessage.EMPTY);
private JLabel lParent;
private JLabel name = Utilities.createDefaultLabel();
private JLabel parent = Utilities.createDefaultLabel();
private JLabel oid = Utilities.createDefaultLabel();
private JLabel origin = Utilities.createDefaultLabel();
private JLabel description = Utilities.createDefaultLabel();
private JLabel aliases = Utilities.createDefaultLabel();
private JLabel type = Utilities.createDefaultLabel();
private JList requiredAttributes = new JList(new DefaultListModel());
private JList optionalAttributes = new JList(new DefaultListModel());
private static LocalizableMessage ABSTRACT_VALUE =
INFO_CTRL_PANEL_OBJECTCLASS_ABSTRACT_LABEL.get();
private static LocalizableMessage STRUCTURAL_VALUE =
INFO_CTRL_PANEL_OBJECTCLASS_STRUCTURAL_LABEL.get();
private static LocalizableMessage AUXILIARY_VALUE =
INFO_CTRL_PANEL_OBJECTCLASS_AUXILIARY_LABEL.get();
private static LocalizableMessage OBSOLETE_VALUE =
INFO_CTRL_PANEL_OBJECTCLASS_OBSOLETE_LABEL.get();
private Map<String, AttributeType> hmAttrs = new HashMap<>();
/** Default constructor of the panel. */
public StandardObjectClassPanel()
{
createLayout();
}
/** {@inheritDoc} */
@Override
public LocalizableMessage getTitle()
{
return INFO_CTRL_PANEL_STANDARD_OBJECTCLASS_TITLE.get();
}
/** {@inheritDoc} */
@Override
public Component getPreferredFocusComponent()
{
return requiredAttributes;
}
/** {@inheritDoc} */
@Override
public void configurationChanged(ConfigurationChangeEvent ev)
{
}
/** {@inheritDoc} */
@Override
public void okClicked()
{
}
/**
* Creates the layout of the panel (but the contents are not populated here).
*/
protected void createLayout()
{
createBasicLayout(this, new GridBagConstraints());
setBorder(PANEL_BORDER);
}
/**
* Creates the basic layout of the panel.
* @param c the container where all the components will be layed out.
* @param gbc the grid bag constraints.
*/
protected void createBasicLayout(Container c, GridBagConstraints gbc)
{
requiredAttributes.setVisibleRowCount(5);
optionalAttributes.setVisibleRowCount(9);
LocalizableMessage[] labels = {
INFO_CTRL_PANEL_OBJECTCLASS_NAME_LABEL.get(),
INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get(),
INFO_CTRL_PANEL_OBJECTCLASS_OID_LABEL.get(),
INFO_CTRL_PANEL_OBJECTCLASS_ALIASES_LABEL.get(),
INFO_CTRL_PANEL_OBJECTCLASS_ORIGIN_LABEL.get(),
INFO_CTRL_PANEL_OBJECTCLASS_DESCRIPTION_LABEL.get(),
INFO_CTRL_PANEL_OBJECTCLASS_TYPE_LABEL.get()
};
JLabel[] values = {name, parent, oid, aliases, origin, description, type};
gbc.gridy = 0;
gbc.gridwidth = 2;
addErrorPane(c, gbc);
gbc.gridy ++;
titlePanel.setTitle(INFO_CTRL_PANEL_OBJECTCLASS_DETAILS.get());
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets.top = 5;
gbc.insets.bottom = 7;
c.add(titlePanel, gbc);
gbc.insets.bottom = 0;
gbc.insets.top = 8;
gbc.gridy ++;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
for (int i=0; i < labels.length; i++)
{
gbc.insets.left = 0;
gbc.gridx = 0;
JLabel l = Utilities.createPrimaryLabel(labels[i]);
if (i == 1)
{
lParent = l;
}
c.add(l, gbc);
gbc.insets.left = 10;
gbc.gridx = 1;
c.add(values[i], gbc);
gbc.gridy ++;
}
labels = new LocalizableMessage[] {
INFO_CTRL_PANEL_REQUIRED_ATTRIBUTES_LABEL.get(),
INFO_CTRL_PANEL_OPTIONAL_ATTRIBUTES_LABEL.get()
};
JList[] lists = {requiredAttributes, optionalAttributes};
gbc.anchor = GridBagConstraints.NORTHWEST;
for (int i=0; i<2; i++)
{
gbc.insets.left = 0;
gbc.gridx = 0;
JLabel l = Utilities.createPrimaryLabel(labels[i]);
gbc.weightx = 0.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
c.add(l, gbc);
gbc.insets.left = 10;
gbc.gridx = 1;
if (i == 0)
{
gbc.weighty = 0.35;
}
else
{
gbc.weighty = 0.65;
}
gbc.weightx = 1.0;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets.top = 10;
c.add(Utilities.createScrollPane(lists[i]), gbc);
gbc.gridy ++;
gbc.weighty = 0.0;
JLabel explanation = Utilities.createInlineHelpLabel(
INFO_CTRL_PANEL_INHERITED_ATTRIBUTES_HELP.get());
gbc.insets.top = 3;
c.add(explanation, gbc);
gbc.gridy ++;
final JList list = lists[i];
MouseAdapter clickListener = new MouseAdapter()
{
/** {@inheritDoc} */
@Override
public void mouseClicked(MouseEvent ev)
{
if (ev.getClickCount() == 1)
{
attrSelected(list);
}
}
};
list.addMouseListener(clickListener);
KeyAdapter keyListener = new KeyAdapter()
{
/** {@inheritDoc} */
@Override
public void keyTyped(KeyEvent ev)
{
if (ev.getKeyChar() == KeyEvent.VK_SPACE ||
ev.getKeyChar() == KeyEvent.VK_ENTER)
{
attrSelected(list);
}
}
};
list.addKeyListener(keyListener);
}
}
/**
* Returns the message describing the schema element origin (file, RFC, etc.).
* @param element the schema element.
* @return the message describing the schema element origin (file, RFC, etc.).
*/
static LocalizableMessage getOrigin(CommonSchemaElements element)
{
LocalizableMessageBuilder returnValue = new LocalizableMessageBuilder();
String fileName = getSchemaFile(element);
String xOrigin = Utilities.getOrigin(element);
if (xOrigin != null)
{
returnValue.append(xOrigin);
if (fileName != null)
{
returnValue.append(" -");
returnValue.append(
INFO_CTRL_PANEL_DEFINED_IN_SCHEMA_FILE.get(fileName));
}
}
else if (fileName != null)
{
returnValue.append(INFO_CTRL_PANEL_DEFINED_IN_SCHEMA_FILE.get(fileName));
}
else
{
returnValue.append(NOT_APPLICABLE);
}
return returnValue.toMessage();
}
/**
* Updates the contents of the panel with the provided object class.
* @param oc the object class.
* @param schema the schema.
*/
public void update(ObjectClass oc, Schema schema)
{
if (oc == null || schema == null)
{
// Ignore: this is called to get an initial panel size.
return;
}
hmAttrs.clear();
String n = oc.getPrimaryName();
if (n == null)
{
n = NOT_APPLICABLE.toString();
}
titlePanel.setDetails(LocalizableMessage.raw(n));
name.setText(n);
parent.setText(getSuperiorText(oc));
oid.setText(oc.getOID());
origin.setText(getOrigin(oc).toString());
n = oc.getDescription();
if (n == null)
{
n = NOT_APPLICABLE.toString();
}
description.setText(n);
ArrayList<String> otherNames = new ArrayList<>();
Iterable<String> ocNames = oc.getNormalizedNames();
String primaryName = oc.getPrimaryName();
if (primaryName == null)
{
primaryName = "";
}
for (String name : ocNames)
{
if (!name.equalsIgnoreCase(primaryName))
{
otherNames.add(name);
}
}
if (!otherNames.isEmpty())
{
n = Utilities.getStringFromCollection(otherNames, ", ");
}
else
{
n = NOT_APPLICABLE.toString();
}
aliases.setText(n);
type.setText(getTypeValue(oc).toString());
Comparator<String> lowerCaseComparator = new LowerCaseComparator();
SortedSet<String> requiredAttrs = new TreeSet<>(lowerCaseComparator);
Set<String> inheritedAttrs = new HashSet<>();
for (AttributeType attr : oc.getRequiredAttributeChain())
{
requiredAttrs.add(attr.getNameOrOID());
}
Set<ObjectClass> parents = oc.getSuperiorClasses();
if (parents != null)
{
if (parents.size() > 1)
{
lParent.setText(
INFO_CTRL_PANEL_OBJECTCLASS_PARENTS_LABEL.get().toString());
}
else
{
lParent.setText(
INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString());
}
for (ObjectClass parent : parents)
{
for (AttributeType attr : parent.getRequiredAttributeChain())
{
inheritedAttrs.add(attr.getNameOrOID());
}
}
}
else
{
lParent.setText(
INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString());
}
DefaultListModel model = (DefaultListModel)requiredAttributes.getModel();
model.clear();
for (String attr : requiredAttrs)
{
String v;
if (inheritedAttrs.contains(attr))
{
v = attr+" (*)";
}
else
{
v = attr;
}
model.addElement(v);
hmAttrs.put(v, schema.getAttributeType(attr.toLowerCase()));
}
SortedSet<String> optionalAttrs = new TreeSet<>(lowerCaseComparator);
inheritedAttrs = new HashSet<>();
for (AttributeType attr : oc.getOptionalAttributeChain())
{
optionalAttrs.add(attr.getNameOrOID());
}
if (parents != null)
{
for (ObjectClass parent : parents)
{
for (AttributeType attr : parent.getOptionalAttributeChain())
{
inheritedAttrs.add(attr.getNameOrOID());
}
}
}
model = (DefaultListModel)optionalAttributes.getModel();
model.clear();
for (String attr : optionalAttrs)
{
String v;
if (inheritedAttrs.contains(attr))
{
v = attr+" (*)";
}
else
{
v = attr;
}
model.addElement(v);
hmAttrs.put(v, schema.getAttributeType(attr.toLowerCase()));
}
}
private String getSuperiorText(ObjectClass oc)
{
String n;
Set<ObjectClass> superiors = oc.getSuperiorClasses();
if (superiors == null)
{
n = null;
}
else
{
if (superiors.isEmpty())
{
n = NOT_APPLICABLE.toString();
}
else if (superiors.size() == 1)
{
n = superiors.iterator().next().getPrimaryName();
}
else
{
SortedSet<String> names = new TreeSet<>();
for (ObjectClass superior : superiors)
{
names.add(superior.getPrimaryName());
}
n = Utilities.getStringFromCollection(names, ", ");
}
}
if (n == null)
{
n = NOT_APPLICABLE.toString();
}
return n;
}
/**
* Returns the message describing the object class type (structural, obsolete,
* etc.) of a given object class.
* @param oc the object class.
* @return the message describing the object class type (structural, obsolete,
* etc.) of the provided object class.
*/
static LocalizableMessage getTypeValue(ObjectClass oc)
{
LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
switch (oc.getObjectClassType())
{
case ABSTRACT:
mb.append(ABSTRACT_VALUE);
break;
case STRUCTURAL:
mb.append(STRUCTURAL_VALUE);
break;
case AUXILIARY:
mb.append(AUXILIARY_VALUE);
break;
}
if (oc.isObsolete())
{
if (mb.length() > 0)
{
mb.append(", ");
}
mb.append(OBSOLETE_VALUE);
}
return mb.toMessage();
}
private void attrSelected(JList list)
{
String o = (String)list.getSelectedValue();
if (o != null)
{
AttributeType attr = hmAttrs.get(o);
if (attr != null)
{
notifySchemaSelectionListeners(attr);
}
}
}
}