/* * 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 2013-2015 ForgeRock AS. */ package org.opends.guitools.controlpanel.ui; import static com.forgerock.opendj.cli.Utils.*; import static org.opends.messages.AdminToolMessages.*; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.StringReader; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.JTextComponent; import javax.swing.tree.TreePath; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import org.forgerock.opendj.ldap.ByteString; import org.opends.guitools.controlpanel.datamodel.BinaryValue; import org.opends.guitools.controlpanel.datamodel.CheckEntrySyntaxException; import org.opends.guitools.controlpanel.datamodel.CustomSearchResult; import org.opends.guitools.controlpanel.datamodel.ObjectClassValue; import org.opends.guitools.controlpanel.event.ScrollPaneBorderListener; import org.opends.guitools.controlpanel.task.OnlineUpdateException; import org.opends.guitools.controlpanel.ui.components.BinaryCellPanel; import org.opends.guitools.controlpanel.ui.components.ObjectClassCellPanel; import org.opends.guitools.controlpanel.ui.nodes.BrowserNodeInfo; import org.opends.guitools.controlpanel.ui.nodes.DndBrowserNodes; import org.opends.guitools.controlpanel.util.Utilities; import org.opends.server.schema.SchemaConstants; import org.opends.server.types.*; import org.opends.server.util.Base64; import org.opends.server.util.LDIFReader; import org.opends.server.util.ServerConstants; /** * The panel displaying a simplified view of an entry. */ public class SimplifiedViewEntryPanel extends ViewEntryPanel { private static final long serialVersionUID = 2775960608128921072L; private JPanel attributesPanel; private ScrollPaneBorderListener scrollListener; private GenericDialog binaryDlg; private BinaryValuePanel binaryPanel; private GenericDialog editBinaryDlg; private BinaryAttributeEditorPanel editBinaryPanel; private GenericDialog editOcDlg; private ObjectClassEditorPanel editOcPanel; private JLabel requiredLabel; private JCheckBox showOnlyAttrsWithValues; private DropTargetListener dropTargetListener; private GenericDialog browseEntriesDlg; private LDAPEntrySelectionPanel browseEntriesPanel; private Map<String, List<String>> lastUserPasswords = new HashMap<>(); private CustomSearchResult searchResult; private boolean isReadOnly; private TreePath treePath; private JScrollPane scrollAttributes; private LinkedHashMap<String, List<EditorComponent>> hmEditors = new LinkedHashMap<>(); private Set<String> requiredAttrs = new HashSet<>(); private Map<String, JComponent> hmLabels = new HashMap<>(); private Map<String, String> hmDisplayedNames = new HashMap<>(); private Map<String, JComponent> hmComponents = new HashMap<>(); private final String CONFIRM_PASSWORD = "confirm password"; /** Map containing as key the attribute name and as value a localizable message. */ static Map<String, LocalizableMessage> hmFriendlyAttrNames = new HashMap<>(); /** * Map containing as key an object class and as value the preferred naming * attribute for the objectclass. */ static Map<String, String> hmNameAttrNames = new HashMap<>(); static Map<String, String[]> hmOrdereredAttrNames = new HashMap<>(); static { hmFriendlyAttrNames.put(ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME, INFO_CTRL_PANEL_OBJECTCLASS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_COMMON_NAME, INFO_CTRL_PANEL_CN_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("givenname", INFO_CTRL_PANEL_GIVENNAME_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("sn", INFO_CTRL_PANEL_SN_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("uid", INFO_CTRL_PANEL_UID_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("employeenumber", INFO_CTRL_PANEL_EMPLOYEENUMBER_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("userpassword", INFO_CTRL_PANEL_USERPASSWORD_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("authpassword", INFO_CTRL_PANEL_AUTHPASSWORD_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("mail", INFO_CTRL_PANEL_MAIL_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("street", INFO_CTRL_PANEL_STREET_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("l", INFO_CTRL_PANEL_L_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("st", INFO_CTRL_PANEL_ST_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("postalcode", INFO_CTRL_PANEL_POSTALCODE_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("mobile", INFO_CTRL_PANEL_MOBILE_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("homephone", INFO_CTRL_PANEL_HOMEPHONE_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("telephonenumber", INFO_CTRL_PANEL_TELEPHONENUMBER_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("pager", INFO_CTRL_PANEL_PAGER_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("facsimiletelephonenumber", INFO_CTRL_PANEL_FACSIMILETELEPHONENUMBER_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("description", INFO_CTRL_PANEL_DESCRIPTION_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("postaladdress", INFO_CTRL_PANEL_POSTALADDRESS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_UNIQUE_MEMBER_LC, INFO_CTRL_PANEL_UNIQUEMEMBER_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_MEMBER, INFO_CTRL_PANEL_MEMBER_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_MEMBER_URL_LC, INFO_CTRL_PANEL_MEMBERURL_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_C, INFO_CTRL_PANEL_C_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("ds-target-group-dn", INFO_CTRL_PANEL_DS_TARGET_GROUP_DN_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("usercertificate", INFO_CTRL_PANEL_USERCERTIFICATE_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put("jpegphoto", INFO_CTRL_PANEL_JPEGPHOTO_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_SUPPORTED_AUTH_PW_SCHEMES_LC, INFO_CTRL_PANEL_SUPPORTEDPWDSCHEMES_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_SUPPORTED_CONTROL_LC, INFO_CTRL_PANEL_SUPPORTEDCONTROLS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_SUPPORTED_LDAP_VERSION_LC, INFO_CTRL_PANEL_SUPPORTEDLDAPVERSIONS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_SUPPORTED_CONTROL_LC, INFO_CTRL_PANEL_SUPPORTEDCONTROLS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_SUPPORTED_EXTENSION_LC, INFO_CTRL_PANEL_SUPPORTEDEXTENSIONS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_SUPPORTED_FEATURE_LC, INFO_CTRL_PANEL_SUPPORTEDFEATURES_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_VENDOR_NAME_LC, INFO_CTRL_PANEL_VENDORNAME_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_VENDOR_VERSION_LC, INFO_CTRL_PANEL_VENDORVERSION_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_NAMING_CONTEXTS_LC, INFO_CTRL_PANEL_NAMINGCONTEXTS_FRIENDLY_NAME.get()); hmFriendlyAttrNames.put(ServerConstants.ATTR_PRIVATE_NAMING_CONTEXTS, INFO_CTRL_PANEL_PRIVATENAMINGCONTEXTS_FRIENDLY_NAME.get()); hmNameAttrNames.put("organizationalunit", ServerConstants.ATTR_OU); hmNameAttrNames.put("domain", ServerConstants.ATTR_DC); hmNameAttrNames.put("organization", ServerConstants.ATTR_O); hmNameAttrNames.put(ServerConstants.OC_GROUP_OF_URLS_LC, ServerConstants.ATTR_COMMON_NAME); hmNameAttrNames.put(ServerConstants.OC_GROUP_OF_NAMES_LC, ServerConstants.ATTR_COMMON_NAME); hmOrdereredAttrNames.put("person", new String[]{"givenname", "sn", ServerConstants.ATTR_COMMON_NAME, "uid", "userpassword", "mail", "telephonenumber", "facsimiletelephonenumber", "employeenumber", "street", "l", "st", "postalcode", "mobile", "homephone", "pager", "description", "postaladdress"}); hmOrdereredAttrNames.put(ServerConstants.OC_GROUP_OF_NAMES_LC, new String[]{"cn", "description", ServerConstants.ATTR_UNIQUE_MEMBER_LC, "ds-target-group-dn"}); hmOrdereredAttrNames.put(ServerConstants.OC_GROUP_OF_URLS_LC, new String[]{"cn", "description", ServerConstants.ATTR_MEMBER_URL_LC}); hmOrdereredAttrNames.put("organizationalunit", new String[]{"ou", "description", "postalAddress", "telephonenumber", "facsimiletelephonenumber"}); hmOrdereredAttrNames.put("organization", new String[]{"o", "description"}); hmOrdereredAttrNames.put("domain", new String[]{"dc", "description"}); } private LocalizableMessage NAME = INFO_CTRL_PANEL_NAME_LABEL.get(); /** Default constructor. */ public SimplifiedViewEntryPanel() { super(); createLayout(); } /** {@inheritDoc} */ public Component getPreferredFocusComponent() { return null; } /** {@inheritDoc} */ public boolean requiresBorder() { return false; } /** * Creates the layout of the panel (but the contents are not populated here). */ private void createLayout() { dropTargetListener = new DropTargetListener() { /** {@inheritDoc} */ public void dragEnter(DropTargetDragEvent e) { } /** {@inheritDoc} */ public void dragExit(DropTargetEvent e) { } /** {@inheritDoc} */ public void dragOver(DropTargetDragEvent e) { } /** {@inheritDoc} */ public void dropActionChanged(DropTargetDragEvent e) { } /** {@inheritDoc} */ public void drop(DropTargetDropEvent e) { try { Transferable tr = e.getTransferable(); //flavor not supported, reject drop if (!tr.isDataFlavorSupported(DndBrowserNodes.INFO_FLAVOR)) { e.rejectDrop(); } //cast into appropriate data type DndBrowserNodes nodes = (DndBrowserNodes) tr.getTransferData(DndBrowserNodes.INFO_FLAVOR); Component comp = e.getDropTargetContext().getComponent(); if (comp instanceof JTextArea) { JTextArea ta = (JTextArea)comp; StringBuilder sb = new StringBuilder(); sb.append(ta.getText()); for (BrowserNodeInfo node : nodes.getNodes()) { if (sb.length() > 0) { sb.append("\n"); } sb.append(node.getNode().getDN()); } ta.setText(sb.toString()); ta.setCaretPosition(sb.length()); } else if (comp instanceof JTextField) { JTextField tf = (JTextField)comp; if (nodes.getNodes().length > 0) { String dn = nodes.getNodes()[0].getNode().getDN(); tf.setText(dn); tf.setCaretPosition(dn.length()); } } e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); e.getDropTargetContext().dropComplete(true); } catch (IOException | UnsupportedFlavorException io) { e.rejectDrop(); } } }; GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.NONE; gbc.anchor = GridBagConstraints.WEST; gbc.weightx = 1.0; gbc.insets = new Insets(10, 10, 0, 10); addTitlePanel(this, gbc); gbc.gridy ++; gbc.insets = new Insets(5, 10, 5, 10); gbc.gridwidth = 1; showOnlyAttrsWithValues = Utilities.createCheckBox( INFO_CTRL_PANEL_SHOW_ATTRS_WITH_VALUES_LABEL.get()); showOnlyAttrsWithValues.setSelected(displayOnlyWithAttrs); showOnlyAttrsWithValues.addActionListener(new ActionListener() { /** {@inheritDoc} */ public void actionPerformed(ActionEvent ev) { updateAttributeVisibility(!showOnlyAttrsWithValues.isSelected()); displayOnlyWithAttrs = showOnlyAttrsWithValues.isSelected(); } }); gbc.weightx = 0.0; gbc.anchor = GridBagConstraints.WEST; add(showOnlyAttrsWithValues, gbc); gbc.gridx ++; gbc.anchor = GridBagConstraints.EAST; gbc.fill = GridBagConstraints.NONE; requiredLabel = createRequiredLabel(); add(requiredLabel, gbc); gbc.insets = new Insets(0, 0, 0, 0); add(Box.createVerticalStrut(10), gbc); showOnlyAttrsWithValues.setFont(requiredLabel.getFont()); attributesPanel = new JPanel(new GridBagLayout()); attributesPanel.setOpaque(false); attributesPanel.setBorder(new EmptyBorder(5, 10, 5, 10)); gbc.gridx = 0; gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.gridwidth = 2; gbc.gridy ++; gbc.fill = GridBagConstraints.BOTH; scrollAttributes = Utilities.createBorderLessScrollBar(attributesPanel); scrollListener = ScrollPaneBorderListener.createBottomAndTopBorderListener( scrollAttributes); gbc.insets = new Insets(0, 0, 0, 0); add(scrollAttributes, gbc); } /** {@inheritDoc} */ public void update(CustomSearchResult sr, boolean isReadOnly, TreePath path) { boolean sameEntry = false; if (searchResult != null && sr != null) { sameEntry = searchResult.getDN().equals(sr.getDN()); } final Point p = sameEntry ? scrollAttributes.getViewport().getViewPosition() : new Point(0, 0); searchResult = sr; this.isReadOnly = isReadOnly; this.treePath = path; updateTitle(sr, path); requiredLabel.setVisible(!isReadOnly); showOnlyAttrsWithValues.setVisible(!isReadOnly); attributesPanel.removeAll(); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; lastUserPasswords.clear(); hmEditors.clear(); hmLabels.clear(); hmDisplayedNames.clear(); hmComponents.clear(); requiredAttrs.clear(); // Build the attributes panel. Collection<String> sortedAttributes = getSortedAttributes(sr, isReadOnly); if (isReadOnly) { for (String attr : sortedAttributes) { JLabel label = getLabelForAttribute(attr, sr); List<Object> values = sr.getAttributeValues(attr); JComponent comp = getReadOnlyComponent(attr, values); gbc.weightx = 0.0; if (values.size() > 1) { gbc.anchor = GridBagConstraints.NORTHWEST; } else { gbc.anchor = GridBagConstraints.WEST; if (values.size() == 1) { Object v = values.get(0); if (v instanceof String && ((String) v).contains("\n")) { gbc.anchor = GridBagConstraints.NORTHWEST; } } } gbc.insets.left = 0; gbc.gridwidth = GridBagConstraints.RELATIVE; attributesPanel.add(label, gbc); gbc.insets.left = 10; gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; attributesPanel.add(comp, gbc); gbc.insets.top = 10; } } else { for (String attr : sortedAttributes) { JLabel label = getLabelForAttribute(attr, sr); if (isRequired(attr, sr)) { Utilities.setRequiredIcon(label); requiredAttrs.add(attr.toLowerCase()); } List<Object> values = sr.getAttributeValues(attr); if (values.isEmpty()) { values = new ArrayList<>(1); if (isBinary(attr)) { values.add(new byte[]{}); } else { values.add(""); } } if (isPassword(attr)) { List<String> pwds = new ArrayList<>(); for (Object o : values) { pwds.add(getPasswordStringValue(o)); } lastUserPasswords.put(attr.toLowerCase(), pwds); } JComponent comp = getReadWriteComponent(attr, values); gbc.weightx = 0.0; if (attr.equalsIgnoreCase( ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME)) { int nOcs = 0; for (Object o : values) { if (!"top".equals(o)) { nOcs ++; } } if (nOcs > 1) { gbc.anchor = GridBagConstraints.NORTHWEST; } else { gbc.anchor = GridBagConstraints.WEST; } } else if (isSingleValue(attr)) { gbc.anchor = GridBagConstraints.WEST; } else if (values.size() <= 1 && (hasBinaryValue(values) || isBinary(attr))) { gbc.anchor = GridBagConstraints.WEST; } else { gbc.anchor = GridBagConstraints.NORTHWEST; } gbc.insets.left = 0; gbc.gridwidth = GridBagConstraints.RELATIVE; attributesPanel.add(label, gbc); gbc.insets.left = 10; gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; attributesPanel.add(comp, gbc); gbc.insets.top = 10; hmLabels.put(attr.toLowerCase(), label); hmComponents.put(attr.toLowerCase(), comp); if (isPassword(attr)) { label = Utilities.createPrimaryLabel( INFO_CTRL_PANEL_PASSWORD_CONFIRM_LABEL.get()); String key = getConfirmPasswordKey(attr); comp = getReadWriteComponent(key, values); hmLabels.put(key, label); hmComponents.put(key, comp); gbc.weightx = 0.0; if (isSingleValue(attr)) { gbc.anchor = GridBagConstraints.WEST; } else { gbc.anchor = GridBagConstraints.NORTHWEST; } gbc.insets.left = 0; gbc.gridwidth = GridBagConstraints.RELATIVE; attributesPanel.add(label, gbc); gbc.insets.left = 10; gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; attributesPanel.add(comp, gbc); gbc.insets.top = 10; } } } gbc.weighty = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.fill = GridBagConstraints.VERTICAL; gbc.insets = new Insets(0, 0, 0, 0); attributesPanel.add(Box.createVerticalGlue(), gbc); scrollListener.updateBorder(); if (showOnlyAttrsWithValues.isSelected()) { updateAttributeVisibility(false); } else if (isVisible()) { repaint(); } SwingUtilities.invokeLater(new Runnable() { /** {@inheritDoc} */ public void run() { if (p != null && scrollAttributes.getViewport().contains(p)) { scrollAttributes.getViewport().setViewPosition(p); } ignoreEntryChangeEvents = false; } }); } private JLabel getLabelForAttribute(String attrName, CustomSearchResult sr) { LocalizableMessageBuilder l = new LocalizableMessageBuilder(); int index = attrName.indexOf(";"); String basicAttrName; String subType; if (index == -1) { basicAttrName = attrName; subType = null; } else { basicAttrName = attrName.substring(0, index); subType = attrName.substring(index + 1); } if (subType != null && subType.equalsIgnoreCase("binary")) { // TODO: use message subType = "binary"; } boolean isNameAttribute = isAttrName(basicAttrName, sr); if (isNameAttribute) { if (subType != null) { l.append(NAME).append(" (").append(subType).append(")"); } else { l.append(NAME); } } else { LocalizableMessage friendly = hmFriendlyAttrNames.get(basicAttrName.toLowerCase()); if (friendly == null) { l.append(attrName); } else { l.append(friendly); if (subType != null) { l.append(" (").append(subType).append(")"); } } } hmDisplayedNames.put(attrName.toLowerCase(), l.toString()); l.append(":"); return Utilities.createPrimaryLabel(l.toMessage()); } private Collection<String> getSortedAttributes(CustomSearchResult sr, boolean isReadOnly) { LinkedHashSet<String> attrNames = new LinkedHashSet<>(); // Get all attributes that the entry can have Set<String> attributes = new LinkedHashSet<>(); ArrayList<String> entryAttrs = new ArrayList<>(sr.getAttributeNames()); ArrayList<String> attrsWithNoOptions = new ArrayList<>(); for (String attr : entryAttrs) { attrsWithNoOptions.add( Utilities.getAttributeNameWithoutOptions(attr).toLowerCase()); } List<Object> values = sr.getAttributeValues(ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME); // Put first the attributes associated with the objectclass in // hmOrderedAttrNames for (Object o : values) { String ocName = (String)o; String[] attrs = hmOrdereredAttrNames.get(ocName.toLowerCase()); if (attrs != null) { for (String attr : attrs) { int index = attrsWithNoOptions.indexOf(attr.toLowerCase()); if (index != -1) { attrNames.add(entryAttrs.get(index)); } else { attrNames.add(attr); } } } } // Handle the root entry separately: most of its attributes are operational // so we filter a list of harcoded attributes. boolean isRootEntry = sr.getDN().equals(""); Schema schema = getInfo().getServerDescriptor().getSchema(); if (isRootEntry) { String[] attrsNotToAdd = {"entryuuid", "hassubordinates", "numsubordinates", "subschemasubentry", "entrydn", "hassubordinates"}; for (String attr : sr.getAttributeNames()) { boolean found = false; for (String addedAttr : attrNames) { found = addedAttr.equalsIgnoreCase(attr); if (found) { break; } } if (!found) { for (String notToAddAttr : attrsNotToAdd) { found = notToAddAttr.equalsIgnoreCase(attr); if (found) { break; } } } if (!found) { attrNames.add(attr); } } } else { // Try to get the attributes from the schema: first display the required // attributes with a friendly name (in alphabetical order), then (in // alphabetical order) the attributes with no friendly name. Finally // do the same with the other attributes. SortedSet<String> requiredAttributes = new TreeSet<>(); SortedSet<String> allowedAttributes = new TreeSet<>(); if (schema != null) { List<Object> ocs = sr.getAttributeValues( ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME); for (Object o : ocs) { String oc = (String)o; ObjectClass objectClass = schema.getObjectClass(oc.toLowerCase()); if (objectClass != null) { for (AttributeType attr : objectClass.getRequiredAttributeChain()) { requiredAttributes.add(attr.getNameOrOID()); } for (AttributeType attr : objectClass.getOptionalAttributeChain()) { allowedAttributes.add(attr.getNameOrOID()); } } } } // Now try to put first the attributes for which we have a friendly // name (the most common ones). updateAttributes(attributes, requiredAttributes, entryAttrs, attrsWithNoOptions, true); updateAttributes(attributes, requiredAttributes, entryAttrs, attrsWithNoOptions, false); updateAttributes(attributes, allowedAttributes, entryAttrs, attrsWithNoOptions, true); updateAttributes(attributes, allowedAttributes, entryAttrs, attrsWithNoOptions, false); attributes.addAll(entryAttrs); attributes.add("aci"); // In read-only mode display only the attributes with values if (isReadOnly) { attributes.retainAll(entryAttrs); } for (String attr : attributes) { boolean add = isEditable(attr, schema); if (add) { boolean found = false; for (String addedAttr : attrNames) { found = addedAttr.equalsIgnoreCase(attr); if (found) { break; } } if (!found) { attrNames.add(attr); } } } } return attrNames; } private void updateAttributes( Collection<String> attributes, Set<String> newAttributes, ArrayList<String> entryAttrs, ArrayList<String> attrsWithNoOptions, boolean addIfFriendlyName) { for (String attr : newAttributes) { String attrLc = attr.toLowerCase(); boolean hasFriendlyName = hmFriendlyAttrNames.get(attrLc) != null; if (hasFriendlyName == addIfFriendlyName) { int index = attrsWithNoOptions.indexOf(attrLc); if (index != -1) { attributes.add(entryAttrs.get(index)); } else { if (!hasCertificateSyntax(attr, getInfo().getServerDescriptor().getSchema())) { attributes.add(attr); } else { attributes.add(attr+";binary"); } } } } } private JComponent getReadOnlyComponent(final String attrName, List<Object> values) { // GridLayout is used to avoid the 512 limit of GridBagLayout JPanel panel = new JPanel(new GridBagLayout()); panel.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridy = 0; boolean isBinary = hasBinaryValue(values); for (Object o : values) { gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; gbc.gridx = 0; if (attrName.equalsIgnoreCase( ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME)) { ObjectClassCellPanel ocPanel = new ObjectClassCellPanel(); Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null) { ObjectClassValue ocDescriptor = getObjectClassDescriptor(values, schema); ocPanel.setValue(ocDescriptor); } ocPanel.setEditButtonVisible(false); panel.add(ocPanel, gbc); break; } else if (Utilities.mustObfuscate(attrName, getInfo().getServerDescriptor().getSchema())) { panel.add( Utilities.createDefaultLabel( LocalizableMessage.raw(OBFUSCATED_VALUE)), gbc); } else if (!isBinary) { Set<String> sValues = toStrings(values); LocalizableMessage text = LocalizableMessage.raw(Utilities.getStringFromCollection(sValues, "\n")); final JTextArea ta; JComponent toAdd; if (values.size() > 15) { ta = Utilities.createNonEditableTextArea(text, 15, 20); toAdd = Utilities.createScrollPane(ta); } else { ta = Utilities.createNonEditableTextArea(text, values.size(), 20); toAdd = ta; } panel.add(toAdd, gbc); break; } else { final BinaryCellPanel pane = new BinaryCellPanel(); pane.setEditButtonText(INFO_CTRL_PANEL_VIEW_BUTTON_LABEL.get()); final byte[] binaryValue = (byte[])o; Schema schema = getInfo().getServerDescriptor().getSchema(); final boolean isImage = Utilities.hasImageSyntax(attrName, schema); pane.setValue(binaryValue, isImage); pane.addEditActionListener(new ActionListener() { /** {@inheritDoc} */ public void actionPerformed(ActionEvent ev) { if (binaryDlg == null) { binaryPanel = new BinaryValuePanel(); binaryPanel.setInfo(getInfo()); binaryDlg = new GenericDialog( Utilities.getFrame(SimplifiedViewEntryPanel.this), binaryPanel); binaryDlg.setModal(true); Utilities.centerGoldenMean(binaryDlg, Utilities.getParentDialog(SimplifiedViewEntryPanel.this)); } binaryPanel.setValue(attrName, binaryValue); binaryDlg.setVisible(true); } }); panel.add(pane, gbc); } } return panel; } private Set<String> toStrings(Collection<Object> objects) { Set<String> results = new TreeSet<>(); for (Object o : objects) { results.add(String.valueOf(o)); } return results; } private JComponent getReadWriteComponent(final String attrName, List<Object> values) { JPanel panel = new JPanel(new GridBagLayout()); panel.setOpaque(false); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridy = 0; List<EditorComponent> components = new ArrayList<>(); hmEditors.put(attrName.toLowerCase(), components); boolean isBinary = hasBinaryValue(values); for (Object o : values) { gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; gbc.gridx = 0; if (attrName.equalsIgnoreCase( ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME)) { final ObjectClassCellPanel ocCellPanel = new ObjectClassCellPanel(); Schema schema = getInfo().getServerDescriptor().getSchema(); final ObjectClassValue ocDescriptor; if (schema != null) { ocDescriptor = getObjectClassDescriptor(values, schema); ocCellPanel.setValue(ocDescriptor); } else { ocDescriptor = null; } ocCellPanel.addEditActionListener(new ActionListener() { private ObjectClassValue newValue; /** {@inheritDoc} */ public void actionPerformed(ActionEvent ev) { if (editOcDlg == null) { editOcPanel = new ObjectClassEditorPanel(); editOcPanel.setInfo(getInfo()); editOcDlg = new GenericDialog( null, editOcPanel); editOcDlg.setModal(true); Utilities.centerGoldenMean(editOcDlg, Utilities.getParentDialog(SimplifiedViewEntryPanel.this)); } if (newValue == null && ocDescriptor != null) { editOcPanel.setValue(ocDescriptor); } else { editOcPanel.setValue(newValue); } editOcDlg.setVisible(true); if (editOcPanel.valueChanged()) { newValue = editOcPanel.getObjectClassValue(); ocCellPanel.setValue(newValue); updatePanel(newValue); } } }); panel = ocCellPanel; components.add(new EditorComponent(ocCellPanel)); break; } else if (isPassword(attrName) || isConfirmPassword(attrName)) { JPasswordField pf = Utilities.createPasswordField(); if (!o.equals("")) { pf.setText(getPasswordStringValue(o)); } panel.add(pf, gbc); components.add(new EditorComponent(pf)); } else if (!isBinary) { if (isSingleValue(attrName)) { final JTextField tf = Utilities.createMediumTextField(); tf.setText(String.valueOf(o)); gbc.gridx = 0; panel.add(tf, gbc); if (mustAddBrowseButton(attrName)) { gbc.insets.left = 5; gbc.weightx = 0.0; gbc.gridx ++; gbc.anchor = GridBagConstraints.NORTH; JButton browse = Utilities.createButton(INFO_CTRL_PANEL_BROWSE_BUTTON_LABEL.get()); browse.addActionListener(new AddBrowseClickedActionListener(tf, attrName)); panel.add(browse, gbc); new DropTarget(tf, dropTargetListener); } components.add(new EditorComponent(tf)); } else { Set<String> sValues = toStrings(values); final LocalizableMessage text = LocalizableMessage.raw(Utilities.getStringFromCollection(sValues, "\n")); final JTextArea ta; JComponent toAdd; if (values.size() > 15) { ta = Utilities.createTextArea(text, 15, 20); toAdd = Utilities.createScrollPane(ta); } else { ta = Utilities.createTextAreaWithBorder(text, values.size(), 20); toAdd = ta; } panel.add(toAdd, gbc); if (mustAddBrowseButton(attrName)) { gbc.insets.left = 5; gbc.weightx = 0.0; gbc.gridx ++; gbc.anchor = GridBagConstraints.NORTH; final JButton browse = Utilities.createButton( INFO_CTRL_PANEL_BROWSE_BUTTON_LABEL.get()); browse.addActionListener(new AddBrowseClickedActionListener(ta, attrName)); if (attrName.equalsIgnoreCase(ServerConstants.ATTR_UNIQUE_MEMBER_LC)) { browse.setText( INFO_CTRL_PANEL_ADD_MEMBERS_BUTTON.get().toString()); } panel.add(browse, gbc); new DropTarget(ta, dropTargetListener); } components.add(new EditorComponent(ta)); } break; } else { final BinaryCellPanel pane = new BinaryCellPanel(); Schema schema = getInfo().getServerDescriptor().getSchema(); final boolean isImage = Utilities.hasImageSyntax(attrName, schema); pane.setDisplayDelete(true); final byte[] binaryValue = (byte[])o; if (binaryValue.length > 0) { pane.setValue(binaryValue, isImage); } pane.addEditActionListener(new ActionListener() { private BinaryValue newValue; /** {@inheritDoc} */ public void actionPerformed(ActionEvent ev) { if (editBinaryDlg == null) { editBinaryPanel = new BinaryAttributeEditorPanel(); editBinaryPanel.setInfo(getInfo()); editBinaryDlg = new GenericDialog( Utilities.getFrame(SimplifiedViewEntryPanel.this), editBinaryPanel); editBinaryDlg.setModal(true); Utilities.centerGoldenMean(editBinaryDlg, Utilities.getParentDialog(SimplifiedViewEntryPanel.this)); } if (newValue == null) { // We use an empty binary array to not breaking the logic: // it means that there is no value for the attribute. if (binaryValue != null && binaryValue.length > 0) { newValue = BinaryValue.createBase64(binaryValue); editBinaryPanel.setValue(attrName, newValue); } else { editBinaryPanel.setValue(attrName, null); } } else { editBinaryPanel.setValue(attrName, newValue); } editBinaryDlg.setVisible(true); if (editBinaryPanel.valueChanged()) { newValue = editBinaryPanel.getBinaryValue(); pane.setValue(newValue, isImage); notifyListeners(); } } }); pane.addDeleteActionListener(new ActionListener() { /** {@inheritDoc} */ public void actionPerformed(ActionEvent ev) { pane.setValue((byte[])null, false); if (editBinaryPanel != null) { editBinaryPanel.setValue(attrName, null); } notifyListeners(); } }); panel.add(pane, gbc); components.add(new EditorComponent(pane)); } gbc.gridy ++; gbc.insets.top = 10; } return panel; } private boolean isSingleValue(String attrName) { boolean isSingleValue = false; Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null) { AttributeType attr = schema.getAttributeType(attrName.toLowerCase()); if (attr != null) { isSingleValue = attr.isSingleValue(); } } return isSingleValue; } private boolean isRequired(String attrName, CustomSearchResult sr) { boolean isRequired = false; attrName = Utilities.getAttributeNameWithoutOptions(attrName); Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null) { AttributeType attr = schema.getAttributeType(attrName.toLowerCase()); if (attr != null) { List<Object> ocs = sr.getAttributeValues( ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME); for (Object o : ocs) { String oc = (String)o; ObjectClass objectClass = schema.getObjectClass(oc.toLowerCase()); if (objectClass != null && objectClass.isRequired(attr)) { isRequired = true; break; } } } } return isRequired; } /** {@inheritDoc} */ public GenericDialog.ButtonType getButtonType() { return GenericDialog.ButtonType.NO_BUTTON; } /** {@inheritDoc} */ public Entry getEntry() throws OpenDsException { Entry entry = null; ArrayList<LocalizableMessage> errors = new ArrayList<>(); try { DN.valueOf(getDisplayedDN()); } catch (Throwable t) { errors.add(ERR_CTRL_PANEL_DN_NOT_VALID.get()); } for (String attrName : hmLabels.keySet()) { setPrimaryValid(hmLabels.get(attrName)); } // Check passwords for (String attrName : lastUserPasswords.keySet()) { List<String> pwds = getNewPasswords(attrName); List<String> confirmPwds = getConfirmPasswords(attrName); if (!pwds.equals(confirmPwds)) { setPrimaryInvalid(hmLabels.get(attrName)); setPrimaryInvalid(hmLabels.get(getConfirmPasswordKey(attrName))); LocalizableMessage msg = ERR_CTRL_PANEL_PASSWORD_DO_NOT_MATCH.get(); if (!errors.contains(msg)) { errors.add(msg); } } } for (String attrName : requiredAttrs) { if (!hasValue(attrName)) { setPrimaryInvalid(hmLabels.get(attrName)); errors.add(ERR_CTRL_PANEL_ATTRIBUTE_REQUIRED.get( hmDisplayedNames.get(attrName))); } } if (!errors.isEmpty()) { throw new CheckEntrySyntaxException(errors); } LDIFImportConfig ldifImportConfig = null; try { String ldif = getLDIF(); ldifImportConfig = new LDIFImportConfig(new StringReader(ldif)); LDIFReader reader = new LDIFReader(ldifImportConfig); entry = reader.readEntry(checkSchema()); addValuesInRDN(entry); } catch (IOException ioe) { throw new OnlineUpdateException( ERR_CTRL_PANEL_ERROR_CHECKING_ENTRY.get(ioe), ioe); } finally { if (ldifImportConfig != null) { ldifImportConfig.close(); } } return entry; } private List<String> getDisplayedStringValues(String attrName) { List<String> values = new ArrayList<>(); List<EditorComponent> comps = hmEditors.get(attrName.toLowerCase()); if (comps != null) { for (EditorComponent comp : comps) { Object value = comp.getValue(); if (value instanceof ObjectClassValue) { ObjectClassValue ocValue = (ObjectClassValue)value; if (ocValue.getStructural() != null) { values.add(ocValue.getStructural()); } values.addAll(ocValue.getAuxiliary()); } else if (value instanceof Collection<?>) { for (Object o : (Collection<?>)value) { values.add((String)o); } } else { values.add(String.valueOf(comp.getValue())); } } } return values; } private List<String> getNewPasswords(String attrName) { String attr = Utilities.getAttributeNameWithoutOptions(attrName).toLowerCase(); return getDisplayedStringValues(attr); } private List<String> getConfirmPasswords(String attrName) { return getDisplayedStringValues(getConfirmPasswordKey(attrName)); } private String getConfirmPasswordKey(String attrName) { return CONFIRM_PASSWORD+ Utilities.getAttributeNameWithoutOptions(attrName).toLowerCase(); } private boolean isConfirmPassword(String key) { return key.startsWith(CONFIRM_PASSWORD); } /** * Returns the LDIF representation of the displayed entry. * @return the LDIF representation of the displayed entry. */ private String getLDIF() { StringBuilder sb = new StringBuilder(); sb.append("dn: ").append(getDisplayedDN()); for (String attrName : hmEditors.keySet()) { if (isConfirmPassword(attrName)) { continue; } else if (isPassword(attrName)) { List<String> newPwds = getNewPasswords(attrName); if (newPwds.equals(lastUserPasswords.get(attrName.toLowerCase()))) { List<Object> oldValues = searchResult.getAttributeValues(attrName); if (!oldValues.isEmpty()) { appendLDIFLines(sb, attrName, oldValues); } } else { appendLDIFLines(sb, attrName); } } else if (!schemaReadOnlyAttributesLowerCase.contains(attrName.toLowerCase())) { appendLDIFLines(sb, attrName); } } // Add the attributes that are not displayed for (String attrName : schemaReadOnlyAttributesLowerCase) { List<Object> values = searchResult.getAttributeValues(attrName); if (!values.isEmpty()) { appendLDIFLines(sb, attrName, values); } } return sb.toString(); } private boolean isAttrName(String attrName, CustomSearchResult sr) { List<Object> values = sr.getAttributeValues(ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME); for (Object o : values) { String ocName = (String)o; String attr = hmNameAttrNames.get(ocName.toLowerCase()); if (attr != null && attr.equalsIgnoreCase(attrName)) { return true; } } return false; } private boolean hasBinaryValue(List<Object> values) { if (!values.isEmpty()) { return values.iterator().next() instanceof byte[]; } return false; } private boolean mustAddBrowseButton(String attrName) { boolean mustAddBrowseButton = attrName.equalsIgnoreCase(ServerConstants.ATTR_UNIQUE_MEMBER_LC) || attrName.equalsIgnoreCase("ds-target-group-dn"); if (!mustAddBrowseButton) { Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null) { AttributeType attr = schema.getAttributeType(attrName.toLowerCase()); if (attr != null) { // There is no name for a regex syntax. String syntaxName = attr.getSyntax().getName(); if (syntaxName!=null) { mustAddBrowseButton=syntaxName.equalsIgnoreCase( SchemaConstants.SYNTAX_DN_NAME); } } } } return mustAddBrowseButton; } /** {@inheritDoc} */ protected List<Object> getValues(String attrName) { List<Object> values = new ArrayList<>(); for (EditorComponent comp : hmEditors.get(attrName)) { if (hasValue(comp)) { Object value = comp.getValue(); if (value instanceof Collection<?>) { values.addAll((Collection<?>) value); } else { values.add(value); } } } return values; } private void appendLDIFLines(StringBuilder sb, String attrName) { List<Object> values = getValues(attrName); if (!values.isEmpty()) { appendLDIFLines(sb, attrName, values); } } /** {@inheritDoc} */ protected String getDisplayedDN() { StringBuilder sb = new StringBuilder(); try { DN oldDN = DN.valueOf(searchResult.getDN()); if (oldDN.size() > 0) { RDN rdn = oldDN.rdn(); List<AttributeType> attributeTypes = new ArrayList<>(); List<String> attributeNames = new ArrayList<>(); List<ByteString> attributeValues = new ArrayList<>(); for (int i=0; i<rdn.getNumValues(); i++) { String attrName = rdn.getAttributeName(i); ByteString value = rdn.getAttributeValue(i); List<String> values = getDisplayedStringValues(attrName); if (!values.contains(value.toString())) { if (!values.isEmpty()) { String firstNonEmpty = getFirstNonEmpty(values); if (firstNonEmpty != null) { AttributeType attr = rdn.getAttributeType(i); attributeTypes.add(attr); attributeNames.add(rdn.getAttributeName(i)); attributeValues.add(ByteString.valueOfUtf8(firstNonEmpty)); } } } else { attributeTypes.add(rdn.getAttributeType(i)); attributeNames.add(rdn.getAttributeName(i)); attributeValues.add(value); } } if (attributeTypes.isEmpty()) { // Check the attributes in the order that we display them and use // the first one. Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null) { for (String attrName : hmEditors.keySet()) { if (isPassword(attrName) || isConfirmPassword(attrName)) { continue; } List<EditorComponent> comps = hmEditors.get(attrName); if (!comps.isEmpty()) { Object o = comps.iterator().next().getValue(); if (o instanceof String) { String aName = Utilities.getAttributeNameWithoutOptions(attrName); AttributeType attr = schema.getAttributeType(aName.toLowerCase()); if (attr != null) { attributeTypes.add(attr); attributeNames.add(attrName); attributeValues.add(ByteString.valueOfUtf8((String) o)); } break; } } } } } DN parent = oldDN.parent(); if (!attributeTypes.isEmpty()) { RDN newRDN = new RDN(attributeTypes, attributeNames, attributeValues); DN newDN; if (parent == null) { newDN = new DN(new RDN[]{newRDN}); } else { newDN = parent.child(newRDN); } sb.append(newDN); } else { if (parent != null) { sb.append(",").append(parent); } } } } catch (Throwable t) { throw new RuntimeException("Unexpected error: "+t, t); } return sb.toString(); } private String getFirstNonEmpty(List<String> values) { for (String v : values) { v = v.trim(); if (v.length() > 0) { return v; } } return null; } private void addBrowseClicked(String attrName, JTextComponent textComponent) { LocalizableMessage previousTitle = null; LDAPEntrySelectionPanel.Filter previousFilter = null; LocalizableMessage title; LDAPEntrySelectionPanel.Filter filter; if (browseEntriesDlg == null) { browseEntriesPanel = new LDAPEntrySelectionPanel(); browseEntriesPanel.setMultipleSelection(false); browseEntriesPanel.setInfo(getInfo()); browseEntriesDlg = new GenericDialog(Utilities.getFrame(this), browseEntriesPanel); Utilities.centerGoldenMean(browseEntriesDlg, Utilities.getParentDialog(this)); browseEntriesDlg.setModal(true); } else { previousTitle = browseEntriesPanel.getTitle(); previousFilter = browseEntriesPanel.getFilter(); } if (attrName.equalsIgnoreCase(ServerConstants.ATTR_UNIQUE_MEMBER_LC)) { title = INFO_CTRL_PANEL_ADD_MEMBERS_LABEL.get(); filter = LDAPEntrySelectionPanel.Filter.USERS; } else if (attrName.equalsIgnoreCase("ds-target-group-dn")) { title = INFO_CTRL_PANEL_CHOOSE_REFERENCE_GROUP.get(); filter = LDAPEntrySelectionPanel.Filter.DYNAMIC_GROUPS; } else { title = INFO_CTRL_PANEL_CHOOSE_ENTRIES.get(); filter = LDAPEntrySelectionPanel.Filter.DEFAULT; } if (!title.equals(previousTitle)) { browseEntriesPanel.setTitle(title); } if (!filter.equals(previousFilter)) { browseEntriesPanel.setFilter(filter); } browseEntriesPanel.setMultipleSelection(!isSingleValue(attrName)); browseEntriesDlg.setVisible(true); String[] dns = browseEntriesPanel.getDNs(); if (dns.length > 0) { if (textComponent instanceof JTextArea) { StringBuilder sb = new StringBuilder(); sb.append(textComponent.getText()); for (String dn : dns) { if (sb.length() > 0) { sb.append("\n"); } sb.append(dn); } textComponent.setText(sb.toString()); textComponent.setCaretPosition(sb.length()); } else { textComponent.setText(dns[0]); } } } private String getPasswordStringValue(Object o) { if (o instanceof byte[]) { return Base64.encode((byte[])o); } else { return String.valueOf(o); } } private void updatePanel(ObjectClassValue newValue) { CustomSearchResult oldResult = searchResult; CustomSearchResult newResult = new CustomSearchResult(searchResult.getDN()); for (String attrName : schemaReadOnlyAttributesLowerCase) { List<Object> values = searchResult.getAttributeValues(attrName); if (!values.isEmpty()) { newResult.set(attrName, values); } } ignoreEntryChangeEvents = true; Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null) { ArrayList<String> attributes = new ArrayList<>(); ArrayList<String> ocs = new ArrayList<>(); if (newValue.getStructural() != null) { ocs.add(newValue.getStructural().toLowerCase()); } for (String oc : newValue.getAuxiliary()) { ocs.add(oc.toLowerCase()); } for (String oc : ocs) { ObjectClass objectClass = schema.getObjectClass(oc); if (objectClass != null) { for (AttributeType attr : objectClass.getRequiredAttributeChain()) { attributes.add(attr.getNameOrOID().toLowerCase()); } for (AttributeType attr : objectClass.getOptionalAttributeChain()) { attributes.add(attr.getNameOrOID().toLowerCase()); } } } for (String attrName : editableOperationalAttrNames) { attributes.add(attrName.toLowerCase()); } for (String attrName : hmEditors.keySet()) { String attrNoOptions = Utilities.getAttributeNameWithoutOptions(attrName); if (!attributes.contains(attrNoOptions)) { continue; } if (isPassword(attrName)) { List<String> newPwds = getNewPasswords(attrName); if (newPwds.equals(lastUserPasswords.get(attrName))) { List<Object> oldValues = searchResult.getAttributeValues(attrName); newResult.set(attrName, oldValues); } else { setValues(newResult, attrName); } } else if (!schemaReadOnlyAttributesLowerCase.contains( attrName.toLowerCase())) { setValues(newResult, attrName); } } } update(newResult, isReadOnly, treePath); ignoreEntryChangeEvents = false; searchResult = oldResult; notifyListeners(); } private void updateAttributeVisibility(boolean showAll) { for (String attrName : hmLabels.keySet()) { Component label = hmLabels.get(attrName); Component comp = hmComponents.get(attrName); if (showAll || requiredAttrs.contains(attrName)) { label.setVisible(true); comp.setVisible(true); } else { List<EditorComponent> editors = hmEditors.get(attrName); boolean hasValue = false; for (EditorComponent editor : editors) { hasValue = hasValue(editor); if (hasValue) { break; } } label.setVisible(hasValue); comp.setVisible(hasValue); } } repaint(); } private boolean hasValue(String attrName) { return !getValues(attrName).isEmpty(); } private boolean hasValue(EditorComponent editor) { Object value = editor.getValue(); if (value instanceof byte[]) { return ((byte[])value).length > 0; } else if (value instanceof String) { return ((String)value).trim().length() > 0; } else if (value instanceof Collection<?>) { return !((Collection<?>)value).isEmpty(); } return value != null; } /** Calls #addBrowseClicked(). */ private final class AddBrowseClickedActionListener implements ActionListener { private final JTextComponent tc; private final String attrName; private AddBrowseClickedActionListener(JTextComponent tc, String attrName) { this.tc = tc; this.attrName = attrName; } @Override public void actionPerformed(ActionEvent ev) { addBrowseClicked(attrName, tc); } } /** * A class that makes an association between a component (JTextField, a * BinaryCellValue...) and the associated value that will be used to create * the modified entry corresponding to the contents of the panel. * */ class EditorComponent { private Component comp; /** * Creates an EditorComponent using a text component. * @param tf the text component. */ public EditorComponent(JTextComponent tf) { comp = tf; tf.getDocument().addDocumentListener(new DocumentListener() { /** {@inheritDoc} */ public void insertUpdate(DocumentEvent ev) { notifyListeners(); } /** {@inheritDoc} */ public void changedUpdate(DocumentEvent ev) { notifyListeners(); } /** {@inheritDoc} */ public void removeUpdate(DocumentEvent ev) { notifyListeners(); } }); } /** * Creates an EditorComponent using a BinaryCellPanel. * @param binaryPanel the BinaryCellPanel. */ public EditorComponent(BinaryCellPanel binaryPanel) { comp = binaryPanel; } /** * Creates an EditorComponent using a ObjectClassCellPanel. * @param ocPanel the ObjectClassCellPanel. */ public EditorComponent(ObjectClassCellPanel ocPanel) { comp = ocPanel; } /** * Returns the value that the component is displaying. The returned value * is a Set of Strings (for multi-valued attributes), a byte[] for binary * values or a String for single-valued attributes. Single-valued * attributes refer to the definition in the schema (and not to the fact * that there is a single value for the attribute in this entry). * @return the value that the component is displaying. */ public Object getValue() { Object returnValue; if (comp instanceof ObjectClassCellPanel) { ObjectClassValue ocDesc = ((ObjectClassCellPanel)comp).getValue(); LinkedHashSet<String> values = new LinkedHashSet<>(); String structural = ocDesc.getStructural(); if (structural != null) { values.add(structural); } values.addAll(ocDesc.getAuxiliary()); Schema schema = getInfo().getServerDescriptor().getSchema(); if (schema != null && structural != null) { ObjectClass oc = schema.getObjectClass(structural.toLowerCase()); if (oc != null) { values.addAll(getObjectClassSuperiorValues(oc)); } } returnValue = values; } else if (comp instanceof JTextArea) { LinkedHashSet<String> values = new LinkedHashSet<>(); String value = ((JTextArea)comp).getText(); String[] lines = value.split("\n"); for (String line : lines) { line = line.trim(); if (line.length() > 0) { values.add(line); } } returnValue = values; } else if (comp instanceof JTextComponent) { returnValue = ((JTextComponent)comp).getText(); } else { Object o = ((BinaryCellPanel)comp).getValue(); if (o instanceof BinaryValue) { try { returnValue = ((BinaryValue)o).getBytes(); } catch (ParseException pe) { throw new RuntimeException("Unexpected error: "+pe); } } else { returnValue = o; } } return returnValue; } } }