/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2008-2010 Sun Microsystems, Inc. * Portions Copyright 2014-2016 ForgeRock AS. */ package org.opends.guitools.controlpanel.ui; import static org.forgerock.opendj.server.config.meta.BackendIndexCfgDefn.IndexType.*; import static org.opends.messages.AdminToolMessages.*; import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.io.File; import java.util.ArrayList; import java.util.List; 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.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.config.PropertyException; import org.forgerock.opendj.config.client.ManagementContext; import org.forgerock.opendj.config.client.ldap.LDAPManagementContext; import org.forgerock.opendj.ldap.schema.AttributeType; import org.forgerock.opendj.server.config.client.BackendIndexCfgClient; import org.forgerock.opendj.server.config.client.PluggableBackendCfgClient; import org.forgerock.opendj.server.config.meta.BackendIndexCfgDefn; import org.forgerock.opendj.server.config.meta.BackendIndexCfgDefn.IndexType; import org.opends.guitools.controlpanel.datamodel.IndexDescriptor; import org.opends.guitools.controlpanel.ui.components.TitlePanel; import org.opends.guitools.controlpanel.ui.renderer.CustomListCellRenderer; import org.opends.guitools.controlpanel.util.Utilities; import org.opends.quicksetup.Installation; import org.opends.server.config.ConfigException; import org.opends.server.types.OpenDsException; /** * Abstract class used to refactor some code between the classes that are used * to edit/create an index. */ abstract class AbstractIndexPanel extends StatusGenericPanel { private static final long serialVersionUID = 4465529396749593707L; /** Custom attributes message. */ static final LocalizableMessage CUSTOM_ATTRIBUTES = INFO_CTRL_PANEL_CUSTOM_ATTRIBUTES_LABEL.get(); /** Standard attributes message. */ static final LocalizableMessage STANDARD_ATTRIBUTES = INFO_CTRL_PANEL_STANDARD_ATTRIBUTES_LABEL.get(); /** Minimum value for entry limit. */ static final int MIN_ENTRY_LIMIT = BackendIndexCfgDefn.getInstance().getIndexEntryLimitPropertyDefinition().getLowerLimit(); /** Maximum value for entry limit. */ static final int MAX_ENTRY_LIMIT = BackendIndexCfgDefn.getInstance().getIndexEntryLimitPropertyDefinition().getUpperLimit(); /** LocalizableMessage to be displayed to indicate that an index is not configurable. */ static final LocalizableMessage NON_CONFIGURABLE_INDEX = INFO_CTRL_PANEL_NON_CONFIGURABLE_INDEX_LABEL.get(); /** LocalizableMessage to be displayed to indicate that an index has been modified. */ static final LocalizableMessage INDEX_MODIFIED = INFO_CTRL_PANEL_INDEX_MODIFIED_LABEL.get(); /** Default value for entry limit. */ static final int DEFAULT_ENTRY_LIMIT = 4000; final TitlePanel titlePanel = new TitlePanel(LocalizableMessage.EMPTY, LocalizableMessage.EMPTY); /** Attributes combo box. */ final JComboBox attributes = Utilities.createComboBox(); /** Name of the index label. */ final JLabel name = Utilities.createDefaultLabel(); /** Backends label. */ private final JLabel lBackend = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BACKEND_LABEL.get()); /** Read-only backend name label. */ final JLabel backendName = Utilities.createDefaultLabel(); final JLabel lAttribute = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_LABEL.get()); final JLabel lEntryLimit = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ENTRY_LIMIT_LABEL.get()); final JTextField entryLimit = Utilities.createShortTextField(); final JLabel lType = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_INDEX_TYPE_LABEL.get()); /** Panel containing all the index types. */ final JPanel typesPanel = new JPanel(new GridBagLayout()); /** Approximate index type check box. */ final JCheckBox approximate = Utilities.createCheckBox(INFO_CTRL_PANEL_APPROXIMATE_LABEL.get()); /** Equality index type check box. */ final JCheckBox equality = Utilities.createCheckBox(INFO_CTRL_PANEL_EQUALITY_LABEL.get()); /** Ordering index type check box. */ final JCheckBox ordering = Utilities.createCheckBox(INFO_CTRL_PANEL_ORDERING_LABEL.get()); /** Presence index type check box. */ final JCheckBox presence = Utilities.createCheckBox(INFO_CTRL_PANEL_PRESENCE_LABEL.get()); /** Substring index type check box. */ final JCheckBox substring = Utilities.createCheckBox(INFO_CTRL_PANEL_SUBSTRING_LABEL.get()); /** Array of checkboxes. */ final JCheckBox[] types = { approximate, equality, ordering, presence, substring }; /** Array of index types that matches the array of checkboxes (types). */ private final IndexType[] configTypes = { APPROXIMATE, EQUALITY, ORDERING, PRESENCE, SUBSTRING }; final JButton deleteIndex = Utilities.createButton(INFO_CTRL_PANEL_DELETE_INDEX_LABEL.get()); final JButton saveChanges = Utilities.createButton(INFO_CTRL_PANEL_SAVE_CHANGES_LABEL.get()); /** Label containing some warning information (such as the fact that the index cannot be edited). */ final JLabel warning = Utilities.createDefaultLabel(); /** * Repopulates the contents of the panel with the provided attribute type. It * will check the checkboxes for which the attribute has a matching rule. * * @param attr * the attribute. */ void repopulateTypesPanel(final AttributeType attr) { typesPanel.removeAll(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridy = 0; gbc.gridx = 0; gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; if (attr != null) { if (attr.getApproximateMatchingRule() != null) { typesPanel.add(approximate, gbc); gbc.insets.top = 10; gbc.gridy++; } if (attr.getEqualityMatchingRule() != null) { typesPanel.add(equality, gbc); gbc.insets.top = 10; gbc.gridy++; } if (attr.getOrderingMatchingRule() != null) { typesPanel.add(ordering, gbc); gbc.insets.top = 10; gbc.gridy++; } typesPanel.add(presence, gbc); gbc.gridx = 1; gbc.weightx = 1.0; typesPanel.add(Box.createHorizontalGlue(), gbc); gbc.weightx = 0.0; gbc.gridx = 0; gbc.gridy++; gbc.insets.top = 10; if (attr.getSubstringMatchingRule() != null) { typesPanel.add(substring, gbc); gbc.insets.top = 10; } } typesPanel.validate(); } /** * Creates the basic layout of the panel. * * @param c * the container of the layout. * @param gbc * the grid bag constraints to be used. * @param nameReadOnly * whether the panel is read-only or not. */ void createBasicLayout(final Container c, final GridBagConstraints gbc, final boolean nameReadOnly) { gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 3; addErrorPane(c, gbc); if (nameReadOnly) { gbc.gridy++; titlePanel.setTitle(INFO_CTRL_PANEL_INDEX_DETAILS_LABEL.get()); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; gbc.insets.top = 10; gbc.weightx = 1.0; JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); c.add(p, gbc); GridBagConstraints gbc2 = new GridBagConstraints(); gbc2.weightx = 0.0; gbc2.gridwidth = GridBagConstraints.RELATIVE; p.add(titlePanel, gbc2); gbc2.gridwidth = GridBagConstraints.REMAINDER; gbc2.fill = GridBagConstraints.HORIZONTAL; gbc2.weightx = 1.0; p.add(Box.createHorizontalGlue(), gbc2); } gbc.gridwidth = 1; gbc.gridy++; gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets.left = 0; gbc.gridx = 0; gbc.weightx = 0.0; c.add(lAttribute, gbc); gbc.insets.left = 10; gbc.gridx = 1; if (!nameReadOnly) { attributes.addItemListener(new IgnoreItemListener(attributes)); attributes.setRenderer(new CustomListCellRenderer(attributes)); c.add(attributes, gbc); } else { c.add(name, gbc); } gbc.insets.top = 10; gbc.gridy++; gbc.insets.left = 0; gbc.gridx = 0; c.add(lBackend, gbc); gbc.insets.left = 10; gbc.gridx = 1; c.add(backendName, gbc); gbc.gridy++; gbc.insets.left = 0; gbc.gridx = 0; c.add(lEntryLimit, gbc); gbc.insets.left = 10; gbc.gridx = 1; JPanel p = new JPanel(new GridBagLayout()); p.setOpaque(false); c.add(p, gbc); GridBagConstraints gbc2 = new GridBagConstraints(); gbc2.weightx = 0.0; gbc2.gridwidth = GridBagConstraints.RELATIVE; p.add(entryLimit, gbc2); gbc2.gridwidth = GridBagConstraints.REMAINDER; gbc2.fill = GridBagConstraints.HORIZONTAL; gbc2.weightx = 1.0; p.add(Box.createHorizontalGlue(), gbc2); gbc.gridx = 0; gbc.insets.left = 0; gbc.gridy++; gbc.weightx = 0.0; gbc.weightx = 0.0; gbc.anchor = GridBagConstraints.NORTHWEST; c.add(lType, gbc); gbc.gridx = 1; gbc.anchor = GridBagConstraints.WEST; gbc.insets.left = 10; gbc.weightx = 1.0; JCheckBox[] types = { approximate, equality, ordering, presence, substring }; typesPanel.setOpaque(false); c.add(typesPanel, gbc); gbc.gridy++; gbc2 = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; for (JCheckBox type : types) { type.setOpaque(false); typesPanel.add(type, gbc2); gbc2.anchor = GridBagConstraints.WEST; gbc2.insets.top = 10; } gbc.weighty = 1.0; gbc.weightx = 0.0; gbc.gridx = 0; gbc.fill = GridBagConstraints.VERTICAL; c.add(Box.createVerticalGlue(), gbc); } /** * Returns a sorted set of index types (that matches what the user selected on * the check boxes). * * @return a sorted set of indexes (that matches what the user selected on the * check boxes). */ SortedSet getTypes() { SortedSet indexTypes = new TreeSet<>(); for (int i = 0; i < types.length; i++) { if (types[i].isSelected()) { indexTypes.add(configTypes[i]); } } return indexTypes; } /** * Returns a list of error message with the problems encountered in the data * provided by the user. * * @return a list of error message with the problems encountered in the data * provided by the user. */ List getErrors() { List errors = new ArrayList<>(); setPrimaryValid(lEntryLimit); setPrimaryValid(lType); String newEntryLimit = entryLimit.getText().trim(); try { int n = Integer.parseInt(newEntryLimit); if (n < MIN_ENTRY_LIMIT || MAX_ENTRY_LIMIT < n) { errors.add(ERR_CTRL_PANEL_INVALID_ENTRY_LIMIT_LABEL.get(MIN_ENTRY_LIMIT, MAX_ENTRY_LIMIT)); setPrimaryInvalid(lEntryLimit); } } catch (Throwable t) { errors.add(ERR_CTRL_PANEL_INVALID_ENTRY_LIMIT_LABEL.get(MIN_ENTRY_LIMIT, MAX_ENTRY_LIMIT)); setPrimaryInvalid(lEntryLimit); } if (getTypes().isEmpty()) { errors.add(ERR_CTRL_PANEL_NO_INDEX_TYPE_SELECTED.get()); setPrimaryInvalid(lType); } return errors; } void createIndexOffline(final String backendName, final String attributeName, final Set indexTypes, final int indexEntryLimit) throws OpenDsException { updateIndexOffline(backendName, null, attributeName, indexTypes, indexEntryLimit); } void modifyIndexOffline(final String backendName, final String attributeName, final IndexDescriptor indexToModify, final Set indexTypes, final int indexEntryLimit) throws OpenDsException { updateIndexOffline(backendName, indexToModify, attributeName, indexTypes, indexEntryLimit); } private void updateIndexOffline(final String backendName, final IndexDescriptor indexToModify, final String attributeName, final Set indexTypes, final int indexEntryLimit) throws OpenDsException { getInfo().initializeConfigurationFramework(); final File configFile = Installation.getLocal().getCurrentConfigurationFile(); try (ManagementContext context = LDAPManagementContext.newLDIFManagementContext(configFile)) { final PluggableBackendCfgClient backend = (PluggableBackendCfgClient) context.getRootConfiguration().getBackend(backendName); updateBackendIndexOnline(backend, indexToModify, attributeName, indexTypes, indexEntryLimit); } catch (final Exception e) { throw new ConfigException(LocalizableMessage.raw(e.getMessage(), e)); } } private void updateBackendIndexOnline(final PluggableBackendCfgClient backend, final IndexDescriptor indexToModify, final String attributeName, final Set indexTypes, final int indexEntryLimit) throws Exception { final boolean isCreation = indexToModify == null; final List exceptions = new ArrayList<>(); final BackendIndexCfgClient index = isCreation ? backend.createBackendIndex(BackendIndexCfgDefn.getInstance(), attributeName, exceptions) : backend.getBackendIndex(attributeName); if (isCreation || indexTypes.equals(indexToModify.getTypes())) { index.setIndexType(indexTypes); } if (indexEntryLimit != index.getIndexEntryLimit()) { index.setIndexEntryLimit(indexEntryLimit); } index.commit(); Utilities.throwFirstFrom(exceptions); } }