From 5991fd9ccc2c1635668cc4b8e4bae181d09b460e Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Thu, 19 Nov 2009 23:53:25 +0000
Subject: [PATCH] Fix for issue 3551 (Consider proposing to initialize a topology when the user imports an LDIF in a replicated base DN) When the user imports a file in a backend with replicated suffixes, the possibility of initializing the whole replication topology using the replication protocol is offered to the user.
---
opends/src/guitools/org/opends/guitools/controlpanel/ui/ConfirmInitializeAndImportDialog.java | 315 +++++++++++++++++++++++++++++++++++
opends/src/messages/messages/admin_tool.properties | 21 ++
opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java | 38 +++
opends/src/guitools/org/opends/guitools/controlpanel/ui/ImportLDIFPanel.java | 156 +++++++++++++++++
4 files changed, 521 insertions(+), 9 deletions(-)
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/ConfirmInitializeAndImportDialog.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/ConfirmInitializeAndImportDialog.java
new file mode 100644
index 0000000..47a48e7
--- /dev/null
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/ConfirmInitializeAndImportDialog.java
@@ -0,0 +1,315 @@
+/*
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.guitools.controlpanel.ui;
+
+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.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
+import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
+import org.opends.guitools.controlpanel.util.Utilities;
+import org.opends.messages.Message;
+
+/**
+ * Dialog used to inform the user that there are unsaved changes in a panel.
+ * It proposes the user to save the changes, do not save them or cancel the
+ * action that make the dialog appear (for instance when the user is editing
+ * an entry and clicks on another node, this dialog appears).
+ *
+ */
+public class ConfirmInitializeAndImportDialog extends GenericDialog
+{
+ /**
+ * The different input that the user can provide.
+ *
+ */
+ public enum Result
+ {
+ /**
+ * The user asks to do the import and then the initialization.
+ */
+ INITIALIZE_ALL,
+ /**
+ * The user asks to only do the import locally.
+ */
+ IMPORT_ONLY,
+ /**
+ * The user asks to cancel the operation that made this dialog to appear.
+ */
+ CANCEL
+ }
+ private static final long serialVersionUID = -442311801035162311L;
+
+ /**
+ * Constructor of the dialog.
+ * @param parentDialog the parent dialog.
+ * @param info the control panel info.
+ */
+ public ConfirmInitializeAndImportDialog(Component parentDialog,
+ ControlPanelInfo info)
+ {
+ super(Utilities.getFrame(parentDialog), getPanel(info));
+ Utilities.centerGoldenMean(this, parentDialog);
+ getRootPane().setDefaultButton(
+ ((ConfirmInitializeAndImportPanel)panel).initializeAllButton);
+ setModal(true);
+ }
+
+ /**
+ * Sets the message to be displayed in this dialog.
+ * @param title the title of the message.
+ * @param details the details of the message.
+ */
+ public void setMessage(Message title, Message details)
+ {
+ panel.updateConfirmationPane(panel.errorPane, title,
+ ColorAndFontConstants.errorTitleFont, details,
+ ColorAndFontConstants.defaultFont);
+ invalidate();
+ pack();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVisible(boolean visible)
+ {
+ if (visible)
+ {
+ ((ConfirmInitializeAndImportPanel)panel).result = Result.CANCEL;
+ }
+ super.setVisible(visible);
+ }
+
+ /**
+ * Returns the option the user gave when closing this dialog.
+ * @return the option the user gave when closing this dialog.
+ */
+ public Result getResult()
+ {
+ return ((ConfirmInitializeAndImportPanel)panel).result;
+ }
+
+ /**
+ * Creates the panel to be displayed inside the dialog.
+ * @param info the control panel info.
+ * @return the panel to be displayed inside the dialog.
+ */
+ private static StatusGenericPanel getPanel(ControlPanelInfo info)
+ {
+ ConfirmInitializeAndImportPanel panel =
+ new ConfirmInitializeAndImportPanel();
+ panel.setInfo(info);
+ return panel;
+ }
+
+ /**
+ * The panel to be displayed inside the dialog.
+ *
+ */
+ private static class ConfirmInitializeAndImportPanel
+ extends StatusGenericPanel
+ {
+ private static final long serialVersionUID = -9890116762604059L;
+
+ private JButton initializeAllButton;
+ private JButton importOnlyButton;
+ private JButton cancelButton;
+
+ private Result result;
+
+ /**
+ * Default constructor.
+ *
+ */
+ public ConfirmInitializeAndImportPanel()
+ {
+ super();
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.gridwidth = 1;
+ addErrorPane(gbc);
+ errorPane.setVisible(true);
+ gbc.gridy ++;
+ gbc.fill = GridBagConstraints.VERTICAL;
+ gbc.weighty = 1.0;
+ add(Box.createVerticalGlue(), gbc);
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+// The button panel
+ gbc.gridy ++;
+ gbc.weighty = 0.0;
+ gbc.insets = new Insets(0, 0, 0, 0);
+ add(createButtonsPanel(), gbc);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean requiresBorder()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean requiresScroll()
+ {
+ return false;
+ }
+
+ private JPanel createButtonsPanel()
+ {
+ JPanel buttonsPanel = new JPanel(new GridBagLayout());
+ buttonsPanel.setOpaque(true);
+ buttonsPanel.setBackground(ColorAndFontConstants.greyBackground);
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.anchor = GridBagConstraints.WEST;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.gridwidth = 1;
+ gbc.gridy = 0;
+ gbc.weightx = 1.0;
+ gbc.gridx ++;
+ buttonsPanel.add(Box.createHorizontalStrut(150));
+ buttonsPanel.add(Box.createHorizontalGlue(), gbc);
+
+ initializeAllButton = Utilities.createButton(
+ INFO_CTRL_PANEL_INITIALIZE_ALL_BUTTON_LABEL.get());
+ initializeAllButton.setOpaque(false);
+ gbc.insets = new Insets(10, 10, 10, 10);
+ gbc.weightx = 0.0;
+ gbc.gridx ++;
+ buttonsPanel.add(initializeAllButton, gbc);
+ initializeAllButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent ev)
+ {
+ result = Result.INITIALIZE_ALL;
+ cancelClicked();
+ }
+ });
+
+ gbc.gridx ++;
+ importOnlyButton = Utilities.createButton(
+ INFO_CTRL_PANEL_IMPORT_ONLY_BUTTON_LABEL.get());
+ importOnlyButton.setOpaque(false);
+ gbc.gridx ++;
+ gbc.insets.left = 0;
+ gbc.insets.right = 10;
+ buttonsPanel.add(importOnlyButton, gbc);
+ importOnlyButton.addActionListener(new ActionListener()
+ {
+ /**
+ * {@inheritDoc}
+ */
+ public void actionPerformed(ActionEvent ev)
+ {
+ result = Result.IMPORT_ONLY;
+ cancelClicked();
+ }
+ });
+
+ cancelButton = Utilities.createButton(
+ INFO_CTRL_PANEL_CANCEL_BUTTON_LABEL.get());
+ cancelButton.setOpaque(false);
+ gbc.insets.right = 10;
+ gbc.gridx ++;
+ buttonsPanel.add(cancelButton, gbc);
+ cancelButton.addActionListener(new ActionListener()
+ {
+ /**
+ * {@inheritDoc}
+ */
+ public void actionPerformed(ActionEvent ev)
+ {
+ result = Result.CANCEL;
+ cancelClicked();
+ }
+ });
+
+ buttonsPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
+ ColorAndFontConstants.defaultBorderColor));
+
+ return buttonsPanel;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Component getPreferredFocusComponent()
+ {
+ return initializeAllButton;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void okClicked()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Message getTitle()
+ {
+ return INFO_CTRL_PANEL_CONFIRM_INITIALIZE_TITLE.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void configurationChanged(ConfigurationChangeEvent ev)
+ {
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public GenericDialog.ButtonType getButtonType()
+ {
+ return GenericDialog.ButtonType.NO_BUTTON;
+ }
+ }
+}
+
diff --git a/opends/src/guitools/org/opends/guitools/controlpanel/ui/ImportLDIFPanel.java b/opends/src/guitools/org/opends/guitools/controlpanel/ui/ImportLDIFPanel.java
index 25ebf7e..caf520e 100644
--- a/opends/src/guitools/org/opends/guitools/controlpanel/ui/ImportLDIFPanel.java
+++ b/opends/src/guitools/org/opends/guitools/controlpanel/ui/ImportLDIFPanel.java
@@ -54,7 +54,9 @@
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
+import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
+import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor;
import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
import org.opends.guitools.controlpanel.event.BrowseActionListener;
@@ -62,8 +64,14 @@
import org.opends.guitools.controlpanel.task.Task;
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
+import org.opends.quicksetup.ui.UIFactory;
import org.opends.quicksetup.util.Utils;
import org.opends.server.tools.ImportLDIF;
+import org.opends.server.tools.dsreplication.ReplicationCliArgumentParser;
+import org.opends.server.tools.dsreplication.ReplicationCliException;
+import org.opends.server.tools.dsreplication.ReplicationCliMain;
+import org.opends.server.types.DN;
+import org.opends.server.util.cli.CommandBuilder;
/**
* The panel where the user can import the contents of an LDIF file to the
@@ -640,18 +648,69 @@
task.canLaunch(newTask, errors);
}
boolean confirmed = true;
+ boolean initializeAll = false;
if (errors.isEmpty())
{
- if (overwrite.isSelected())
+ Set<DN> replicatedBaseDNs = getReplicatedBaseDNs();
+ boolean canInitialize =
+ !replicatedBaseDNs.isEmpty() && isServerRunning();
+ if (overwrite.isSelected() && !canInitialize)
{
confirmed = displayConfirmationDialog(
INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
INFO_CTRL_PANEL_CONFIRMATION_IMPORT_LDIF_DETAILS.get(
- backends.getSelectedItem().toString()));
+ backendName));
+ }
+ else if (!overwrite.isSelected() && canInitialize)
+ {
+ ArrayList<String> dns = new ArrayList<String>();
+ for (DN dn : replicatedBaseDNs)
+ {
+ dns.add(dn.toString());
+ }
+ initializeAll = displayConfirmationDialog(
+ INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
+ INFO_CTRL_PANEL_CONFIRMATION_INITIALIZE_ALL_DETAILS.get(
+ Utilities.getStringFromCollection(dns, "<br>")));
+ }
+ else if (overwrite.isSelected() && canInitialize)
+ {
+ ArrayList<String> dns = new ArrayList<String>();
+ for (DN dn : replicatedBaseDNs)
+ {
+ dns.add(dn.toString());
+ }
+ ConfirmInitializeAndImportDialog dlg =
+ new ConfirmInitializeAndImportDialog(
+ Utilities.getParentDialog(this), getInfo());
+ dlg.setMessage(INFO_CTRL_PANEL_CONFIRM_INITIALIZE_TITLE.get(),
+ INFO_CTRL_PANEL_CONFIRMATION_INITIALIZE_ALL_AND_OVERWRITE_DETAILS.get(
+ backendName, Utilities.getStringFromCollection(dns, "<br>")));
+ dlg.setModal(true);
+ dlg.setVisible(true);
+
+ ConfirmInitializeAndImportDialog.Result result = dlg.getResult();
+ switch (result)
+ {
+ case CANCEL:
+ confirmed = false;
+ break;
+ case INITIALIZE_ALL:
+ confirmed = true;
+ initializeAll = true;
+ break;
+ case IMPORT_ONLY:
+ confirmed = true;
+ initializeAll = false;
+ break;
+ default:
+ throw new RuntimeException("Unexpected result: "+result);
+ }
}
}
if ((errors.isEmpty()) && confirmed)
{
+ newTask.setInitializeAll(initializeAll);
launchOperation(newTask,
INFO_CTRL_PANEL_IMPORTING_LDIF_SUMMARY.get(
backends.getSelectedItem().toString()),
@@ -687,6 +746,30 @@
super.cancelClicked();
}
+ private Set<DN> getReplicatedBaseDNs()
+ {
+ Set<DN> baseDNs = new TreeSet<DN>();
+ String backendID = (String)backends.getSelectedItem();
+ if (backendID != null)
+ {
+ for (BackendDescriptor backend :
+ getInfo().getServerDescriptor().getBackends())
+ {
+ if (backendID.equalsIgnoreCase(backend.getBackendID()))
+ {
+ for (BaseDNDescriptor baseDN : backend.getBaseDns())
+ {
+ if (baseDN.getReplicaID() != -1)
+ {
+ baseDNs.add(baseDN.getDn());
+ }
+ }
+ }
+ }
+ }
+ return baseDNs;
+ }
+
/**
* The class that performs the import.
*
@@ -695,6 +778,8 @@
{
private Set<String> backendSet;
private String fileName;
+ private boolean initializeAll;
+ private Set<DN> replicatedBaseDNs;
/**
* The constructor of the task.
@@ -707,6 +792,12 @@
backendSet = new HashSet<String>();
backendSet.add((String)backends.getSelectedItem());
fileName = file.getText();
+ replicatedBaseDNs = getReplicatedBaseDNs();
+ }
+
+ private void setInitializeAll(boolean initializeAll)
+ {
+ this.initializeAll = initializeAll;
}
/**
@@ -849,6 +940,10 @@
{
returnCode = ImportLDIF.mainImportLDIF(args, false, outPrintStream,
errorPrintStream);
+ if (returnCode == 0 && initializeAll)
+ {
+ initializeAll();
+ }
}
else
{
@@ -898,5 +993,62 @@
{
return backendSet;
}
+
+ private void initializeAll() throws ReplicationCliException
+ {
+ ReplicationCliMain repl = new ReplicationCliMain(outPrintStream,
+ errorPrintStream, System.in);
+ getProgressDialog().appendProgressHtml(
+ UIFactory.HTML_SEPARATOR+"<br><br>");
+
+ String cmd = getCommandLineToInitializeAll();
+
+ getProgressDialog().appendProgressHtml(Utilities.applyFont(
+ INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_INITIALIZE_ALL.get().toString()+
+ "<br><b>"+cmd+"</b><br><br>",
+ ColorAndFontConstants.progressFont));
+
+ for (DN baseDN : replicatedBaseDNs)
+ {
+ Message msg = INFO_PROGRESS_INITIALIZING_SUFFIX.get(baseDN.toString(),
+ ConnectionUtils.getHostPort(getInfo().getDirContext()));
+ getProgressDialog().appendProgressHtml(Utilities.applyFont(
+ msg.toString()+"<br>", ColorAndFontConstants.progressFont));
+ repl.initializeAllSuffix(baseDN.toString(), getInfo().getDirContext(),
+ true);
+ }
+ }
+
+ private String getCommandLineToInitializeAll()
+ {
+ StringBuilder sb = new StringBuilder();
+ String cmdLineName = getCommandLinePath("dsreplication");
+ sb.append(cmdLineName);
+ ArrayList<String> args = new ArrayList<String>();
+ args.add(
+ ReplicationCliArgumentParser.INITIALIZE_ALL_REPLICATION_SUBCMD_NAME);
+ args.add("--hostName");
+ args.add(getInfo().getServerDescriptor().getHostname());
+ args.add("--port");
+ args.add(String.valueOf(
+ ConnectionUtils.getPort(getInfo().getDirContext())));
+ for (DN baseDN : replicatedBaseDNs)
+ {
+ args.add("--baseDN");
+ args.add(baseDN.toString());
+ }
+ args.add("--adminUID");
+ args.add("admin");
+ args.add("--adminPassword");
+ args.add(Utilities.OBFUSCATED_VALUE);
+ args.add("--trustAll");
+ args.add("--no-prompt");
+
+ for (String arg : args)
+ {
+ sb.append(" "+CommandBuilder.escapeValue(arg));
+ }
+ return sb.toString();
+ }
};
}
diff --git a/opends/src/messages/messages/admin_tool.properties b/opends/src/messages/messages/admin_tool.properties
index 4d3dbf6..6cd70f2 100644
--- a/opends/src/messages/messages/admin_tool.properties
+++ b/opends/src/messages/messages/admin_tool.properties
@@ -1788,10 +1788,29 @@
MILD_ERR_CTRL_PANEL_SKIPS_FILE_REQUIRED=You must provide a value for the \
skips file.
#
-# Note that the following property contains line breaks in HTML format (<br>)
+# Note that the following three properties contain line breaks in HTML format
+# (<br>)
#
INFO_CTRL_PANEL_CONFIRMATION_IMPORT_LDIF_DETAILS=All the data in backend '%s' \
will be overwritten.<br><br>Do you want to continue?
+INFO_CTRL_PANEL_CONFIRMATION_INITIALIZE_ALL_DETAILS=The following base DNs are \
+ replicated:<br>%s<br><br>In order replication to work, these base DNs must \
+ be initialized once the import of the LDIF is finished.<br><br>Do you want to \
+ initialize automatically the contents of the replicated base DNs in the \
+ remote servers once the import LDIF has finished? Note that if you click \
+ 'Yes' all the data in the remote server base DNs will be overwritten.
+INFO_CTRL_PANEL_CONFIRMATION_INITIALIZE_ALL_AND_OVERWRITE_DETAILS=All the data \
+ in backend '%s' will be overwritten.<br><br>The following base DNs are \
+ replicated:<br>%s<br><br>In order replication to work, these base DNs must \
+ be initialized once the import of the LDIF is finished.<br><br>You can choose \
+ to initialize automatically the contents of the replicated base DNs in the \
+ remote servers once the import LDIF has finished. Note that if you choose \
+ to initialize all the data in the remote server base DNs will be overwritten.
+INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_INITIALIZE_ALL=Equivalent command to \
+ initialize remote servers:
+INFO_CTRL_PANEL_CONFIRM_INITIALIZE_TITLE=Confirmation Required
+INFO_CTRL_PANEL_INITIALIZE_ALL_BUTTON_LABEL=Import and Initialize
+INFO_CTRL_PANEL_IMPORT_ONLY_BUTTON_LABEL=Import Only
INFO_CTRL_PANEL_IMPORTING_LDIF_SUMMARY=Importing to backend '%s'...
INFO_CTRL_PANEL_IMPORTING_LDIF_SUCCESSFUL_SUMMARY=Import Complete
INFO_CTRL_PANEL_IMPORTING_LDIF_SUCCESSFUL_DETAILS=The import finished \
diff --git a/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java b/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java
index e603575..16f8b62 100644
--- a/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java
+++ b/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java
@@ -335,8 +335,7 @@
// program.
try
{
- argParser = new ReplicationCliArgumentParser(CLASS_NAME);
- argParser.initializeParser(getOutputStream());
+ createArgumenParser();
}
catch (ArgumentException ae)
{
@@ -574,6 +573,12 @@
return returnValue.getReturnCode();
}
+ private void createArgumenParser() throws ArgumentException
+ {
+ argParser = new ReplicationCliArgumentParser(CLASS_NAME);
+ argParser.initializeParser(getOutputStream());
+ }
+
/**
* Based on the data provided in the command-line it enables replication
* between two servers.
@@ -7588,9 +7593,29 @@
}
}
- private void initializeAllSuffix(String baseDN, InitialLdapContext ctx,
+ /**
+ * Initializes all the replicas in the topology with the contents of a
+ * given replica.
+ * @param ctx the connection to the server where the source replica of the
+ * initialization is.
+ * @param baseDN the dn of the suffix.
+ * @param displayProgress whether we want to display progress or not.
+ * @throws ReplicationCliException if an unexpected error occurs.
+ */
+ public void initializeAllSuffix(String baseDN, InitialLdapContext ctx,
boolean displayProgress) throws ReplicationCliException
{
+ if (argParser == null)
+ {
+ try
+ {
+ createArgumenParser();
+ }
+ catch (ArgumentException ae)
+ {
+ throw new RuntimeException("Error creating argument parser: "+ae, ae);
+ }
+ }
int nTries = 5;
boolean initDone = false;
while (!initDone)
@@ -7836,9 +7861,10 @@
}
/**
- * Initializes a suffix with the contents of a replica that has a given
- * replication id.
- * @param ctx the connection to the server whose suffix we want to initialize.
+ * Initializes all the replicas in the topology with the contents of a
+ * given replica. This method will try to create the task only once.
+ * @param ctx the connection to the server where the source replica of the
+ * initialization is.
* @param baseDN the dn of the suffix.
* @param displayProgress whether we want to display progress or not.
* @throws ApplicationException if an unexpected error occurs.
--
Gitblit v1.10.0