/*
|
* 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 2007-2010 Sun Microsystems, Inc.
|
*/
|
|
package org.opends.server.tools.dsreplication;
|
|
import static org.opends.admin.ads.ServerDescriptor.getReplicationServer;
|
import static org.opends.admin.ads.ServerDescriptor.getServerRepresentation;
|
import static org.opends.admin.ads.ServerDescriptor.getSuffixDisplay;
|
import static org.opends.messages.AdminToolMessages.*;
|
import static org.opends.messages.QuickSetupMessages.*;
|
import static org.opends.messages.ToolMessages.*;
|
import static org.opends.messages.UtilityMessages.
|
ERR_CONFIRMATION_TRIES_LIMIT_REACHED;
|
import static org.opends.quicksetup.util.Utils.getFirstValue;
|
import static org.opends.quicksetup.util.Utils.getThrowableMsg;
|
import static org.opends.server.tools.ToolConstants.*;
|
import static org.opends.server.tools.dsreplication.ReplicationCliReturnCode.*;
|
|
import java.io.BufferedWriter;
|
import java.io.File;
|
import java.io.FileWriter;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
import java.io.PrintStream;
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.Collections;
|
import java.util.Comparator;
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.HashSet;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.SortedSet;
|
import java.util.TreeSet;
|
import java.util.logging.Level;
|
import java.util.logging.Logger;
|
|
import javax.naming.NameAlreadyBoundException;
|
import javax.naming.NameNotFoundException;
|
import javax.naming.NamingEnumeration;
|
import javax.naming.NamingException;
|
import javax.naming.directory.Attribute;
|
import javax.naming.directory.BasicAttribute;
|
import javax.naming.directory.BasicAttributes;
|
import javax.naming.directory.DirContext;
|
import javax.naming.directory.SearchControls;
|
import javax.naming.directory.SearchResult;
|
import javax.naming.ldap.InitialLdapContext;
|
import javax.net.ssl.TrustManager;
|
|
import org.opends.admin.ads.ADSContext;
|
import org.opends.admin.ads.ADSContextException;
|
import org.opends.admin.ads.ReplicaDescriptor;
|
import org.opends.admin.ads.ServerDescriptor;
|
import org.opends.admin.ads.SuffixDescriptor;
|
import org.opends.admin.ads.TopologyCache;
|
import org.opends.admin.ads.TopologyCacheException;
|
import org.opends.admin.ads.TopologyCacheFilter;
|
import org.opends.admin.ads.ADSContext.ADSPropertySyntax;
|
import org.opends.admin.ads.ADSContext.AdministratorProperty;
|
import org.opends.admin.ads.util.ApplicationTrustManager;
|
import org.opends.admin.ads.util.ConnectionUtils;
|
import org.opends.admin.ads.util.PreferredConnection;
|
import org.opends.admin.ads.util.ServerLoader;
|
import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
|
import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor;
|
import org.opends.guitools.controlpanel.util.ConfigFromDirContext;
|
import org.opends.guitools.controlpanel.util.ConfigFromFile;
|
import org.opends.guitools.controlpanel.util.ControlPanelLog;
|
import org.opends.guitools.controlpanel.util.ProcessReader;
|
import org.opends.guitools.controlpanel.util.Utilities;
|
import org.opends.messages.Message;
|
import org.opends.messages.MessageBuilder;
|
import org.opends.quicksetup.ApplicationException;
|
import org.opends.quicksetup.Constants;
|
import org.opends.quicksetup.Installation;
|
import org.opends.quicksetup.ReturnCode;
|
import org.opends.quicksetup.event.ProgressUpdateEvent;
|
import org.opends.quicksetup.event.ProgressUpdateListener;
|
import org.opends.quicksetup.installer.Installer;
|
import org.opends.quicksetup.installer.InstallerHelper;
|
import org.opends.quicksetup.installer.PeerNotFoundException;
|
import org.opends.quicksetup.installer.offline.OfflineInstaller;
|
import org.opends.quicksetup.util.PlainTextProgressMessageFormatter;
|
import org.opends.quicksetup.util.Utils;
|
import org.opends.server.admin.AttributeTypePropertyDefinition;
|
import org.opends.server.admin.ClassLoaderProvider;
|
import org.opends.server.admin.ClassPropertyDefinition;
|
import org.opends.server.admin.DefaultBehaviorException;
|
import org.opends.server.admin.ManagedObjectNotFoundException;
|
import org.opends.server.admin.client.ManagementContext;
|
import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
|
import org.opends.server.admin.client.ldap.LDAPManagementContext;
|
import org.opends.server.admin.std.client.*;
|
import org.opends.server.admin.std.meta.*;
|
import org.opends.server.config.ConfigException;
|
import org.opends.server.core.DirectoryServer;
|
import org.opends.server.tasks.PurgeConflictsHistoricalTask;
|
import org.opends.server.tools.ClientException;
|
import org.opends.server.tools.ToolConstants;
|
import org.opends.server.tools.tasks.TaskEntry;
|
import org.opends.server.tools.tasks.TaskScheduleInteraction;
|
import org.opends.server.tools.tasks.TaskScheduleUserData;
|
import org.opends.server.types.DN;
|
import org.opends.server.types.InitializationException;
|
import org.opends.server.types.NullOutputStream;
|
import org.opends.server.types.OpenDsException;
|
import org.opends.server.util.ServerConstants;
|
import org.opends.server.util.SetupUtils;
|
import org.opends.server.util.StaticUtils;
|
import org.opends.server.util.args.Argument;
|
import org.opends.server.util.args.ArgumentException;
|
import org.opends.server.util.args.BooleanArgument;
|
import org.opends.server.util.args.FileBasedArgument;
|
import org.opends.server.util.args.IntegerArgument;
|
import org.opends.server.util.args.StringArgument;
|
import org.opends.server.util.cli.CLIException;
|
import org.opends.server.util.cli.CommandBuilder;
|
import org.opends.server.util.cli.ConsoleApplication;
|
import org.opends.server.util.cli.LDAPConnectionConsoleInteraction;
|
import org.opends.server.util.cli.MenuBuilder;
|
import org.opends.server.util.cli.MenuResult;
|
import org.opends.server.util.cli.PointAdder;
|
import org.opends.server.util.table.TableBuilder;
|
import org.opends.server.util.table.TextTablePrinter;
|
|
/**
|
* This class provides a tool that can be used to enable and disable replication
|
* and also to initialize the contents of a replicated suffix with the contents
|
* of another suffix. It also allows to display the replicated status of the
|
* different base DNs of the servers that are registered in the ADS.
|
*/
|
public class ReplicationCliMain extends ConsoleApplication
|
{
|
/**
|
* The fully-qualified name of this class.
|
*/
|
private static final String CLASS_NAME = ReplicationCliMain.class.getName();
|
|
/** Prefix for log files. */
|
static public final String LOG_FILE_PREFIX = "opends-replication-";
|
|
/** Suffix for log files. */
|
static public final String LOG_FILE_SUFFIX = ".log";
|
|
/**
|
* Property used to call the dsreplication script and ReplicationCliMain to
|
* know which are the java properties to be used (those of dsreplication or
|
* those of dsreplication.offline).
|
*/
|
private static final String SCRIPT_CALL_STATUS =
|
"org.opends.server.dsreplicationcallstatus";
|
|
/**
|
* The value set by the dsreplication script if it is called the first time.
|
*/
|
private static final String FIRST_SCRIPT_CALL =
|
"firstcall";
|
|
private boolean forceNonInteractive;
|
|
private static final Logger LOG =
|
Logger.getLogger(ReplicationCliMain.class.getName());
|
|
// Always use SSL with the administration connector
|
private final boolean useSSL = true;
|
private final boolean useStartTLS = false;
|
|
/**
|
* The enumeration containing the different options we display when we ask
|
* the user to provide the subcommand interactively.
|
*/
|
private enum SubcommandChoice
|
{
|
/**
|
* Enable replication.
|
*/
|
ENABLE(INFO_REPLICATION_ENABLE_MENU_PROMPT.get()),
|
/**
|
* Disable replication.
|
*/
|
DISABLE(INFO_REPLICATION_DISABLE_MENU_PROMPT.get()),
|
/**
|
* Initialize replication.
|
*/
|
INITIALIZE(INFO_REPLICATION_INITIALIZE_MENU_PROMPT.get()),
|
/**
|
* Initialize All.
|
*/
|
INITIALIZE_ALL(INFO_REPLICATION_INITIALIZE_ALL_MENU_PROMPT.get()),
|
/**
|
* Pre external initialization.
|
*/
|
PRE_EXTERNAL_INITIALIZATION(
|
INFO_REPLICATION_PRE_EXTERNAL_INITIALIZATION_MENU_PROMPT.get()),
|
/**
|
* Post external initialization.
|
*/
|
POST_EXTERNAL_INITIALIZATION(
|
INFO_REPLICATION_POST_EXTERNAL_INITIALIZATION_MENU_PROMPT.get()),
|
/**
|
* Replication status.
|
*/
|
STATUS(INFO_REPLICATION_STATUS_MENU_PROMPT.get()),
|
/**
|
* Replication purge historical.
|
*/
|
PURGE_HISTORICAL(INFO_REPLICATION_PURGE_HISTORICAL_MENU_PROMPT.get()),
|
/**
|
* Cancel operation.
|
*/
|
CANCEL(null);
|
private Message prompt;
|
private SubcommandChoice(Message prompt)
|
{
|
this.prompt = prompt;
|
}
|
Message getPrompt()
|
{
|
return prompt;
|
}
|
};
|
|
// The argument parser to be used.
|
private ReplicationCliArgumentParser argParser;
|
private FileBasedArgument userProvidedAdminPwdFile;
|
private LDAPConnectionConsoleInteraction ci = null;
|
private CommandBuilder firstServerCommandBuilder;
|
// The message formatter
|
PlainTextProgressMessageFormatter formatter =
|
new PlainTextProgressMessageFormatter();
|
|
/**
|
* Constructor for the ReplicationCliMain object.
|
*
|
* @param out the print stream to use for standard output.
|
* @param err the print stream to use for standard error.
|
* @param in the input stream to use for standard input.
|
*/
|
public ReplicationCliMain(PrintStream out, PrintStream err, InputStream in)
|
{
|
super(in, out, err);
|
}
|
|
/**
|
* The main method for the replication tool.
|
*
|
* @param args the command-line arguments provided to this program.
|
*/
|
|
public static void main(String[] args)
|
{
|
int retCode = mainCLI(args, true, System.out, System.err, System.in);
|
|
System.exit(retCode);
|
}
|
|
/**
|
* Parses the provided command-line arguments and uses that information to
|
* run the replication tool.
|
*
|
* @param args the command-line arguments provided to this program.
|
*
|
* @return The error code.
|
*/
|
|
public static int mainCLI(String[] args)
|
{
|
return mainCLI(args, true, System.out, System.err, System.in);
|
}
|
|
/**
|
* Parses the provided command-line arguments and uses that information to
|
* run the replication tool.
|
*
|
* @param args The command-line arguments provided to this
|
* program.
|
* @param initializeServer Indicates whether to initialize the server.
|
* @param outStream The output stream to use for standard output, or
|
* <CODE>null</CODE> if standard output is not
|
* needed.
|
* @param errStream The output stream to use for standard error, or
|
* <CODE>null</CODE> if standard error is not
|
* needed.
|
* @param inStream The input stream to use for standard input.
|
* @return The error code.
|
*/
|
|
public static int mainCLI(String[] args, boolean initializeServer,
|
OutputStream outStream, OutputStream errStream, InputStream inStream)
|
{
|
PrintStream out;
|
if (outStream == null)
|
{
|
out = NullOutputStream.printStream();
|
}
|
else
|
{
|
out = new PrintStream(outStream);
|
}
|
|
PrintStream err;
|
if (errStream == null)
|
{
|
err = NullOutputStream.printStream();
|
}
|
else
|
{
|
err = new PrintStream(errStream);
|
}
|
|
try
|
{
|
ControlPanelLog.initLogFileHandler(
|
File.createTempFile(LOG_FILE_PREFIX, LOG_FILE_SUFFIX));
|
} catch (Throwable t) {
|
System.err.println("Unable to initialize log");
|
t.printStackTrace();
|
}
|
ReplicationCliMain replicationCli = new ReplicationCliMain(out, err,
|
inStream);
|
return replicationCli.execute(args, initializeServer);
|
}
|
|
/**
|
* Parses the provided command-line arguments and uses that information to
|
* run the replication tool.
|
*
|
* @param args the command-line arguments provided to this program.
|
* @param initializeServer Indicates whether to initialize the server.
|
*
|
* @return The error code.
|
*/
|
public int execute(String[] args, boolean initializeServer)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
// Create the command-line argument parser for use with this
|
// program.
|
try
|
{
|
createArgumenParser();
|
}
|
catch (ArgumentException ae)
|
{
|
Message message =
|
ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
|
println(message);
|
LOG.log(Level.SEVERE, "Complete error stack:", ae);
|
returnValue = CANNOT_INITIALIZE_ARGS;
|
}
|
|
if (returnValue == SUCCESSFUL_NOP)
|
{
|
try
|
{
|
argParser.getSecureArgsList().initArgumentsWithConfiguration();
|
}
|
catch (ConfigException ce)
|
{
|
// Ignore.
|
}
|
|
// Parse the command-line arguments provided to this program.
|
try
|
{
|
argParser.parseArguments(args);
|
}
|
catch (ArgumentException ae)
|
{
|
Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
|
|
println(message);
|
println();
|
println(Message.raw(argParser.getUsage()));
|
LOG.log(Level.SEVERE, "Complete error stack:", ae);
|
returnValue = ERROR_USER_DATA;
|
}
|
}
|
|
if (!argParser.usageOrVersionDisplayed())
|
{
|
if (returnValue == SUCCESSFUL_NOP)
|
{
|
/* Check that the provided parameters are compatible.
|
*/
|
MessageBuilder buf = new MessageBuilder();
|
argParser.validateOptions(buf);
|
if (buf.length() > 0)
|
{
|
println(buf.toMessage());
|
println(Message.raw(argParser.getUsage()));
|
returnValue = ERROR_USER_DATA;
|
}
|
}
|
if (initializeServer && returnValue == SUCCESSFUL_NOP)
|
{
|
DirectoryServer.bootstrapClient();
|
|
// Bootstrap definition classes.
|
try
|
{
|
if (!ClassLoaderProvider.getInstance().isEnabled())
|
{
|
ClassLoaderProvider.getInstance().enable();
|
}
|
// Switch off class name validation in client.
|
ClassPropertyDefinition.setAllowClassValidation(false);
|
|
// Switch off attribute type name validation in client.
|
AttributeTypePropertyDefinition.setCheckSchema(false);
|
}
|
catch (InitializationException ie)
|
{
|
println(ie.getMessageObject());
|
returnValue = ERROR_INITIALIZING_ADMINISTRATION_FRAMEWORK;
|
}
|
}
|
|
if (returnValue == SUCCESSFUL_NOP)
|
{
|
if (argParser.getSecureArgsList().
|
bindPasswordFileArg.isPresent())
|
{
|
try
|
{
|
userProvidedAdminPwdFile = new FileBasedArgument(
|
"adminPasswordFile",
|
OPTION_SHORT_BINDPWD_FILE, "adminPasswordFile", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get());
|
userProvidedAdminPwdFile.getNameToValueMap().putAll(
|
argParser.getSecureArgsList().
|
bindPasswordFileArg.getNameToValueMap());
|
}
|
catch (Throwable t)
|
{
|
throw new IllegalStateException("Unexpected error: "+t, t);
|
}
|
}
|
ci = new LDAPConnectionConsoleInteraction(this,
|
argParser.getSecureArgsList());
|
ci.setDisplayLdapIfSecureParameters(false);
|
}
|
if (returnValue == SUCCESSFUL_NOP)
|
{
|
boolean subcommandLaunched = true;
|
String subCommand = null;
|
if (argParser.isEnableReplicationSubcommand())
|
{
|
returnValue = enableReplication();
|
subCommand =
|
ReplicationCliArgumentParser.ENABLE_REPLICATION_SUBCMD_NAME;
|
}
|
else if (argParser.isDisableReplicationSubcommand())
|
{
|
returnValue = disableReplication();
|
subCommand =
|
ReplicationCliArgumentParser.DISABLE_REPLICATION_SUBCMD_NAME;
|
}
|
else if (argParser.isInitializeReplicationSubcommand())
|
{
|
returnValue = initializeReplication();
|
subCommand =
|
ReplicationCliArgumentParser.INITIALIZE_REPLICATION_SUBCMD_NAME;
|
}
|
else if (argParser.isInitializeAllReplicationSubcommand())
|
{
|
returnValue = initializeAllReplication();
|
subCommand =
|
ReplicationCliArgumentParser.INITIALIZE_ALL_REPLICATION_SUBCMD_NAME;
|
}
|
else if (argParser.isPreExternalInitializationSubcommand())
|
{
|
returnValue = preExternalInitialization();
|
subCommand =
|
ReplicationCliArgumentParser.PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME;
|
}
|
else if (argParser.isPostExternalInitializationSubcommand())
|
{
|
returnValue = postExternalInitialization();
|
subCommand =
|
ReplicationCliArgumentParser.POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME;
|
}
|
else if (argParser.isStatusReplicationSubcommand())
|
{
|
returnValue = statusReplication();
|
subCommand =
|
ReplicationCliArgumentParser.STATUS_REPLICATION_SUBCMD_NAME;
|
}
|
else if (argParser.isPurgeHistoricalSubcommand())
|
{
|
returnValue = purgeHistorical();
|
subCommand =
|
ReplicationCliArgumentParser.PURGE_HISTORICAL_SUBCMD_NAME;
|
}
|
else
|
{
|
if (argParser.isInteractive())
|
{
|
switch (promptForSubcommand())
|
{
|
case ENABLE:
|
subCommand =
|
ReplicationCliArgumentParser.ENABLE_REPLICATION_SUBCMD_NAME;
|
break;
|
|
case DISABLE:
|
subCommand =
|
ReplicationCliArgumentParser.DISABLE_REPLICATION_SUBCMD_NAME;
|
break;
|
|
case INITIALIZE:
|
subCommand =
|
ReplicationCliArgumentParser.INITIALIZE_REPLICATION_SUBCMD_NAME;
|
break;
|
|
case INITIALIZE_ALL:
|
subCommand =
|
ReplicationCliArgumentParser.
|
INITIALIZE_ALL_REPLICATION_SUBCMD_NAME;
|
break;
|
|
case PRE_EXTERNAL_INITIALIZATION:
|
subCommand = ReplicationCliArgumentParser.
|
PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME;
|
break;
|
|
case POST_EXTERNAL_INITIALIZATION:
|
subCommand = ReplicationCliArgumentParser.
|
POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME;
|
break;
|
|
case STATUS:
|
subCommand =
|
ReplicationCliArgumentParser.STATUS_REPLICATION_SUBCMD_NAME;
|
break;
|
|
case PURGE_HISTORICAL:
|
subCommand =
|
ReplicationCliArgumentParser.PURGE_HISTORICAL_SUBCMD_NAME;
|
break;
|
|
default:
|
// User canceled
|
returnValue = USER_CANCELLED;
|
}
|
|
if (subCommand != null)
|
{
|
String[] newArgs = new String[args.length + 1];
|
newArgs[0] = subCommand;
|
for (int i=0; i<args.length ; i++)
|
{
|
newArgs[i+1] = args[i];
|
}
|
// The server (if requested) has already been initialized.
|
return execute(newArgs, false);
|
}
|
}
|
else
|
{
|
println(ERR_REPLICATION_VALID_SUBCOMMAND_NOT_FOUND.get(
|
"--"+ToolConstants.OPTION_LONG_NO_PROMPT));
|
println(Message.raw(argParser.getUsage()));
|
returnValue = ERROR_USER_DATA;
|
subcommandLaunched = false;
|
}
|
}
|
|
|
// Display the log file only if the operation is successful (when there
|
// is a critical error this is already displayed).
|
if (subcommandLaunched && (returnValue == SUCCESSFUL) &&
|
displayLogFileAtEnd(subCommand))
|
{
|
File logFile = ControlPanelLog.getLogFile();
|
if (logFile != null)
|
{
|
println();
|
println(INFO_GENERAL_SEE_FOR_DETAILS.get(logFile.getPath()));
|
println();
|
}
|
}
|
}
|
}
|
|
return returnValue.getReturnCode();
|
}
|
|
private boolean isFirstCallFromScript()
|
{
|
return FIRST_SCRIPT_CALL.equals(System.getProperty(SCRIPT_CALL_STATUS));
|
}
|
|
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.
|
* @return the error code if the operation failed and 0 if it was successful.
|
*/
|
private ReplicationCliReturnCode enableReplication()
|
{
|
ReplicationCliReturnCode returnValue;
|
EnableReplicationUserData uData = new EnableReplicationUserData();
|
if (argParser.isInteractive())
|
{
|
try
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = enableReplication(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
catch (ReplicationCliException rce)
|
{
|
returnValue = rce.getErrorCode();
|
println();
|
println(getCriticalExceptionMessage(rce));
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = enableReplication(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Based on the data provided in the command-line it disables replication
|
* in the server.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode disableReplication()
|
{
|
ReplicationCliReturnCode returnValue;
|
DisableReplicationUserData uData = new DisableReplicationUserData();
|
if (argParser.isInteractive())
|
{
|
try
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = disableReplication(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
catch (ReplicationCliException rce)
|
{
|
returnValue = rce.getErrorCode();
|
println();
|
println(getCriticalExceptionMessage(rce));
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = disableReplication(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Based on the data provided in the command-line initialize the contents
|
* of the whole replication topology.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode initializeAllReplication()
|
{
|
ReplicationCliReturnCode returnValue;
|
InitializeAllReplicationUserData uData =
|
new InitializeAllReplicationUserData();
|
if (argParser.isInteractive())
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = initializeAllReplication(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = initializeAllReplication(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Based on the data provided in the command-line execute the pre external
|
* initialization operation.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode preExternalInitialization()
|
{
|
ReplicationCliReturnCode returnValue;
|
PreExternalInitializationUserData uData =
|
new PreExternalInitializationUserData();
|
if (argParser.isInteractive())
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = preExternalInitialization(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = preExternalInitialization(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Based on the data provided in the command-line execute the post external
|
* initialization operation.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode postExternalInitialization()
|
{
|
ReplicationCliReturnCode returnValue;
|
PostExternalInitializationUserData uData =
|
new PostExternalInitializationUserData();
|
if (argParser.isInteractive())
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = postExternalInitialization(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = postExternalInitialization(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Based on the data provided in the command-line it displays replication
|
* status.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode statusReplication()
|
{
|
ReplicationCliReturnCode returnValue;
|
StatusReplicationUserData uData = new StatusReplicationUserData();
|
if (argParser.isInteractive())
|
{
|
try
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = statusReplication(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
catch (ReplicationCliException rce)
|
{
|
returnValue = rce.getErrorCode();
|
println();
|
println(getCriticalExceptionMessage(rce));
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = statusReplication(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Based on the data provided in the command-line it displays replication
|
* status.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode purgeHistorical()
|
{
|
ReplicationCliReturnCode returnValue;
|
PurgeHistoricalUserData uData = new PurgeHistoricalUserData();
|
|
if (argParser.isInteractive())
|
{
|
uData = new PurgeHistoricalUserData();
|
if (promptIfRequired(uData))
|
{
|
returnValue = purgeHistorical(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = purgeHistorical(uData);
|
}
|
return returnValue;
|
}
|
|
/**
|
* Initializes the contents of the provided purge historical replication user
|
* data object with what was provided in the command-line without prompting to
|
* the user.
|
* @param uData the purge historical replication user data object to be
|
* initialized.
|
*/
|
private void initializeWithArgParser(PurgeHistoricalUserData uData)
|
{
|
PurgeHistoricalUserData.initializeWithArgParser(uData, argParser);
|
}
|
|
private ReplicationCliReturnCode purgeHistorical(
|
PurgeHistoricalUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = null;
|
if (uData.isOnline())
|
{
|
returnValue = purgeHistoricalRemotely(uData);
|
}
|
else
|
{
|
returnValue = purgeHistoricalLocally(uData);
|
}
|
return returnValue;
|
}
|
|
private ReplicationCliReturnCode purgeHistoricalLocally(
|
PurgeHistoricalUserData uData)
|
{
|
ReplicationCliReturnCode returnValue;
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
checkSuffixesForLocalPurgeHistorical(baseDNs, false);
|
if (!baseDNs.isEmpty())
|
{
|
uData.setBaseDNs(baseDNs);
|
printPurgeHistoricalEquivalentIfRequired(uData);
|
|
returnValue = SUCCESSFUL;
|
try
|
{
|
returnValue = purgeHistoricalLocallyTask(uData);
|
}
|
catch (ReplicationCliException rce)
|
{
|
println();
|
println(getCriticalExceptionMessage(rce));
|
returnValue = rce.getErrorCode();
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
else
|
{
|
returnValue = HISTORICAL_CANNOT_BE_PURGED_ON_BASEDN;
|
}
|
|
return returnValue;
|
}
|
|
private void printPurgeProgressMessage(PurgeHistoricalUserData uData)
|
{
|
String separator = formatter.getLineBreak().toString() +
|
formatter.getTab().toString();
|
printlnProgress();
|
Message msg = formatter.getFormattedProgress(
|
INFO_PROGRESS_PURGE_HISTORICAL.get(separator,
|
Utils.getStringFromCollection(uData.getBaseDNs(), separator)));
|
printProgress(msg);
|
printlnProgress();
|
|
}
|
|
private ReplicationCliReturnCode purgeHistoricalLocallyTask(
|
PurgeHistoricalUserData uData)
|
throws ReplicationCliException
|
{
|
ReplicationCliReturnCode returnCode = ReplicationCliReturnCode.SUCCESSFUL;
|
if (isFirstCallFromScript())
|
{
|
// Launch the process: launch dsreplication in non-interactive mode with
|
// the recursive property set.
|
ArrayList<String> args = new ArrayList<String>();
|
args.add(getCommandLinePath(getCommandName()));
|
args.add(ReplicationCliArgumentParser.PURGE_HISTORICAL_SUBCMD_NAME);
|
args.add("--"+argParser.noPromptArg.getLongIdentifier());
|
args.add("--"+argParser.maximumDurationArg.getLongIdentifier());
|
args.add(String.valueOf(uData.getMaximumDuration()));
|
for (String baseDN : uData.getBaseDNs())
|
{
|
args.add("--"+argParser.baseDNsArg.getLongIdentifier());
|
args.add(baseDN);
|
}
|
ProcessBuilder pb = new ProcessBuilder(args);
|
// Use the java args in the script.
|
Map<String, String> env = pb.environment();
|
env.put("RECURSIVE_LOCAL_CALL", "true");
|
try
|
{
|
ProcessReader outReader = null;
|
ProcessReader errReader = null;
|
Process process = pb.start();
|
outReader = new ProcessReader(process, getOutputStream(), false);
|
errReader = new ProcessReader(process, getErrorStream(), true);
|
|
outReader.startReading();
|
errReader.startReading();
|
|
int code = process.waitFor();
|
for (ReplicationCliReturnCode c : ReplicationCliReturnCode.values())
|
{
|
if (c.getReturnCode() == code)
|
{
|
returnCode = c;
|
break;
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
Message msg = ERR_LAUNCHING_PURGE_HISTORICAL.get();
|
ReplicationCliReturnCode code = ERROR_LAUNCHING_PURGE_HISTORICAL;
|
throw new ReplicationCliException(
|
getThrowableMsg(msg, e), code, e);
|
}
|
}
|
else
|
{
|
printPurgeProgressMessage(uData);
|
LocalPurgeHistorical localPurgeHistorical =
|
new LocalPurgeHistorical(uData, this, formatter,
|
argParser.getConfigFile(),
|
argParser.getConfigClass());
|
returnCode = localPurgeHistorical.execute();
|
|
if (returnCode == ReplicationCliReturnCode.SUCCESSFUL)
|
{
|
printSuccessMessage(uData, null);
|
}
|
}
|
return returnCode;
|
}
|
|
private void printPurgeHistoricalEquivalentIfRequired(
|
PurgeHistoricalUserData uData)
|
{
|
if (mustPrintCommandBuilder())
|
{
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.PURGE_HISTORICAL_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
}
|
|
private ReplicationCliReturnCode purgeHistoricalRemotely(
|
PurgeHistoricalUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctx = null;
|
|
// Connect to the provided server
|
try
|
{
|
ctx = createAdministrativeContext(uData.getHostName(), uData.getPort(),
|
useSSL, useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort =
|
getServerRepresentation(uData.getHostName(), uData.getPort());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
|
if (ctx != null)
|
{
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
checkSuffixesForPurgeHistorical(baseDNs, ctx, false);
|
if (!baseDNs.isEmpty())
|
{
|
uData.setBaseDNs(baseDNs);
|
printPurgeHistoricalEquivalentIfRequired(uData);
|
|
returnValue = SUCCESSFUL;
|
try
|
{
|
returnValue = purgeHistoricalRemoteTask(ctx, uData);
|
}
|
catch (ReplicationCliException rce)
|
{
|
println();
|
println(getCriticalExceptionMessage(rce));
|
returnValue = rce.getErrorCode();
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
else
|
{
|
returnValue = HISTORICAL_CANNOT_BE_PURGED_ON_BASEDN;
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
return returnValue;
|
}
|
|
private void printSuccessMessage(PurgeHistoricalUserData uData, String taskID)
|
{
|
printlnProgress();
|
if (!uData.isOnline())
|
{
|
printProgress(
|
INFO_PROGRESS_PURGE_HISTORICAL_FINISHED_PROCEDURE.get());
|
}
|
else if (uData.getTaskSchedule().isStartNow())
|
{
|
printProgress(INFO_TASK_TOOL_TASK_SUCESSFULL.get(
|
INFO_PURGE_HISTORICAL_TASK_NAME.get(),
|
taskID));
|
}
|
else if (uData.getTaskSchedule().getStartDate() != null)
|
{
|
printProgress(INFO_TASK_TOOL_TASK_SCHEDULED_FUTURE.get(
|
INFO_PURGE_HISTORICAL_TASK_NAME.get(),
|
taskID,
|
StaticUtils.formatDateTimeString(
|
uData.getTaskSchedule().getStartDate())));
|
}
|
else
|
{
|
printProgress(INFO_TASK_TOOL_RECURRING_TASK_SCHEDULED.get(
|
INFO_PURGE_HISTORICAL_TASK_NAME.get(),
|
taskID));
|
}
|
|
printlnProgress();
|
}
|
|
/**
|
* Launches the purge historical operation using the
|
* provided connection.
|
* @param ctx the connection to the server.
|
* @throws ReplicationCliException if there is an error performing the
|
* operation.
|
*/
|
private ReplicationCliReturnCode purgeHistoricalRemoteTask(
|
InitialLdapContext ctx,
|
PurgeHistoricalUserData uData)
|
throws ReplicationCliException
|
{
|
printPurgeProgressMessage(uData);
|
ReplicationCliReturnCode returnCode = ReplicationCliReturnCode.SUCCESSFUL;
|
boolean taskCreated = false;
|
int i = 0;
|
boolean isOver = false;
|
String dn = null;
|
String taskID = null;
|
while (!taskCreated)
|
{
|
BasicAttributes attrs = PurgeHistoricalUserData.getTaskAttributes(uData);
|
dn = PurgeHistoricalUserData.getTaskDN(attrs);
|
taskID = PurgeHistoricalUserData.getTaskID(attrs);
|
try
|
{
|
DirContext dirCtx = ctx.createSubcontext(dn, attrs);
|
taskCreated = true;
|
LOG.log(Level.INFO, "created task entry: "+attrs);
|
dirCtx.close();
|
}
|
catch (NameAlreadyBoundException x)
|
{
|
}
|
catch (NamingException ne)
|
{
|
LOG.log(Level.SEVERE, "Error creating task "+attrs, ne);
|
Message msg = ERR_LAUNCHING_PURGE_HISTORICAL.get();
|
ReplicationCliReturnCode code = ERROR_LAUNCHING_PURGE_HISTORICAL;
|
throw new ReplicationCliException(
|
getThrowableMsg(msg, ne), code, ne);
|
}
|
i++;
|
}
|
// Wait until it is over
|
SearchControls searchControls = new SearchControls();
|
searchControls.setCountLimit(1);
|
searchControls.setSearchScope(
|
SearchControls. OBJECT_SCOPE);
|
String filter = "objectclass=*";
|
searchControls.setReturningAttributes(
|
new String[] {
|
"ds-task-log-message",
|
"ds-task-state",
|
"ds-task-purge-conflicts-historical-purged-values-count",
|
"ds-task-purge-conflicts-historical-purge-completed-in-time",
|
"ds-task-purge-conflicts-historical-purge-completed-in-time",
|
"ds-task-purge-conflicts-historical-last-purged-changenumber"
|
});
|
String lastLogMsg = null;
|
|
// Polling only makes sense when we are recurrently scheduling a task
|
// or the task is being executed now.
|
while (!isOver && (uData.getTaskSchedule().getStartDate() == null))
|
{
|
try
|
{
|
Thread.sleep(500);
|
}
|
catch (Throwable t)
|
{
|
}
|
try
|
{
|
NamingEnumeration<SearchResult> res =
|
ctx.search(dn, filter, searchControls);
|
SearchResult sr = null;
|
try
|
{
|
sr = res.next();
|
}
|
finally
|
{
|
res.close();
|
}
|
String logMsg = getFirstValue(sr, "ds-task-log-message");
|
if (logMsg != null)
|
{
|
if (!logMsg.equals(lastLogMsg))
|
{
|
LOG.log(Level.INFO, logMsg);
|
lastLogMsg = logMsg;
|
}
|
}
|
InstallerHelper helper = new InstallerHelper();
|
String state = getFirstValue(sr, "ds-task-state");
|
|
if (helper.isDone(state) || helper.isStoppedByError(state))
|
{
|
isOver = true;
|
Message errorMsg;
|
String server = ConnectionUtils.getHostPort(ctx);
|
if (lastLogMsg == null)
|
{
|
errorMsg = INFO_ERROR_DURING_PURGE_HISTORICAL_NO_LOG.get(
|
state, server);
|
}
|
else
|
{
|
errorMsg = INFO_ERROR_DURING_PURGE_HISTORICAL_LOG.get(
|
lastLogMsg, state, server);
|
}
|
|
if (helper.isCompletedWithErrors(state))
|
{
|
LOG.log(Level.WARNING, "Completed with error: "+errorMsg);
|
println(errorMsg);
|
}
|
else if (!helper.isSuccessful(state) ||
|
helper.isStoppedByError(state))
|
{
|
LOG.log(Level.WARNING, "Error: "+errorMsg);
|
ReplicationCliReturnCode code = ERROR_LAUNCHING_PURGE_HISTORICAL;
|
throw new ReplicationCliException(errorMsg, code, null);
|
}
|
}
|
}
|
catch (NameNotFoundException x)
|
{
|
isOver = true;
|
}
|
catch (NamingException ne)
|
{
|
Message msg = ERR_POOLING_PURGE_HISTORICAL.get();
|
throw new ReplicationCliException(
|
getThrowableMsg(msg, ne), ERROR_CONNECTING, ne);
|
}
|
}
|
|
if (returnCode == ReplicationCliReturnCode.SUCCESSFUL)
|
{
|
printSuccessMessage(uData, taskID);
|
}
|
return returnCode;
|
}
|
|
/**
|
* Checks that historical can actually be purged in the provided baseDNs
|
* for the server.
|
* @param suffixes the suffixes provided by the user. This Collection is
|
* updated with the base DNs that the user provided interactively.
|
* @param ctx connection to the server.
|
* @param interactive whether to ask the user to provide interactively
|
* base DNs if none of the provided base DNs can be purged.
|
*/
|
private void checkSuffixesForPurgeHistorical(Collection<String> suffixes,
|
InitialLdapContext ctx, boolean interactive)
|
{
|
TreeSet<String> availableSuffixes = new TreeSet<String>();
|
TreeSet<String> notReplicatedSuffixes = new TreeSet<String>();
|
|
Collection<ReplicaDescriptor> replicas = getReplicas(ctx);
|
for (ReplicaDescriptor rep : replicas)
|
{
|
String dn = rep.getSuffix().getDN();
|
if (rep.isReplicated())
|
{
|
availableSuffixes.add(dn);
|
}
|
else
|
{
|
notReplicatedSuffixes.add(dn);
|
}
|
}
|
|
checkSuffixesForPurgeHistorical(suffixes, availableSuffixes,
|
notReplicatedSuffixes, interactive);
|
}
|
|
/**
|
* Checks that historical can actually be purged in the provided baseDNs
|
* for the local server.
|
* @param suffixes the suffixes provided by the user. This Collection is
|
* updated with the base DNs that the user provided interactively.
|
* @param interactive whether to ask the user to provide interactively
|
* base DNs if none of the provided base DNs can be purged.
|
*/
|
private void checkSuffixesForLocalPurgeHistorical(Collection<String> suffixes,
|
boolean interactive)
|
{
|
TreeSet<String> availableSuffixes = new TreeSet<String>();
|
TreeSet<String> notReplicatedSuffixes = new TreeSet<String>();
|
|
Collection<ReplicaDescriptor> replicas = getLocalReplicas();
|
|
for (ReplicaDescriptor rep : replicas)
|
{
|
String dn = rep.getSuffix().getDN();
|
if (rep.isReplicated())
|
{
|
availableSuffixes.add(dn);
|
}
|
else
|
{
|
notReplicatedSuffixes.add(dn);
|
}
|
}
|
|
checkSuffixesForPurgeHistorical(suffixes, availableSuffixes,
|
notReplicatedSuffixes, interactive);
|
}
|
|
private Collection<ReplicaDescriptor> getLocalReplicas()
|
{
|
Collection<ReplicaDescriptor> replicas = new ArrayList<ReplicaDescriptor>();
|
ConfigFromFile configFromFile = new ConfigFromFile();
|
configFromFile.readConfiguration();
|
Collection<BackendDescriptor> backends = configFromFile.getBackends();
|
for (BackendDescriptor backend : backends)
|
{
|
for (BaseDNDescriptor baseDN : backend.getBaseDns())
|
{
|
SuffixDescriptor suffix = new SuffixDescriptor();
|
suffix.setDN(baseDN.getDn().toString());
|
|
ReplicaDescriptor replica = new ReplicaDescriptor();
|
|
if (baseDN.getType() == BaseDNDescriptor.Type.REPLICATED)
|
{
|
replica.setReplicationId(baseDN.getReplicaID());
|
}
|
else
|
{
|
replica.setReplicationId(-1);
|
}
|
replica.setBackendName(backend.getBackendID());
|
replica.setSuffix(suffix);
|
suffix.setReplicas(Collections.singleton(replica));
|
|
replicas.add(replica);
|
}
|
}
|
return replicas;
|
}
|
|
private void checkSuffixesForPurgeHistorical(Collection<String> suffixes,
|
Collection<String> availableSuffixes,
|
Collection<String> notReplicatedSuffixes,
|
boolean interactive)
|
{
|
if (availableSuffixes.size() == 0)
|
{
|
println();
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_PURGE_HISTORICAL.get());
|
suffixes.clear();
|
}
|
else
|
{
|
// Verify that the provided suffixes are configured in the servers.
|
TreeSet<String> notFound = new TreeSet<String>();
|
TreeSet<String> alreadyNotReplicated = new TreeSet<String>();
|
for (String dn : suffixes)
|
{
|
boolean found = false;
|
for (String dn1 : availableSuffixes)
|
{
|
if (Utils.areDnsEqual(dn, dn1))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
boolean notReplicated = false;
|
for (String s : notReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s, dn))
|
{
|
notReplicated = true;
|
break;
|
}
|
}
|
if (notReplicated)
|
{
|
alreadyNotReplicated.add(dn);
|
}
|
else
|
{
|
notFound.add(dn);
|
}
|
}
|
}
|
suffixes.removeAll(notFound);
|
suffixes.removeAll(alreadyNotReplicated);
|
if (notFound.size() > 0)
|
{
|
println();
|
println(ERR_REPLICATION_PURGE_SUFFIXES_NOT_FOUND.get(
|
Utils.getStringFromCollection(notFound,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (interactive)
|
{
|
boolean confirmationLimitReached = false;
|
while (suffixes.isEmpty())
|
{
|
boolean noSchemaOrAds = false;
|
for (String s: availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(s, ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(s, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(s, Constants.REPLICATION_CHANGES_DN))
|
{
|
noSchemaOrAds = true;
|
}
|
}
|
if (!noSchemaOrAds)
|
{
|
// In interactive mode we do not propose to manage the
|
// administration suffix.
|
println();
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_PURGE_HISTORICAL.get());
|
break;
|
}
|
else
|
{
|
println();
|
println(ERR_NO_SUFFIXES_SELECTED_TO_PURGE_HISTORICAL.get());
|
for (String dn : availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(dn,
|
ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(dn, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(dn, Constants.REPLICATION_CHANGES_DN))
|
{
|
try
|
{
|
if (askConfirmation(
|
INFO_REPLICATION_PURGE_HISTORICAL_PROMPT.get(dn), true,
|
LOG))
|
{
|
suffixes.add(dn);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
confirmationLimitReached = true;
|
break;
|
}
|
}
|
}
|
}
|
if (confirmationLimitReached)
|
{
|
suffixes.clear();
|
break;
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* Based on the data provided in the command-line it initializes replication
|
* between two servers.
|
* @return the error code if the operation failed and SUCCESSFUL if it was
|
* successful.
|
*/
|
private ReplicationCliReturnCode initializeReplication()
|
{
|
ReplicationCliReturnCode returnValue;
|
InitializeReplicationUserData uData = new InitializeReplicationUserData();
|
if (argParser.isInteractive())
|
{
|
if (promptIfRequired(uData))
|
{
|
returnValue = initializeReplication(uData);
|
}
|
else
|
{
|
returnValue = USER_CANCELLED;
|
}
|
}
|
else
|
{
|
initializeWithArgParser(uData);
|
returnValue = initializeReplication(uData);
|
}
|
return returnValue;
|
}
|
|
|
/**
|
* Updates the contents of the provided PurgeHistoricalUserData
|
* object with the information provided in the command-line. If some
|
* information is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user canceled the operation.
|
*/
|
private boolean promptIfRequired(PurgeHistoricalUserData uData)
|
{
|
boolean cancelled = false;
|
boolean onlineSet = false;
|
|
boolean firstTry = true;
|
Boolean serverRunning = null;
|
|
InitialLdapContext ctx = null;
|
while (!cancelled && !onlineSet)
|
{
|
boolean promptForConnection = false;
|
if (argParser.connectionArgumentsPresent() && firstTry)
|
{
|
promptForConnection = true;
|
}
|
else
|
{
|
if (serverRunning == null)
|
{
|
serverRunning = Utilities.isServerRunning(
|
Installation.getLocal().getInstanceDirectory());
|
}
|
if (!serverRunning)
|
{
|
try
|
{
|
printlnProgress();
|
promptForConnection =
|
!askConfirmation(
|
INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_PROMPT.get(),
|
true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
else
|
{
|
promptForConnection = true;
|
}
|
}
|
if (promptForConnection)
|
{
|
try
|
{
|
ci.run();
|
String host = ci.getHostName();
|
int port = ci.getPortNumber();
|
String adminUid = ci.getAdministratorUID();
|
String adminPwd = ci.getBindPassword();
|
|
ctx = createInitialLdapContextInteracting(ci);
|
if (ctx == null)
|
{
|
cancelled = true;
|
}
|
else
|
{
|
uData.setOnline(true);
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
uData.setHostName(host);
|
uData.setPort(port);
|
onlineSet = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
else
|
{
|
uData.setOnline(false);
|
onlineSet = true;
|
}
|
firstTry = false;
|
}
|
|
if (!cancelled)
|
{
|
int maximumDuration = argParser.getMaximumDuration();
|
/* Prompt for maximum duration */
|
if (!argParser.maximumDurationArg.isPresent())
|
{
|
printlnProgress();
|
maximumDuration = askInteger(
|
INFO_REPLICATION_PURGE_HISTORICAL_MAXIMUM_DURATION_PROMPT.get(),
|
argParser.getDefaultMaximumDuration(), LOG);
|
}
|
uData.setMaximumDuration(maximumDuration);
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
if (uData.isOnline())
|
{
|
checkSuffixesForPurgeHistorical(suffixes, ctx, true);
|
}
|
else
|
{
|
checkSuffixesForLocalPurgeHistorical(suffixes, true);
|
}
|
cancelled = suffixes.isEmpty();
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (uData.isOnline() && !cancelled)
|
{
|
List<? extends TaskEntry> taskEntries = getAvailableTaskEntries(ctx);
|
|
TaskScheduleInteraction interaction =
|
new TaskScheduleInteraction(uData.getTaskSchedule(), argParser.taskArgs,
|
this, formatter, taskEntries,
|
INFO_PURGE_HISTORICAL_TASK_NAME.get());
|
try
|
{
|
interaction.run();
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return !cancelled;
|
}
|
|
private List<? extends TaskEntry> getAvailableTaskEntries(
|
InitialLdapContext ctx)
|
{
|
List<TaskEntry> taskEntries = new ArrayList<TaskEntry>();
|
List<OpenDsException> exceptions = new ArrayList<OpenDsException>();
|
ConfigFromDirContext cfg = new ConfigFromDirContext();
|
cfg.updateTaskInformation(ctx, exceptions, taskEntries);
|
for (OpenDsException ode : exceptions)
|
{
|
LOG.log(Level.WARNING, "Error retrieving task entries: "+ode, ode);
|
}
|
return taskEntries;
|
}
|
|
/**
|
* Updates the contents of the provided EnableReplicationUserData object
|
* with the information provided in the command-line. If some information
|
* is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
* @throws ReplicationCliException if a critical error occurs reading the
|
* ADS.
|
*/
|
private boolean promptIfRequired(EnableReplicationUserData uData)
|
throws ReplicationCliException
|
{
|
boolean cancelled = false;
|
|
boolean administratorDefined = false;
|
|
ci.setUseAdminOrBindDn(true);
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
|
/*
|
* Try to connect to the first server.
|
*/
|
String host1 = argParser.getHostName1();
|
int port1 = argParser.getPort1();
|
String bindDn1 = argParser.getBindDn1();
|
String pwd1 = argParser.getBindPassword1();
|
String pwd = null;
|
LinkedHashMap<String, String> pwdFile = null;
|
if (argParser.bindPassword1Arg.isPresent())
|
{
|
pwd = argParser.bindPassword1Arg.getValue();
|
}
|
else if (argParser.bindPasswordFile1Arg.isPresent())
|
{
|
pwdFile = argParser.bindPasswordFile1Arg.getNameToValueMap();
|
}
|
else if (bindDn1 == null)
|
{
|
pwd = adminPwd;
|
if (argParser.getSecureArgsList().bindPasswordFileArg.isPresent())
|
{
|
pwdFile = argParser.getSecureArgsList().bindPasswordFileArg.
|
getNameToValueMap();
|
}
|
}
|
|
/*
|
* Use a copy of the argument properties since the map might be cleared
|
* in initializeGlobalArguments.
|
*/
|
ci.initializeGlobalArguments(host1, port1, adminUid,
|
bindDn1, pwd,
|
pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile));
|
InitialLdapContext ctx1 = null;
|
|
while ((ctx1 == null) && !cancelled)
|
{
|
try
|
{
|
ci.setHeadingMessage(
|
INFO_REPLICATION_ENABLE_HOST1_CONNECTION_PARAMETERS.get());
|
ci.run();
|
host1 = ci.getHostName();
|
port1 = ci.getPortNumber();
|
if (ci.getProvidedAdminUID() != null)
|
{
|
adminUid = ci.getProvidedAdminUID();
|
if (ci.getProvidedBindDN() == null)
|
{
|
// If the explicit bind DN is not null, the password corresponds
|
// to that bind DN. We are in the case where the user provides
|
// bind DN on first server and admin UID globally.
|
adminPwd = ci.getBindPassword();
|
}
|
}
|
bindDn1 = ci.getBindDN();
|
pwd1 = ci.getBindPassword();
|
|
ctx1 = createInitialLdapContextInteracting(ci);
|
|
if (ctx1 == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
|
if (!cancelled)
|
{
|
uData.setHostName1(host1);
|
uData.setPort1(port1);
|
uData.setBindDn1(bindDn1);
|
uData.setPwd1(pwd1);
|
}
|
int replicationPort1 = -1;
|
boolean secureReplication1 = argParser.isSecureReplication1();
|
boolean configureReplicationServer1 =
|
!argParser.noReplicationServer1Arg.isPresent();
|
boolean configureReplicationDomain1 =
|
!argParser.onlyReplicationServer1Arg.isPresent();
|
if (ctx1 != null)
|
{
|
int repPort1 = getReplicationPort(ctx1);
|
boolean replicationServer1Configured = repPort1 > 0;
|
if (replicationServer1Configured && !configureReplicationServer1)
|
{
|
try
|
{
|
if (!askConfirmation(
|
INFO_REPLICATION_SERVER_CONFIGURED_WARNING_PROMPT.
|
get(ConnectionUtils.getHostPort(ctx1), repPort1), false, LOG))
|
{
|
cancelled = true;
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
|
// Try to get the replication port for server 1 only if it is required.
|
if (!replicationServer1Configured && configureReplicationServer1 &&
|
!cancelled)
|
{
|
if (argParser.advancedArg.isPresent() &&
|
configureReplicationDomain1)
|
{
|
// Only ask if the replication domain will be configured (if not
|
// the replication server MUST be configured).
|
try
|
{
|
configureReplicationServer1 = askConfirmation(
|
INFO_REPLICATION_ENABLE_REPLICATION_SERVER1_PROMPT.get(),
|
true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
}
|
if (!cancelled &&
|
!replicationServer1Configured && configureReplicationServer1)
|
{
|
boolean tryWithDefault = argParser.getReplicationPort1() != -1;
|
while (replicationPort1 == -1)
|
{
|
if (tryWithDefault)
|
{
|
replicationPort1 = argParser.getReplicationPort1();
|
tryWithDefault = false;
|
}
|
else
|
{
|
replicationPort1 = askPort(
|
INFO_REPLICATION_ENABLE_REPLICATIONPORT1_PROMPT.get(),
|
argParser.getDefaultReplicationPort1(), LOG);
|
println();
|
}
|
if (!argParser.skipReplicationPortCheck() && Utils.isLocalHost(host1))
|
{
|
if (!SetupUtils.canUseAsPort(replicationPort1))
|
{
|
println();
|
println(getCannotBindToPortError(replicationPort1));
|
println();
|
replicationPort1 = -1;
|
}
|
}
|
else
|
{
|
// This is something that we must do in any case... this test is
|
// already included when we call SetupUtils.canUseAsPort
|
if (replicationPort1 == port1)
|
{
|
println();
|
println(
|
ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
|
host1, String.valueOf(replicationPort1)));
|
println();
|
replicationPort1 = -1;
|
}
|
}
|
}
|
if (!secureReplication1)
|
{
|
try
|
{
|
secureReplication1 =
|
askConfirmation(INFO_REPLICATION_ENABLE_SECURE1_PROMPT.get(
|
String.valueOf(replicationPort1)), false, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
}
|
if (!cancelled &&
|
configureReplicationDomain1 &&
|
configureReplicationServer1 &&
|
argParser.advancedArg.isPresent())
|
{
|
// Only necessary to ask if the replication server will be configured
|
try
|
{
|
configureReplicationDomain1 = askConfirmation(
|
INFO_REPLICATION_ENABLE_REPLICATION_DOMAIN1_PROMPT.get(),
|
true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
// If the server contains an ADS. Try to load it and only load it: if
|
// there are issues with the ADS they will be encountered in the
|
// enableReplication(EnableReplicationUserData) method. Here we have
|
// to load the ADS to ask the user to accept the certificates and
|
// eventually admin authentication data.
|
InitialLdapContext[] aux = new InitialLdapContext[] {ctx1};
|
cancelled = !loadADSAndAcceptCertificates(aux, uData, true);
|
ctx1 = aux[0];
|
if (!cancelled)
|
{
|
administratorDefined |= hasAdministrator(ctx1);
|
if (uData.getAdminPwd() != null)
|
{
|
adminPwd = uData.getAdminPwd();
|
}
|
}
|
}
|
uData.setReplicationPort1(replicationPort1);
|
uData.setSecureReplication1(secureReplication1);
|
uData.setConfigureReplicationServer1(configureReplicationServer1);
|
uData.setConfigureReplicationDomain1(configureReplicationDomain1);
|
firstServerCommandBuilder = new CommandBuilder(null);
|
if (mustPrintCommandBuilder())
|
{
|
firstServerCommandBuilder.append(ci.getCommandBuilder());
|
}
|
|
/*
|
* Prompt for information on the second server.
|
*/
|
String host2 = null;
|
int port2 = -1;
|
String bindDn2 = null;
|
String pwd2 = null;
|
ci.resetHeadingDisplayed();
|
|
boolean doNotDisplayFirstError = false;
|
|
if (!cancelled)
|
{
|
host2 = argParser.getHostName2();
|
port2 = argParser.getPort2();
|
bindDn2 = argParser.getBindDn2();
|
pwd2 = argParser.getBindPassword2();
|
|
pwdFile = null;
|
pwd = null;
|
if (argParser.bindPassword2Arg.isPresent())
|
{
|
pwd = argParser.bindPassword2Arg.getValue();
|
}
|
else if (argParser.bindPasswordFile2Arg.isPresent())
|
{
|
pwdFile = argParser.bindPasswordFile2Arg.getNameToValueMap();
|
}
|
else if (bindDn2 == null)
|
{
|
doNotDisplayFirstError = true;
|
pwd = adminPwd;
|
if (argParser.getSecureArgsList().bindPasswordFileArg.isPresent())
|
{
|
pwdFile = argParser.getSecureArgsList().bindPasswordFileArg.
|
getNameToValueMap();
|
}
|
}
|
|
/*
|
* Use a copy of the argument properties since the map might be cleared
|
* in initializeGlobalArguments.
|
*/
|
ci.initializeGlobalArguments(host2, port2, adminUid,
|
bindDn2, pwd,
|
pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile));
|
}
|
InitialLdapContext ctx2 = null;
|
|
while ((ctx2 == null) && !cancelled)
|
{
|
try
|
{
|
ci.setHeadingMessage(
|
INFO_REPLICATION_ENABLE_HOST2_CONNECTION_PARAMETERS.get());
|
ci.run();
|
host2 = ci.getHostName();
|
port2 = ci.getPortNumber();
|
if (ci.getProvidedAdminUID() != null)
|
{
|
adminUid = ci.getProvidedAdminUID();
|
if (ci.getProvidedBindDN() == null)
|
{
|
// If the explicit bind DN is not null, the password corresponds
|
// to that bind DN. We are in the case where the user provides
|
// bind DN on first server and admin UID globally.
|
adminPwd = ci.getBindPassword();
|
}
|
}
|
bindDn2 = ci.getBindDN();
|
pwd2 = ci.getBindPassword();
|
|
boolean error = false;
|
if (host1.equalsIgnoreCase(host2))
|
{
|
if (port1 == port2)
|
{
|
port2 = -1;
|
Message message = ERR_REPLICATION_ENABLE_SAME_SERVER_PORT.get(
|
host1, String.valueOf(port1));
|
println();
|
println(message);
|
println();
|
error = true;
|
}
|
}
|
|
if (!error)
|
{
|
ctx2 = createInitialLdapContextInteracting(ci, true);
|
|
if (ctx2 == null)
|
{
|
cancelled = true;
|
}
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
if (!doNotDisplayFirstError)
|
{
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
else
|
{
|
// Reset only the credential parameters.
|
ci.resetConnectionArguments();
|
ci.initializeGlobalArguments(host2, port2, null, null, null, null);
|
}
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
finally
|
{
|
doNotDisplayFirstError = false;
|
}
|
}
|
|
if (!cancelled)
|
{
|
uData.setHostName2(host2);
|
uData.setPort2(port2);
|
uData.setBindDn2(bindDn2);
|
uData.setPwd2(pwd2);
|
}
|
|
int replicationPort2 = -1;
|
boolean secureReplication2 = argParser.isSecureReplication2();
|
boolean configureReplicationServer2 =
|
!argParser.noReplicationServer2Arg.isPresent();
|
boolean configureReplicationDomain2 =
|
!argParser.onlyReplicationServer2Arg.isPresent();
|
if (ctx2 != null)
|
{
|
int repPort2 = getReplicationPort(ctx2);
|
boolean replicationServer2Configured = repPort2 > 0;
|
if (replicationServer2Configured && !configureReplicationServer2)
|
{
|
try
|
{
|
if (!askConfirmation(
|
INFO_REPLICATION_SERVER_CONFIGURED_WARNING_PROMPT.
|
get(ConnectionUtils.getHostPort(ctx2), repPort2), false, LOG))
|
{
|
cancelled = true;
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
|
// Try to get the replication port for server 2 only if it is required.
|
if (!replicationServer2Configured && configureReplicationServer2 &&
|
!cancelled)
|
{
|
// Only ask if the replication domain will be configured (if not the
|
// replication server MUST be configured).
|
if (argParser.advancedArg.isPresent() &&
|
configureReplicationDomain2)
|
{
|
try
|
{
|
configureReplicationServer2 = askConfirmation(
|
INFO_REPLICATION_ENABLE_REPLICATION_SERVER2_PROMPT.get(),
|
true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
if (!cancelled &&
|
!replicationServer2Configured && configureReplicationServer2)
|
{
|
boolean tryWithDefault = argParser.getReplicationPort2() != -1;
|
while (replicationPort2 == -1)
|
{
|
if (tryWithDefault)
|
{
|
replicationPort2 = argParser.getReplicationPort2();
|
tryWithDefault = false;
|
}
|
else
|
{
|
replicationPort2 = askPort(
|
INFO_REPLICATION_ENABLE_REPLICATIONPORT2_PROMPT.get(),
|
argParser.getDefaultReplicationPort2(), LOG);
|
println();
|
}
|
if (!argParser.skipReplicationPortCheck() &&
|
Utils.isLocalHost(host2))
|
{
|
if (!SetupUtils.canUseAsPort(replicationPort2))
|
{
|
println();
|
println(getCannotBindToPortError(replicationPort2));
|
println();
|
replicationPort2 = -1;
|
}
|
}
|
else
|
{
|
// This is something that we must do in any case... this test is
|
// already included when we call SetupUtils.canUseAsPort
|
if (replicationPort2 == port2)
|
{
|
println();
|
println(
|
ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
|
host2, String.valueOf(replicationPort2)));
|
replicationPort2 = -1;
|
}
|
}
|
if (host1.equalsIgnoreCase(host2))
|
{
|
if ((replicationPort1 > 0) &&
|
(replicationPort1 == replicationPort2))
|
{
|
println();
|
println(ERR_REPLICATION_SAME_REPLICATION_PORT.get(
|
String.valueOf(replicationPort2), host1));
|
println();
|
replicationPort2 = -1;
|
}
|
}
|
}
|
if (!secureReplication2)
|
{
|
try
|
{
|
secureReplication2 =
|
askConfirmation(INFO_REPLICATION_ENABLE_SECURE2_PROMPT.get(
|
String.valueOf(replicationPort2)), false, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
}
|
}
|
if (!cancelled &&
|
configureReplicationDomain2 &&
|
configureReplicationServer2 &&
|
argParser.advancedArg.isPresent())
|
{
|
// Only necessary to ask if the replication server will be configured
|
try
|
{
|
configureReplicationDomain2 = askConfirmation(
|
INFO_REPLICATION_ENABLE_REPLICATION_DOMAIN2_PROMPT.get(),
|
true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
// If the server contains an ADS. Try to load it and only load it: if
|
// there are issues with the ADS they will be encountered in the
|
// enableReplication(EnableReplicationUserData) method. Here we have
|
// to load the ADS to ask the user to accept the certificates.
|
InitialLdapContext[] aux = new InitialLdapContext[] {ctx2};
|
cancelled = !loadADSAndAcceptCertificates(aux, uData, false);
|
ctx2 = aux[0];
|
if (!cancelled)
|
{
|
administratorDefined |= hasAdministrator(ctx2);
|
}
|
}
|
uData.setReplicationPort2(replicationPort2);
|
uData.setSecureReplication2(secureReplication2);
|
uData.setConfigureReplicationServer2(configureReplicationServer2);
|
uData.setConfigureReplicationDomain2(configureReplicationDomain2);
|
|
// If the adminUid and adminPwd are not set in the EnableReplicationUserData
|
// object, that means that there are no administrators and that they
|
// must be created. The adminUId and adminPwd are updated inside
|
// loadADSAndAcceptCertificates.
|
boolean promptedForAdmin = false;
|
|
// There is a case where we haven't had need for the administrator
|
// credentials even if the administrators are defined: where all the servers
|
// can be accessed with another user (for instance if all the server have
|
// defined cn=directory manager and all the entries have the same password).
|
if (!cancelled && (uData.getAdminUid() == null) && !administratorDefined)
|
{
|
if (adminUid == null)
|
{
|
println(INFO_REPLICATION_ENABLE_ADMINISTRATOR_MUST_BE_CREATED.get());
|
promptedForAdmin = true;
|
adminUid= askForAdministratorUID(
|
argParser.getDefaultAdministratorUID(), LOG);
|
println();
|
}
|
uData.setAdminUid(adminUid);
|
}
|
|
if (uData.getAdminPwd() == null)
|
{
|
uData.setAdminPwd(adminPwd);
|
}
|
if (!cancelled && (uData.getAdminPwd() == null) && !administratorDefined)
|
{
|
adminPwd = null;
|
int nPasswordPrompts = 0;
|
while (adminPwd == null)
|
{
|
if (nPasswordPrompts > CONFIRMATION_MAX_TRIES)
|
{
|
println(ERR_CONFIRMATION_TRIES_LIMIT_REACHED.get(
|
CONFIRMATION_MAX_TRIES));
|
cancelled = true;
|
break;
|
}
|
nPasswordPrompts ++;
|
if (!promptedForAdmin)
|
{
|
println();
|
println(INFO_REPLICATION_ENABLE_ADMINISTRATOR_MUST_BE_CREATED.get());
|
println();
|
}
|
while (adminPwd == null)
|
{
|
adminPwd = askForAdministratorPwd(LOG);
|
println();
|
}
|
String adminPwdConfirm = null;
|
while (adminPwdConfirm == null)
|
{
|
adminPwdConfirm =
|
readPassword(INFO_ADMINISTRATOR_PWD_CONFIRM_PROMPT.get(), LOG);
|
println();
|
}
|
if (!adminPwd.equals(adminPwdConfirm))
|
{
|
println();
|
println(ERR_ADMINISTRATOR_PWD_DO_NOT_MATCH.get());
|
println();
|
adminPwd = null;
|
}
|
}
|
uData.setAdminPwd(adminPwd);
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
checkSuffixesForEnableReplication(suffixes, ctx1, ctx2, true, uData);
|
cancelled = suffixes.isEmpty();
|
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (ctx1 != null)
|
{
|
try
|
{
|
ctx1.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
if (ctx2 != null)
|
{
|
try
|
{
|
ctx2.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
uData.setReplicateSchema(!argParser.noSchemaReplication());
|
|
return !cancelled;
|
}
|
|
/**
|
* Updates the contents of the provided DisableReplicationUserData object
|
* with the information provided in the command-line. If some information
|
* is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
* @throws ReplicationCliException if there is a critical error reading the
|
* ADS.
|
*/
|
private boolean promptIfRequired(DisableReplicationUserData uData)
|
throws ReplicationCliException
|
{
|
boolean cancelled = false;
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
String bindDn = argParser.getBindDNToDisable();
|
|
// This is done because we want to ask explicitly for this
|
|
String host = argParser.getHostNameToDisable();
|
int port = argParser.getPortToDisable();
|
|
/*
|
* Try to connect to the server.
|
*/
|
InitialLdapContext ctx = null;
|
|
while ((ctx == null) && !cancelled)
|
{
|
try
|
{
|
ci.setUseAdminOrBindDn(true);
|
ci.run();
|
host = ci.getHostName();
|
port = ci.getPortNumber();
|
bindDn = ci.getProvidedBindDN();
|
adminUid = ci.getProvidedAdminUID();
|
adminPwd = ci.getBindPassword();
|
|
ctx = createInitialLdapContextInteracting(ci);
|
|
if (ctx == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
|
if (!cancelled)
|
{
|
uData.setHostName(host);
|
uData.setPort(port);
|
uData.setAdminUid(adminUid);
|
uData.setBindDn(bindDn);
|
uData.setAdminPwd(adminPwd);
|
}
|
if ((ctx != null) && (adminUid != null))
|
{
|
// If the server contains an ADS, try to load it and only load it: if
|
// there are issues with the ADS they will be encountered in the
|
// disableReplication(DisableReplicationUserData) method. Here we have
|
// to load the ADS to ask the user to accept the certificates and
|
// eventually admin authentication data.
|
InitialLdapContext[] aux = new InitialLdapContext[] {ctx};
|
cancelled = !loadADSAndAcceptCertificates(aux, uData, false);
|
ctx = aux[0];
|
}
|
|
boolean disableAll = argParser.disableAllArg.isPresent();
|
boolean disableReplicationServer =
|
argParser.disableReplicationServerArg.isPresent();
|
if (disableAll ||
|
(argParser.advancedArg.isPresent() &&
|
argParser.getBaseDNs().isEmpty() &&
|
!disableReplicationServer))
|
{
|
try
|
{
|
disableAll = askConfirmation(INFO_REPLICATION_PROMPT_DISABLE_ALL.get(),
|
disableAll, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
int repPort = getReplicationPort(ctx);
|
if (!disableAll &&
|
(argParser.advancedArg.isPresent() ||
|
disableReplicationServer))
|
{
|
if (repPort > 0)
|
{
|
try
|
{
|
disableReplicationServer = askConfirmation(
|
INFO_REPLICATION_PROMPT_DISABLE_REPLICATION_SERVER.get(repPort),
|
disableReplicationServer,
|
LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
}
|
if (disableReplicationServer && repPort < 0)
|
{
|
disableReplicationServer = false;
|
try
|
{
|
cancelled = askConfirmation(
|
INFO_REPLICATION_PROMPT_NO_REPLICATION_SERVER_TO_DISABLE.get(
|
ConnectionUtils.getHostPort(ctx)),
|
false,
|
LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
if (repPort > 0 && disableAll)
|
{
|
disableReplicationServer = true;
|
}
|
uData.setDisableAll(disableAll);
|
uData.setDisableReplicationServer(disableReplicationServer);
|
if (!cancelled && !disableAll)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
|
checkSuffixesForDisableReplication(suffixes, ctx, true,
|
!disableReplicationServer, !disableReplicationServer);
|
cancelled = suffixes.isEmpty() && !disableReplicationServer;
|
|
uData.setBaseDNs(suffixes);
|
|
if (!uData.disableReplicationServer() && repPort > 0 &&
|
disableAllBaseDns(ctx, uData) && !argParser.advancedArg.isPresent())
|
{
|
try
|
{
|
uData.setDisableReplicationServer(askConfirmation(
|
INFO_REPLICATION_DISABLE_ALL_SUFFIXES_DISABLE_REPLICATION_SERVER.get(
|
ConnectionUtils.getHostPort(ctx), repPort), true, LOG));
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
}
|
|
if (!cancelled)
|
{
|
// Ask for confirmation to disable if not already done.
|
boolean disableADS = false;
|
boolean disableSchema = false;
|
for (String dn : uData.getBaseDNs())
|
{
|
if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
|
{
|
disableADS = true;
|
}
|
else if (Utils.areDnsEqual(Constants.SCHEMA_DN, dn))
|
{
|
disableSchema = true;
|
}
|
}
|
if (disableADS)
|
{
|
println();
|
try
|
{
|
cancelled = !askConfirmation(INFO_REPLICATION_CONFIRM_DISABLE_ADS.get(
|
ADSContext.getAdministrationSuffixDN()), true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
if (disableSchema)
|
{
|
println();
|
try
|
{
|
cancelled = !askConfirmation(
|
INFO_REPLICATION_CONFIRM_DISABLE_SCHEMA.get(), true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
if (!disableSchema && !disableADS)
|
{
|
println();
|
try
|
{
|
if (uData.disableAll())
|
{
|
// Another confirmation is redundant: we already asked the user...
|
}
|
else
|
{
|
if (!uData.getBaseDNs().isEmpty())
|
{
|
cancelled = !askConfirmation(
|
INFO_REPLICATION_CONFIRM_DISABLE_GENERIC.get(), true,
|
LOG);
|
}
|
else
|
{
|
// Another confirmation for the replication server is redundant.
|
}
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return !cancelled;
|
}
|
|
/**
|
* Updates the contents of the provided InitializeAllReplicationUserData
|
* object with the information provided in the command-line. If some
|
* information is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
*/
|
private boolean promptIfRequired(InitializeAllReplicationUserData uData)
|
{
|
boolean cancelled = false;
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
|
String host = argParser.getHostNameToInitializeAll();
|
int port = argParser.getPortToInitializeAll();
|
|
/*
|
* Try to connect to the server.
|
*/
|
InitialLdapContext ctx = null;
|
|
while ((ctx == null) && !cancelled)
|
{
|
try
|
{
|
ci.setHeadingMessage(
|
INFO_REPLICATION_INITIALIZE_SOURCE_CONNECTION_PARAMETERS.get());
|
ci.run();
|
host = ci.getHostName();
|
port = ci.getPortNumber();
|
adminUid = ci.getAdministratorUID();
|
adminPwd = ci.getBindPassword();
|
|
ctx = createInitialLdapContextInteracting(ci);
|
|
if (ctx == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
if (!cancelled)
|
{
|
uData.setHostName(host);
|
uData.setPort(port);
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
checkSuffixesForInitializeReplication(suffixes, ctx, true);
|
cancelled = suffixes.isEmpty();
|
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (!cancelled)
|
{
|
// Ask for confirmation to initialize.
|
boolean initializeADS = false;
|
for (String dn : uData.getBaseDNs())
|
{
|
if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
|
{
|
initializeADS = true;
|
}
|
}
|
String hostPortSource = ConnectionUtils.getHostPort(ctx);
|
if (initializeADS)
|
{
|
println();
|
try
|
{
|
cancelled = !askConfirmation(
|
INFO_REPLICATION_CONFIRM_INITIALIZE_ALL_ADS.get(
|
ADSContext.getAdministrationSuffixDN(), hostPortSource), true,
|
LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
else
|
{
|
println();
|
try
|
{
|
cancelled = !askConfirmation(
|
INFO_REPLICATION_CONFIRM_INITIALIZE_ALL_GENERIC.get(
|
hostPortSource), true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return !cancelled;
|
}
|
|
/**
|
* Updates the contents of the provided PreExternalInitializationUserData
|
* object with the information provided in the command-line. If some
|
* information is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
*/
|
private boolean promptIfRequired(PreExternalInitializationUserData uData)
|
{
|
boolean cancelled = false;
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
|
String host = argParser.getHostNameToInitializeAll();
|
int port = argParser.getPortToInitializeAll();
|
|
/*
|
* Try to connect to the server.
|
*/
|
InitialLdapContext ctx = null;
|
|
while ((ctx == null) && !cancelled)
|
{
|
try
|
{
|
ci.run();
|
host = ci.getHostName();
|
port = ci.getPortNumber();
|
adminUid = ci.getAdministratorUID();
|
adminPwd = ci.getBindPassword();
|
|
ctx = createInitialLdapContextInteracting(ci);
|
|
if (ctx == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
if (!cancelled)
|
{
|
uData.setHostName(host);
|
uData.setPort(port);
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
checkSuffixesForInitializeReplication(suffixes, ctx, true);
|
cancelled = suffixes.isEmpty();
|
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return !cancelled;
|
}
|
|
/**
|
* Updates the contents of the provided PostExternalInitializationUserData
|
* object with the information provided in the command-line. If some
|
* information is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
*/
|
private boolean promptIfRequired(PostExternalInitializationUserData uData)
|
{
|
boolean cancelled = false;
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
|
String host = argParser.getHostNameToInitializeAll();
|
int port = argParser.getPortToInitializeAll();
|
|
/*
|
* Try to connect to the server.
|
*/
|
InitialLdapContext ctx = null;
|
|
while ((ctx == null) && !cancelled)
|
{
|
try
|
{
|
ci.run();
|
host = ci.getHostName();
|
port = ci.getPortNumber();
|
adminUid = ci.getAdministratorUID();
|
adminPwd = ci.getBindPassword();
|
|
ctx = createInitialLdapContextInteracting(ci);
|
|
if (ctx == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
if (!cancelled)
|
{
|
uData.setHostName(host);
|
uData.setPort(port);
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
checkSuffixesForInitializeReplication(suffixes, ctx, true);
|
cancelled = suffixes.isEmpty();
|
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return !cancelled;
|
}
|
|
/**
|
* Updates the contents of the provided StatusReplicationUserData object
|
* with the information provided in the command-line. If some information
|
* is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
* @throws ReplicationCliException if a critical error occurs reading the
|
* ADS.
|
*/
|
private boolean promptIfRequired(StatusReplicationUserData uData)
|
throws ReplicationCliException
|
{
|
boolean cancelled = false;
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
|
String host = argParser.getHostNameToStatus();
|
int port = argParser.getPortToStatus();
|
|
/*
|
* Try to connect to the server.
|
*/
|
InitialLdapContext ctx = null;
|
|
while ((ctx == null) && !cancelled)
|
{
|
try
|
{
|
ci.run();
|
host = ci.getHostName();
|
port = ci.getPortNumber();
|
adminUid = ci.getAdministratorUID();
|
adminPwd = ci.getBindPassword();
|
|
ctx = createInitialLdapContextInteracting(ci);
|
|
if (ctx == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
if (!cancelled)
|
{
|
uData.setHostName(host);
|
uData.setPort(port);
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
uData.setScriptFriendly(argParser.isScriptFriendly());
|
}
|
if (ctx != null)
|
{
|
// If the server contains an ADS, try to load it and only load it: if
|
// there are issues with the ADS they will be encountered in the
|
// statusReplication(StatusReplicationUserData) method. Here we have
|
// to load the ADS to ask the user to accept the certificates and
|
// eventually admin authentication data.
|
InitialLdapContext[] aux = new InitialLdapContext[] {ctx};
|
cancelled = !loadADSAndAcceptCertificates(aux, uData, false);
|
ctx = aux[0];
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return !cancelled;
|
}
|
|
/**
|
* Updates the contents of the provided InitializeReplicationUserData object
|
* with the information provided in the command-line. If some information
|
* is missing, ask the user to provide valid data.
|
* We assume that if this method is called we are in interactive mode.
|
* @param uData the object to be updated.
|
* @return <CODE>true</CODE> if the object was successfully updated and
|
* <CODE>false</CODE> if the user cancelled the operation.
|
*/
|
private boolean promptIfRequired(InitializeReplicationUserData uData)
|
{
|
boolean cancelled = false;
|
|
String adminPwd = argParser.getBindPasswordAdmin();
|
String adminUid = argParser.getAdministratorUID();
|
|
String hostSource = argParser.getHostNameSource();
|
int portSource = argParser.getPortSource();
|
|
LinkedHashMap<String, String> pwdFile = null;
|
|
if (argParser.getSecureArgsList().bindPasswordFileArg.isPresent())
|
{
|
pwdFile =
|
argParser.getSecureArgsList().bindPasswordFileArg.
|
getNameToValueMap();
|
}
|
|
|
/*
|
* Use a copy of the argument properties since the map might be cleared
|
* in initializeGlobalArguments.
|
*/
|
ci.initializeGlobalArguments(hostSource, portSource, adminUid, null,
|
adminPwd,
|
pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile));
|
/*
|
* Try to connect to the source server.
|
*/
|
InitialLdapContext ctxSource = null;
|
|
while ((ctxSource == null) && !cancelled)
|
{
|
try
|
{
|
ci.setHeadingMessage(
|
INFO_REPLICATION_INITIALIZE_SOURCE_CONNECTION_PARAMETERS.get());
|
ci.run();
|
hostSource = ci.getHostName();
|
portSource = ci.getPortNumber();
|
adminUid = ci.getAdministratorUID();
|
adminPwd = ci.getBindPassword();
|
|
ctxSource = createInitialLdapContextInteracting(ci);
|
|
if (ctxSource == null)
|
{
|
cancelled = true;
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
}
|
if (!cancelled)
|
{
|
uData.setHostNameSource(hostSource);
|
uData.setPortSource(portSource);
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
}
|
|
firstServerCommandBuilder = new CommandBuilder(null);
|
if (mustPrintCommandBuilder())
|
{
|
firstServerCommandBuilder.append(ci.getCommandBuilder());
|
}
|
|
/* Prompt for destination server credentials */
|
String hostDestination = argParser.getHostNameDestination();
|
int portDestination = argParser.getPortDestination();
|
|
/*
|
* Use a copy of the argument properties since the map might be cleared
|
* in initializeGlobalArguments.
|
*/
|
ci.initializeGlobalArguments(hostDestination, portDestination,
|
adminUid, null, adminPwd,
|
pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile));
|
/*
|
* Try to connect to the destination server.
|
*/
|
InitialLdapContext ctxDestination = null;
|
|
ci.resetHeadingDisplayed();
|
while ((ctxDestination == null) && !cancelled)
|
{
|
try
|
{
|
ci.setHeadingMessage(
|
INFO_REPLICATION_INITIALIZE_DESTINATION_CONNECTION_PARAMETERS.get());
|
ci.run();
|
hostDestination = ci.getHostName();
|
portDestination = ci.getPortNumber();
|
|
boolean error = false;
|
if (hostSource.equalsIgnoreCase(hostDestination))
|
{
|
if (portSource == portDestination)
|
{
|
portDestination = -1;
|
Message message = ERR_REPLICATION_INITIALIZE_SAME_SERVER_PORT.get(
|
hostSource, String.valueOf(portSource));
|
println();
|
println(message);
|
println();
|
error = true;
|
}
|
}
|
|
if (!error)
|
{
|
ctxDestination = createInitialLdapContextInteracting(ci, true);
|
|
if (ctxDestination == null)
|
{
|
cancelled = true;
|
}
|
}
|
}
|
catch (ClientException ce)
|
{
|
LOG.log(Level.WARNING, "Client exception "+ce);
|
println();
|
println(ce.getMessageObject());
|
println();
|
ci.resetConnectionArguments();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Argument exception "+ae);
|
println();
|
println(ae.getMessageObject());
|
println();
|
cancelled = true;
|
}
|
} if (!cancelled)
|
{
|
uData.setHostNameDestination(hostDestination);
|
uData.setPortDestination(portDestination);
|
}
|
|
if (!cancelled)
|
{
|
LinkedList<String> suffixes = argParser.getBaseDNs();
|
checkSuffixesForInitializeReplication(suffixes, ctxSource, ctxDestination,
|
true);
|
cancelled = suffixes.isEmpty();
|
|
uData.setBaseDNs(suffixes);
|
}
|
|
if (!cancelled)
|
{
|
// Ask for confirmation to initialize.
|
boolean initializeADS = false;
|
for (String dn : uData.getBaseDNs())
|
{
|
if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
|
{
|
initializeADS = true;
|
break;
|
}
|
}
|
String hostPortSource = ConnectionUtils.getHostPort(ctxSource);
|
String hostPortDestination = ConnectionUtils.getHostPort(ctxDestination);
|
|
if (initializeADS)
|
{
|
println();
|
try
|
{
|
cancelled = !askConfirmation(
|
INFO_REPLICATION_CONFIRM_INITIALIZE_ADS.get(
|
ADSContext.getAdministrationSuffixDN(), hostPortDestination,
|
hostPortSource), true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
else
|
{
|
println();
|
try
|
{
|
cancelled = !askConfirmation(
|
INFO_REPLICATION_CONFIRM_INITIALIZE_GENERIC.get(
|
hostPortDestination, hostPortSource), true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
println();
|
}
|
}
|
|
if (ctxSource != null)
|
{
|
try
|
{
|
ctxSource.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
if (ctxDestination != null)
|
{
|
try
|
{
|
ctxDestination.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
return !cancelled;
|
}
|
|
/**
|
* Commodity method that simply checks if a provided value is null or not,
|
* if it is not <CODE>null</CODE> returns it and if it is <CODE>null</CODE>
|
* returns the provided default value.
|
* @param v the value to analyze.
|
* @param defaultValue the default value.
|
* @return if the provided value is not <CODE>null</CODE> returns it and if it
|
* is <CODE>null</CODE> returns the provided default value.
|
*/
|
private String getValue(String v, String defaultValue)
|
{
|
if (v != null)
|
{
|
return v;
|
}
|
else
|
{
|
return defaultValue;
|
}
|
}
|
|
/**
|
* Commodity method that simply checks if a provided value is -1 or not,
|
* if it is not -1 returns it and if it is -1 returns the provided default
|
* value.
|
* @param v the value to analyze.
|
* @param defaultValue the default value.
|
* @return if the provided value is not -1 returns it and if it is -1 returns
|
* the provided default value.
|
*/
|
private int getValue(int v, int defaultValue)
|
{
|
if (v != -1)
|
{
|
return v;
|
}
|
else
|
{
|
return defaultValue;
|
}
|
}
|
|
/**
|
* Returns the trust manager to be used by this application.
|
* @return the trust manager to be used by this application.
|
*/
|
private ApplicationTrustManager getTrustManager()
|
{
|
ApplicationTrustManager trust;
|
if (isInteractive())
|
{
|
TrustManager t = ci.getTrustManager();
|
if (t == null)
|
{
|
trust = null;
|
}
|
else if (t instanceof ApplicationTrustManager)
|
{
|
trust = (ApplicationTrustManager)t;
|
}
|
else
|
{
|
trust = new ApplicationTrustManager(ci.getKeyStore());
|
}
|
}
|
else
|
{
|
trust = argParser.getTrustManager();
|
}
|
return trust;
|
}
|
|
/**
|
* Initializes the contents of the provided enable replication user data
|
* object with what was provided in the command-line without prompting to the
|
* user.
|
* @param uData the enable replication user data object to be initialized.
|
*/
|
private void initializeWithArgParser(EnableReplicationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
uData.setAdminUid(adminUid);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String host1Name = getValue(argParser.getHostName1(),
|
argParser.getDefaultHostName1());
|
uData.setHostName1(host1Name);
|
int port1 = getValue(argParser.getPort1(),
|
argParser.getDefaultPort1());
|
uData.setPort1(port1);
|
String pwd1 = argParser.getBindPassword1();
|
if (pwd1 == null)
|
{
|
uData.setBindDn1(ADSContext.getAdministratorDN(adminUid));
|
uData.setPwd1(adminPwd);
|
}
|
else
|
{
|
// Best-effort: try to use admin, if it does not work, use bind DN.
|
try
|
{
|
InitialLdapContext ctx = createAdministrativeContext(
|
uData.getHostName1(), uData.getPort1(), useSSL,
|
useStartTLS, ADSContext.getAdministratorDN(adminUid),
|
adminPwd, getConnectTimeout(), getTrustManager());
|
uData.setBindDn1(ADSContext.getAdministratorDN(adminUid));
|
uData.setPwd1(adminPwd);
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
String bindDn = getValue(argParser.getBindDn1(),
|
argParser.getDefaultBindDn1());
|
uData.setBindDn1(bindDn);
|
uData.setPwd1(pwd1);
|
}
|
}
|
uData.setSecureReplication1(argParser.isSecureReplication1());
|
|
String host2Name = getValue(argParser.getHostName2(),
|
argParser.getDefaultHostName2());
|
uData.setHostName2(host2Name);
|
int port2 = getValue(argParser.getPort2(),
|
argParser.getDefaultPort2());
|
uData.setPort2(port2);
|
String pwd2 = argParser.getBindPassword2();
|
if (pwd2 == null)
|
{
|
uData.setBindDn2(ADSContext.getAdministratorDN(adminUid));
|
uData.setPwd2(adminPwd);
|
}
|
else
|
{
|
// Best-effort: try to use admin, if it does not work, use bind DN.
|
try
|
{
|
InitialLdapContext ctx = createAdministrativeContext(
|
uData.getHostName2(), uData.getPort2(), useSSL,
|
useStartTLS, ADSContext.getAdministratorDN(adminUid),
|
adminPwd, getConnectTimeout(), getTrustManager());
|
uData.setBindDn2(ADSContext.getAdministratorDN(adminUid));
|
uData.setPwd2(adminPwd);
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
String bindDn = getValue(argParser.getBindDn2(),
|
argParser.getDefaultBindDn2());
|
uData.setBindDn2(bindDn);
|
uData.setPwd2(pwd2);
|
}
|
}
|
uData.setSecureReplication2(argParser.isSecureReplication2());
|
uData.setReplicateSchema(!argParser.noSchemaReplication());
|
uData.setConfigureReplicationDomain1(
|
!argParser.onlyReplicationServer1Arg.isPresent());
|
uData.setConfigureReplicationDomain2(
|
!argParser.onlyReplicationServer2Arg.isPresent());
|
uData.setConfigureReplicationServer1(
|
!argParser.noReplicationServer1Arg.isPresent());
|
uData.setConfigureReplicationServer2(
|
!argParser.noReplicationServer2Arg.isPresent());
|
|
int replicationPort1 = getValue(argParser.getReplicationPort1(),
|
argParser.getDefaultReplicationPort1());
|
if (uData.configureReplicationServer1())
|
{
|
uData.setReplicationPort1(replicationPort1);
|
}
|
|
int replicationPort2 = getValue(argParser.getReplicationPort2(),
|
argParser.getDefaultReplicationPort2());
|
if (uData.configureReplicationServer2())
|
{
|
uData.setReplicationPort2(replicationPort2);
|
}
|
}
|
|
/**
|
* Initializes the contents of the provided initialize replication user data
|
* object with what was provided in the command-line without prompting to the
|
* user.
|
* @param uData the initialize replication user data object to be initialized.
|
*/
|
private void initializeWithArgParser(InitializeReplicationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
uData.setAdminUid(adminUid);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String hostNameSource = getValue(argParser.getHostNameSource(),
|
argParser.getDefaultHostNameSource());
|
uData.setHostNameSource(hostNameSource);
|
int portSource = getValue(argParser.getPortSource(),
|
argParser.getDefaultPortSource());
|
uData.setPortSource(portSource);
|
|
String hostNameDestination = getValue(
|
argParser.getHostNameDestination(),
|
argParser.getDefaultHostNameDestination());
|
uData.setHostNameDestination(hostNameDestination);
|
int portDestination = getValue(argParser.getPortDestination(),
|
argParser.getDefaultPortDestination());
|
uData.setPortDestination(portDestination);
|
}
|
|
/**
|
* Initializes the contents of the provided disable replication user data
|
* object with what was provided in the command-line without prompting to the
|
* user.
|
* @param uData the disable replication user data object to be initialized.
|
*/
|
private void initializeWithArgParser(DisableReplicationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = argParser.getAdministratorUID();
|
String bindDn = argParser.getBindDNToDisable();
|
if ((bindDn == null) && (adminUid == null))
|
{
|
adminUid = argParser.getDefaultAdministratorUID();
|
bindDn = ADSContext.getAdministratorDN(adminUid);
|
}
|
uData.setAdminUid(adminUid);
|
uData.setBindDn(bindDn);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String hostName = getValue(argParser.getHostNameToDisable(),
|
argParser.getDefaultHostNameToDisable());
|
uData.setHostName(hostName);
|
int port = getValue(argParser.getPortToDisable(),
|
argParser.getDefaultPortToDisable());
|
uData.setPort(port);
|
|
uData.setDisableAll(argParser.disableAllArg.isPresent());
|
uData.setDisableReplicationServer(
|
argParser.disableReplicationServerArg.isPresent());
|
}
|
|
/**
|
* Initializes the contents of the provided initialize all replication user
|
* data object with what was provided in the command-line without prompting to
|
* the user.
|
* @param uData the initialize all replication user data object to be
|
* initialized.
|
*/
|
private void initializeWithArgParser(InitializeAllReplicationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
uData.setAdminUid(adminUid);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String hostName = getValue(argParser.getHostNameToInitializeAll(),
|
argParser.getDefaultHostNameToInitializeAll());
|
uData.setHostName(hostName);
|
int port = getValue(argParser.getPortToInitializeAll(),
|
argParser.getDefaultPortToInitializeAll());
|
uData.setPort(port);
|
}
|
|
/**
|
* Initializes the contents of the provided pre external replication user
|
* data object with what was provided in the command-line without prompting to
|
* the user.
|
* @param uData the pre external replication user data object to be
|
* initialized.
|
*/
|
private void initializeWithArgParser(PreExternalInitializationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
uData.setAdminUid(adminUid);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String hostName = getValue(argParser.getHostNameToInitializeAll(),
|
argParser.getDefaultHostNameToInitializeAll());
|
uData.setHostName(hostName);
|
int port = getValue(argParser.getPortToInitializeAll(),
|
argParser.getDefaultPortToInitializeAll());
|
uData.setPort(port);
|
}
|
|
/**
|
* Initializes the contents of the provided post external replication user
|
* data object with what was provided in the command-line without prompting to
|
* the user.
|
* @param uData the pre external replication user data object to be
|
* initialized.
|
*/
|
private void initializeWithArgParser(PostExternalInitializationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
uData.setAdminUid(adminUid);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String hostName = getValue(argParser.getHostNameToInitializeAll(),
|
argParser.getDefaultHostNameToInitializeAll());
|
uData.setHostName(hostName);
|
int port = getValue(argParser.getPortToInitializeAll(),
|
argParser.getDefaultPortToInitializeAll());
|
uData.setPort(port);
|
}
|
|
|
/**
|
* Initializes the contents of the provided status replication user data
|
* object with what was provided in the command-line without prompting to the
|
* user.
|
* @param uData the status replication user data object to be initialized.
|
*/
|
private void initializeWithArgParser(StatusReplicationUserData uData)
|
{
|
uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
|
String adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
uData.setAdminUid(adminUid);
|
String adminPwd = argParser.getBindPasswordAdmin();
|
uData.setAdminPwd(adminPwd);
|
|
String hostName = getValue(argParser.getHostNameToStatus(),
|
argParser.getDefaultHostNameToStatus());
|
uData.setHostName(hostName);
|
int port = getValue(argParser.getPortToStatus(),
|
argParser.getDefaultPortToStatus());
|
uData.setPort(port);
|
|
uData.setScriptFriendly(argParser.isScriptFriendly());
|
}
|
|
/**
|
* Tells whether the server to which the LdapContext is connected has a
|
* replication port or not.
|
* @param ctx the InitialLdapContext to be used.
|
* @return <CODE>true</CODE> if the replication port for the server could
|
* be found and <CODE>false</CODE> otherwise.
|
*/
|
private boolean hasReplicationPort(InitialLdapContext ctx)
|
{
|
return getReplicationPort(ctx) != -1;
|
}
|
|
/**
|
* Returns the replication port of server to which the LdapContext is
|
* connected and -1 if the replication port could not be found.
|
* @param ctx the InitialLdapContext to be used.
|
* @return the replication port of server to which the LdapContext is
|
* connected and -1 if the replication port could not be found.
|
*/
|
private int getReplicationPort(InitialLdapContext ctx)
|
{
|
int replicationPort = -1;
|
try
|
{
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
|
ReplicationSynchronizationProviderCfgClient sync = null;
|
sync = (ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
if (sync.hasReplicationServer())
|
{
|
ReplicationServerCfgClient replicationServer =
|
sync.getReplicationServer();
|
replicationPort = replicationServer.getReplicationPort();
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING,
|
"Unexpected error retrieving the replication port: "+t, t);
|
}
|
return replicationPort;
|
}
|
|
/**
|
* Loads the ADS with the provided context. If there are certificates to
|
* be accepted we prompt them to the user. If there are errors loading the
|
* servers we display them to the user and we ask for confirmation. If the
|
* provided ctx is not using Global Administrator credentials, we prompt the
|
* user to provide them and update the provide ReplicationUserData
|
* accordingly.
|
* @param ctx the Ldap context to be used in an array: note the context
|
* may be modified with the new credentials provided by the user.
|
* @param uData the ReplicationUserData to be udpated.
|
* @param isFirstOrSourceServer whether this is the first server in the
|
* enable replication subcommand or the source server in the initialize server
|
* subcommand.
|
* @throws ReplicationCliException if a critical error occurred.
|
* @return <CODE>true</CODE> if everything went fine and the user accepted
|
* all the certificates and confirmed everything. Returns <CODE>false</CODE>
|
* if the user did not accept a certificate or any of the confirmation
|
* messages.
|
*/
|
private boolean loadADSAndAcceptCertificates(InitialLdapContext[] ctx,
|
ReplicationUserData uData, boolean isFirstOrSourceServer)
|
throws ReplicationCliException
|
{
|
boolean cancelled = false;
|
boolean triedWithUserProvidedAdmin = false;
|
String host = ConnectionUtils.getHostName(ctx[0]);
|
int port = ConnectionUtils.getPort(ctx[0]);
|
boolean isSSL = ConnectionUtils.isSSL(ctx[0]);
|
boolean isStartTLS = ConnectionUtils.isStartTLS(ctx[0]);
|
if (getTrustManager() == null)
|
{
|
// This is required when the user did connect to the server using SSL or
|
// Start TLS. In this case LDAPConnectionConsoleInteraction.run does not
|
// initialize the keystore and the trust manager is null.
|
forceTrustManagerInitialization();
|
}
|
try
|
{
|
ADSContext adsContext = new ADSContext(ctx[0]);
|
if (adsContext.hasAdminData())
|
{
|
boolean reloadTopology = true;
|
LinkedList<Message> exceptionMsgs = new LinkedList<Message>();
|
while (reloadTopology && !cancelled)
|
{
|
// We must recreate the cache because the trust manager in the
|
// LDAPConnectionConsoleInteraction object might have changed.
|
|
TopologyCache cache = new TopologyCache(adsContext,
|
getTrustManager(), getConnectTimeout());
|
cache.getFilter().setSearchMonitoringInformation(false);
|
cache.getFilter().setSearchBaseDNInformation(false);
|
cache.setPreferredConnections(
|
PreferredConnection.getPreferredConnections(ctx[0]));
|
cache.reloadTopology();
|
|
reloadTopology = false;
|
exceptionMsgs.clear();
|
|
/* Analyze if we had any exception while loading servers. For the
|
* moment only throw the exception found if the user did not provide
|
* the Administrator DN and this caused a problem authenticating in
|
* one server or if there is a certificate problem.
|
*/
|
Set<TopologyCacheException> exceptions =
|
new HashSet<TopologyCacheException>();
|
Set<ServerDescriptor> servers = cache.getServers();
|
for (ServerDescriptor server : servers)
|
{
|
TopologyCacheException e = server.getLastException();
|
if (e != null)
|
{
|
exceptions.add(e);
|
}
|
}
|
/* Check the exceptions and see if we throw them or not. */
|
boolean notGlobalAdministratorError = false;
|
for (TopologyCacheException e : exceptions)
|
{
|
if (notGlobalAdministratorError)
|
{
|
break;
|
}
|
switch (e.getType())
|
{
|
case NOT_GLOBAL_ADMINISTRATOR:
|
notGlobalAdministratorError = true;
|
boolean connected = false;
|
|
String adminUid = uData.getAdminUid();
|
String adminPwd = uData.getAdminPwd();
|
|
boolean errorDisplayed = false;
|
while (!connected)
|
{
|
if ((!triedWithUserProvidedAdmin) && (adminPwd == null))
|
{
|
adminUid = getValue(argParser.getAdministratorUID(),
|
argParser.getDefaultAdministratorUID());
|
adminPwd = argParser.getBindPasswordAdmin();
|
triedWithUserProvidedAdmin = true;
|
}
|
if (adminPwd == null)
|
{
|
if (!errorDisplayed)
|
{
|
println();
|
println(
|
INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get());
|
errorDisplayed = true;
|
}
|
adminUid = askForAdministratorUID(
|
argParser.getDefaultAdministratorUID(), LOG);
|
println();
|
adminPwd = askForAdministratorPwd(LOG);
|
println();
|
}
|
try
|
{
|
ctx[0].close();
|
}
|
catch (Throwable t)
|
{
|
}
|
try
|
{
|
ctx[0] = createAdministrativeContext(host, port, isSSL,
|
isStartTLS, ADSContext.getAdministratorDN(adminUid),
|
adminPwd, getConnectTimeout(), getTrustManager());
|
adsContext = new ADSContext(ctx[0]);
|
cache = new TopologyCache(adsContext, getTrustManager(),
|
getConnectTimeout());
|
cache.getFilter().setSearchMonitoringInformation(false);
|
cache.getFilter().setSearchBaseDNInformation(false);
|
cache.setPreferredConnections(
|
PreferredConnection.getPreferredConnections(ctx[0]));
|
connected = true;
|
}
|
catch (Throwable t)
|
{
|
println();
|
println(
|
ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
|
getServerRepresentation(host, port), t.getMessage()));
|
LOG.log(Level.WARNING, "Complete error stack:", t);
|
println();
|
}
|
}
|
uData.setAdminUid(adminUid);
|
uData.setAdminPwd(adminPwd);
|
if (uData instanceof EnableReplicationUserData)
|
{
|
EnableReplicationUserData enableData =
|
(EnableReplicationUserData)uData;
|
if (isFirstOrSourceServer)
|
{
|
enableData.setBindDn1(
|
ADSContext.getAdministratorDN(adminUid));
|
enableData.setPwd1(adminPwd);
|
}
|
else
|
{
|
enableData.setBindDn2(
|
ADSContext.getAdministratorDN(adminUid));
|
enableData.setPwd2(adminPwd);
|
}
|
}
|
reloadTopology = true;
|
break;
|
case GENERIC_CREATING_CONNECTION:
|
if ((e.getCause() != null) &&
|
Utils.isCertificateException(e.getCause()))
|
{
|
reloadTopology = true;
|
cancelled = !ci.promptForCertificateConfirmation(e.getCause(),
|
e.getTrustManager(), e.getLdapUrl(), true, LOG);
|
}
|
else
|
{
|
exceptionMsgs.add(Utils.getMessage(e));
|
}
|
break;
|
default:
|
exceptionMsgs.add(Utils.getMessage(e));
|
}
|
}
|
}
|
if ((exceptionMsgs.size() > 0) && !cancelled)
|
{
|
if (uData instanceof StatusReplicationUserData)
|
{
|
println(
|
ERR_REPLICATION_STATUS_READING_REGISTERED_SERVERS.get(
|
Utils.getMessageFromCollection(exceptionMsgs,
|
Constants.LINE_SEPARATOR).toString()));
|
println();
|
}
|
else
|
{
|
try
|
{
|
cancelled = !askConfirmation(
|
ERR_REPLICATION_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.
|
get(Utils.getMessageFromCollection(exceptionMsgs,
|
Constants.LINE_SEPARATOR).toString()), true, LOG);
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
cancelled = true;
|
}
|
}
|
}
|
}
|
}
|
catch (ADSContextException ace)
|
{
|
LOG.log(Level.SEVERE, "Complete error stack:", ace);
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(ace.getMessage()),
|
ERROR_READING_ADS, ace);
|
}
|
catch (TopologyCacheException tce)
|
{
|
LOG.log(Level.SEVERE, "Complete error stack:", tce);
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
|
ERROR_READING_TOPOLOGY_CACHE, tce);
|
}
|
return !cancelled;
|
}
|
|
/**
|
* Tells whether there is a Global Administrator defined in the server
|
* to which the InitialLdapContext is connected.
|
* @param ctx the InitialLdapContext.
|
* @return <CODE>true</CODE> if we could find an administrator and
|
* <CODE>false</CODE> otherwise.
|
*/
|
private boolean hasAdministrator(InitialLdapContext ctx)
|
{
|
boolean isAdminDefined = false;
|
try
|
{
|
ADSContext adsContext = new ADSContext(ctx);
|
if (adsContext.hasAdminData())
|
{
|
Set<?> administrators = adsContext.readAdministratorRegistry();
|
isAdminDefined = administrators.size() > 0;
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING,
|
"Unexpected error retrieving the ADS data: "+t, t);
|
}
|
return isAdminDefined;
|
}
|
|
/**
|
* Tells whether there is a Global Administrator corresponding to the provided
|
* ReplicationUserData defined in the server to which the InitialLdapContext
|
* is connected.
|
* @param ctx the InitialLdapContext.
|
* @param uData the user data
|
* @return <CODE>true</CODE> if we could find an administrator and
|
* <CODE>false</CODE> otherwise.
|
*/
|
private boolean hasAdministrator(InitialLdapContext ctx,
|
ReplicationUserData uData)
|
{
|
boolean isAdminDefined = false;
|
String adminUid = uData.getAdminUid();
|
try
|
{
|
ADSContext adsContext = new ADSContext(ctx);
|
Set<Map<AdministratorProperty, Object>> administrators =
|
adsContext.readAdministratorRegistry();
|
for (Map<AdministratorProperty, Object> admin : administrators)
|
{
|
String uid = (String)admin.get(AdministratorProperty.UID);
|
if (uid != null)
|
{
|
// If the administrator UID is null it means that we are just
|
// checking for the existence of an administrator
|
isAdminDefined = uid.equalsIgnoreCase(adminUid) || (adminUid == null);
|
if (isAdminDefined)
|
{
|
break;
|
}
|
}
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING,
|
"Unexpected error retrieving the ADS data: "+t, t);
|
}
|
return isAdminDefined;
|
}
|
|
/**
|
* Helper type for the <CODE>getCommonSuffixes</CODE> method.
|
*/
|
private enum SuffixRelationType
|
{
|
NOT_REPLICATED, FULLY_REPLICATED, REPLICATED, NOT_FULLY_REPLICATED, ALL
|
}
|
|
/**
|
* Returns a Collection containing a list of suffixes that are defined in
|
* two servers at the same time (depending on the value of the argument
|
* replicated this list contains only the suffixes that are replicated
|
* between the servers or the list of suffixes that are not replicated
|
* between the servers).
|
* @param ctx1 the connection to the first server.
|
* @param ctx2 the connection to the second server.
|
* @param type whether to return a list with the suffixes that are
|
* replicated, fully replicated (replicas have exactly the same list of
|
* replication servers), not replicated or all the common suffixes.
|
* @return a Collection containing a list of suffixes that are replicated
|
* (or those that can be replicated) in two servers.
|
*/
|
private Collection<String> getCommonSuffixes(
|
InitialLdapContext ctx1, InitialLdapContext ctx2, SuffixRelationType type)
|
{
|
LinkedList<String> suffixes = new LinkedList<String>();
|
try
|
{
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
ServerDescriptor server1 =
|
ServerDescriptor.createStandalone(ctx1, filter);
|
ServerDescriptor server2 =
|
ServerDescriptor.createStandalone(ctx2, filter);
|
Set<ReplicaDescriptor> replicas1 = server1.getReplicas();
|
Set<ReplicaDescriptor> replicas2 = server2.getReplicas();
|
|
for (ReplicaDescriptor rep1 : replicas1)
|
{
|
for (ReplicaDescriptor rep2 : replicas2)
|
{
|
|
switch (type)
|
{
|
case NOT_REPLICATED:
|
if (!areReplicated(rep1, rep2) &&
|
Utils.areDnsEqual(rep1.getSuffix().getDN(),
|
rep2.getSuffix().getDN()))
|
{
|
suffixes.add(rep1.getSuffix().getDN());
|
}
|
break;
|
case FULLY_REPLICATED:
|
if (areFullyReplicated(rep1, rep2))
|
{
|
suffixes.add(rep1.getSuffix().getDN());
|
}
|
break;
|
case REPLICATED:
|
if (areReplicated(rep1, rep2))
|
{
|
suffixes.add(rep1.getSuffix().getDN());
|
}
|
break;
|
case NOT_FULLY_REPLICATED:
|
if (!areFullyReplicated(rep1, rep2) &&
|
Utils.areDnsEqual(rep1.getSuffix().getDN(),
|
rep2.getSuffix().getDN()))
|
{
|
suffixes.add(rep1.getSuffix().getDN());
|
}
|
break;
|
case ALL:
|
if (Utils.areDnsEqual(rep1.getSuffix().getDN(),
|
rep2.getSuffix().getDN()))
|
{
|
suffixes.add(rep1.getSuffix().getDN());
|
}
|
break;
|
default:
|
throw new IllegalStateException("Unknown type: "+type);
|
}
|
}
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING,
|
"Unexpected error retrieving the server configuration: "+t, t);
|
}
|
return suffixes;
|
}
|
|
/**
|
* Tells whether the two provided replicas are fully replicated or not. The
|
* code in fact checks that both replicas have the same DN that they are
|
* replicated if both servers are replication servers and that both replicas
|
* make reference to the other replication server.
|
* @param rep1 the first replica.
|
* @param rep2 the second replica.
|
* @return <CODE>true</CODE> if we can assure that the two replicas are
|
* replicated using the replication server and replication port information
|
* and <CODE>false</CODE> otherwise.
|
*/
|
private boolean areFullyReplicated(ReplicaDescriptor rep1,
|
ReplicaDescriptor rep2)
|
{
|
boolean areFullyReplicated = false;
|
if (Utils.areDnsEqual(rep1.getSuffix().getDN(), rep2.getSuffix().getDN()) &&
|
rep1.isReplicated() && rep2.isReplicated() &&
|
rep1.getServer().isReplicationServer() &&
|
rep2.getServer().isReplicationServer())
|
{
|
Set<String> servers1 = rep1.getReplicationServers();
|
Set<String> servers2 = rep2.getReplicationServers();
|
String server1 = rep1.getServer().getReplicationServerHostPort();
|
String server2 = rep2.getServer().getReplicationServerHostPort();
|
areFullyReplicated = servers1.contains(server2) &&
|
servers2.contains(server1);
|
}
|
return areFullyReplicated;
|
}
|
|
/**
|
* Tells whether the two provided replicas are replicated or not. The
|
* code in fact checks that both replicas have the same DN and that they
|
* have at least one common replication server referenced.
|
* @param rep1 the first replica.
|
* @param rep2 the second replica.
|
* @return <CODE>true</CODE> if we can assure that the two replicas are
|
* replicated and <CODE>false</CODE> otherwise.
|
*/
|
private boolean areReplicated(ReplicaDescriptor rep1, ReplicaDescriptor rep2)
|
{
|
boolean areReplicated = false;
|
if (Utils.areDnsEqual(rep1.getSuffix().getDN(), rep2.getSuffix().getDN()) &&
|
rep1.isReplicated() && rep2.isReplicated())
|
{
|
Set<String> servers1 = rep1.getReplicationServers();
|
Set<String> servers2 = rep2.getReplicationServers();
|
servers1.retainAll(servers2);
|
areReplicated = !servers1.isEmpty();
|
}
|
return areReplicated;
|
}
|
|
/**
|
* Returns a Collection containing a list of replicas in a server.
|
* @param ctx the connection to the server.
|
* @return a Collection containing a list of replicas in a server.
|
*/
|
private Collection<ReplicaDescriptor> getReplicas(InitialLdapContext ctx)
|
{
|
LinkedList<ReplicaDescriptor> suffixes =
|
new LinkedList<ReplicaDescriptor>();
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
try
|
{
|
ServerDescriptor server = ServerDescriptor.createStandalone(ctx, filter);
|
suffixes.addAll(server.getReplicas());
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING,
|
"Unexpected error retrieving the server configuration: "+t, t);
|
}
|
return suffixes;
|
}
|
|
/**
|
* Enables the replication between two servers using the parameters in the
|
* provided EnableReplicationUserData. This method does not prompt to the
|
* user for information if something is missing.
|
* @param uData the EnableReplicationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and the replication could be enabled and an error code
|
* otherwise.
|
*/
|
private ReplicationCliReturnCode enableReplication(
|
EnableReplicationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
|
InitialLdapContext ctx1 = null;
|
InitialLdapContext ctx2 = null;
|
|
String host1 = uData.getHostName1();
|
String host2 = uData.getHostName2();
|
int port1 = uData.getPort1();
|
int port2 = uData.getPort2();
|
|
LinkedList<Message> errorMessages = new LinkedList<Message>();
|
|
printlnProgress();
|
printProgress(
|
formatter.getFormattedWithPoints(INFO_REPLICATION_CONNECTING.get()));
|
try
|
{
|
ctx1 = createAdministrativeContext(host1, port1, useSSL,
|
useStartTLS, uData.getBindDn1(), uData.getPwd1(),
|
getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort = getServerRepresentation(host1, port1);
|
errorMessages.add(getMessageForException(ne, hostPort));
|
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
try
|
{
|
ctx2 = createAdministrativeContext(host2, port2, useSSL,
|
useStartTLS, uData.getBindDn2(), uData.getPwd2(),
|
getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort = getServerRepresentation(host2, port2);
|
errorMessages.add(getMessageForException(ne, hostPort));
|
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
|
if (errorMessages.size() > 0)
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (errorMessages.isEmpty())
|
{
|
// This done is for the message informing that we are connecting.
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
|
// If we are not in interactive mode do some checks...
|
if (!argParser.isInteractive())
|
{
|
int replPort1 = getReplicationPort(ctx1);
|
boolean hasReplicationPort1 = replPort1 > 0;
|
if (replPort1 < 0 && uData.configureReplicationServer1())
|
{
|
replPort1 = uData.getReplicationPort1();
|
}
|
int replPort2 = getReplicationPort(ctx2);
|
boolean hasReplicationPort2 = replPort2 > 0;
|
if (replPort2 < 0 && uData.configureReplicationServer2())
|
{
|
replPort2 = uData.getReplicationPort2();
|
}
|
boolean checkReplicationPort1 = replPort1 > 0;
|
boolean checkReplicationPort2 = replPort2 > 0;
|
if (!hasReplicationPort1 && checkReplicationPort1)
|
{
|
if (!argParser.skipReplicationPortCheck() &&
|
uData.configureReplicationServer1() &&
|
Utils.isLocalHost(host1) &&
|
!SetupUtils.canUseAsPort(replPort1))
|
{
|
errorMessages.add(getCannotBindToPortError(replPort1));
|
}
|
}
|
if (!hasReplicationPort2 && checkReplicationPort2)
|
{
|
if (!argParser.skipReplicationPortCheck() &&
|
uData.configureReplicationServer2() &&
|
Utils.isLocalHost(host2) &&
|
!SetupUtils.canUseAsPort(replPort2))
|
{
|
errorMessages.add(getCannotBindToPortError(replPort2));
|
}
|
}
|
if (checkReplicationPort1 && checkReplicationPort2 &&
|
(replPort1 == replPort2) &&
|
(host1.equalsIgnoreCase(host2)))
|
{
|
errorMessages.add(ERR_REPLICATION_SAME_REPLICATION_PORT.get(
|
String.valueOf(replPort1), host1));
|
}
|
|
if (argParser.skipReplicationPortCheck())
|
{
|
// This is something that we must do in any case... this test is
|
// already included when we call SetupUtils.canUseAsPort
|
if (checkReplicationPort1 && replPort1 == port1)
|
{
|
errorMessages.add(
|
ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
|
host1, String.valueOf(replPort1)));
|
}
|
|
if (checkReplicationPort2 && replPort2 == port2)
|
{
|
errorMessages.add(
|
ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
|
host2, String.valueOf(replPort2)));
|
}
|
}
|
}
|
if (errorMessages.size() > 0)
|
{
|
returnValue = ERROR_USER_DATA;
|
}
|
}
|
|
if (errorMessages.isEmpty())
|
{
|
LinkedList<String> suffixes = uData.getBaseDNs();
|
checkSuffixesForEnableReplication(suffixes, ctx1, ctx2, false, uData);
|
if (!suffixes.isEmpty())
|
{
|
uData.setBaseDNs(suffixes);
|
|
if (mustPrintCommandBuilder())
|
{
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.ENABLE_REPLICATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
|
if (!isInteractive())
|
{
|
int repPort1 = getReplicationPort(ctx1);
|
int repPort2 = getReplicationPort(ctx2);
|
|
if (!uData.configureReplicationServer1() && repPort1 > 0)
|
{
|
|
println(INFO_REPLICATION_SERVER_CONFIGURED_WARNING.get(
|
ConnectionUtils.getHostPort(ctx1), repPort1));
|
println();
|
}
|
if (!uData.configureReplicationServer2() && repPort2 > 0)
|
{
|
println(INFO_REPLICATION_SERVER_CONFIGURED_WARNING.get(
|
ConnectionUtils.getHostPort(ctx2), repPort2));
|
println();
|
}
|
}
|
|
try
|
{
|
updateConfiguration(ctx1, ctx2, uData);
|
returnValue = SUCCESSFUL;
|
}
|
catch (ReplicationCliException rce)
|
{
|
returnValue = rce.getErrorCode();
|
println();
|
println(getCriticalExceptionMessage(rce));
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
else
|
{
|
// The error messages are already displayed in the method
|
// checkSuffixesForEnableReplication.
|
returnValue = REPLICATION_CANNOT_BE_ENABLED_ON_BASEDN;
|
}
|
}
|
|
for (Message msg : errorMessages)
|
{
|
println();
|
println(msg);
|
}
|
|
if (returnValue == SUCCESSFUL)
|
{
|
long time1 = Utils.getServerClock(ctx1);
|
long time2 = Utils.getServerClock(ctx2);
|
if ((time1 != -1) && (time2 != -1))
|
{
|
if (Math.abs(time1 - time2) >
|
(Installer.WARNING_CLOCK_DIFFERENCE_THRESOLD_MINUTES * 60 * 1000))
|
{
|
println(INFO_WARNING_SERVERS_CLOCK_DIFFERENCE.get(
|
ConnectionUtils.getHostPort(ctx1),
|
ConnectionUtils.getHostPort(ctx2),
|
String.valueOf(
|
Installer.WARNING_CLOCK_DIFFERENCE_THRESOLD_MINUTES)));
|
}
|
}
|
printlnProgress();
|
printProgress(INFO_REPLICATION_POST_ENABLE_INFO.get("dsreplication",
|
ReplicationCliArgumentParser.INITIALIZE_REPLICATION_SUBCMD_NAME));
|
printlnProgress();
|
}
|
|
if (ctx1 != null)
|
{
|
try
|
{
|
ctx1.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
if (ctx2 != null)
|
{
|
try
|
{
|
ctx2.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
return returnValue;
|
}
|
|
/**
|
* Disables the replication in the server for the provided suffixes using the
|
* data in the DisableReplicationUserData object. This method does not prompt
|
* to the user for information if something is missing.
|
* @param uData the DisableReplicationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and an error code otherwise.
|
*/
|
private ReplicationCliReturnCode disableReplication(
|
DisableReplicationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctx = null;
|
printProgress(
|
formatter.getFormattedWithPoints(INFO_REPLICATION_CONNECTING.get()));
|
String bindDn = uData.getAdminUid() == null ? uData.getBindDn() :
|
ADSContext.getAdministratorDN(uData.getAdminUid());
|
try
|
{
|
ctx = createAdministrativeContext(uData.getHostName(), uData.getPort(),
|
useSSL, useStartTLS, bindDn, uData.getAdminPwd(), getConnectTimeout(),
|
getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort =
|
getServerRepresentation(uData.getHostName(), uData.getPort());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
|
if (ctx != null)
|
{
|
// This done is for the message informing that we are connecting.
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
LinkedList<String> suffixes = uData.getBaseDNs();
|
checkSuffixesForDisableReplication(suffixes, ctx, false,
|
!uData.disableReplicationServer(), !uData.disableReplicationServer());
|
if (!suffixes.isEmpty() || uData.disableReplicationServer() ||
|
uData.disableAll())
|
{
|
uData.setBaseDNs(suffixes);
|
|
if (!isInteractive())
|
{
|
boolean hasReplicationPort = hasReplicationPort(ctx);
|
if (uData.disableAll() && hasReplicationPort)
|
{
|
uData.setDisableReplicationServer(true);
|
}
|
else if (uData.disableReplicationServer() && !hasReplicationPort &&
|
!uData.disableAll())
|
{
|
uData.setDisableReplicationServer(false);
|
println(
|
INFO_REPLICATION_WARNING_NO_REPLICATION_SERVER_TO_DISABLE.get(
|
ConnectionUtils.getHostPort(ctx)));
|
println();
|
}
|
}
|
|
if (mustPrintCommandBuilder())
|
{
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.DISABLE_REPLICATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
|
if (!isInteractive() && !uData.disableReplicationServer() &&
|
!uData.disableAll() && disableAllBaseDns(ctx, uData) &&
|
hasReplicationPort(ctx))
|
{
|
// Inform the user that the replication server will not be disabled.
|
// Inform also of the user of the disableReplicationServerArg
|
println(
|
INFO_REPLICATION_DISABLE_ALL_SUFFIXES_KEEP_REPLICATION_SERVER.get(
|
ConnectionUtils.getHostPort(ctx),
|
argParser.disableReplicationServerArg.getLongIdentifier(),
|
argParser.disableAllArg.getLongIdentifier()));
|
}
|
try
|
{
|
updateConfiguration(ctx, uData);
|
returnValue = SUCCESSFUL;
|
}
|
catch (ReplicationCliException rce)
|
{
|
returnValue = rce.getErrorCode();
|
println();
|
println(getCriticalExceptionMessage(rce));
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
else
|
{
|
returnValue = REPLICATION_CANNOT_BE_DISABLED_ON_BASEDN;
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
return returnValue;
|
}
|
|
/**
|
* Displays the replication status of the baseDNs specified in the
|
* StatusReplicationUserData object. This method does not prompt
|
* to the user for information if something is missing.
|
* @param uData the StatusReplicationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and an error code otherwise.
|
*/
|
private ReplicationCliReturnCode statusReplication(
|
StatusReplicationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctx = null;
|
try
|
{
|
ctx = createAdministrativeContext(uData.getHostName(), uData.getPort(),
|
useSSL, useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort =
|
getServerRepresentation(uData.getHostName(), uData.getPort());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
displayStatus(ctx, uData);
|
returnValue = SUCCESSFUL;
|
}
|
catch (ReplicationCliException rce)
|
{
|
returnValue = rce.getErrorCode();
|
println();
|
println(getCriticalExceptionMessage(rce));
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
return returnValue;
|
}
|
|
/**
|
* Initializes the contents of one server with the contents of the other
|
* using the parameters in the provided InitializeReplicationUserData.
|
* This method does not prompt to the user for information if something is
|
* missing.
|
* @param uData the InitializeReplicationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and an error code otherwise.
|
*/
|
private ReplicationCliReturnCode initializeReplication(
|
InitializeReplicationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctxSource = null;
|
InitialLdapContext ctxDestination = null;
|
try
|
{
|
ctxSource = createAdministrativeContext(uData.getHostNameSource(),
|
uData.getPortSource(), useSSL,
|
useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort = getServerRepresentation(uData.getHostNameSource(),
|
uData.getPortSource());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
try
|
{
|
ctxDestination = createAdministrativeContext(
|
uData.getHostNameDestination(),
|
uData.getPortDestination(), useSSL,
|
useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort = getServerRepresentation(uData.getHostNameDestination(),
|
uData.getPortDestination());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
if ((ctxSource != null) && (ctxDestination != null))
|
{
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
checkSuffixesForInitializeReplication(baseDNs, ctxSource, ctxDestination,
|
false);
|
if (!baseDNs.isEmpty())
|
{
|
if (mustPrintCommandBuilder())
|
{
|
try
|
{
|
uData.setBaseDNs(baseDNs);
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.INITIALIZE_REPLICATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
|
for (String baseDN : baseDNs)
|
{
|
try
|
{
|
printlnProgress();
|
Message msg = formatter.getFormattedProgress(
|
INFO_PROGRESS_INITIALIZING_SUFFIX.get(baseDN,
|
ConnectionUtils.getHostPort(ctxSource)));
|
printProgress(msg);
|
printlnProgress();
|
initializeSuffix(baseDN, ctxSource, ctxDestination, true);
|
returnValue = SUCCESSFUL;
|
}
|
catch (ReplicationCliException rce)
|
{
|
println();
|
println(getCriticalExceptionMessage(rce));
|
returnValue = rce.getErrorCode();
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
}
|
else
|
{
|
returnValue = REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN;
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctxSource != null)
|
{
|
try
|
{
|
ctxSource.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
if (ctxDestination != null)
|
{
|
try
|
{
|
ctxDestination.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
return returnValue;
|
}
|
|
/**
|
* Initializes the contents of a whole topology with the contents of the other
|
* using the parameters in the provided InitializeAllReplicationUserData.
|
* This method does not prompt to the user for information if something is
|
* missing.
|
* @param uData the InitializeAllReplicationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and an error code otherwise.
|
*/
|
private ReplicationCliReturnCode initializeAllReplication(
|
InitializeAllReplicationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctx = null;
|
try
|
{
|
ctx = createAdministrativeContext(uData.getHostName(), uData.getPort(),
|
useSSL, useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort =
|
getServerRepresentation(uData.getHostName(), uData.getPort());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
if (ctx != null)
|
{
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
checkSuffixesForInitializeReplication(baseDNs, ctx, false);
|
if (!baseDNs.isEmpty())
|
{
|
if (mustPrintCommandBuilder())
|
{
|
uData.setBaseDNs(baseDNs);
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.INITIALIZE_ALL_REPLICATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
for (String baseDN : baseDNs)
|
{
|
try
|
{
|
printlnProgress();
|
Message msg = formatter.getFormattedProgress(
|
INFO_PROGRESS_INITIALIZING_SUFFIX.get(baseDN,
|
ConnectionUtils.getHostPort(ctx)));
|
printProgress(msg);
|
println();
|
initializeAllSuffix(baseDN, ctx, true);
|
returnValue = SUCCESSFUL;
|
}
|
catch (ReplicationCliException rce)
|
{
|
println();
|
println(getCriticalExceptionMessage(rce));
|
returnValue = rce.getErrorCode();
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
}
|
else
|
{
|
returnValue = REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN;
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return returnValue;
|
}
|
|
/**
|
* Performs the operation that must be made before initializing the topology
|
* using the import-ldif command or the binary copy. The operation uses
|
* the parameters in the provided InitializeAllReplicationUserData.
|
* This method does not prompt to the user for information if something is
|
* missing.
|
* @param uData the PreExternalInitializationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and an error code otherwise.
|
*/
|
private ReplicationCliReturnCode preExternalInitialization(
|
PreExternalInitializationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctx = null;
|
try
|
{
|
ctx = createAdministrativeContext(uData.getHostName(), uData.getPort(),
|
useSSL, useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort =
|
getServerRepresentation(uData.getHostName(), uData.getPort());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
if (ctx != null)
|
{
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
checkSuffixesForInitializeReplication(baseDNs, ctx, false);
|
if (!baseDNs.isEmpty())
|
{
|
if (mustPrintCommandBuilder())
|
{
|
uData.setBaseDNs(baseDNs);
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
returnValue = SUCCESSFUL;
|
for (String baseDN : baseDNs)
|
{
|
try
|
{
|
printlnProgress();
|
Message msg = formatter.getFormattedWithPoints(
|
INFO_PROGRESS_PRE_EXTERNAL_INITIALIZATION.get(baseDN));
|
printProgress(msg);
|
preExternalInitialization(baseDN, ctx, false);
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
catch (ReplicationCliException rce)
|
{
|
println();
|
println(getCriticalExceptionMessage(rce));
|
returnValue = rce.getErrorCode();
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
printlnProgress();
|
printProgress(
|
INFO_PROGRESS_PRE_INITIALIZATION_FINISHED_PROCEDURE.get(
|
ReplicationCliArgumentParser.
|
POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME));
|
printlnProgress();
|
}
|
else
|
{
|
returnValue = REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN;
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return returnValue;
|
}
|
|
/**
|
* Performs the operation that must be made after initializing the topology
|
* using the import-ldif command or the binary copy. The operation uses
|
* the parameters in the provided InitializeAllReplicationUserData.
|
* This method does not prompt to the user for information if something is
|
* missing.
|
* @param uData the PostExternalInitializationUserData object.
|
* @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
|
* successful and an error code otherwise.
|
*/
|
private ReplicationCliReturnCode postExternalInitialization(
|
PostExternalInitializationUserData uData)
|
{
|
ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
|
InitialLdapContext ctx = null;
|
try
|
{
|
ctx = createAdministrativeContext(uData.getHostName(), uData.getPort(),
|
useSSL, useStartTLS,
|
ADSContext.getAdministratorDN(uData.getAdminUid()),
|
uData.getAdminPwd(), getConnectTimeout(), getTrustManager());
|
}
|
catch (NamingException ne)
|
{
|
String hostPort =
|
getServerRepresentation(uData.getHostName(), uData.getPort());
|
println();
|
println(getMessageForException(ne, hostPort));
|
LOG.log(Level.SEVERE, "Complete error stack:", ne);
|
}
|
if (ctx != null)
|
{
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
checkSuffixesForInitializeReplication(baseDNs, ctx, false);
|
if (!baseDNs.isEmpty())
|
{
|
if (mustPrintCommandBuilder())
|
{
|
uData.setBaseDNs(baseDNs);
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
returnValue = SUCCESSFUL;
|
for (String baseDN : baseDNs)
|
{
|
try
|
{
|
printlnProgress();
|
Message msg = formatter.getFormattedWithPoints(
|
INFO_PROGRESS_POST_EXTERNAL_INITIALIZATION.get(baseDN));
|
printProgress(msg);
|
postExternalInitialization(baseDN, ctx, false);
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
catch (ReplicationCliException rce)
|
{
|
println();
|
println(getCriticalExceptionMessage(rce));
|
returnValue = rce.getErrorCode();
|
LOG.log(Level.SEVERE, "Complete error stack:", rce);
|
}
|
}
|
printlnProgress();
|
printProgress(
|
INFO_PROGRESS_POST_INITIALIZATION_FINISHED_PROCEDURE.get());
|
printlnProgress();
|
}
|
else
|
{
|
returnValue = REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN;
|
}
|
}
|
else
|
{
|
returnValue = ERROR_CONNECTING;
|
}
|
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
|
return returnValue;
|
}
|
|
|
/**
|
* Checks that replication can actually be enabled in the provided baseDNs
|
* for the two servers.
|
* @param suffixes the suffixes provided by the user. This Collection is
|
* updated by removing the base DNs that cannot be enabled and with the
|
* base DNs that the user provided interactively.
|
* @param ctx1 connection to the first server.
|
* @param ctx2 connection to the second server.
|
* @param interactive whether to ask the user to provide interactively
|
* base DNs if none of the provided base DNs can be enabled.
|
* @param uData the user data. This object will not be updated by this method
|
* but it is assumed that it contains information about whether the
|
* replication domains must be configured or not.
|
*/
|
private void checkSuffixesForEnableReplication(Collection<String> suffixes,
|
InitialLdapContext ctx1, InitialLdapContext ctx2,
|
boolean interactive, EnableReplicationUserData uData)
|
{
|
|
TreeSet<String> availableSuffixes;
|
TreeSet<String> alreadyReplicatedSuffixes;
|
if (uData.configureReplicationDomain1() &&
|
uData.configureReplicationDomain2())
|
{
|
availableSuffixes =
|
new TreeSet<String>(getCommonSuffixes(ctx1, ctx2,
|
SuffixRelationType.NOT_FULLY_REPLICATED));
|
alreadyReplicatedSuffixes =
|
new TreeSet<String>(getCommonSuffixes(ctx1, ctx2,
|
SuffixRelationType.FULLY_REPLICATED));
|
}
|
else if (uData.configureReplicationDomain1())
|
{
|
availableSuffixes = new TreeSet<String>();
|
alreadyReplicatedSuffixes = new TreeSet<String>();
|
|
updateAvailableAndReplicatedSuffixesForOneDomain(ctx1, ctx2,
|
availableSuffixes, alreadyReplicatedSuffixes);
|
}
|
else if (uData.configureReplicationDomain2())
|
{
|
availableSuffixes = new TreeSet<String>();
|
alreadyReplicatedSuffixes = new TreeSet<String>();
|
|
updateAvailableAndReplicatedSuffixesForOneDomain(ctx2, ctx1,
|
availableSuffixes, alreadyReplicatedSuffixes);
|
}
|
else
|
{
|
availableSuffixes = new TreeSet<String>();
|
alreadyReplicatedSuffixes = new TreeSet<String>();
|
|
updateAvailableAndReplicatedSuffixesForNoDomain(ctx1, ctx2,
|
availableSuffixes, alreadyReplicatedSuffixes);
|
}
|
|
if (availableSuffixes.size() == 0)
|
{
|
println();
|
if (!uData.configureReplicationDomain1() &&
|
!uData.configureReplicationDomain1() &&
|
alreadyReplicatedSuffixes.isEmpty())
|
{
|
// Use a clarifying message: there is no replicated base DN.
|
println(
|
ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION_NO_DOMAIN.get());
|
}
|
else
|
{
|
println(
|
ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION.get());
|
}
|
|
LinkedList<String> userProvidedSuffixes = argParser.getBaseDNs();
|
TreeSet<String> userProvidedReplicatedSuffixes = new TreeSet<String>();
|
|
for (String s1 : userProvidedSuffixes)
|
{
|
for (String s2 : alreadyReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s1, s2))
|
{
|
userProvidedReplicatedSuffixes.add(s1);
|
}
|
}
|
}
|
if (userProvidedReplicatedSuffixes.size() > 0)
|
{
|
println();
|
println(
|
INFO_ALREADY_REPLICATED_SUFFIXES.get(
|
Utils.getStringFromCollection(userProvidedReplicatedSuffixes,
|
Constants.LINE_SEPARATOR)));
|
}
|
suffixes.clear();
|
}
|
else
|
{
|
// Verify that the provided suffixes are configured in the servers.
|
TreeSet<String> notFound = new TreeSet<String>();
|
TreeSet<String> alreadyReplicated = new TreeSet<String>();
|
for (String dn : suffixes)
|
{
|
boolean found = false;
|
for (String dn1 : availableSuffixes)
|
{
|
if (Utils.areDnsEqual(dn, dn1))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
boolean isReplicated = false;
|
for (String s : alreadyReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s, dn))
|
{
|
isReplicated = true;
|
break;
|
}
|
}
|
if (isReplicated)
|
{
|
alreadyReplicated.add(dn);
|
}
|
else
|
{
|
notFound.add(dn);
|
}
|
}
|
}
|
suffixes.removeAll(notFound);
|
suffixes.removeAll(alreadyReplicated);
|
if (notFound.size() > 0)
|
{
|
println();
|
println(ERR_REPLICATION_ENABLE_SUFFIXES_NOT_FOUND.get(
|
Utils.getStringFromCollection(notFound,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (alreadyReplicated.size() > 0)
|
{
|
println();
|
println(INFO_ALREADY_REPLICATED_SUFFIXES.get(
|
Utils.getStringFromCollection(alreadyReplicated,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (interactive)
|
{
|
boolean confirmationLimitReached = false;
|
while (suffixes.isEmpty())
|
{
|
boolean noSchemaOrAds = false;
|
for (String s: availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(s, ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(s, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(s, Constants.REPLICATION_CHANGES_DN))
|
{
|
noSchemaOrAds = true;
|
}
|
}
|
if (!noSchemaOrAds)
|
{
|
// In interactive mode we do not propose to manage the
|
// administration suffix.
|
println();
|
println(
|
ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION.get());
|
break;
|
}
|
else
|
{
|
println();
|
println(ERR_NO_SUFFIXES_SELECTED_TO_REPLICATE.get());
|
for (String dn : availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(dn,
|
ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(dn, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(dn, Constants.REPLICATION_CHANGES_DN))
|
{
|
try
|
{
|
if (askConfirmation(
|
INFO_REPLICATION_ENABLE_SUFFIX_PROMPT.get(dn), true, LOG))
|
{
|
suffixes.add(dn);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
confirmationLimitReached = true;
|
break;
|
}
|
}
|
}
|
}
|
if (confirmationLimitReached)
|
{
|
suffixes.clear();
|
break;
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* Checks that replication can actually be disabled in the provided baseDNs
|
* for the server.
|
* @param suffixes the suffixes provided by the user. This Collection is
|
* updated by removing the base DNs that cannot be disabled and with the
|
* base DNs that the user provided interactively.
|
* @param ctx connection to the server.
|
* @param interactive whether to ask the user to provide interactively
|
* base DNs if none of the provided base DNs can be disabled.
|
* @param displayErrors whether to display errors or not.
|
* @param areSuffixRequired whether the user must provide base DNs or not
|
* (if it is <CODE>false</CODE> the user will be proposed the suffixes
|
* only once).
|
*/
|
private void checkSuffixesForDisableReplication(Collection<String> suffixes,
|
InitialLdapContext ctx, boolean interactive, boolean displayErrors,
|
boolean areSuffixRequired)
|
{
|
TreeSet<String> availableSuffixes = new TreeSet<String>();
|
TreeSet<String> notReplicatedSuffixes = new TreeSet<String>();
|
|
Collection<ReplicaDescriptor> replicas = getReplicas(ctx);
|
for (ReplicaDescriptor rep : replicas)
|
{
|
String dn = rep.getSuffix().getDN();
|
if (rep.isReplicated())
|
{
|
availableSuffixes.add(dn);
|
}
|
else
|
{
|
notReplicatedSuffixes.add(dn);
|
}
|
}
|
if (availableSuffixes.size() == 0)
|
{
|
if (displayErrors)
|
{
|
println();
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_DISABLE_REPLICATION.get());
|
}
|
LinkedList<String> userProvidedSuffixes = argParser.getBaseDNs();
|
TreeSet<String> userProvidedNotReplicatedSuffixes =
|
new TreeSet<String>();
|
for (String s1 : userProvidedSuffixes)
|
{
|
for (String s2 : notReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s1, s2))
|
{
|
userProvidedNotReplicatedSuffixes.add(s1);
|
}
|
}
|
}
|
if (userProvidedNotReplicatedSuffixes.size() > 0 && displayErrors)
|
{
|
println();
|
println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(
|
Utils.getStringFromCollection(
|
userProvidedNotReplicatedSuffixes,
|
Constants.LINE_SEPARATOR)));
|
}
|
suffixes.clear();
|
}
|
else
|
{
|
// Verify that the provided suffixes are configured in the servers.
|
TreeSet<String> notFound = new TreeSet<String>();
|
TreeSet<String> alreadyNotReplicated = new TreeSet<String>();
|
for (String dn : suffixes)
|
{
|
boolean found = false;
|
for (String dn1 : availableSuffixes)
|
{
|
if (Utils.areDnsEqual(dn, dn1))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
boolean notReplicated = false;
|
for (String s : notReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s, dn))
|
{
|
notReplicated = true;
|
break;
|
}
|
}
|
if (notReplicated)
|
{
|
alreadyNotReplicated.add(dn);
|
}
|
else
|
{
|
notFound.add(dn);
|
}
|
}
|
}
|
suffixes.removeAll(notFound);
|
suffixes.removeAll(alreadyNotReplicated);
|
if (notFound.size() > 0 && displayErrors)
|
{
|
println();
|
println(ERR_REPLICATION_DISABLE_SUFFIXES_NOT_FOUND.get(
|
Utils.getStringFromCollection(notFound,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (alreadyNotReplicated.size() > 0 && displayErrors)
|
{
|
println();
|
println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(
|
Utils.getStringFromCollection(alreadyNotReplicated,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (interactive)
|
{
|
boolean confirmationLimitReached = false;
|
while (suffixes.isEmpty())
|
{
|
boolean noSchemaOrAds = false;
|
for (String s: availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(s, ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(s, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(s, Constants.REPLICATION_CHANGES_DN))
|
{
|
noSchemaOrAds = true;
|
}
|
}
|
if (!noSchemaOrAds)
|
{
|
// In interactive mode we do not propose to manage the
|
// administration suffix.
|
if (displayErrors)
|
{
|
println();
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_DISABLE_REPLICATION.get());
|
}
|
break;
|
}
|
else
|
{
|
if (areSuffixRequired)
|
{
|
println();
|
println(ERR_NO_SUFFIXES_SELECTED_TO_DISABLE.get());
|
}
|
for (String dn : availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(dn,
|
ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(dn, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(dn, Constants.REPLICATION_CHANGES_DN))
|
{
|
try
|
{
|
if (askConfirmation(
|
INFO_REPLICATION_DISABLE_SUFFIX_PROMPT.get(dn), true,
|
LOG))
|
{
|
suffixes.add(dn);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
confirmationLimitReached = true;
|
break;
|
}
|
}
|
}
|
}
|
if (confirmationLimitReached)
|
{
|
suffixes.clear();
|
break;
|
}
|
if (!areSuffixRequired)
|
{
|
break;
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* Checks that replication can actually be initialized in the provided baseDNs
|
* for the server.
|
* @param suffixes the suffixes provided by the user. This Collection is
|
* updated by removing the base DNs that cannot be initialized and with the
|
* base DNs that the user provided interactively.
|
* @param ctx connection to the server.
|
* @param interactive whether to ask the user to provide interactively
|
* base DNs if none of the provided base DNs can be initialized.
|
*/
|
private void checkSuffixesForInitializeReplication(
|
Collection<String> suffixes, InitialLdapContext ctx, boolean interactive)
|
{
|
TreeSet<String> availableSuffixes = new TreeSet<String>();
|
TreeSet<String> notReplicatedSuffixes = new TreeSet<String>();
|
|
Collection<ReplicaDescriptor> replicas = getReplicas(ctx);
|
for (ReplicaDescriptor rep : replicas)
|
{
|
String dn = rep.getSuffix().getDN();
|
if (rep.isReplicated())
|
{
|
availableSuffixes.add(dn);
|
}
|
else
|
{
|
notReplicatedSuffixes.add(dn);
|
}
|
}
|
if (availableSuffixes.size() == 0)
|
{
|
println();
|
if (argParser.isInitializeAllReplicationSubcommand())
|
{
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_ALL_REPLICATION.get());
|
}
|
else
|
{
|
println(
|
ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_LOCAL_REPLICATION.get());
|
}
|
LinkedList<String> userProvidedSuffixes = argParser.getBaseDNs();
|
TreeSet<String> userProvidedNotReplicatedSuffixes =
|
new TreeSet<String>();
|
for (String s1 : userProvidedSuffixes)
|
{
|
for (String s2 : notReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s1, s2))
|
{
|
userProvidedNotReplicatedSuffixes.add(s1);
|
}
|
}
|
}
|
if (userProvidedNotReplicatedSuffixes.size() > 0)
|
{
|
println();
|
println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(
|
Utils.getStringFromCollection(
|
userProvidedNotReplicatedSuffixes,
|
Constants.LINE_SEPARATOR)));
|
}
|
suffixes.clear();
|
}
|
else
|
{
|
// Verify that the provided suffixes are configured in the servers.
|
TreeSet<String> notFound = new TreeSet<String>();
|
TreeSet<String> alreadyNotReplicated = new TreeSet<String>();
|
for (String dn : suffixes)
|
{
|
boolean found = false;
|
for (String dn1 : availableSuffixes)
|
{
|
if (Utils.areDnsEqual(dn, dn1))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
boolean notReplicated = false;
|
for (String s : notReplicatedSuffixes)
|
{
|
if (Utils.areDnsEqual(s, dn))
|
{
|
notReplicated = true;
|
break;
|
}
|
}
|
if (notReplicated)
|
{
|
alreadyNotReplicated.add(dn);
|
}
|
else
|
{
|
notFound.add(dn);
|
}
|
}
|
}
|
suffixes.removeAll(notFound);
|
suffixes.removeAll(alreadyNotReplicated);
|
if (notFound.size() > 0)
|
{
|
println();
|
println(ERR_REPLICATION_INITIALIZE_LOCAL_SUFFIXES_NOT_FOUND.get(
|
Utils.getStringFromCollection(notFound,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (alreadyNotReplicated.size() > 0)
|
{
|
println();
|
println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(
|
Utils.getStringFromCollection(alreadyNotReplicated,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (interactive)
|
{
|
boolean confirmationLimitReached = false;
|
while (suffixes.isEmpty())
|
{
|
boolean noSchemaOrAds = false;
|
for (String s: availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(s, ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(s, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(s, Constants.REPLICATION_CHANGES_DN))
|
{
|
noSchemaOrAds = true;
|
}
|
}
|
if (!noSchemaOrAds)
|
{
|
// In interactive mode we do not propose to manage the
|
// administration suffix.
|
println();
|
if (argParser.isInitializeAllReplicationSubcommand())
|
{
|
println(
|
ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_ALL_REPLICATION.get());
|
}
|
else
|
{
|
println(
|
ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_LOCAL_REPLICATION.get());
|
}
|
break;
|
}
|
else
|
{
|
println();
|
if (argParser.isInitializeAllReplicationSubcommand())
|
{
|
println(ERR_NO_SUFFIXES_SELECTED_TO_INITIALIZE_ALL.get());
|
}
|
else if (argParser.isPreExternalInitializationSubcommand())
|
{
|
println(
|
ERR_NO_SUFFIXES_SELECTED_TO_PRE_EXTERNAL_INITIALIZATION.get());
|
}
|
else if (argParser.isPostExternalInitializationSubcommand())
|
{
|
println(
|
ERR_NO_SUFFIXES_SELECTED_TO_POST_EXTERNAL_INITIALIZATION.get());
|
}
|
for (String dn : availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(dn,
|
ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(dn, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(dn, Constants.REPLICATION_CHANGES_DN))
|
{
|
boolean addSuffix;
|
try
|
{
|
if (argParser.isPreExternalInitializationSubcommand())
|
{
|
addSuffix = askConfirmation(
|
INFO_REPLICATION_PRE_EXTERNAL_INITIALIZATION_SUFFIX_PROMPT.
|
get(dn), true, LOG);
|
}
|
else if (argParser.isPostExternalInitializationSubcommand())
|
{
|
addSuffix = askConfirmation(
|
INFO_REPLICATION_POST_EXTERNAL_INITIALIZATION_SUFFIX_PROMPT.
|
get(dn), true, LOG);
|
}
|
else
|
{
|
addSuffix = askConfirmation(
|
INFO_REPLICATION_INITIALIZE_ALL_SUFFIX_PROMPT.get(dn),
|
true, LOG);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
confirmationLimitReached = true;
|
break;
|
}
|
if (addSuffix)
|
{
|
suffixes.add(dn);
|
}
|
}
|
}
|
}
|
if (confirmationLimitReached)
|
{
|
suffixes.clear();
|
break;
|
}
|
}
|
}
|
}
|
}
|
|
|
/**
|
* Checks that we can initialize the provided baseDNs between the two servers.
|
* @param suffixes the suffixes provided by the user. This Collection is
|
* updated by removing the base DNs that cannot be enabled and with the
|
* base DNs that the user provided interactively.
|
* @param ctxSource connection to the source server.
|
* @param ctxDestination connection to the destination server.
|
* @param interactive whether to ask the user to provide interactively
|
* base DNs if none of the provided base DNs can be initialized.
|
*/
|
private void checkSuffixesForInitializeReplication(
|
Collection<String> suffixes, InitialLdapContext ctxSource,
|
InitialLdapContext ctxDestination, boolean interactive)
|
{
|
TreeSet<String> availableSuffixes = new TreeSet<String>(
|
getCommonSuffixes(ctxSource, ctxDestination,
|
SuffixRelationType.REPLICATED));
|
if (availableSuffixes.size() == 0)
|
{
|
println();
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_REPLICATION.get());
|
suffixes.clear();
|
}
|
else
|
{
|
// Verify that the provided suffixes are configured in the servers.
|
LinkedList<String> notFound = new LinkedList<String>();
|
for (String dn : suffixes)
|
{
|
boolean found = false;
|
for (String dn1 : availableSuffixes)
|
{
|
if (Utils.areDnsEqual(dn, dn1))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
notFound.add(dn);
|
}
|
}
|
suffixes.removeAll(notFound);
|
if (notFound.size() > 0)
|
{
|
println();
|
println(ERR_SUFFIXES_CANNOT_BE_INITIALIZED.get(
|
Utils.getStringFromCollection(notFound,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (interactive)
|
{
|
boolean confirmationLimitReached = false;
|
while (suffixes.isEmpty())
|
{
|
boolean noSchemaOrAds = false;
|
for (String s: availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(s, ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(s, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(s, Constants.REPLICATION_CHANGES_DN))
|
{
|
noSchemaOrAds = true;
|
}
|
}
|
if (!noSchemaOrAds)
|
{
|
// In interactive mode we do not propose to manage the
|
// administration suffix.
|
println();
|
println(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_REPLICATION.get());
|
break;
|
}
|
else
|
{
|
println();
|
println(ERR_NO_SUFFIXES_SELECTED_TO_INITIALIZE.get());
|
|
for (String dn : availableSuffixes)
|
{
|
if (!Utils.areDnsEqual(dn,
|
ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(dn, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(dn, Constants.REPLICATION_CHANGES_DN))
|
{
|
try
|
{
|
if (askConfirmation(
|
INFO_REPLICATION_INITIALIZE_SUFFIX_PROMPT.get(dn), true,
|
LOG))
|
{
|
suffixes.add(dn);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
confirmationLimitReached = true;
|
break;
|
}
|
}
|
}
|
}
|
if (confirmationLimitReached)
|
{
|
suffixes.clear();
|
break;
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* Updates the configuration in the two servers (and in other servers if
|
* they are referenced) to enable replication.
|
* @param ctx1 the connection to the first server.
|
* @param ctx2 the connection to the second server.
|
* @param uData the EnableReplicationUserData object containing the required
|
* parameters to update the configuration.
|
* @throws ReplicationCliException if there is an error.
|
*/
|
private void updateConfiguration(InitialLdapContext ctx1,
|
InitialLdapContext ctx2, EnableReplicationUserData uData)
|
throws ReplicationCliException
|
{
|
LinkedHashSet<String> twoReplServers = new LinkedHashSet<String>();
|
LinkedHashSet<String> allRepServers = new LinkedHashSet<String>();
|
HashMap<String, LinkedHashSet<String>> hmRepServers =
|
new HashMap<String, LinkedHashSet<String>>();
|
Set<Integer> usedReplicationServerIds = new HashSet<Integer>();
|
HashMap<String, Set<Integer>> hmUsedReplicationDomainIds =
|
new HashMap<String, Set<Integer>>();
|
|
ServerDescriptor server1;
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
filter.addBaseDNToSearch(ADSContext.getAdministrationSuffixDN());
|
filter.addBaseDNToSearch(Constants.SCHEMA_DN);
|
for (String dn : uData.getBaseDNs())
|
{
|
filter.addBaseDNToSearch(dn);
|
}
|
try
|
{
|
server1 = ServerDescriptor.createStandalone(ctx1, filter);
|
}
|
catch (NamingException ne)
|
{
|
throw new ReplicationCliException(
|
getMessageForException(ne, ConnectionUtils.getHostPort(ctx1)),
|
ERROR_READING_CONFIGURATION, ne);
|
}
|
ServerDescriptor server2;
|
try
|
{
|
server2 = ServerDescriptor.createStandalone(ctx2, filter);
|
}
|
catch (NamingException ne)
|
{
|
throw new ReplicationCliException(
|
getMessageForException(ne, ConnectionUtils.getHostPort(ctx2)),
|
ERROR_READING_CONFIGURATION, ne);
|
}
|
|
ADSContext adsCtx1 = new ADSContext(ctx1);
|
ADSContext adsCtx2 = new ADSContext(ctx2);
|
|
if (!argParser.isInteractive())
|
{
|
// Inform the user of the potential errors that we found in the already
|
// registered servers.
|
LinkedHashSet<Message> messages = new LinkedHashSet<Message>();
|
try
|
{
|
LinkedHashSet<PreferredConnection> cnx =
|
new LinkedHashSet<PreferredConnection>();
|
cnx.addAll(PreferredConnection.getPreferredConnections(ctx1));
|
cnx.addAll(PreferredConnection.getPreferredConnections(ctx2));
|
if (adsCtx1.hasAdminData())
|
{
|
TopologyCache cache = new TopologyCache(adsCtx1, getTrustManager(),
|
getConnectTimeout());
|
cache.setPreferredConnections(cnx);
|
cache.getFilter().setSearchMonitoringInformation(false);
|
for (String dn : uData.getBaseDNs())
|
{
|
cache.getFilter().addBaseDNToSearch(dn);
|
}
|
cache.reloadTopology();
|
messages.addAll(cache.getErrorMessages());
|
}
|
|
if (adsCtx2.hasAdminData())
|
{
|
TopologyCache cache = new TopologyCache(adsCtx2, getTrustManager(),
|
getConnectTimeout());
|
cache.setPreferredConnections(cnx);
|
cache.getFilter().setSearchMonitoringInformation(false);
|
for (String dn : uData.getBaseDNs())
|
{
|
cache.getFilter().addBaseDNToSearch(dn);
|
}
|
cache.reloadTopology();
|
messages.addAll(cache.getErrorMessages());
|
}
|
}
|
catch (TopologyCacheException tce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
|
ERROR_READING_TOPOLOGY_CACHE, tce);
|
}
|
catch (ADSContextException adce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(adce.getMessage()),
|
ERROR_READING_ADS, adce);
|
}
|
if (!messages.isEmpty())
|
{
|
println(ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING.get(
|
Utils.getMessageFromCollection(messages,
|
Constants.LINE_SEPARATOR).toString()));
|
}
|
}
|
// Check whether there is more than one replication server in the
|
// topology.
|
Set<String> baseDNsWithOneReplicationServer = new TreeSet<String>();
|
Set<String> baseDNsWithNoReplicationServer = new TreeSet<String>();
|
updateBaseDnsWithNotEnoughReplicationServer(adsCtx1, adsCtx2, uData,
|
baseDNsWithNoReplicationServer, baseDNsWithOneReplicationServer);
|
|
if (!baseDNsWithNoReplicationServer.isEmpty())
|
{
|
Message errorMsg =
|
ERR_REPLICATION_NO_REPLICATION_SERVER.get(
|
Utils.getStringFromCollection(baseDNsWithNoReplicationServer,
|
Constants.LINE_SEPARATOR));
|
throw new ReplicationCliException(
|
errorMsg,
|
ReplicationCliReturnCode.ERROR_USER_DATA, null);
|
}
|
else if (!baseDNsWithOneReplicationServer.isEmpty())
|
{
|
if (isInteractive())
|
{
|
Message confirmMsg =
|
INFO_REPLICATION_ONLY_ONE_REPLICATION_SERVER_CONFIRM.get(
|
Utils.getStringFromCollection(baseDNsWithOneReplicationServer,
|
Constants.LINE_SEPARATOR));
|
try
|
{
|
if (!confirmAction(confirmMsg, false))
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
catch (Throwable t)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, t);
|
}
|
}
|
else
|
{
|
Message warningMsg =
|
INFO_REPLICATION_ONLY_ONE_REPLICATION_SERVER_WARNING.get(
|
Utils.getStringFromCollection(baseDNsWithOneReplicationServer,
|
Constants.LINE_SEPARATOR));
|
println(warningMsg);
|
println();
|
}
|
}
|
|
// These are used to identify which server we use to initialize
|
// the contents of the other server (if any).
|
InitialLdapContext ctxSource = null;
|
InitialLdapContext ctxDestination = null;
|
ADSContext adsCtxSource = null;
|
|
boolean adsAlreadyReplicated = false;
|
boolean adsMergeDone = false;
|
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_ENABLE_UPDATING_ADS_CONTENTS.get()));
|
try
|
{
|
if (adsCtx1.hasAdminData() && adsCtx2.hasAdminData())
|
{
|
Set<Map<ADSContext.ServerProperty, Object>> registry1 =
|
adsCtx1.readServerRegistry();
|
Set<Map<ADSContext.ServerProperty, Object>> registry2 =
|
adsCtx2.readServerRegistry();
|
if (registry2.size() <= 1)
|
{
|
if (!hasAdministrator(adsCtx1.getDirContext(), uData))
|
{
|
adsCtx1.createAdministrator(getAdministratorProperties(uData));
|
}
|
server2.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx1, server2.getAdsProperties());
|
if (!ADSContext.isRegistered(server1, registry1))
|
{
|
server1.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx1, server1.getAdsProperties());
|
}
|
|
ctxSource = ctx1;
|
ctxDestination = ctx2;
|
adsCtxSource = adsCtx1;
|
}
|
else if (registry1.size() <= 1)
|
{
|
if (!hasAdministrator(adsCtx2.getDirContext(), uData))
|
{
|
adsCtx2.createAdministrator(getAdministratorProperties(uData));
|
}
|
server1.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx2, server1.getAdsProperties());
|
|
if (!ADSContext.isRegistered(server2, registry2))
|
{
|
server2.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx2, server2.getAdsProperties());
|
}
|
|
ctxSource = ctx2;
|
ctxDestination = ctx1;
|
adsCtxSource = adsCtx2;
|
}
|
else if (!areEqual(registry1, registry2))
|
{
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
|
boolean isFirstSource = mergeRegistries(adsCtx1, adsCtx2);
|
if (isFirstSource)
|
{
|
ctxSource = ctx1;
|
}
|
else
|
{
|
ctxSource = ctx2;
|
}
|
adsMergeDone = true;
|
}
|
else
|
{
|
// They are already replicated: nothing to do in terms of ADS
|
// initialization or ADS update data
|
adsAlreadyReplicated = isBaseDNReplicated(server1, server2,
|
ADSContext.getAdministrationSuffixDN());
|
|
if (!adsAlreadyReplicated)
|
{
|
// Try to merge if both are replicated
|
boolean isADS1Replicated = isBaseDNReplicated(server1,
|
ADSContext.getAdministrationSuffixDN());
|
boolean isADS2Replicated = isBaseDNReplicated(server2,
|
ADSContext.getAdministrationSuffixDN());
|
if (isADS1Replicated && isADS2Replicated)
|
{
|
// Merge
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
|
boolean isFirstSource = mergeRegistries(adsCtx1, adsCtx2);
|
if (isFirstSource)
|
{
|
ctxSource = ctx1;
|
}
|
else
|
{
|
ctxSource = ctx2;
|
}
|
adsMergeDone = true;
|
}
|
else if (isADS1Replicated || !isADS2Replicated)
|
{
|
// The case where only the first ADS is replicated or none
|
// is replicated.
|
if (!hasAdministrator(adsCtx1.getDirContext(), uData))
|
{
|
adsCtx1.createAdministrator(getAdministratorProperties(uData));
|
}
|
server2.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx1, server2.getAdsProperties());
|
if (!ADSContext.isRegistered(server1, registry1))
|
{
|
server1.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx1, server1.getAdsProperties());
|
}
|
|
ctxSource = ctx1;
|
ctxDestination = ctx2;
|
adsCtxSource = adsCtx1;
|
}
|
else if (isADS2Replicated)
|
{
|
if (!hasAdministrator(adsCtx2.getDirContext(), uData))
|
{
|
adsCtx2.createAdministrator(getAdministratorProperties(uData));
|
}
|
server1.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx2, server1.getAdsProperties());
|
if (!ADSContext.isRegistered(server2, registry2))
|
{
|
server2.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx2, server2.getAdsProperties());
|
}
|
|
ctxSource = ctx2;
|
ctxDestination = ctx1;
|
adsCtxSource = adsCtx2;
|
}
|
}
|
}
|
}
|
else if (!adsCtx1.hasAdminData() && adsCtx2.hasAdminData())
|
{
|
// adsCtx1.createAdministrationSuffix(null);
|
if (!hasAdministrator(adsCtx2.getDirContext(), uData))
|
{
|
adsCtx2.createAdministrator(getAdministratorProperties(uData));
|
}
|
server1.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx2, server1.getAdsProperties());
|
Set<Map<ADSContext.ServerProperty, Object>> registry2 =
|
adsCtx2.readServerRegistry();
|
if (!ADSContext.isRegistered(server2, registry2))
|
{
|
server2.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx2, server2.getAdsProperties());
|
}
|
|
ctxSource = ctx2;
|
ctxDestination = ctx1;
|
adsCtxSource = adsCtx2;
|
}
|
else if (adsCtx1.hasAdminData() && !adsCtx2.hasAdminData())
|
{
|
// adsCtx2.createAdministrationSuffix(null);
|
if (!hasAdministrator(adsCtx1.getDirContext(), uData))
|
{
|
adsCtx1.createAdministrator(getAdministratorProperties(uData));
|
}
|
server2.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx1, server2.getAdsProperties());
|
Set<Map<ADSContext.ServerProperty, Object>> registry1 =
|
adsCtx1.readServerRegistry();
|
if (!ADSContext.isRegistered(server1, registry1))
|
{
|
server1.updateAdsPropertiesWithServerProperties();
|
registerServer(adsCtx1, server1.getAdsProperties());
|
}
|
|
ctxSource = ctx1;
|
ctxDestination = ctx2;
|
adsCtxSource = adsCtx1;
|
}
|
else
|
{
|
adsCtx1.createAdminData(null);
|
if (!hasAdministrator(ctx1, uData))
|
{
|
// This could occur if the user created an administrator without
|
// registering any server.
|
adsCtx1.createAdministrator(getAdministratorProperties(uData));
|
}
|
server1.updateAdsPropertiesWithServerProperties();
|
adsCtx1.registerServer(server1.getAdsProperties());
|
server2.updateAdsPropertiesWithServerProperties();
|
adsCtx1.registerServer(server2.getAdsProperties());
|
// adsCtx2.createAdministrationSuffix(null);
|
|
ctxSource = ctx1;
|
ctxDestination = ctx2;
|
adsCtxSource = adsCtx1;
|
}
|
}
|
catch (ADSContextException adce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
|
ERROR_UPDATING_ADS, adce);
|
}
|
if (!adsAlreadyReplicated && !adsMergeDone)
|
{
|
try
|
{
|
ServerDescriptor.seedAdsTrustStore(ctxDestination,
|
adsCtxSource.getTrustedCertificates());
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error seeding truststores: "+t, t);
|
String arg = (t instanceof OpenDsException) ?
|
((OpenDsException)t).getMessageObject().toString() : t.toString();
|
throw new ReplicationCliException(
|
ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(
|
ConnectionUtils.getHostPort(ctxDestination),
|
ConnectionUtils.getHostPort(adsCtxSource.getDirContext()),
|
arg),
|
ERROR_SEEDING_TRUSTORE, t);
|
}
|
}
|
if (!adsMergeDone)
|
{
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
if (!adsAlreadyReplicated)
|
{
|
boolean found = false;
|
for (String dn : baseDNs)
|
{
|
if (Utils.areDnsEqual(dn, ADSContext.getAdministrationSuffixDN()))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
baseDNs.add(ADSContext.getAdministrationSuffixDN());
|
uData.setBaseDNs(baseDNs);
|
}
|
}
|
|
if (uData.replicateSchema())
|
{
|
baseDNs = uData.getBaseDNs();
|
baseDNs.add(Constants.SCHEMA_DN);
|
uData.setBaseDNs(baseDNs);
|
}
|
TopologyCache cache1 = null;
|
TopologyCache cache2 = null;
|
|
try
|
{
|
LinkedHashSet<PreferredConnection> cnx =
|
new LinkedHashSet<PreferredConnection>();
|
cnx.addAll(PreferredConnection.getPreferredConnections(ctx1));
|
cnx.addAll(PreferredConnection.getPreferredConnections(ctx2));
|
if (adsCtx1.hasAdminData())
|
{
|
cache1 = new TopologyCache(adsCtx1, getTrustManager(),
|
getConnectTimeout());
|
cache1.setPreferredConnections(cnx);
|
cache1.getFilter().setSearchMonitoringInformation(false);
|
for (String dn : uData.getBaseDNs())
|
{
|
cache1.getFilter().addBaseDNToSearch(dn);
|
}
|
cache1.reloadTopology();
|
usedReplicationServerIds.addAll(getReplicationServerIds(cache1));
|
}
|
|
if (adsCtx2.hasAdminData())
|
{
|
cache2 = new TopologyCache(adsCtx2, getTrustManager(),
|
getConnectTimeout());
|
cache2.setPreferredConnections(cnx);
|
cache2.getFilter().setSearchMonitoringInformation(false);
|
for (String dn : uData.getBaseDNs())
|
{
|
cache2.getFilter().addBaseDNToSearch(dn);
|
}
|
cache2.reloadTopology();
|
usedReplicationServerIds.addAll(getReplicationServerIds(cache2));
|
}
|
}
|
catch (ADSContextException adce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(adce.getMessage()),
|
ERROR_READING_ADS, adce);
|
}
|
catch (TopologyCacheException tce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
|
ERROR_READING_TOPOLOGY_CACHE, tce);
|
}
|
|
if (server1.isReplicationServer())
|
{
|
twoReplServers.add(server1.getReplicationServerHostPort());
|
usedReplicationServerIds.add(server1.getReplicationServerId());
|
}
|
else if (uData.configureReplicationServer1())
|
{
|
twoReplServers.add(getReplicationServer(
|
ConnectionUtils.getHostName(ctx1), uData.getReplicationPort1()));
|
}
|
if (server2.isReplicationServer())
|
{
|
twoReplServers.add(server2.getReplicationServerHostPort());
|
usedReplicationServerIds.add(server2.getReplicationServerId());
|
}
|
else if (uData.configureReplicationServer2())
|
{
|
twoReplServers.add(getReplicationServer(
|
ConnectionUtils.getHostName(ctx2), uData.getReplicationPort2()));
|
}
|
|
for (String baseDN : uData.getBaseDNs())
|
{
|
LinkedHashSet<String> repServersForBaseDN = new LinkedHashSet<String>();
|
repServersForBaseDN.addAll(getReplicationServers(baseDN, cache1,
|
server1));
|
repServersForBaseDN.addAll(getReplicationServers(baseDN, cache2,
|
server2));
|
repServersForBaseDN.addAll(twoReplServers);
|
hmRepServers.put(baseDN, repServersForBaseDN);
|
|
Set<Integer> ids = new HashSet<Integer>();
|
ids.addAll(getReplicationDomainIds(baseDN, server1));
|
ids.addAll(getReplicationDomainIds(baseDN, server2));
|
if (cache1 != null)
|
{
|
for (ServerDescriptor server : cache1.getServers())
|
{
|
ids.addAll(getReplicationDomainIds(baseDN, server));
|
}
|
}
|
if (cache2 != null)
|
{
|
for (ServerDescriptor server : cache2.getServers())
|
{
|
ids.addAll(getReplicationDomainIds(baseDN, server));
|
}
|
}
|
hmUsedReplicationDomainIds.put(baseDN, ids);
|
}
|
for (LinkedHashSet<String> v : hmRepServers.values())
|
{
|
allRepServers.addAll(v);
|
}
|
|
Set<String> alreadyConfiguredReplicationServers = new HashSet<String>();
|
if (!server1.isReplicationServer() && uData.configureReplicationServer1())
|
{
|
try
|
{
|
configureAsReplicationServer(ctx1, uData.getReplicationPort1(),
|
uData.isSecureReplication1(), allRepServers,
|
usedReplicationServerIds);
|
}
|
catch (OpenDsException ode)
|
{
|
throw new ReplicationCliException(
|
getMessageForReplicationServerException(ode,
|
ConnectionUtils.getHostPort(ctx1)),
|
ERROR_CONFIGURING_REPLICATIONSERVER, ode);
|
}
|
}
|
else if (server1.isReplicationServer())
|
{
|
try
|
{
|
updateReplicationServer(ctx1, allRepServers);
|
}
|
catch (OpenDsException ode)
|
{
|
throw new ReplicationCliException(
|
getMessageForReplicationServerException(ode,
|
ConnectionUtils.getHostPort(ctx1)),
|
ERROR_CONFIGURING_REPLICATIONSERVER, ode);
|
}
|
if (argParser.replicationPort1Arg.isPresent())
|
{
|
// Inform the user that the provided value will be ignored
|
if (uData.getReplicationPort1() !=
|
server1.getReplicationServerPort())
|
{
|
LOG.log(Level.WARNING, "Ignoring provided replication port for "+
|
"first server (already configured with port "+
|
server1.getReplicationServerPort()+")");
|
println(WARN_FIRST_REPLICATION_SERVER_ALREADY_CONFIGURED.get(
|
server1.getReplicationServerPort(), uData.getReplicationPort1()));
|
}
|
}
|
}
|
alreadyConfiguredReplicationServers.add(server1.getId());
|
if (!server2.isReplicationServer() && uData.configureReplicationServer2())
|
{
|
try
|
{
|
configureAsReplicationServer(ctx2, uData.getReplicationPort2(),
|
uData.isSecureReplication2(), allRepServers,
|
usedReplicationServerIds);
|
}
|
catch (OpenDsException ode)
|
{
|
throw new ReplicationCliException(
|
getMessageForReplicationServerException(ode,
|
ConnectionUtils.getHostPort(ctx1)),
|
ERROR_CONFIGURING_REPLICATIONSERVER, ode);
|
}
|
}
|
else if (server2.isReplicationServer())
|
{
|
try
|
{
|
updateReplicationServer(ctx2, allRepServers);
|
}
|
catch (OpenDsException ode)
|
{
|
throw new ReplicationCliException(
|
getMessageForReplicationServerException(ode,
|
ConnectionUtils.getHostPort(ctx1)),
|
ERROR_CONFIGURING_REPLICATIONSERVER, ode);
|
}
|
if (argParser.replicationPort2Arg.isPresent())
|
{
|
// Inform the user that the provided value will be ignored
|
if (uData.getReplicationPort2() !=
|
server2.getReplicationServerPort())
|
{
|
LOG.log(Level.WARNING, "Ignoring provided replication port for "+
|
"second server (already configured with port "+
|
server2.getReplicationServerPort()+")");
|
println(WARN_SECOND_REPLICATION_SERVER_ALREADY_CONFIGURED.get(
|
server2.getReplicationServerPort(), uData.getReplicationPort2()));
|
}
|
}
|
}
|
alreadyConfiguredReplicationServers.add(server2.getId());
|
|
for (String baseDN : uData.getBaseDNs())
|
{
|
LinkedHashSet<String> repServers = hmRepServers.get(baseDN);
|
Set<Integer> usedIds = hmUsedReplicationDomainIds.get(baseDN);
|
Set<String> alreadyConfiguredServers = new HashSet<String>();
|
|
if (uData.configureReplicationDomain1() ||
|
Utils.areDnsEqual(baseDN, ADSContext.getAdministrationSuffixDN()))
|
{
|
try
|
{
|
configureToReplicateBaseDN(ctx1, baseDN, repServers, usedIds);
|
}
|
catch (OpenDsException ode)
|
{
|
Message msg = getMessageForEnableException(ode,
|
ConnectionUtils.getHostPort(ctx1), baseDN);
|
throw new ReplicationCliException(msg,
|
ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
|
}
|
}
|
alreadyConfiguredServers.add(server1.getId());
|
|
if (uData.configureReplicationDomain2() ||
|
Utils.areDnsEqual(baseDN, ADSContext.getAdministrationSuffixDN()))
|
{
|
try
|
{
|
configureToReplicateBaseDN(ctx2, baseDN, repServers, usedIds);
|
}
|
catch (OpenDsException ode)
|
{
|
Message msg = getMessageForEnableException(ode,
|
ConnectionUtils.getHostPort(ctx2), baseDN);
|
throw new ReplicationCliException(msg,
|
ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
|
}
|
}
|
alreadyConfiguredServers.add(server2.getId());
|
|
if (cache1 != null)
|
{
|
configureToReplicateBaseDN(baseDN, repServers, usedIds, cache1, server1,
|
alreadyConfiguredServers, allRepServers,
|
alreadyConfiguredReplicationServers);
|
}
|
if (cache2 != null)
|
{
|
configureToReplicateBaseDN(baseDN, repServers, usedIds, cache2, server2,
|
alreadyConfiguredServers, allRepServers,
|
alreadyConfiguredReplicationServers);
|
}
|
}
|
|
// Now that replication is configured in all servers, simply try to
|
// initialize the contents of one ADS with the other (in the case where
|
// already both servers were replicating the same ADS there is nothing to be
|
// done).
|
if (adsMergeDone)
|
{
|
PointAdder pointAdder = new PointAdder(this);
|
printProgress(
|
INFO_ENABLE_REPLICATION_INITIALIZING_ADS_ALL.get(
|
ConnectionUtils.getHostPort(ctxSource)));
|
pointAdder.start();
|
try
|
{
|
initializeAllSuffix(ADSContext.getAdministrationSuffixDN(),
|
ctxSource, false);
|
}
|
finally
|
{
|
pointAdder.stop();
|
}
|
printProgress(formatter.getSpace());
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
else if ((ctxSource != null) && (ctxDestination != null))
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_ENABLE_REPLICATION_INITIALIZING_ADS.get(
|
ConnectionUtils.getHostPort(ctxDestination),
|
ConnectionUtils.getHostPort(ctxSource))));
|
|
initializeSuffix(ADSContext.getAdministrationSuffixDN(), ctxSource,
|
ctxDestination, false);
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
|
// If we must initialize the schema do so.
|
if (mustInitializeSchema(server1, server2, uData))
|
{
|
if (argParser.useSecondServerAsSchemaSource())
|
{
|
ctxSource = ctx2;
|
ctxDestination = ctx1;
|
}
|
else
|
{
|
ctxSource = ctx1;
|
ctxDestination = ctx2;
|
}
|
if (adsMergeDone)
|
{
|
PointAdder pointAdder = new PointAdder(this);
|
printProgress(
|
INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get(
|
ConnectionUtils.getHostPort(ctxDestination),
|
ConnectionUtils.getHostPort(ctxSource)));
|
pointAdder.start();
|
try
|
{
|
initializeAllSuffix(Constants.SCHEMA_DN, ctxSource, false);
|
}
|
finally
|
{
|
pointAdder.stop();
|
}
|
printProgress(formatter.getSpace());
|
}
|
else
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get(
|
ConnectionUtils.getHostPort(ctxDestination),
|
ConnectionUtils.getHostPort(ctxSource))));
|
initializeSuffix(Constants.SCHEMA_DN, ctxSource,
|
ctxDestination, false);
|
}
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
}
|
|
/**
|
* Updates the configuration in the server (and in other servers if
|
* they are referenced) to disable replication.
|
* @param ctx the connection to the server.
|
* @param uData the DisableReplicationUserData object containing the required
|
* parameters to update the configuration.
|
* @throws ReplicationCliException if there is an error.
|
*/
|
private void updateConfiguration(InitialLdapContext ctx,
|
DisableReplicationUserData uData) throws ReplicationCliException
|
{
|
ServerDescriptor server;
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
if (!uData.disableAll())
|
{
|
filter.addBaseDNToSearch(ADSContext.getAdministrationSuffixDN());
|
for (String dn : uData.getBaseDNs())
|
{
|
filter.addBaseDNToSearch(dn);
|
}
|
}
|
try
|
{
|
server = ServerDescriptor.createStandalone(ctx, filter);
|
}
|
catch (NamingException ne)
|
{
|
throw new ReplicationCliException(
|
getMessageForException(ne, ConnectionUtils.getHostPort(ctx)),
|
ERROR_READING_CONFIGURATION, ne);
|
}
|
|
ADSContext adsCtx = new ADSContext(ctx);
|
|
TopologyCache cache = null;
|
// Only try to update remote server if the user provided a Global
|
// Administrator to authenticate.
|
boolean tryToUpdateRemote = uData.getAdminUid() != null;
|
try
|
{
|
if (adsCtx.hasAdminData() && tryToUpdateRemote)
|
{
|
cache = new TopologyCache(adsCtx, getTrustManager(),
|
getConnectTimeout());
|
cache.setPreferredConnections(
|
PreferredConnection.getPreferredConnections(ctx));
|
cache.getFilter().setSearchMonitoringInformation(false);
|
if (!uData.disableAll())
|
{
|
for (String dn : uData.getBaseDNs())
|
{
|
cache.getFilter().addBaseDNToSearch(dn);
|
}
|
}
|
cache.reloadTopology();
|
}
|
}
|
catch (ADSContextException adce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(adce.getMessage()),
|
ERROR_READING_ADS, adce);
|
}
|
catch (TopologyCacheException tce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
|
ERROR_READING_TOPOLOGY_CACHE, tce);
|
}
|
if (!argParser.isInteractive())
|
{
|
// Inform the user of the potential errors that we found.
|
LinkedHashSet<Message> messages = new LinkedHashSet<Message>();
|
if (cache != null)
|
{
|
messages.addAll(cache.getErrorMessages());
|
}
|
if (!messages.isEmpty())
|
{
|
println(
|
ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING.get(
|
Utils.getMessageFromCollection(messages,
|
Constants.LINE_SEPARATOR).toString()));
|
}
|
}
|
|
boolean disableReplicationServer = false;
|
if (server.isReplicationServer() &&
|
(uData.disableReplicationServer() || uData.disableAll()))
|
{
|
disableReplicationServer = true;
|
}
|
|
if ((cache != null) && disableReplicationServer)
|
{
|
String replicationServer = server.getReplicationServerHostPort();
|
// Figure out if this is the last replication server for a given
|
// topology (containing a different replica) or there will be only
|
// another replication server left (single point of failure).
|
Set<SuffixDescriptor> lastRepServer =
|
new TreeSet<SuffixDescriptor>(new SuffixComparator());
|
|
Set<SuffixDescriptor> beforeLastRepServer =
|
new TreeSet<SuffixDescriptor>(new SuffixComparator());
|
|
for (SuffixDescriptor suffix : cache.getSuffixes())
|
{
|
if (Utils.areDnsEqual(suffix.getDN(),
|
ADSContext.getAdministrationSuffixDN()) ||
|
Utils.areDnsEqual(suffix.getDN(), Constants.SCHEMA_DN))
|
{
|
// Do not display these suffixes.
|
continue;
|
}
|
|
Set<String> repServers = suffix.getReplicationServers();
|
|
if (repServers.size() <= 2)
|
{
|
boolean found = false;
|
for (String repServer : repServers)
|
{
|
if (repServer.equalsIgnoreCase(replicationServer))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (found)
|
{
|
if (repServers.size() == 2)
|
{
|
beforeLastRepServer.add(suffix);
|
}
|
else
|
{
|
lastRepServer.add(suffix);
|
}
|
}
|
}
|
}
|
|
// Inform the user
|
if (beforeLastRepServer.size() > 0)
|
{
|
LinkedHashSet<String> baseDNs = new LinkedHashSet<String>();
|
for (SuffixDescriptor suffix : beforeLastRepServer)
|
{
|
if (!Utils.areDnsEqual(suffix.getDN(),
|
ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(suffix.getDN(), Constants.SCHEMA_DN))
|
{
|
// Do not display these suffixes.
|
baseDNs.add(suffix.getDN());
|
}
|
}
|
if (!baseDNs.isEmpty())
|
{
|
String arg =
|
Utils.getStringFromCollection(baseDNs, Constants.LINE_SEPARATOR);
|
if (!isInteractive())
|
{
|
println(INFO_DISABLE_REPLICATION_ONE_POINT_OF_FAILURE.get(arg));
|
}
|
else
|
{
|
try
|
{
|
if (!askConfirmation(
|
INFO_DISABLE_REPLICATION_ONE_POINT_OF_FAILURE_PROMPT.get(arg),
|
false, LOG))
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
}
|
}
|
if (lastRepServer.size() > 0)
|
{
|
// Check that there are other replicas and that this message, really
|
// makes sense to be displayed.
|
LinkedHashSet<String> suffixArg = new LinkedHashSet<String>();
|
for (SuffixDescriptor suffix : lastRepServer)
|
{
|
boolean baseDNSpecified = false;
|
for (String baseDN : uData.getBaseDNs())
|
{
|
if (Utils.areDnsEqual(baseDN,
|
ADSContext.getAdministrationSuffixDN()) ||
|
Utils.areDnsEqual(baseDN, Constants.SCHEMA_DN))
|
{
|
// Do not display these suffixes.
|
continue;
|
}
|
if (Utils.areDnsEqual(baseDN, suffix.getDN()))
|
{
|
baseDNSpecified = true;
|
break;
|
}
|
}
|
if (!baseDNSpecified)
|
{
|
Set<ServerDescriptor> servers =
|
new TreeSet<ServerDescriptor>(new ServerComparator());
|
for (ReplicaDescriptor replica : suffix.getReplicas())
|
{
|
servers.add(replica.getServer());
|
}
|
suffixArg.add(getSuffixDisplay(suffix.getDN(), servers));
|
}
|
else
|
{
|
// Check that there are other replicas.
|
if (suffix.getReplicas().size() > 1)
|
{
|
// If there is just one replica, it is the one in this server.
|
Set<ServerDescriptor> servers =
|
new TreeSet<ServerDescriptor>(new ServerComparator());
|
for (ReplicaDescriptor replica : suffix.getReplicas())
|
{
|
if (!replica.getServer().isSameServer(server))
|
{
|
servers.add(replica.getServer());
|
}
|
}
|
if (!servers.isEmpty())
|
{
|
suffixArg.add(getSuffixDisplay(suffix.getDN(), servers));
|
}
|
}
|
}
|
}
|
|
if (!suffixArg.isEmpty())
|
{
|
String arg =
|
Utils.getStringFromCollection(suffixArg, Constants.LINE_SEPARATOR);
|
if (!isInteractive())
|
{
|
println(INFO_DISABLE_REPLICATION_DISABLE_IN_REMOTE.get(arg));
|
}
|
else
|
{
|
try
|
{
|
if (!askConfirmation(
|
INFO_DISABLE_REPLICATION_DISABLE_IN_REMOTE_PROMPT.get(arg),
|
false, LOG))
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* Try to figure out if we must explicitly disable replication on
|
* cn=admin data and cn=schema.
|
*/
|
boolean forceDisableSchema = false;
|
boolean forceDisableADS = false;
|
boolean schemaReplicated = false;
|
boolean adsReplicated = false;
|
boolean disableAllBaseDns = disableAllBaseDns(ctx, uData);
|
|
Collection<ReplicaDescriptor> replicas = getReplicas(ctx);
|
for (ReplicaDescriptor rep : replicas)
|
{
|
String dn = rep.getSuffix().getDN();
|
if (rep.isReplicated())
|
{
|
if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
|
{
|
adsReplicated = true;
|
}
|
else if (Utils.areDnsEqual(Constants.SCHEMA_DN, dn))
|
{
|
schemaReplicated = true;
|
}
|
}
|
}
|
|
|
if (disableAllBaseDns &&
|
(disableReplicationServer || !server.isReplicationServer()))
|
{
|
// Unregister the server from the ADS if no other server has dependencies
|
// with it (no replicated base DNs and no replication server).
|
server.updateAdsPropertiesWithServerProperties();
|
try
|
{
|
adsCtx.unregisterServer(server.getAdsProperties());
|
try
|
{
|
// To be sure that the change gets propagated
|
Thread.sleep(2000);
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
catch (ADSContextException adce)
|
{
|
LOG.log(Level.SEVERE, "Error unregistering server: "+
|
server.getAdsProperties(), adce);
|
if (adce.getError() != ADSContextException.ErrorType.NOT_YET_REGISTERED)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
|
ERROR_READING_ADS, adce);
|
}
|
}
|
}
|
|
Set<String> suffixesToDisable = new HashSet<String>();
|
|
if (uData.disableAll())
|
{
|
for (ReplicaDescriptor replica : server.getReplicas())
|
{
|
if (replica.isReplicated())
|
{
|
suffixesToDisable.add(replica.getSuffix().getDN());
|
}
|
}
|
}
|
else
|
{
|
suffixesToDisable.addAll(uData.getBaseDNs());
|
|
if (disableAllBaseDns &&
|
(disableReplicationServer || !server.isReplicationServer()))
|
{
|
forceDisableSchema = schemaReplicated;
|
forceDisableADS = adsReplicated;
|
}
|
for (String dn : uData.getBaseDNs())
|
{
|
if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
|
{
|
// The user already asked this to be explicitly disabled
|
forceDisableADS = false;
|
}
|
else if (Utils.areDnsEqual(Constants.SCHEMA_DN, dn))
|
{
|
// The user already asked this to be explicitly disabled
|
forceDisableSchema = false;
|
}
|
}
|
|
if (forceDisableSchema)
|
{
|
suffixesToDisable.add(Constants.SCHEMA_DN);
|
}
|
if (forceDisableADS)
|
{
|
suffixesToDisable.add(ADSContext.getAdministrationSuffixDN());
|
}
|
}
|
|
String replicationServerHostPort = null;
|
if (server.isReplicationServer())
|
{
|
replicationServerHostPort = server.getReplicationServerHostPort();
|
}
|
boolean replicationServerDisabled = false;
|
|
for (String baseDN : suffixesToDisable)
|
{
|
try
|
{
|
deleteReplicationDomain(ctx, baseDN);
|
}
|
catch (OpenDsException ode)
|
{
|
Message msg = getMessageForDisableException(ode,
|
ConnectionUtils.getHostPort(ctx), baseDN);
|
throw new ReplicationCliException(msg,
|
ERROR_DISABLING_REPLICATION_ON_BASEDN, ode);
|
}
|
}
|
|
if ((replicationServerHostPort != null) && (cache != null))
|
{
|
Set<ServerDescriptor> serversToUpdate =
|
new LinkedHashSet<ServerDescriptor>();
|
Set<String> baseDNsToUpdate = new HashSet<String>(suffixesToDisable);
|
for (String baseDN : baseDNsToUpdate)
|
{
|
SuffixDescriptor suffix = getSuffix(baseDN, cache, server);
|
if (suffix != null)
|
{
|
for (ReplicaDescriptor replica : suffix.getReplicas())
|
{
|
serversToUpdate.add(replica.getServer());
|
}
|
}
|
}
|
if (disableReplicationServer)
|
{
|
// Find references in all servers.
|
Set<SuffixDescriptor> suffixes = cache.getSuffixes();
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
boolean found = false;
|
for (String repServer : suffix.getReplicationServers())
|
{
|
found = repServer.equalsIgnoreCase(replicationServerHostPort);
|
if (found)
|
{
|
break;
|
}
|
}
|
if (found)
|
{
|
baseDNsToUpdate.add(suffix.getDN());
|
for (ReplicaDescriptor replica : suffix.getReplicas())
|
{
|
serversToUpdate.add(replica.getServer());
|
}
|
}
|
}
|
}
|
String bindDn = ConnectionUtils.getBindDN(ctx);
|
String pwd = ConnectionUtils.getBindPassword(ctx);
|
for (ServerDescriptor s : serversToUpdate)
|
{
|
removeReferencesInServer(s, replicationServerHostPort, bindDn, pwd,
|
baseDNsToUpdate, disableReplicationServer,
|
PreferredConnection.getPreferredConnections(ctx));
|
}
|
|
if (disableReplicationServer)
|
{
|
// Disable replication server
|
disableReplicationServer(ctx);
|
replicationServerDisabled = true;
|
// Wait to be sure that changes are taken into account and reset the
|
// contents of the ADS.
|
try
|
{
|
Thread.sleep(5000);
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
}
|
if (disableReplicationServer && !replicationServerDisabled)
|
{
|
// This can happen if we could not retrieve the TopologyCache
|
disableReplicationServer(ctx);
|
replicationServerDisabled = true;
|
}
|
|
if (uData.disableAll())
|
{
|
try
|
{
|
// Delete all contents from ADSContext.
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_REMOVE_ADS_CONTENTS.get()));
|
adsCtx.removeAdminData();
|
String adminBackendName = null;
|
for (ReplicaDescriptor replica : server.getReplicas())
|
{
|
if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(),
|
replica.getSuffix().getDN()))
|
{
|
adminBackendName = replica.getBackendName();
|
break;
|
}
|
}
|
adsCtx.createAdminData(adminBackendName);
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
catch (ADSContextException adce)
|
{
|
LOG.log(Level.SEVERE, "Error removing contents of cn=admin data: "+
|
adce, adce);
|
throw new ReplicationCliException(
|
ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
|
ERROR_UPDATING_ADS, adce);
|
}
|
try
|
{
|
// Delete all contents from truststore.
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_REMOVE_TRUSTSTORE_CONTENTS.get()));
|
ServerDescriptor.cleanAdsTrustStore(adsCtx.getDirContext());
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error removing contents of truststore: "+t, t);
|
throw new ReplicationCliException(
|
ERR_REPLICATION_UPDATING_ADS.get(t.toString()),
|
ERROR_UPDATING_ADS, t);
|
}
|
}
|
else if (disableAllBaseDns &&
|
(disableReplicationServer || !server.isReplicationServer()))
|
{
|
// Unregister the servers from the ADS of the local server.
|
try
|
{
|
Set<Map<ADSContext.ServerProperty, Object>> registry =
|
adsCtx.readServerRegistry();
|
for (Map<ADSContext.ServerProperty, Object> s : registry)
|
{
|
adsCtx.unregisterServer(s);
|
}
|
try
|
{
|
// To be sure that the change gets propagated
|
Thread.sleep(2000);
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
catch (ADSContextException adce)
|
{
|
// This is not critical, do not send an error
|
LOG.log(Level.WARNING, "Error unregistering server: "+
|
server.getAdsProperties(), adce);
|
}
|
}
|
}
|
|
/**
|
* Displays the replication status of the different base DNs in the servers
|
* registered in the ADS.
|
* @param ctx the connection to the server.
|
* @param uData the StatusReplicationUserData object containing the required
|
* parameters to update the configuration.
|
* @throws ReplicationCliException if there is an error.
|
*/
|
private void displayStatus(InitialLdapContext ctx,
|
StatusReplicationUserData uData) throws ReplicationCliException
|
{
|
ADSContext adsCtx = new ADSContext(ctx);
|
|
boolean somethingDisplayed = false;
|
TopologyCache cache = null;
|
try
|
{
|
cache = new TopologyCache(adsCtx, getTrustManager(),
|
getConnectTimeout());
|
cache.setPreferredConnections(
|
PreferredConnection.getPreferredConnections(ctx));
|
for (String dn : uData.getBaseDNs())
|
{
|
cache.getFilter().addBaseDNToSearch(dn);
|
}
|
cache.reloadTopology();
|
}
|
catch (TopologyCacheException tce)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
|
ERROR_READING_TOPOLOGY_CACHE, tce);
|
}
|
if (mustPrintCommandBuilder())
|
{
|
try
|
{
|
CommandBuilder commandBuilder = createCommandBuilder(
|
ReplicationCliArgumentParser.STATUS_REPLICATION_SUBCMD_NAME,
|
uData);
|
printCommandBuilder(commandBuilder);
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error printing equivalente command-line: "+t,
|
t);
|
}
|
}
|
if (!argParser.isInteractive())
|
{
|
// Inform the user of the potential errors that we found.
|
LinkedHashSet<Message> messages = new LinkedHashSet<Message>();
|
if (cache != null)
|
{
|
messages.addAll(cache.getErrorMessages());
|
}
|
if (!messages.isEmpty())
|
{
|
Message msg =
|
ERR_REPLICATION_STATUS_READING_REGISTERED_SERVERS.get(
|
Utils.getMessageFromCollection(messages,
|
Constants.LINE_SEPARATOR).toString());
|
println(msg);
|
}
|
}
|
|
LinkedList<String> userBaseDNs = uData.getBaseDNs();
|
LinkedList<Set<ReplicaDescriptor>> replicaLists =
|
new LinkedList<Set<ReplicaDescriptor>>();
|
|
boolean oneReplicated = false;
|
|
boolean displayAll = userBaseDNs.isEmpty();
|
for (SuffixDescriptor suffix : cache.getSuffixes())
|
{
|
String dn = suffix.getDN();
|
|
// If no base DNs where specified display all the base DNs but the schema
|
// and cn=admin data.
|
boolean found = displayAll &&
|
!Utils.areDnsEqual(dn, ADSContext.getAdministrationSuffixDN()) &&
|
!Utils.areDnsEqual(dn, Constants.SCHEMA_DN) &&
|
!Utils.areDnsEqual(dn, Constants.REPLICATION_CHANGES_DN);
|
for (String baseDN : userBaseDNs)
|
{
|
found = Utils.areDnsEqual(baseDN, dn);
|
if (found)
|
{
|
break;
|
}
|
}
|
if (found)
|
{
|
boolean replicated = false;
|
for (ReplicaDescriptor replica : suffix.getReplicas())
|
{
|
if (replica.isReplicated())
|
{
|
replicated = true;
|
break;
|
}
|
}
|
if (replicated)
|
{
|
oneReplicated = true;
|
replicaLists.add(suffix.getReplicas());
|
}
|
else
|
{
|
// Check if there are already some non replicated base DNs.
|
found = false;
|
for (Set<ReplicaDescriptor> replicas : replicaLists)
|
{
|
ReplicaDescriptor replica = replicas.iterator().next();
|
if (!replica.isReplicated() &&
|
Utils.areDnsEqual(dn, replica.getSuffix().getDN()))
|
{
|
replicas.addAll(suffix.getReplicas());
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
replicaLists.add(suffix.getReplicas());
|
}
|
}
|
}
|
}
|
|
if (!oneReplicated)
|
{
|
if (displayAll)
|
{
|
// Maybe there are some replication server configured...
|
SortedSet<ServerDescriptor> rServers =
|
new TreeSet<ServerDescriptor>(new ReplicationServerComparator());
|
for (ServerDescriptor server : cache.getServers())
|
{
|
if (server.isReplicationServer())
|
{
|
rServers.add(server);
|
}
|
}
|
if (!rServers.isEmpty())
|
{
|
displayStatus(rServers, uData.isScriptFriendly(),
|
PreferredConnection.getPreferredConnections(ctx));
|
somethingDisplayed = true;
|
}
|
}
|
}
|
|
if (!replicaLists.isEmpty())
|
{
|
LinkedList<Set<ReplicaDescriptor>> orderedReplicaLists =
|
new LinkedList<Set<ReplicaDescriptor>>();
|
for (Set<ReplicaDescriptor> replicas : replicaLists)
|
{
|
String dn1 = replicas.iterator().next().getSuffix().getDN();
|
boolean inserted = false;
|
for (int i=0; i<orderedReplicaLists.size() && !inserted; i++)
|
{
|
String dn2 =
|
orderedReplicaLists.get(i).iterator().next().getSuffix().getDN();
|
if (dn1.compareTo(dn2) < 0)
|
{
|
orderedReplicaLists.add(i, replicas);
|
inserted = true;
|
}
|
}
|
if (!inserted)
|
{
|
orderedReplicaLists.add(replicas);
|
}
|
}
|
Set<ReplicaDescriptor> replicasWithNoReplicationServer =
|
new HashSet<ReplicaDescriptor>();
|
Set<ServerDescriptor> serversWithNoReplica =
|
new HashSet<ServerDescriptor>();
|
for (Set<ReplicaDescriptor> replicas : orderedReplicaLists)
|
{
|
printlnProgress();
|
displayStatus(replicas, uData.isScriptFriendly(),
|
PreferredConnection.getPreferredConnections(ctx),
|
cache.getServers(),
|
replicasWithNoReplicationServer, serversWithNoReplica);
|
somethingDisplayed = true;
|
}
|
if (oneReplicated && !uData.isScriptFriendly())
|
{
|
printlnProgress();
|
printProgress(INFO_REPLICATION_STATUS_REPLICATED_LEGEND.get());
|
|
if (!replicasWithNoReplicationServer.isEmpty() ||
|
!serversWithNoReplica.isEmpty())
|
{
|
printlnProgress();
|
printProgress(
|
INFO_REPLICATION_STATUS_NOT_A_REPLICATION_SERVER_LEGEND.get());
|
|
printlnProgress();
|
printProgress(
|
INFO_REPLICATION_STATUS_NOT_A_REPLICATION_DOMAIN_LEGEND.get());
|
}
|
printlnProgress();
|
somethingDisplayed = true;
|
}
|
}
|
if (!somethingDisplayed)
|
{
|
if (displayAll)
|
{
|
printProgress(INFO_REPLICATION_STATUS_NO_REPLICATION_INFORMATION.get());
|
printlnProgress();
|
}
|
else
|
{
|
printProgress(INFO_REPLICATION_STATUS_NO_BASEDNS.get());
|
printlnProgress();
|
}
|
}
|
}
|
|
/**
|
* Displays the replication status of the replicas provided. The code assumes
|
* that all the replicas have the same baseDN and that if they are replicated
|
* all the replicas are replicated with each other.
|
* Note: the code assumes that all the objects come from the same read of the
|
* topology cache. So comparisons in terms of pointers can be made.
|
* @param replicas the list of replicas that we are trying to display.
|
* @param cnx the preferred connections used to connect to the server.
|
* @param scriptFriendly wheter to display it on script-friendly mode or not.
|
* @param servers all the servers configured in the topology.
|
* @param replicasWithNoReplicationServer the set of replicas that will be
|
* updated with all the replicas that have no replication server.
|
* @param serversWithNoReplica the set of servers that will be updated with
|
* all the servers that act as replication server in the topology but have
|
* no replica.
|
*/
|
private void displayStatus(Set<ReplicaDescriptor> replicas,
|
boolean scriptFriendly, LinkedHashSet<PreferredConnection> cnx,
|
Set<ServerDescriptor> servers,
|
Set<ReplicaDescriptor> replicasWithNoReplicationServer,
|
Set<ServerDescriptor> serversWithNoReplica)
|
{
|
boolean isReplicated = false;
|
Set<ReplicaDescriptor> orderedReplicas =
|
new LinkedHashSet<ReplicaDescriptor>();
|
Set<String> hostPorts = new TreeSet<String>();
|
Set<ServerDescriptor> notAddedReplicationServers =
|
new TreeSet<ServerDescriptor>(new ReplicationServerComparator());
|
for (ReplicaDescriptor replica : replicas)
|
{
|
if (replica.isReplicated())
|
{
|
isReplicated = true;
|
}
|
hostPorts.add(getHostPort(replica.getServer(), cnx));
|
}
|
for (String hostPort : hostPorts)
|
{
|
for (ReplicaDescriptor replica : replicas)
|
{
|
if (getHostPort(replica.getServer(), cnx).equals(hostPort))
|
{
|
orderedReplicas.add(replica);
|
}
|
}
|
}
|
for (ServerDescriptor server : servers)
|
{
|
if (server.isReplicationServer())
|
{
|
boolean isDomain = false;
|
boolean isRepServer = false;
|
String replicationServer = server.getReplicationServerHostPort();
|
for (ReplicaDescriptor replica : replicas)
|
{
|
if (!isRepServer)
|
{
|
Set<String> repServers = replica.getReplicationServers();
|
for (String repServer : repServers)
|
{
|
if (replicationServer.equalsIgnoreCase(repServer))
|
{
|
isRepServer = true;
|
}
|
}
|
}
|
if (replica.getServer() == server)
|
{
|
isDomain = true;
|
}
|
if (isDomain && isRepServer)
|
{
|
break;
|
}
|
}
|
if (!isDomain && isRepServer)
|
{
|
notAddedReplicationServers.add(server);
|
}
|
}
|
}
|
final int SERVERPORT = 0;
|
final int NUMBER_ENTRIES = 1;
|
final int MISSING_CHANGES = 2;
|
final int AGE_OF_OLDEST_MISSING_CHANGE = 3;
|
final int REPLICATION_PORT = 4;
|
final int SECURE = 5;
|
Message[] headers;
|
if (scriptFriendly)
|
{
|
if (isReplicated)
|
{
|
headers = new Message[] {
|
INFO_REPLICATION_STATUS_LABEL_SERVERPORT.get(),
|
INFO_REPLICATION_STATUS_LABEL_NUMBER_ENTRIES.get(),
|
INFO_REPLICATION_STATUS_LABEL_MISSING_CHANGES.get(),
|
INFO_REPLICATION_STATUS_LABEL_AGE_OF_OLDEST_MISSING_CHANGE.get(),
|
INFO_REPLICATION_STATUS_LABEL_REPLICATION_PORT.get(),
|
INFO_REPLICATION_STATUS_LABEL_SECURE.get()
|
};
|
}
|
else
|
{
|
headers = new Message[] {
|
INFO_REPLICATION_STATUS_LABEL_SERVERPORT.get(),
|
INFO_REPLICATION_STATUS_LABEL_NUMBER_ENTRIES.get()
|
};
|
}
|
}
|
else
|
{
|
if (isReplicated)
|
{
|
headers = new Message[] {
|
INFO_REPLICATION_STATUS_HEADER_SERVERPORT.get(),
|
INFO_REPLICATION_STATUS_HEADER_NUMBER_ENTRIES.get(),
|
INFO_REPLICATION_STATUS_HEADER_MISSING_CHANGES.get(),
|
INFO_REPLICATION_STATUS_HEADER_AGE_OF_OLDEST_MISSING_CHANGE.get(),
|
INFO_REPLICATION_STATUS_HEADER_REPLICATION_PORT.get(),
|
INFO_REPLICATION_STATUS_HEADER_SECURE.get()
|
};
|
}
|
else
|
{
|
headers = new Message[] {
|
INFO_REPLICATION_STATUS_HEADER_SERVERPORT.get(),
|
INFO_REPLICATION_STATUS_HEADER_NUMBER_ENTRIES.get()
|
};
|
}
|
}
|
Message[][] values = new Message[
|
notAddedReplicationServers.size() +orderedReplicas.size()][headers.length];
|
|
int i = 0;
|
|
for (ServerDescriptor server : notAddedReplicationServers)
|
{
|
serversWithNoReplica.add(server);
|
Message v;
|
for (int j=0; j<headers.length; j++)
|
{
|
switch (j)
|
{
|
case SERVERPORT:
|
v = Message.raw(getHostPort(server, cnx));
|
break;
|
case NUMBER_ENTRIES:
|
if (scriptFriendly)
|
{
|
v = INFO_REPLICATION_STATUS_NOT_A_REPLICATION_DOMAIN_LONG.get();
|
}
|
else
|
{
|
v = INFO_REPLICATION_STATUS_NOT_A_REPLICATION_DOMAIN_SHORT.get();
|
}
|
break;
|
case MISSING_CHANGES:
|
v = INFO_NOT_APPLICABLE_LABEL.get();
|
break;
|
case AGE_OF_OLDEST_MISSING_CHANGE:
|
v = INFO_NOT_APPLICABLE_LABEL.get();
|
break;
|
case REPLICATION_PORT:
|
int replicationPort = server.getReplicationServerPort();
|
if (replicationPort >= 0)
|
{
|
v = Message.raw(String.valueOf(replicationPort));
|
}
|
else
|
{
|
v = INFO_NOT_AVAILABLE_SHORT_LABEL.get();
|
}
|
break;
|
case SECURE:
|
if (server.isReplicationSecure())
|
{
|
v = INFO_REPLICATION_STATUS_SECURITY_ENABLED.get();
|
}
|
else
|
{
|
v = INFO_REPLICATION_STATUS_SECURITY_DISABLED.get();
|
}
|
break;
|
default:
|
throw new IllegalStateException("Unknown index: "+j);
|
}
|
values[i][j] = v;
|
}
|
i++;
|
}
|
|
for (ReplicaDescriptor replica : orderedReplicas)
|
{
|
Message v;
|
for (int j=0; j<headers.length; j++)
|
{
|
switch (j)
|
{
|
case SERVERPORT:
|
v = Message.raw(getHostPort(replica.getServer(), cnx));
|
break;
|
case NUMBER_ENTRIES:
|
int nEntries = replica.getEntries();
|
if (nEntries >= 0)
|
{
|
v = Message.raw(String.valueOf(nEntries));
|
}
|
else
|
{
|
v = INFO_NOT_AVAILABLE_SHORT_LABEL.get();
|
}
|
break;
|
case MISSING_CHANGES:
|
int missingChanges = replica.getMissingChanges();
|
if (missingChanges >= 0)
|
{
|
v = Message.raw(String.valueOf(missingChanges));
|
}
|
else
|
{
|
v = INFO_NOT_AVAILABLE_SHORT_LABEL.get();
|
}
|
break;
|
case AGE_OF_OLDEST_MISSING_CHANGE:
|
long ageOfOldestMissingChange = replica.getAgeOfOldestMissingChange();
|
if (ageOfOldestMissingChange > 0)
|
{
|
Date date = new Date(ageOfOldestMissingChange);
|
v = Message.raw(date.toString());
|
}
|
else
|
{
|
v = INFO_NOT_AVAILABLE_SHORT_LABEL.get();
|
}
|
break;
|
case REPLICATION_PORT:
|
int replicationPort = replica.getServer().getReplicationServerPort();
|
if (!replica.getServer().isReplicationServer())
|
{
|
if (scriptFriendly)
|
{
|
v = INFO_REPLICATION_STATUS_NOT_A_REPLICATION_SERVER_LONG.get();
|
}
|
else
|
{
|
v = INFO_REPLICATION_STATUS_NOT_A_REPLICATION_SERVER_SHORT.get();
|
}
|
replicasWithNoReplicationServer.add(replica);
|
}
|
else if (replicationPort >= 0)
|
{
|
v = Message.raw(String.valueOf(replicationPort));
|
}
|
else
|
{
|
v = INFO_NOT_AVAILABLE_SHORT_LABEL.get();
|
}
|
break;
|
case SECURE:
|
if (!replica.getServer().isReplicationServer())
|
{
|
v = INFO_NOT_APPLICABLE_LABEL.get();
|
}
|
else if (replica.getServer().isReplicationSecure())
|
{
|
v = INFO_REPLICATION_STATUS_SECURITY_ENABLED.get();
|
}
|
else
|
{
|
v = INFO_REPLICATION_STATUS_SECURITY_DISABLED.get();
|
}
|
break;
|
default:
|
throw new IllegalStateException("Unknown index: "+j);
|
}
|
values[i][j] = v;
|
}
|
i++;
|
}
|
|
String dn = replicas.iterator().next().getSuffix().getDN();
|
if (scriptFriendly)
|
{
|
Message[] labels = {
|
INFO_REPLICATION_STATUS_BASEDN.get(),
|
INFO_REPLICATION_STATUS_IS_REPLICATED.get()
|
};
|
Message[] vs = {
|
Message.raw(dn),
|
isReplicated ? INFO_BASEDN_REPLICATED_LABEL.get() :
|
INFO_BASEDN_NOT_REPLICATED_LABEL.get()
|
};
|
for (i=0; i<labels.length; i++)
|
{
|
printProgress(Message.raw(labels[i]+" "+vs[i]));
|
printlnProgress();
|
}
|
|
for (i=0; i<values.length; i++)
|
{
|
printProgress(Message.raw("-"));
|
printlnProgress();
|
for (int j=0; j<values[i].length; j++)
|
{
|
printProgress(Message.raw(headers[j]+" "+values[i][j]));
|
printlnProgress();
|
}
|
}
|
}
|
else
|
{
|
Message msg;
|
if (isReplicated)
|
{
|
msg = INFO_REPLICATION_STATUS_REPLICATED.get(dn);
|
}
|
else
|
{
|
msg = INFO_REPLICATION_STATUS_NOT_REPLICATED.get(dn);
|
}
|
printProgressMessageNoWrap(msg);
|
printlnProgress();
|
int length = msg.length();
|
StringBuffer buf = new StringBuffer();
|
for (i=0; i<length; i++)
|
{
|
buf.append("=");
|
}
|
printProgressMessageNoWrap(Message.raw(buf.toString()));
|
printlnProgress();
|
|
TableBuilder table = new TableBuilder();
|
for (i=0; i< headers.length; i++)
|
{
|
table.appendHeading(headers[i]);
|
}
|
for (i=0; i<values.length; i++)
|
{
|
table.startRow();
|
for (int j=0; j<headers.length; j++)
|
{
|
table.appendCell(values[i][j]);
|
}
|
}
|
TextTablePrinter printer = new TextTablePrinter(getOutputStream());
|
printer.setColumnSeparator(ToolConstants.LIST_TABLE_SEPARATOR);
|
table.print(printer);
|
}
|
}
|
|
/**
|
* Displays the replication status of the replication servers provided. The
|
* code assumes that all the servers have a replication server and that there
|
* are associated with no replication domain.
|
* @param servers the servers
|
* @param cnx the preferred connections used to connect to the server.
|
* @param scriptFriendly wheter to display it on script-friendly mode or not.
|
*/
|
private void displayStatus(Set<ServerDescriptor> servers,
|
boolean scriptFriendly, LinkedHashSet<PreferredConnection> cnx)
|
{
|
final int SERVERPORT = 0;
|
final int REPLICATION_PORT = 1;
|
final int SECURE = 2;
|
Message[] headers;
|
if (scriptFriendly)
|
{
|
headers = new Message[] {
|
INFO_REPLICATION_STATUS_LABEL_SERVERPORT.get(),
|
INFO_REPLICATION_STATUS_LABEL_REPLICATION_PORT.get(),
|
INFO_REPLICATION_STATUS_LABEL_SECURE.get()
|
};
|
}
|
else
|
{
|
headers = new Message[] {
|
INFO_REPLICATION_STATUS_HEADER_SERVERPORT.get(),
|
INFO_REPLICATION_STATUS_HEADER_REPLICATION_PORT.get(),
|
INFO_REPLICATION_STATUS_HEADER_SECURE.get()
|
};
|
}
|
Message[][] values = new Message[servers.size()][headers.length];
|
|
int i = 0;
|
|
for (ServerDescriptor server : servers)
|
{
|
Message v;
|
for (int j=0; j<headers.length; j++)
|
{
|
switch (j)
|
{
|
case SERVERPORT:
|
v = Message.raw(getHostPort(server, cnx));
|
break;
|
case REPLICATION_PORT:
|
int replicationPort = server.getReplicationServerPort();
|
if (replicationPort >= 0)
|
{
|
v = Message.raw(String.valueOf(replicationPort));
|
}
|
else
|
{
|
v = INFO_NOT_AVAILABLE_SHORT_LABEL.get();
|
}
|
break;
|
case SECURE:
|
if (server.isReplicationSecure())
|
{
|
v = INFO_REPLICATION_STATUS_SECURITY_ENABLED.get();
|
}
|
else
|
{
|
v = INFO_REPLICATION_STATUS_SECURITY_DISABLED.get();
|
}
|
break;
|
default:
|
throw new IllegalStateException("Unknown index: "+j);
|
}
|
values[i][j] = v;
|
}
|
i++;
|
}
|
|
if (scriptFriendly)
|
{
|
printProgress(
|
INFO_REPLICATION_STATUS_INDEPENDENT_REPLICATION_SERVERS.get());
|
printlnProgress();
|
|
for (i=0; i<values.length; i++)
|
{
|
printProgress(Message.raw("-"));
|
printlnProgress();
|
for (int j=0; j<values[i].length; j++)
|
{
|
printProgress(Message.raw(headers[j]+" "+values[i][j]));
|
printlnProgress();
|
}
|
}
|
}
|
else
|
{
|
Message msg =
|
INFO_REPLICATION_STATUS_INDEPENDENT_REPLICATION_SERVERS.get();
|
printProgressMessageNoWrap(msg);
|
printlnProgress();
|
int length = msg.length();
|
StringBuffer buf = new StringBuffer();
|
for (i=0; i<length; i++)
|
{
|
buf.append("=");
|
}
|
printProgressMessageNoWrap(Message.raw(buf.toString()));
|
printlnProgress();
|
|
TableBuilder table = new TableBuilder();
|
for (i=0; i< headers.length; i++)
|
{
|
table.appendHeading(headers[i]);
|
}
|
for (i=0; i<values.length; i++)
|
{
|
table.startRow();
|
for (int j=0; j<headers.length; j++)
|
{
|
table.appendCell(values[i][j]);
|
}
|
}
|
TextTablePrinter printer = new TextTablePrinter(getOutputStream());
|
printer.setColumnSeparator(ToolConstants.LIST_TABLE_SEPARATOR);
|
table.print(printer);
|
}
|
}
|
|
/**
|
* Retrieves all the replication servers for a given baseDN. The
|
* ServerDescriptor is used to identify the server where the suffix is
|
* defined and it cannot be null. The TopologyCache is used to retrieve
|
* replication servers defined in other replicas but not in the one we
|
* get in the ServerDescriptor.
|
* @param baseDN the base DN.
|
* @param cache the TopologyCache (might be null).
|
* @param server the ServerDescriptor.
|
* @return a Set containing the replication servers currently being used
|
* to replicate the baseDN defined in the server described by the
|
* ServerDescriptor.
|
*/
|
private LinkedHashSet<String> getReplicationServers(String baseDN,
|
TopologyCache cache, ServerDescriptor server)
|
{
|
LinkedHashSet<String> servers = new LinkedHashSet<String>();
|
for (ReplicaDescriptor replica : server.getReplicas())
|
{
|
if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
servers.addAll(replica.getReplicationServers());
|
break;
|
}
|
}
|
if (cache != null)
|
{
|
Set<SuffixDescriptor> suffixes = cache.getSuffixes();
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
if (Utils.areDnsEqual(suffix.getDN(), baseDN))
|
{
|
Set<String> s = suffix.getReplicationServers();
|
// Test that at least we share one of the replication servers.
|
// If we do: we are dealing with the same replication topology
|
// (we must consider the case of disjoint replication topologies
|
// replicating the same base DN).
|
HashSet<String> copy = new HashSet<String>(s);
|
copy.retainAll(servers);
|
if (!copy.isEmpty())
|
{
|
servers.addAll(s);
|
break;
|
}
|
else
|
{
|
// Check if this server is acting as replication server with
|
// no domain.
|
if (server.isReplicationServer())
|
{
|
boolean found = false;
|
String repServer = server.getReplicationServerHostPort();
|
for (String rS : s)
|
{
|
if (rS.equalsIgnoreCase(repServer))
|
{
|
servers.addAll(s);
|
found = true;
|
break;
|
}
|
}
|
if (found)
|
{
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
return servers;
|
}
|
|
/**
|
* Retrieves the suffix in the TopologyCache for a given baseDN. The
|
* ServerDescriptor is used to identify the server where the suffix is
|
* defined.
|
* @param baseDN the base DN.
|
* @param cache the TopologyCache.
|
* @param server the ServerDescriptor.
|
* @return the suffix in the TopologyCache for a given baseDN.
|
*/
|
private SuffixDescriptor getSuffix(String baseDN, TopologyCache cache,
|
ServerDescriptor server)
|
{
|
SuffixDescriptor returnValue = null;
|
String replicationServer = null;
|
if (server.isReplicationServer())
|
{
|
replicationServer = server.getReplicationServerHostPort();
|
}
|
Set<String> servers = new LinkedHashSet<String>();
|
for (ReplicaDescriptor replica : server.getReplicas())
|
{
|
if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
servers.addAll(replica.getReplicationServers());
|
break;
|
}
|
}
|
|
Set<SuffixDescriptor> suffixes = cache.getSuffixes();
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
if (Utils.areDnsEqual(suffix.getDN(), baseDN))
|
{
|
Set<String> s = suffix.getReplicationServers();
|
// Test that at least we share one of the replication servers.
|
// If we do: we are dealing with the same replication topology
|
// (we must consider the case of disjoint replication topologies
|
// replicating the same base DN).
|
HashSet<String> copy = new HashSet<String>(s);
|
copy.retainAll(servers);
|
if (!copy.isEmpty())
|
{
|
returnValue = suffix;
|
break;
|
}
|
else if (replicationServer != null)
|
{
|
// Check if the server is only a replication server.
|
for (String repServer : s)
|
{
|
if (repServer.equalsIgnoreCase(replicationServer))
|
{
|
returnValue = suffix;
|
break;
|
}
|
}
|
}
|
}
|
}
|
return returnValue;
|
}
|
|
/**
|
* Retrieves all the replication domain IDs for a given baseDN in the
|
* ServerDescriptor.
|
* @param baseDN the base DN.
|
* @param server the ServerDescriptor.
|
* @return a Set containing the replication domain IDs for a given baseDN in
|
* the ServerDescriptor.
|
*/
|
private Set<Integer> getReplicationDomainIds(String baseDN,
|
ServerDescriptor server)
|
{
|
Set<Integer> ids = new HashSet<Integer>();
|
for (ReplicaDescriptor replica : server.getReplicas())
|
{
|
if ((replica.isReplicated()) &&
|
Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
ids.add(replica.getReplicationId());
|
break;
|
}
|
}
|
return ids;
|
}
|
|
/**
|
* Configures the server to which the provided InitialLdapContext is connected
|
* as a replication server. The replication server listens in the provided
|
* port.
|
* @param ctx the context connected to the server that we want to configure.
|
* @param replicationPort the replication port of the replication server.
|
* @param useSecureReplication whether to have encrypted communication with
|
* the replication port or not.
|
* @param replicationServers the list of replication servers to which the
|
* replication server will communicate with.
|
* @param usedReplicationServerIds the set of replication server IDs that
|
* are already in use. The set will be updated with the replication ID
|
* that will be used by the newly configured replication server.
|
* @throws OpenDsException if there is an error updating the configuration.
|
*/
|
private void configureAsReplicationServer(InitialLdapContext ctx,
|
int replicationPort, boolean useSecureReplication,
|
LinkedHashSet<String> replicationServers,
|
Set<Integer> usedReplicationServerIds) throws OpenDsException
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_ENABLE_CONFIGURING_REPLICATION_SERVER.get(
|
ConnectionUtils.getHostPort(ctx))));
|
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
|
/*
|
* Configure Synchronization plugin.
|
*/
|
ReplicationSynchronizationProviderCfgClient sync = null;
|
try
|
{
|
sync = (ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
}
|
catch (ManagedObjectNotFoundException monfe)
|
{
|
LOG.log(Level.INFO, "Synchronization server does not exist in "+
|
ConnectionUtils.getHostPort(ctx));
|
}
|
if (sync == null)
|
{
|
ReplicationSynchronizationProviderCfgDefn provider =
|
ReplicationSynchronizationProviderCfgDefn.getInstance();
|
sync = root.createSynchronizationProvider(provider,
|
"Multimaster Synchronization",
|
new ArrayList<DefaultBehaviorException>());
|
sync.setJavaClass(
|
org.opends.server.replication.plugin.MultimasterReplication.class.
|
getName());
|
sync.setEnabled(Boolean.TRUE);
|
}
|
else
|
{
|
if (!sync.isEnabled())
|
{
|
sync.setEnabled(Boolean.TRUE);
|
}
|
}
|
sync.commit();
|
|
/*
|
* Configure the replication server.
|
*/
|
ReplicationServerCfgClient replicationServer = null;
|
|
boolean mustCommit = false;
|
|
if (!sync.hasReplicationServer())
|
{
|
CryptoManagerCfgClient crypto = root.getCryptoManager();
|
if (useSecureReplication != crypto.isSSLEncryption())
|
{
|
crypto.setSSLEncryption(useSecureReplication);
|
crypto.commit();
|
}
|
int id = InstallerHelper.getReplicationId(usedReplicationServerIds);
|
usedReplicationServerIds.add(id);
|
replicationServer = sync.createReplicationServer(
|
ReplicationServerCfgDefn.getInstance(),
|
new ArrayList<DefaultBehaviorException>());
|
replicationServer.setReplicationServerId(id);
|
replicationServer.setReplicationPort(replicationPort);
|
replicationServer.setReplicationServer(replicationServers);
|
mustCommit = true;
|
}
|
else
|
{
|
replicationServer = sync.getReplicationServer();
|
usedReplicationServerIds.add(
|
replicationServer.getReplicationServerId());
|
Set<String> servers = replicationServer.getReplicationServer();
|
if (servers == null)
|
{
|
replicationServer.setReplicationServer(replicationServers);
|
mustCommit = true;
|
}
|
else if (!areReplicationServersEqual(servers, replicationServers))
|
{
|
replicationServer.setReplicationServer(
|
mergeReplicationServers(replicationServers, servers));
|
mustCommit = true;
|
}
|
}
|
if (mustCommit)
|
{
|
replicationServer.commit();
|
}
|
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
|
/**
|
* Updates the configuration of the replication server with the list of
|
* replication servers provided.
|
* @param ctx the context connected to the server that we want to update.
|
* @param replicationServers the list of replication servers to which the
|
* replication server will communicate with.
|
* @throws OpenDsException if there is an error updating the configuration.
|
*/
|
private void updateReplicationServer(InitialLdapContext ctx,
|
LinkedHashSet<String> replicationServers) throws OpenDsException
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_ENABLE_UPDATING_REPLICATION_SERVER.get(
|
ConnectionUtils.getHostPort(ctx))));
|
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
|
ReplicationSynchronizationProviderCfgClient sync =
|
(ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
boolean mustCommit = false;
|
ReplicationServerCfgClient replicationServer = sync.getReplicationServer();
|
Set<String> servers = replicationServer.getReplicationServer();
|
if (servers == null)
|
{
|
replicationServer.setReplicationServer(replicationServers);
|
mustCommit = true;
|
}
|
else if (!areReplicationServersEqual(servers, replicationServers))
|
{
|
replicationServers.addAll(servers);
|
replicationServer.setReplicationServer(
|
mergeReplicationServers(replicationServers, servers));
|
mustCommit = true;
|
}
|
if (mustCommit)
|
{
|
replicationServer.commit();
|
}
|
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
|
/**
|
* Returns a Set containing all the replication server ids found in the
|
* servers of a given TopologyCache object.
|
* @param cache the TopologyCache object to use.
|
* @return a Set containing all the replication server ids found in a given
|
* TopologyCache object.
|
*/
|
private Set<Integer> getReplicationServerIds(TopologyCache cache)
|
{
|
Set<Integer> ids = new HashSet<Integer>();
|
for (ServerDescriptor server : cache.getServers())
|
{
|
if (server.isReplicationServer())
|
{
|
ids.add(server.getReplicationServerId());
|
}
|
}
|
return ids;
|
}
|
|
/**
|
* Configures a replication domain for a given base DN in the server to which
|
* the provided InitialLdapContext is connected.
|
* @param ctx the context connected to the server that we want to configure.
|
* @param baseDN the base DN of the replication domain to configure.
|
* @param replicationServers the list of replication servers to which the
|
* replication domain will communicate with.
|
* @param usedReplicationDomainIds the set of replication domain IDs that
|
* are already in use. The set will be updated with the replication ID
|
* that will be used by the newly configured replication server.
|
* @throws OpenDsException if there is an error updating the configuration.
|
*/
|
private void configureToReplicateBaseDN(InitialLdapContext ctx,
|
String baseDN,
|
LinkedHashSet<String> replicationServers,
|
Set<Integer> usedReplicationDomainIds) throws OpenDsException
|
{
|
boolean userSpecifiedAdminBaseDN = false;
|
LinkedList<String> l = argParser.getBaseDNs();
|
if (l != null)
|
{
|
for (String dn : l)
|
{
|
if (Utils.areDnsEqual(dn, ADSContext.getAdministrationSuffixDN()))
|
{
|
userSpecifiedAdminBaseDN = true;
|
break;
|
}
|
}
|
}
|
if (!userSpecifiedAdminBaseDN && Utils.areDnsEqual(baseDN,
|
ADSContext.getAdministrationSuffixDN()))
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_ENABLE_CONFIGURING_ADS.get(
|
ConnectionUtils.getHostPort(ctx))));
|
}
|
else
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_ENABLE_CONFIGURING_BASEDN.get(baseDN,
|
ConnectionUtils.getHostPort(ctx))));
|
}
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
|
ReplicationSynchronizationProviderCfgClient sync =
|
(ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
|
String[] domainNames = sync.listReplicationDomains();
|
if (domainNames == null)
|
{
|
domainNames = new String[]{};
|
}
|
ReplicationDomainCfgClient[] domains =
|
new ReplicationDomainCfgClient[domainNames.length];
|
for (int i=0; i<domains.length; i++)
|
{
|
domains[i] = sync.getReplicationDomain(domainNames[i]);
|
}
|
ReplicationDomainCfgClient domain = null;
|
String domainName = null;
|
for (int i=0; i<domains.length && (domain == null); i++)
|
{
|
if (Utils.areDnsEqual(baseDN, domains[i].getBaseDN().toString()))
|
{
|
domain = domains[i];
|
domainName = domainNames[i];
|
}
|
}
|
boolean mustCommit = false;
|
if (domain == null)
|
{
|
int domainId = InstallerHelper.getReplicationId(usedReplicationDomainIds);
|
usedReplicationDomainIds.add(domainId);
|
domainName = InstallerHelper.getDomainName(domainNames, domainId, baseDN);
|
domain = sync.createReplicationDomain(
|
ReplicationDomainCfgDefn.getInstance(), domainName,
|
new ArrayList<DefaultBehaviorException>());
|
domain.setServerId(domainId);
|
domain.setBaseDN(DN.decode(baseDN));
|
domain.setReplicationServer(replicationServers);
|
mustCommit = true;
|
}
|
else
|
{
|
Set<String> servers = domain.getReplicationServer();
|
if (servers == null)
|
{
|
domain.setReplicationServer(servers);
|
mustCommit = true;
|
}
|
else if (!areReplicationServersEqual(servers, replicationServers))
|
{
|
domain.setReplicationServer(mergeReplicationServers(replicationServers,
|
servers));
|
mustCommit = true;
|
}
|
}
|
|
if (mustCommit)
|
{
|
domain.commit();
|
}
|
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
|
/**
|
* Configures the baseDN to replicate in all the Replicas found in a Topology
|
* Cache that are replicated with the Replica of the same base DN in the
|
* provided ServerDescriptor object.
|
* @param baseDN the base DN to replicate.
|
* @param repServers the replication servers to be defined in the domain.
|
* @param usedIds the replication domain Ids already used. This Set is
|
* updated with the new domains that are used.
|
* @param cache the TopologyCache used to retrieve the different defined
|
* replicas.
|
* @param server the ServerDescriptor that is used to identify the
|
* replication topology that we are interested at (we only update the replicas
|
* that are already replicated with this server).
|
* @param alreadyConfiguredServers the list of already configured servers. If
|
* a server is in this list no updates are performed to the domain.
|
* @param alreadyConfiguredReplicationServers the list of already configured
|
* servers. If a server is in this list no updates are performed to the
|
* replication server.
|
* @throws ReplicationCliException if something goes wrong.
|
*/
|
private void configureToReplicateBaseDN(String baseDN,
|
LinkedHashSet<String> repServers, Set<Integer> usedIds,
|
TopologyCache cache, ServerDescriptor server,
|
Set<String> alreadyConfiguredServers, LinkedHashSet<String> allRepServers,
|
Set<String> alreadyConfiguredReplicationServers)
|
throws ReplicationCliException
|
{
|
LOG.log(Level.INFO, "Configuring base DN '"+baseDN+
|
"' the replication servers are "+repServers);
|
Set<ServerDescriptor> serversToConfigureDomain =
|
new HashSet<ServerDescriptor>();
|
Set<ServerDescriptor> replicationServersToConfigure =
|
new HashSet<ServerDescriptor>();
|
SuffixDescriptor suffix = getSuffix(baseDN, cache, server);
|
if (suffix != null)
|
{
|
for (ReplicaDescriptor replica: suffix.getReplicas())
|
{
|
ServerDescriptor s = replica.getServer();
|
if (!alreadyConfiguredServers.contains(s.getId()))
|
{
|
serversToConfigureDomain.add(s);
|
}
|
}
|
}
|
// Now check the replication servers.
|
for (ServerDescriptor s : cache.getServers())
|
{
|
if (s.isReplicationServer() &&
|
!alreadyConfiguredReplicationServers.contains(s.getId()))
|
{
|
// Check if it is part of the replication topology
|
boolean isInTopology = false;
|
String repServerID = s.getReplicationServerHostPort();
|
for (String rID : repServers)
|
{
|
if (repServerID.equalsIgnoreCase(rID))
|
{
|
isInTopology = true;
|
break;
|
}
|
}
|
if (isInTopology)
|
{
|
replicationServersToConfigure.add(s);
|
}
|
}
|
}
|
|
Set<ServerDescriptor> allServers = new HashSet<ServerDescriptor>();
|
allServers.addAll(serversToConfigureDomain);
|
allServers.addAll(replicationServersToConfigure);
|
|
for (ServerDescriptor s : allServers)
|
{
|
LOG.log(Level.INFO,"Configuring server "+server.getHostPort(true));
|
InitialLdapContext ctx = null;
|
try
|
{
|
ctx = getDirContextForServer(cache, s);
|
if (serversToConfigureDomain.contains(s))
|
{
|
configureToReplicateBaseDN(ctx, baseDN, repServers, usedIds);
|
}
|
if (replicationServersToConfigure.contains(s))
|
{
|
updateReplicationServer(ctx, allRepServers);
|
}
|
}
|
catch (NamingException ne)
|
{
|
String hostPort = getHostPort(s, cache.getPreferredConnections());
|
Message msg = getMessageForException(ne, hostPort);
|
throw new ReplicationCliException(msg, ERROR_CONNECTING, ne);
|
}
|
catch (OpenDsException ode)
|
{
|
String hostPort = getHostPort(s, cache.getPreferredConnections());
|
Message msg = getMessageForEnableException(ode, hostPort, baseDN);
|
throw new ReplicationCliException(msg,
|
ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
|
}
|
finally
|
{
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
}
|
alreadyConfiguredServers.add(s.getId());
|
alreadyConfiguredReplicationServers.add(s.getId());
|
}
|
}
|
|
/**
|
* Returns the Map of properties to be used to update the ADS.
|
* This map uses the data provided by the user.
|
* @return the Map of properties to be used to update the ADS.
|
* This map uses the data provided by the user
|
*/
|
private Map<ADSContext.AdministratorProperty, Object>
|
getAdministratorProperties(ReplicationUserData uData)
|
{
|
Map<ADSContext.AdministratorProperty, Object> adminProperties =
|
new HashMap<ADSContext.AdministratorProperty, Object>();
|
adminProperties.put(ADSContext.AdministratorProperty.UID,
|
uData.getAdminUid());
|
adminProperties.put(ADSContext.AdministratorProperty.PASSWORD,
|
uData.getAdminPwd());
|
adminProperties.put(ADSContext.AdministratorProperty.DESCRIPTION,
|
INFO_GLOBAL_ADMINISTRATOR_DESCRIPTION.get().toString());
|
return adminProperties;
|
}
|
|
private void initializeSuffix(String baseDN, InitialLdapContext ctxSource,
|
InitialLdapContext ctxDestination, boolean displayProgress)
|
throws ReplicationCliException
|
{
|
int replicationId = -1;
|
try
|
{
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
filter.addBaseDNToSearch(baseDN);
|
ServerDescriptor source = ServerDescriptor.createStandalone(ctxSource,
|
filter);
|
for (ReplicaDescriptor replica : source.getReplicas())
|
{
|
if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
replicationId = replica.getReplicationId();
|
break;
|
}
|
}
|
}
|
catch (NamingException ne)
|
{
|
String hostPort = ConnectionUtils.getHostPort(ctxSource);
|
Message msg = getMessageForException(ne, hostPort);
|
throw new ReplicationCliException(msg, ERROR_READING_CONFIGURATION, ne);
|
}
|
|
if (replicationId == -1)
|
{
|
throw new ReplicationCliException(
|
ERR_INITIALIZING_REPLICATIONID_NOT_FOUND.get(
|
ConnectionUtils.getHostPort(ctxSource), baseDN),
|
REPLICATIONID_NOT_FOUND, null);
|
}
|
|
OfflineInstaller installer = new OfflineInstaller();
|
installer.setProgressMessageFormatter(formatter);
|
installer.addProgressUpdateListener(new ProgressUpdateListener()
|
{
|
public void progressUpdate(ProgressUpdateEvent ev)
|
{
|
Message newLogDetails = ev.getNewLogs();
|
if ((newLogDetails != null) &&
|
!newLogDetails.toString().trim().equals(""))
|
{
|
printProgress(newLogDetails);
|
printlnProgress();
|
}
|
}
|
});
|
int nTries = 5;
|
boolean initDone = false;
|
while (!initDone)
|
{
|
try
|
{
|
installer.initializeSuffix(ctxDestination, replicationId, baseDN,
|
displayProgress, ConnectionUtils.getHostPort(ctxSource));
|
initDone = true;
|
}
|
catch (PeerNotFoundException pnfe)
|
{
|
LOG.log(Level.INFO, "Peer could not be found");
|
if (nTries == 1)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get(
|
pnfe.getMessageObject().toString()),
|
INITIALIZING_TRIES_COMPLETED, pnfe);
|
}
|
try
|
{
|
Thread.sleep((5 - nTries) * 3000);
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
catch (ApplicationException ae)
|
{
|
throw new ReplicationCliException(ae.getMessageObject(),
|
ERROR_INITIALIZING_BASEDN_GENERIC, ae);
|
}
|
nTries--;
|
}
|
}
|
|
/**
|
* 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)
|
{
|
try
|
{
|
initializeAllSuffixTry(baseDN, ctx, displayProgress);
|
postPreExternalInitialization(baseDN, ctx, displayProgress, false);
|
initDone = true;
|
}
|
catch (PeerNotFoundException pnfe)
|
{
|
LOG.log(Level.INFO, "Peer could not be found");
|
if (nTries == 1)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get(
|
pnfe.getMessageObject().toString()),
|
INITIALIZING_TRIES_COMPLETED, pnfe);
|
}
|
try
|
{
|
Thread.sleep((5 - nTries) * 3000);
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
catch (ApplicationException ae)
|
{
|
throw new ReplicationCliException(ae.getMessageObject(),
|
ERROR_INITIALIZING_BASEDN_GENERIC, ae);
|
}
|
nTries--;
|
}
|
}
|
|
/**
|
* Launches the pre external initialization operation using the provided
|
* connection on a given base DN.
|
* @param baseDN the base DN that we want to reset.
|
* @param ctx the connection to the server.
|
* @param displayProgress whether to display operation progress or not.
|
* @throws ReplicationCliException if there is an error performing the
|
* operation.
|
*/
|
private void preExternalInitialization(String baseDN, InitialLdapContext ctx,
|
boolean displayProgress) throws ReplicationCliException
|
{
|
postPreExternalInitialization(baseDN, ctx, displayProgress,
|
true);
|
}
|
|
/**
|
* Launches the post external initialization operation using the provided
|
* connection on a given base DN required for replication to work.
|
* @param baseDN the base DN that we want to reset.
|
* @param ctx the connection to the server.
|
* @param displayProgress whether to display operation progress or not.
|
* @throws ReplicationCliException if there is an error performing the
|
* operation.
|
*/
|
private void postExternalInitialization(String baseDN, InitialLdapContext ctx,
|
boolean displayProgress) throws ReplicationCliException
|
{
|
postPreExternalInitialization(baseDN, ctx, displayProgress, false);
|
}
|
|
/**
|
* Launches the pre or post external initialization operation using the
|
* provided connection on a given base DN.
|
* @param baseDN the base DN that we want to reset.
|
* @param ctx the connection to the server.
|
* @param displayProgress whether to display operation progress or not.
|
* @param isPre whether this is the pre operation or the post operation.
|
* @throws ReplicationCliException if there is an error performing the
|
* operation.
|
*/
|
private void postPreExternalInitialization(String baseDN,
|
InitialLdapContext ctx, boolean displayProgress,
|
boolean isPre) throws ReplicationCliException
|
{
|
boolean taskCreated = false;
|
int i = 1;
|
boolean isOver = false;
|
String dn = null;
|
BasicAttributes attrs = new BasicAttributes();
|
Attribute oc = new BasicAttribute("objectclass");
|
oc.add("top");
|
oc.add("ds-task");
|
oc.add("ds-task-reset-generation-id");
|
attrs.put(oc);
|
attrs.put("ds-task-class-name",
|
"org.opends.server.tasks.SetGenerationIdTask");
|
if (isPre)
|
{
|
attrs.put("ds-task-reset-generation-id-new-value", "-1");
|
}
|
attrs.put("ds-task-reset-generation-id-domain-base-dn", baseDN);
|
while (!taskCreated)
|
{
|
String id = "dsreplication-reset-generation-id-"+i;
|
dn = "ds-task-id="+id+",cn=Scheduled Tasks,cn=Tasks";
|
attrs.put("ds-task-id", id);
|
try
|
{
|
DirContext dirCtx = ctx.createSubcontext(dn, attrs);
|
taskCreated = true;
|
LOG.log(Level.INFO, "created task entry: "+attrs);
|
dirCtx.close();
|
}
|
catch (NameAlreadyBoundException x)
|
{
|
}
|
catch (NamingException ne)
|
{
|
LOG.log(Level.SEVERE, "Error creating task "+attrs, ne);
|
Message msg = isPre ?
|
ERR_LAUNCHING_PRE_EXTERNAL_INITIALIZATION.get():
|
ERR_LAUNCHING_POST_EXTERNAL_INITIALIZATION.get();
|
ReplicationCliReturnCode code = isPre?
|
ERROR_LAUNCHING_PRE_EXTERNAL_INITIALIZATION:
|
ERROR_LAUNCHING_POST_EXTERNAL_INITIALIZATION;
|
throw new ReplicationCliException(
|
getThrowableMsg(msg, ne), code, ne);
|
}
|
i++;
|
}
|
// Wait until it is over
|
SearchControls searchControls = new SearchControls();
|
searchControls.setSearchScope(
|
SearchControls. OBJECT_SCOPE);
|
String filter = "objectclass=*";
|
searchControls.setReturningAttributes(
|
new String[] {
|
"ds-task-log-message",
|
"ds-task-state"
|
});
|
String lastLogMsg = null;
|
while (!isOver)
|
{
|
try
|
{
|
Thread.sleep(500);
|
}
|
catch (Throwable t)
|
{
|
}
|
try
|
{
|
NamingEnumeration<SearchResult> res =
|
ctx.search(dn, filter, searchControls);
|
SearchResult sr = null;
|
try
|
{
|
while (res.hasMore())
|
{
|
sr = res.next();
|
}
|
}
|
finally
|
{
|
res.close();
|
}
|
String logMsg = getFirstValue(sr, "ds-task-log-message");
|
if (logMsg != null)
|
{
|
if (!logMsg.equals(lastLogMsg))
|
{
|
LOG.log(Level.INFO, logMsg);
|
lastLogMsg = logMsg;
|
}
|
}
|
InstallerHelper helper = new InstallerHelper();
|
String state = getFirstValue(sr, "ds-task-state");
|
|
if (helper.isDone(state) || helper.isStoppedByError(state))
|
{
|
isOver = true;
|
Message errorMsg;
|
String server = ConnectionUtils.getHostPort(ctx);
|
if (lastLogMsg == null)
|
{
|
errorMsg = isPre ?
|
INFO_ERROR_DURING_PRE_EXTERNAL_INITIALIZATION_NO_LOG.get(
|
state, server) :
|
INFO_ERROR_DURING_POST_EXTERNAL_INITIALIZATION_NO_LOG.get(
|
state, server);
|
}
|
else
|
{
|
errorMsg = isPre ?
|
INFO_ERROR_DURING_PRE_EXTERNAL_INITIALIZATION_LOG.get(
|
lastLogMsg, state, server) :
|
INFO_ERROR_DURING_POST_EXTERNAL_INITIALIZATION_LOG.get(
|
lastLogMsg, state, server);
|
}
|
|
if (helper.isCompletedWithErrors(state))
|
{
|
LOG.log(Level.WARNING, "Completed with error: "+errorMsg);
|
println(errorMsg);
|
}
|
else if (!helper.isSuccessful(state) ||
|
helper.isStoppedByError(state))
|
{
|
LOG.log(Level.WARNING, "Error: "+errorMsg);
|
ReplicationCliReturnCode code = isPre?
|
ERROR_LAUNCHING_PRE_EXTERNAL_INITIALIZATION:
|
ERROR_LAUNCHING_POST_EXTERNAL_INITIALIZATION;
|
throw new ReplicationCliException(errorMsg, code, null);
|
}
|
}
|
}
|
catch (NameNotFoundException x)
|
{
|
isOver = true;
|
}
|
catch (NamingException ne)
|
{
|
Message msg = isPre ?
|
ERR_POOLING_PRE_EXTERNAL_INITIALIZATION.get():
|
ERR_POOLING_POST_EXTERNAL_INITIALIZATION.get();
|
throw new ReplicationCliException(
|
getThrowableMsg(msg, ne), ERROR_CONNECTING, ne);
|
}
|
}
|
}
|
|
/**
|
* 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.
|
* @throws PeerNotFoundException if the replication mechanism cannot find
|
* a peer.
|
*/
|
public void initializeAllSuffixTry(String baseDN, InitialLdapContext ctx,
|
boolean displayProgress)
|
throws ApplicationException, PeerNotFoundException
|
{
|
boolean taskCreated = false;
|
int i = 1;
|
boolean isOver = false;
|
String dn = null;
|
String serverDisplay = ConnectionUtils.getHostPort(ctx);
|
BasicAttributes attrs = new BasicAttributes();
|
Attribute oc = new BasicAttribute("objectclass");
|
oc.add("top");
|
oc.add("ds-task");
|
oc.add("ds-task-initialize-remote-replica");
|
attrs.put(oc);
|
attrs.put("ds-task-class-name",
|
"org.opends.server.tasks.InitializeTargetTask");
|
attrs.put("ds-task-initialize-domain-dn", baseDN);
|
attrs.put("ds-task-initialize-replica-server-id", "all");
|
while (!taskCreated)
|
{
|
String id = "dsreplication-initialize"+i;
|
dn = "ds-task-id="+id+",cn=Scheduled Tasks,cn=Tasks";
|
attrs.put("ds-task-id", id);
|
try
|
{
|
DirContext dirCtx = ctx.createSubcontext(dn, attrs);
|
taskCreated = true;
|
LOG.log(Level.INFO, "created task entry: "+attrs);
|
dirCtx.close();
|
}
|
catch (NameAlreadyBoundException x)
|
{
|
LOG.log(Level.WARNING, "A task with dn: "+dn+" already existed.");
|
}
|
catch (NamingException ne)
|
{
|
LOG.log(Level.SEVERE, "Error creating task "+attrs, ne);
|
throw new ApplicationException(
|
ReturnCode.APPLICATION_ERROR,
|
getThrowableMsg(INFO_ERROR_LAUNCHING_INITIALIZATION.get(
|
serverDisplay), ne), ne);
|
}
|
i++;
|
}
|
// Wait until it is over
|
SearchControls searchControls = new SearchControls();
|
searchControls.setSearchScope(
|
SearchControls. OBJECT_SCOPE);
|
String filter = "objectclass=*";
|
searchControls.setReturningAttributes(
|
new String[] {
|
"ds-task-unprocessed-entry-count",
|
"ds-task-processed-entry-count",
|
"ds-task-log-message",
|
"ds-task-state"
|
});
|
Message lastDisplayedMsg = null;
|
String lastLogMsg = null;
|
long lastTimeMsgDisplayed = -1;
|
long lastTimeMsgLogged = -1;
|
int totalEntries = 0;
|
while (!isOver)
|
{
|
try
|
{
|
Thread.sleep(500);
|
}
|
catch (Throwable t)
|
{
|
}
|
try
|
{
|
NamingEnumeration<SearchResult> res =
|
ctx.search(dn, filter, searchControls);
|
SearchResult sr = null;
|
try
|
{
|
while (res.hasMore())
|
{
|
sr = res.next();
|
}
|
}
|
finally
|
{
|
res.close();
|
}
|
|
// Get the number of entries that have been handled and
|
// a percentage...
|
Message msg;
|
String sProcessed = getFirstValue(sr,
|
"ds-task-processed-entry-count");
|
String sUnprocessed = getFirstValue(sr,
|
"ds-task-unprocessed-entry-count");
|
int processed = -1;
|
int unprocessed = -1;
|
if (sProcessed != null)
|
{
|
processed = Integer.parseInt(sProcessed);
|
}
|
if (sUnprocessed != null)
|
{
|
unprocessed = Integer.parseInt(sUnprocessed);
|
}
|
totalEntries = Math.max(totalEntries, processed+unprocessed);
|
|
if ((processed != -1) && (unprocessed != -1))
|
{
|
if (processed + unprocessed > 0)
|
{
|
int perc = (100 * processed) / (processed + unprocessed);
|
msg = INFO_INITIALIZE_PROGRESS_WITH_PERCENTAGE.get(sProcessed,
|
String.valueOf(perc));
|
}
|
else
|
{
|
//msg = INFO_NO_ENTRIES_TO_INITIALIZE.get();
|
msg = null;
|
}
|
}
|
else if (processed != -1)
|
{
|
msg = INFO_INITIALIZE_PROGRESS_WITH_PROCESSED.get(sProcessed);
|
}
|
else if (unprocessed != -1)
|
{
|
msg = INFO_INITIALIZE_PROGRESS_WITH_UNPROCESSED.get(sUnprocessed);
|
}
|
else
|
{
|
msg = lastDisplayedMsg;
|
}
|
|
if (msg != null)
|
{
|
long currentTime = System.currentTimeMillis();
|
/* Refresh period: to avoid having too many lines in the log */
|
long minRefreshPeriod;
|
if (totalEntries < 100)
|
{
|
minRefreshPeriod = 0;
|
}
|
else if (totalEntries < 1000)
|
{
|
minRefreshPeriod = 1000;
|
}
|
else if (totalEntries < 10000)
|
{
|
minRefreshPeriod = 5000;
|
}
|
else
|
{
|
minRefreshPeriod = 10000;
|
}
|
if (((currentTime - minRefreshPeriod) > lastTimeMsgLogged))
|
{
|
lastTimeMsgLogged = currentTime;
|
LOG.log(Level.INFO, "Progress msg: "+msg);
|
}
|
if (displayProgress)
|
{
|
if (((currentTime - minRefreshPeriod) > lastTimeMsgDisplayed) &&
|
!msg.equals(lastDisplayedMsg))
|
{
|
printProgress(msg);
|
lastDisplayedMsg = msg;
|
printlnProgress();
|
lastTimeMsgDisplayed = currentTime;
|
}
|
}
|
}
|
|
String logMsg = getFirstValue(sr, "ds-task-log-message");
|
if (logMsg != null)
|
{
|
if (!logMsg.equals(lastLogMsg))
|
{
|
LOG.log(Level.INFO, logMsg);
|
lastLogMsg = logMsg;
|
}
|
}
|
InstallerHelper helper = new InstallerHelper();
|
String state = getFirstValue(sr, "ds-task-state");
|
|
if (helper.isDone(state) || helper.isStoppedByError(state))
|
{
|
isOver = true;
|
Message errorMsg;
|
LOG.log(Level.INFO, "Last task entry: "+sr);
|
if (displayProgress && (msg != null) && !msg.equals(lastDisplayedMsg))
|
{
|
printProgress(msg);
|
lastDisplayedMsg = msg;
|
printlnProgress();
|
}
|
if (lastLogMsg == null)
|
{
|
errorMsg = INFO_ERROR_DURING_INITIALIZATION_NO_LOG.get(
|
serverDisplay, state, serverDisplay);
|
}
|
else
|
{
|
errorMsg = INFO_ERROR_DURING_INITIALIZATION_LOG.get(
|
serverDisplay, lastLogMsg, state, serverDisplay);
|
}
|
|
if (helper.isCompletedWithErrors(state))
|
{
|
LOG.log(Level.WARNING, "Processed errorMsg: "+errorMsg);
|
if (displayProgress)
|
{
|
println(errorMsg);
|
}
|
}
|
else if (!helper.isSuccessful(state) ||
|
helper.isStoppedByError(state))
|
{
|
LOG.log(Level.WARNING, "Processed errorMsg: "+errorMsg);
|
ApplicationException ae = new ApplicationException(
|
ReturnCode.APPLICATION_ERROR, errorMsg,
|
null);
|
if ((lastLogMsg == null) ||
|
helper.isPeersNotFoundError(lastLogMsg))
|
{
|
LOG.log(Level.WARNING, "Throwing peer not found error. "+
|
"Last Log Msg: "+lastLogMsg);
|
// Assume that this is a peer not found error.
|
throw new PeerNotFoundException(errorMsg);
|
}
|
else
|
{
|
LOG.log(Level.SEVERE, "Throwing ApplicationException.");
|
throw ae;
|
}
|
}
|
else
|
{
|
if (displayProgress)
|
{
|
printProgress(INFO_SUFFIX_INITIALIZED_SUCCESSFULLY.get());
|
printlnProgress();
|
}
|
LOG.log(Level.INFO, "Processed msg: "+errorMsg);
|
LOG.log(Level.INFO, "Initialization completed successfully.");
|
}
|
}
|
}
|
catch (NameNotFoundException x)
|
{
|
isOver = true;
|
LOG.log(Level.INFO, "Initialization entry not found.");
|
if (displayProgress)
|
{
|
printProgress(INFO_SUFFIX_INITIALIZED_SUCCESSFULLY.get());
|
printlnProgress();
|
}
|
}
|
catch (NamingException ne)
|
{
|
throw new ApplicationException(
|
ReturnCode.APPLICATION_ERROR,
|
getThrowableMsg(INFO_ERROR_POOLING_INITIALIZATION.get(
|
serverDisplay), ne), ne);
|
}
|
}
|
}
|
|
/**
|
* Removes the references to a replication server in the base DNs of a
|
* given server.
|
* @param server the server that we want to update.
|
* @param replicationServer the replication server whose references we want
|
* to remove.
|
* @param bindDn the bindDn that must be used to log to the server.
|
* @param pwd the password that must be used to log to the server.
|
* @param baseDNs the list of base DNs where we want to remove the references
|
* to the provided replication server.
|
* @param removeFromReplicationServers if references must be removed from
|
* the replication servers.
|
* @param preferredURLs the preferred LDAP URLs to be used to connect to the
|
* server.
|
* @throws ReplicationCliException if there is an error updating the
|
* configuration.
|
*/
|
private void removeReferencesInServer(ServerDescriptor server,
|
String replicationServer, String bindDn, String pwd,
|
Collection<String> baseDNs, boolean updateReplicationServers,
|
LinkedHashSet<PreferredConnection> cnx)
|
throws ReplicationCliException
|
{
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
filter.setSearchBaseDNInformation(false);
|
ServerLoader loader = new ServerLoader(server.getAdsProperties(), bindDn,
|
pwd, getTrustManager(), getConnectTimeout(), cnx, filter);
|
InitialLdapContext ctx = null;
|
String lastBaseDN = null;
|
String hostPort = null;
|
|
try
|
{
|
ctx = loader.createContext();
|
hostPort = ConnectionUtils.getHostPort(ctx);
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
ReplicationSynchronizationProviderCfgClient sync = null;
|
try
|
{
|
sync = (ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
}
|
catch (ManagedObjectNotFoundException monfe)
|
{
|
// It does not exist.
|
LOG.log(Level.INFO, "No synchronization found on "+ hostPort +".",
|
monfe);
|
}
|
if (sync != null)
|
{
|
String[] domainNames = sync.listReplicationDomains();
|
if (domainNames != null)
|
{
|
for (int i=0; i<domainNames.length; i++)
|
{
|
ReplicationDomainCfgClient domain =
|
sync.getReplicationDomain(domainNames[i]);
|
for (String baseDN : baseDNs)
|
{
|
lastBaseDN = baseDN;
|
if (Utils.areDnsEqual(domain.getBaseDN().toString(),
|
baseDN))
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_REMOVING_REFERENCES_ON_REMOTE.get(baseDN,
|
hostPort)));
|
Set<String> replServers = domain.getReplicationServer();
|
if (replServers != null)
|
{
|
String replServer = null;
|
for (String o : replServers)
|
{
|
if (replicationServer.equalsIgnoreCase(o))
|
{
|
replServer = o;
|
break;
|
}
|
}
|
if (replServer != null)
|
{
|
LOG.log(Level.INFO, "Updating references in domain " +
|
domain.getBaseDN()+" on " + hostPort + ".");
|
replServers.remove(replServer);
|
if (replServers.size() > 0)
|
{
|
domain.setReplicationServer(replServers);
|
domain.commit();
|
}
|
else
|
{
|
sync.removeReplicationDomain(domainNames[i]);
|
sync.commit();
|
}
|
}
|
}
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
}
|
}
|
}
|
if (updateReplicationServers && sync.hasReplicationServer())
|
{
|
ReplicationServerCfgClient rServerObj = sync.getReplicationServer();
|
Set<String> replServers = rServerObj.getReplicationServer();
|
if (replServers != null)
|
{
|
String replServer = null;
|
for (String o : replServers)
|
{
|
if (replicationServer.equalsIgnoreCase(o))
|
{
|
replServer = o;
|
break;
|
}
|
}
|
if (replServer != null)
|
{
|
replServers.remove(replServer);
|
if (replServers.size() > 0)
|
{
|
rServerObj.setReplicationServer(replServers);
|
rServerObj.commit();
|
}
|
else
|
{
|
sync.removeReplicationServer();
|
sync.commit();
|
}
|
}
|
}
|
}
|
}
|
}
|
catch (NamingException ne)
|
{
|
hostPort = getHostPort(server, cnx);
|
Message msg = getMessageForException(ne, hostPort);
|
throw new ReplicationCliException(msg, ERROR_CONNECTING, ne);
|
}
|
catch (OpenDsException ode)
|
{
|
if (lastBaseDN != null)
|
{
|
Message msg = getMessageForDisableException(ode, hostPort, lastBaseDN);
|
throw new ReplicationCliException(msg,
|
ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN, ode);
|
}
|
else
|
{
|
Message msg = ERR_REPLICATION_ERROR_READING_CONFIGURATION.get(hostPort,
|
ode.getMessage());
|
throw new ReplicationCliException(msg, ERROR_CONNECTING, ode);
|
}
|
}
|
finally
|
{
|
if (ctx != null)
|
{
|
try
|
{
|
ctx.close();
|
}
|
catch (Throwable t)
|
{
|
}
|
}
|
}
|
}
|
|
/**
|
* Deletes a replication domain in a server for a given base DN (disable
|
* replication of the base DN).
|
* @param ctx the connection to the server.
|
* @param baseDN the base DN of the replication domain that we want to
|
* delete.
|
* @throws ReplicationCliException if there is an error updating the
|
* configuration of the server.
|
*/
|
private void deleteReplicationDomain(InitialLdapContext ctx,
|
String baseDN) throws ReplicationCliException
|
{
|
String hostPort = ConnectionUtils.getHostPort(ctx);
|
try
|
{
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
ReplicationSynchronizationProviderCfgClient sync = null;
|
try
|
{
|
sync = (ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
}
|
catch (ManagedObjectNotFoundException monfe)
|
{
|
// It does not exist.
|
LOG.log(Level.INFO, "No synchronization found on "+ hostPort +".",
|
monfe);
|
}
|
if (sync != null)
|
{
|
String[] domainNames = sync.listReplicationDomains();
|
if (domainNames != null)
|
{
|
for (int i=0; i<domainNames.length; i++)
|
{
|
ReplicationDomainCfgClient domain =
|
sync.getReplicationDomain(domainNames[i]);
|
if (Utils.areDnsEqual(domain.getBaseDN().toString(), baseDN))
|
{
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_DISABLING_BASEDN.get(baseDN,
|
hostPort)));
|
sync.removeReplicationDomain(domainNames[i]);
|
sync.commit();
|
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
}
|
}
|
}
|
}
|
catch (OpenDsException ode)
|
{
|
Message msg = getMessageForDisableException(ode, hostPort, baseDN);
|
throw new ReplicationCliException(msg,
|
ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN, ode);
|
}
|
}
|
|
/**
|
* Disables the replication server for a given server.
|
* @param ctx the connection to the server.
|
* @throws ReplicationCliException if there is an error updating the
|
* configuration of the server.
|
*/
|
private void disableReplicationServer(InitialLdapContext ctx)
|
throws ReplicationCliException
|
{
|
String hostPort = ConnectionUtils.getHostPort(ctx);
|
try
|
{
|
ManagementContext mCtx = LDAPManagementContext.createFromContext(
|
JNDIDirContextAdaptor.adapt(ctx));
|
RootCfgClient root = mCtx.getRootConfiguration();
|
ReplicationSynchronizationProviderCfgClient sync = null;
|
ReplicationServerCfgClient replicationServer = null;
|
try
|
{
|
sync = (ReplicationSynchronizationProviderCfgClient)
|
root.getSynchronizationProvider("Multimaster Synchronization");
|
if (sync.hasReplicationServer())
|
{
|
replicationServer = sync.getReplicationServer();
|
}
|
}
|
catch (ManagedObjectNotFoundException monfe)
|
{
|
// It does not exist.
|
LOG.log(Level.INFO, "No synchronization found on "+ hostPort +".",
|
monfe);
|
}
|
if (replicationServer != null)
|
{
|
|
String s = String.valueOf(replicationServer.getReplicationPort());
|
printProgress(formatter.getFormattedWithPoints(
|
INFO_REPLICATION_DISABLING_REPLICATION_SERVER.get(s,
|
hostPort)));
|
|
sync.removeReplicationServer();
|
sync.commit();
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
}
|
}
|
catch (OpenDsException ode)
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_DISABLING_REPLICATIONSERVER.get(hostPort),
|
ERROR_DISABLING_REPLICATION_SERVER,
|
ode);
|
}
|
}
|
|
/**
|
* Returns a message for a given OpenDsException (we assume that was an
|
* exception generated updating the configuration of the server) that
|
* occurred when we were configuring the replication server.
|
* @param ode the OpenDsException.
|
* @param hostPort the hostPort representation of the server we were
|
* contacting when the OpenDsException occurred.
|
* @return a message for a given OpenDsException (we assume that was an
|
* exception generated updating the configuration of the server) that
|
* occurred when we were configuring the replication server.
|
*/
|
private Message getMessageForReplicationServerException(OpenDsException ode,
|
String hostPort)
|
{
|
return ERR_REPLICATION_CONFIGURING_REPLICATIONSERVER.get(hostPort);
|
}
|
|
/**
|
* Returns a message for a given OpenDsException (we assume that was an
|
* exception generated updating the configuration of the server) that
|
* occurred when we were configuring some replication domain (creating
|
* the replication domain or updating the list of replication servers of
|
* the replication domain).
|
* @param ode the OpenDsException.
|
* @param hostPort the hostPort representation of the server we were
|
* contacting when the OpenDsException occurred.
|
* @return a message for a given OpenDsException (we assume that was an
|
* exception generated updating the configuration of the server) that
|
* occurred when we were configuring some replication domain (creating
|
* the replication domain or updating the list of replication servers of
|
* the replication domain).
|
*/
|
private Message getMessageForEnableException(OpenDsException ode,
|
String hostPort, String baseDN)
|
{
|
return ERR_REPLICATION_CONFIGURING_BASEDN.get(baseDN, hostPort);
|
}
|
|
/**
|
* Returns a message for a given OpenDsException (we assume that was an
|
* exception generated updating the configuration of the server) that
|
* occurred when we were configuring some replication domain (deleting
|
* the replication domain or updating the list of replication servers of
|
* the replication domain).
|
* @param ode the OpenDsException.
|
* @param hostPort the hostPort representation of the server we were
|
* contacting when the OpenDsException occurred.
|
* @return a message for a given OpenDsException (we assume that was an
|
* exception generated updating the configuration of the server) that
|
* occurred when we were configuring some replication domain (deleting
|
* the replication domain or updating the list of replication servers of
|
* the replication domain).
|
*/
|
private Message getMessageForDisableException(OpenDsException ode,
|
String hostPort, String baseDN)
|
{
|
return ERR_REPLICATION_CONFIGURING_BASEDN.get(baseDN, hostPort);
|
}
|
|
/**
|
* Returns a message informing the user that the provided port cannot be used.
|
* @param port the port that cannot be used.
|
* @return a message informing the user that the provided port cannot be used.
|
*/
|
private Message getCannotBindToPortError(int port)
|
{
|
Message message;
|
if (SetupUtils.isPriviledgedPort(port))
|
{
|
message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(port);
|
}
|
else
|
{
|
message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(port);
|
}
|
return message;
|
}
|
|
/**
|
* Convenience method used to know if one Set of replication servers equals
|
* another set of replication servers.
|
* @param s1 the first set of replication servers.
|
* @param s2 the second set of replication servers.
|
* @return <CODE>true</CODE> if the two sets represent the same replication
|
* servers and <CODE>false</CODE> otherwise.
|
*/
|
private boolean areReplicationServersEqual(Set<String> s1, Set<String> s2)
|
{
|
Set<String> c1 = new HashSet<String>();
|
for (String s : s1)
|
{
|
c1.add(s.toLowerCase());
|
}
|
Set<String> c2 = new HashSet<String>();
|
for (String s : s2)
|
{
|
c2.add(s.toLowerCase());
|
}
|
return c1.equals(c2);
|
}
|
|
/**
|
* Convenience method used to merge two Sets of replication servers.
|
* @param s1 the first set of replication servers.
|
* @param s2 the second set of replication servers.
|
* @return a Set of replication servers containing all the replication servers
|
* specified in the provided Sets.
|
*/
|
private Set<String> mergeReplicationServers(Set<String> s1, Set<String> s2)
|
{
|
Set<String> c1 = new HashSet<String>();
|
for (String s : s1)
|
{
|
c1.add(s.toLowerCase());
|
}
|
for (String s : s2)
|
{
|
c1.add(s.toLowerCase());
|
}
|
return c1;
|
}
|
|
/**
|
* Returns the message that must be displayed to the user for a given
|
* exception. This is assumed to be a critical exception that stops all
|
* the processing.
|
* @param rce the ReplicationCliException.
|
* @return a message to be displayed to the user.
|
*/
|
private Message getCriticalExceptionMessage(ReplicationCliException rce)
|
{
|
MessageBuilder mb = new MessageBuilder();
|
mb.append(rce.getMessageObject());
|
File logFile = ControlPanelLog.getLogFile();
|
if ((logFile != null) &&
|
(rce.getErrorCode() != ReplicationCliReturnCode.USER_CANCELLED))
|
{
|
mb.append(Constants.LINE_SEPARATOR);
|
mb.append(INFO_GENERAL_SEE_FOR_DETAILS.get(logFile.getPath()));
|
}
|
// Check if the cause has already been included in the message
|
Throwable c = rce.getCause();
|
if (c != null)
|
{
|
String s;
|
if (c instanceof NamingException)
|
{
|
s = ((NamingException)c).toString(true);
|
}
|
else if (c instanceof OpenDsException)
|
{
|
Message msg = ((OpenDsException)c).getMessageObject();
|
if (msg != null)
|
{
|
s = msg.toString();
|
}
|
else
|
{
|
s = c.toString();
|
}
|
}
|
else
|
{
|
s = c.toString();
|
}
|
if (mb.toString().indexOf(s) == -1)
|
{
|
mb.append(Constants.LINE_SEPARATOR);
|
mb.append(INFO_REPLICATION_CRITICAL_ERROR_DETAILS.get(s));
|
}
|
}
|
return mb.toMessage();
|
}
|
|
private boolean mustInitializeSchema(ServerDescriptor server1,
|
ServerDescriptor server2, EnableReplicationUserData uData)
|
{
|
boolean mustInitializeSchema = false;
|
if (!argParser.noSchemaReplication())
|
{
|
String id1 = server1.getSchemaReplicationID();
|
String id2 = server2.getSchemaReplicationID();
|
if (id1 != null)
|
{
|
mustInitializeSchema = id1.equals(id2);
|
}
|
else
|
{
|
mustInitializeSchema = true;
|
}
|
}
|
if (mustInitializeSchema)
|
{
|
// Check that both will contain replication data
|
mustInitializeSchema = uData.configureReplicationDomain1() &&
|
uData.configureReplicationDomain2();
|
}
|
return mustInitializeSchema;
|
}
|
|
/**
|
* This method registers a server in a given ADSContext. If the server was
|
* already registered it unregisters it and registers again (some properties
|
* might have changed).
|
* @param adsContext the ADS Context to be used.
|
* @param server the server to be registered.
|
* @throws ADSContextException if an error occurs during the registration or
|
* unregistration of the server.
|
*/
|
private void registerServer(ADSContext adsContext,
|
Map<ADSContext.ServerProperty, Object> serverProperties)
|
throws ADSContextException
|
{
|
try
|
{
|
adsContext.registerServer(serverProperties);
|
}
|
catch (ADSContextException ade)
|
{
|
if (ade.getError() ==
|
ADSContextException.ErrorType.ALREADY_REGISTERED)
|
{
|
LOG.log(Level.WARNING, "The server was already registered: "+
|
serverProperties);
|
adsContext.unregisterServer(serverProperties);
|
adsContext.registerServer(serverProperties);
|
}
|
else
|
{
|
throw ade;
|
}
|
}
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean isAdvancedMode() {
|
return false;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean isInteractive() {
|
if (forceNonInteractive)
|
{
|
return false;
|
}
|
else
|
{
|
return argParser.isInteractive();
|
}
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean isMenuDrivenMode() {
|
return true;
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean isQuiet()
|
{
|
return argParser.isQuiet();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean isScriptFriendly() {
|
return argParser.isScriptFriendly();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean isVerbose() {
|
return true;
|
}
|
|
/**
|
* Prints a message to the output with no wrapping if we are not in quiet
|
* mode.
|
* @param msg the message to be displayed.
|
*/
|
private void printProgressMessageNoWrap(Message msg)
|
{
|
if (!isQuiet())
|
{
|
getOutputStream().print(msg.toString());
|
}
|
}
|
|
/**
|
* Forces the initialization of the trust manager in the
|
* LDAPConnectionInteraction object.
|
*/
|
private void forceTrustManagerInitialization()
|
{
|
forceNonInteractive = true;
|
try
|
{
|
ci.initializeTrustManagerIfRequired();
|
}
|
catch (ArgumentException ae)
|
{
|
LOG.log(Level.WARNING, "Error initializing trust store: "+ae, ae);
|
}
|
forceNonInteractive = false;
|
}
|
|
/**
|
* Method used to compare two server registries.
|
* @param registry1 the first registry to compare.
|
* @param registry2 the second registry to compare.
|
* @return <CODE>true</CODE> if the registries are equal and
|
* <CODE>false</CODE> otherwise.
|
*/
|
private boolean areEqual(
|
Set<Map<ADSContext.ServerProperty, Object>> registry1,
|
Set<Map<ADSContext.ServerProperty, Object>> registry2)
|
{
|
boolean areEqual = registry1.size() == registry2.size();
|
if (areEqual)
|
{
|
Set<ADSContext.ServerProperty> propertiesToCompare =
|
new HashSet<ADSContext.ServerProperty>();
|
ADSContext.ServerProperty[] properties =
|
ADSContext.ServerProperty.values();
|
for (int i=0; i<properties.length; i++)
|
{
|
if (properties[i].getAttributeSyntax() !=
|
ADSPropertySyntax.CERTIFICATE_BINARY)
|
{
|
propertiesToCompare.add(properties[i]);
|
}
|
}
|
for (Map<ADSContext.ServerProperty, Object> server1 : registry1)
|
{
|
boolean found = false;
|
|
for (Map<ADSContext.ServerProperty, Object> server2 : registry2)
|
{
|
found = true;
|
for (ADSContext.ServerProperty prop : propertiesToCompare)
|
{
|
Object v1 = server1.get(prop);
|
Object v2 = server2.get(prop);
|
if (v1 != null)
|
{
|
found = v1.equals(v2);
|
}
|
else if (v2 != null)
|
{
|
found = false;
|
}
|
if (!found)
|
{
|
break;
|
}
|
}
|
if (found)
|
{
|
break;
|
}
|
}
|
|
areEqual = found;
|
if (!areEqual)
|
{
|
break;
|
}
|
}
|
}
|
return areEqual;
|
}
|
|
/**
|
* Tells whether we are trying to disable all the replicated suffixes.
|
* @param uData the disable replication data provided by the user.
|
* @return <CODE>true</CODE> if we want to disable all the replicated suffixes
|
* and <CODE>false</CODE> otherwise.
|
*/
|
private boolean disableAllBaseDns(InitialLdapContext ctx,
|
DisableReplicationUserData uData)
|
{
|
if (uData.disableAll())
|
{
|
return true;
|
}
|
|
boolean returnValue = true;
|
Collection<ReplicaDescriptor> replicas = getReplicas(ctx);
|
Set<String> replicatedSuffixes = new HashSet<String>();
|
for (ReplicaDescriptor rep : replicas)
|
{
|
String dn = rep.getSuffix().getDN();
|
if (rep.isReplicated())
|
{
|
replicatedSuffixes.add(dn);
|
}
|
}
|
|
for (String dn1 : replicatedSuffixes)
|
{
|
if (!Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn1) &&
|
!Utils.areDnsEqual(Constants.SCHEMA_DN, dn1))
|
{
|
boolean found = false;
|
for (String dn2 : uData.getBaseDNs())
|
{
|
if (Utils.areDnsEqual(dn1, dn2))
|
{
|
found = true;
|
break;
|
}
|
}
|
if (!found)
|
{
|
returnValue = false;
|
break;
|
}
|
}
|
}
|
return returnValue;
|
}
|
|
/**
|
* Returns the host port representation of the server to be used in progress,
|
* status and error messages. It takes into account the fact the host and
|
* port provided by the user.
|
* @param server the ServerDescriptor.
|
* @param cnx the preferred connections list.
|
* @return the host port string representation of the provided server.
|
*/
|
protected String getHostPort(ServerDescriptor server,
|
Collection<PreferredConnection> cnx)
|
{
|
String hostPort = null;
|
|
for (PreferredConnection connection : cnx)
|
{
|
String url = connection.getLDAPURL();
|
if (url.equals(server.getLDAPURL()))
|
{
|
hostPort = server.getHostPort(false);
|
}
|
else if (url.equals(server.getLDAPsURL()))
|
{
|
hostPort = server.getHostPort(true);
|
}
|
}
|
if (hostPort == null)
|
{
|
hostPort = server.getHostPort(true);
|
}
|
return hostPort;
|
}
|
|
/**
|
* Prompts the user for the subcommand that should be executed.
|
* @return the subcommand choice of the user.
|
*/
|
private SubcommandChoice promptForSubcommand()
|
{
|
SubcommandChoice returnValue;
|
MenuBuilder<SubcommandChoice> builder =
|
new MenuBuilder<SubcommandChoice>(this);
|
builder.setPrompt(INFO_REPLICATION_SUBCOMMAND_PROMPT.get());
|
builder.addCancelOption(false);
|
for (SubcommandChoice choice : SubcommandChoice.values())
|
{
|
if (choice != SubcommandChoice.CANCEL)
|
{
|
builder.addNumberedOption(choice.getPrompt(),
|
MenuResult.success(choice));
|
}
|
}
|
try
|
{
|
MenuResult<SubcommandChoice> m = builder.toMenu().run();
|
if (m.isSuccess())
|
{
|
returnValue = m.getValue();
|
}
|
else
|
{
|
// The user cancelled
|
returnValue = SubcommandChoice.CANCEL;
|
}
|
}
|
catch (CLIException ce)
|
{
|
returnValue = SubcommandChoice.CANCEL;
|
LOG.log(Level.WARNING, "Error reading input: "+ce, ce);
|
}
|
return returnValue;
|
}
|
|
private boolean mustPrintCommandBuilder()
|
{
|
return argParser.isInteractive() &&
|
(argParser.displayEquivalentArgument.isPresent() ||
|
argParser.equivalentCommandFileArgument.isPresent());
|
}
|
|
/**
|
* Prints the contents of a command builder. This method has been created
|
* since SetPropSubCommandHandler calls it. All the logic of DSConfig is on
|
* this method. Currently it simply writes the content of the CommandBuilder
|
* to the standard output, but if we provide an option to write the content
|
* to a file only the implementation of this method must be changed.
|
* @param commandBuilder the command builder to be printed.
|
*/
|
private void printCommandBuilder(CommandBuilder commandBuilder)
|
{
|
if (argParser.displayEquivalentArgument.isPresent())
|
{
|
println();
|
// We assume that the app we are running is this one.
|
println(
|
INFO_REPLICATION_NON_INTERACTIVE.get(commandBuilder.toString()));
|
}
|
if (argParser.equivalentCommandFileArgument.isPresent())
|
{
|
// Write to the file.
|
String file = argParser.equivalentCommandFileArgument.getValue();
|
try
|
{
|
BufferedWriter writer =
|
new BufferedWriter(new FileWriter(file, true));
|
|
writer.write(SHELL_COMMENT_SEPARATOR+getCurrentOperationDateMessage());
|
writer.newLine();
|
|
writer.write(commandBuilder.toString());
|
writer.newLine();
|
writer.newLine();
|
|
writer.flush();
|
writer.close();
|
}
|
catch (IOException ioe)
|
{
|
println(
|
ERR_REPLICATION_ERROR_WRITING_EQUIVALENT_COMMAND_LINE.get(file,
|
ioe.toString()));
|
}
|
}
|
}
|
|
/**
|
* Creates a command builder with the global options: script friendly,
|
* verbose, etc. for a given subcommand name. It also adds systematically the
|
* no-prompt option.
|
* @param subcommandName the subcommand name.
|
* @param uData the user data.
|
* @return the command builder that has been created with the specified
|
* subcommandName.
|
*/
|
private CommandBuilder createCommandBuilder(String subcommandName,
|
ReplicationUserData uData) throws ArgumentException
|
{
|
String commandName = getCommandName();
|
|
CommandBuilder commandBuilder =
|
new CommandBuilder(commandName, subcommandName);
|
|
|
if (subcommandName.equals(
|
ReplicationCliArgumentParser.ENABLE_REPLICATION_SUBCMD_NAME))
|
{
|
// All the arguments for enable replication are update here.
|
updateCommandBuilder(commandBuilder, (EnableReplicationUserData)uData);
|
}
|
else if (subcommandName.equals(
|
ReplicationCliArgumentParser.INITIALIZE_REPLICATION_SUBCMD_NAME))
|
{
|
// All the arguments for initialize replication are update here.
|
updateCommandBuilder(commandBuilder,
|
(InitializeReplicationUserData)uData);
|
}
|
else if (subcommandName.equals(
|
ReplicationCliArgumentParser.PURGE_HISTORICAL_SUBCMD_NAME))
|
{
|
// All the arguments for initialize replication are update here.
|
updateCommandBuilder(commandBuilder, (PurgeHistoricalUserData)uData);
|
}
|
else
|
{
|
// Update the arguments used in the console interaction with the
|
// actual arguments of dsreplication.
|
updateCommandBuilderWithConsoleInteraction(commandBuilder, ci);
|
}
|
|
if (subcommandName.equals(
|
ReplicationCliArgumentParser.DISABLE_REPLICATION_SUBCMD_NAME))
|
{
|
DisableReplicationUserData disableData =
|
(DisableReplicationUserData)uData;
|
if (disableData.disableAll())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
argParser.disableAllArg.getName(),
|
argParser.disableAllArg.getShortIdentifier(),
|
argParser.disableAllArg.getLongIdentifier(),
|
INFO_DESCRIPTION_DISABLE_ALL.get()));
|
}
|
else if (disableData.disableReplicationServer())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
argParser.disableReplicationServerArg.getName(),
|
argParser.disableReplicationServerArg.getShortIdentifier(),
|
argParser.disableReplicationServerArg.getLongIdentifier(),
|
INFO_DESCRIPTION_DISABLE_REPLICATION_SERVER.get()));
|
}
|
}
|
|
addGlobalArguments(commandBuilder, uData);
|
return commandBuilder;
|
}
|
|
private String getCommandName()
|
{
|
String commandName =
|
System.getProperty(ServerConstants.PROPERTY_SCRIPT_NAME);
|
if (commandName == null)
|
{
|
commandName = "dsreplication";
|
}
|
return commandName;
|
}
|
|
private void updateCommandBuilderWithConsoleInteraction(
|
CommandBuilder commandBuilder,
|
LDAPConnectionConsoleInteraction ci) throws ArgumentException
|
{
|
if ((ci != null) && (ci.getCommandBuilder() != null))
|
{
|
CommandBuilder interactionBuilder = ci.getCommandBuilder();
|
for (Argument arg : interactionBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD))
|
{
|
StringArgument bindPasswordArg = new StringArgument("adminPassword",
|
OPTION_SHORT_BINDPWD, "adminPassword", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD_FILE))
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"adminPasswordFile",
|
OPTION_SHORT_BINDPWD_FILE, "adminPasswordFile", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get());
|
bindPasswordFileArg.getNameToValueMap().putAll(
|
((FileBasedArgument)arg).getNameToValueMap());
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
else
|
{
|
if (interactionBuilder.isObfuscated(arg))
|
{
|
commandBuilder.addObfuscatedArgument(arg);
|
}
|
else
|
{
|
commandBuilder.addArgument(arg);
|
}
|
}
|
}
|
}
|
}
|
|
private void updateCommandBuilder(CommandBuilder commandBuilder,
|
PurgeHistoricalUserData uData) throws ArgumentException
|
{
|
if (uData.isOnline())
|
{
|
updateCommandBuilderWithConsoleInteraction(commandBuilder, ci);
|
if (uData.getTaskSchedule() != null)
|
{
|
updateCommandBuilderWithTaskSchedule(commandBuilder,
|
uData.getTaskSchedule());
|
}
|
}
|
|
IntegerArgument maximumDurationArg = new IntegerArgument(
|
argParser.maximumDurationArg.getName(),
|
argParser.maximumDurationArg.getShortIdentifier(),
|
argParser.maximumDurationArg.getLongIdentifier(),
|
argParser.maximumDurationArg.isRequired(),
|
argParser.maximumDurationArg.isMultiValued(),
|
argParser.maximumDurationArg.needsValue(),
|
argParser.maximumDurationArg.getValuePlaceholder(),
|
PurgeConflictsHistoricalTask.DEFAULT_MAX_DURATION,
|
argParser.maximumDurationArg.getPropertyName(),
|
argParser.maximumDurationArg.getDescription());
|
maximumDurationArg.addValue(String.valueOf(uData.getMaximumDuration()));
|
commandBuilder.addArgument(maximumDurationArg);
|
}
|
|
private void updateCommandBuilderWithTaskSchedule(
|
CommandBuilder commandBuilder,
|
TaskScheduleUserData taskSchedule)
|
{
|
TaskScheduleUserData.updateCommandBuilderWithTaskSchedule(
|
commandBuilder, taskSchedule);
|
}
|
|
private void addGlobalArguments(CommandBuilder commandBuilder,
|
ReplicationUserData uData)
|
throws ArgumentException
|
{
|
LinkedList<String> baseDNs = uData.getBaseDNs();
|
StringArgument baseDNsArg = new StringArgument("baseDNs",
|
OPTION_SHORT_BASEDN,
|
OPTION_LONG_BASEDN, false, true, true, INFO_BASEDN_PLACEHOLDER.get(),
|
null,
|
null, INFO_DESCRIPTION_REPLICATION_BASEDNS.get());
|
for (String baseDN : baseDNs)
|
{
|
baseDNsArg.addValue(baseDN);
|
}
|
commandBuilder.addArgument(baseDNsArg);
|
|
// Try to find some arguments and put them at the end.
|
String[] identifiersToMove ={
|
OPTION_LONG_ADMIN_UID,
|
"adminPassword",
|
"adminPasswordFile",
|
OPTION_LONG_SASLOPTION,
|
OPTION_LONG_TRUSTALL,
|
OPTION_LONG_TRUSTSTOREPATH,
|
OPTION_LONG_TRUSTSTORE_PWD,
|
OPTION_LONG_TRUSTSTORE_PWD_FILE,
|
OPTION_LONG_KEYSTOREPATH,
|
OPTION_LONG_KEYSTORE_PWD,
|
OPTION_LONG_KEYSTORE_PWD_FILE,
|
OPTION_LONG_CERT_NICKNAME
|
};
|
|
ArrayList<Argument> toMoveArgs = new ArrayList<Argument>();
|
for (String longID : identifiersToMove)
|
{
|
for (Argument arg : commandBuilder.getArguments())
|
{
|
if (longID.equals(arg.getLongIdentifier()))
|
{
|
toMoveArgs.add(arg);
|
break;
|
}
|
}
|
}
|
for (Argument argToMove : toMoveArgs)
|
{
|
boolean toObfuscate = commandBuilder.isObfuscated(argToMove);
|
commandBuilder.removeArgument(argToMove);
|
if (toObfuscate)
|
{
|
commandBuilder.addObfuscatedArgument(argToMove);
|
}
|
else
|
{
|
commandBuilder.addArgument(argToMove);
|
}
|
}
|
|
if (argParser.isVerbose())
|
{
|
commandBuilder.addArgument(new BooleanArgument("verbose",
|
OPTION_SHORT_VERBOSE,
|
OPTION_LONG_VERBOSE, INFO_DESCRIPTION_VERBOSE.get()));
|
}
|
|
if (argParser.isScriptFriendly())
|
{
|
commandBuilder.addArgument(argParser.scriptFriendlyArg);
|
}
|
|
commandBuilder.addArgument(argParser.noPromptArg);
|
|
if (argParser.propertiesFileArgument.isPresent())
|
{
|
commandBuilder.addArgument(argParser.propertiesFileArgument);
|
}
|
|
if (argParser.noPropertiesFileArgument.isPresent())
|
{
|
commandBuilder.addArgument(argParser.noPropertiesFileArgument);
|
}
|
}
|
|
private void updateCommandBuilder(CommandBuilder commandBuilder,
|
EnableReplicationUserData uData)
|
throws ArgumentException
|
{
|
// Update the arguments used in the console interaction with the
|
// actual arguments of dsreplication.
|
boolean adminInformationAdded = false;
|
|
if (firstServerCommandBuilder != null)
|
{
|
boolean useAdminUID = false;
|
for (Argument arg : firstServerCommandBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_ADMIN_UID))
|
{
|
useAdminUID = true;
|
break;
|
}
|
}
|
// This is required when both the bindDN and the admin UID are provided
|
// in the command-line.
|
boolean forceAddBindDN1 = false;
|
boolean forceAddBindPwdFile1 = false;
|
if (useAdminUID)
|
{
|
String bindDN1 = uData.getBindDn1();
|
String adminUID = uData.getAdminUid();
|
if (bindDN1 != null && adminUID != null)
|
{
|
if (!Utils.areDnsEqual(ADSContext.getAdministratorDN(adminUID),
|
bindDN1))
|
{
|
forceAddBindDN1 = true;
|
|
for (Argument arg : firstServerCommandBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD_FILE))
|
{
|
forceAddBindPwdFile1 = true;
|
break;
|
}
|
}
|
}
|
}
|
}
|
for (Argument arg : firstServerCommandBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_HOST))
|
{
|
StringArgument host = new StringArgument("host1", OPTION_SHORT_HOST,
|
"host1", false, false, true, INFO_HOST_PLACEHOLDER.get(),
|
null,
|
null, INFO_DESCRIPTION_ENABLE_REPLICATION_HOST1.get());
|
host.addValue(uData.getHostName1());
|
commandBuilder.addArgument(host);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_PORT))
|
{
|
IntegerArgument port = new IntegerArgument("port1", OPTION_SHORT_PORT,
|
"port1",
|
false, false, true, INFO_PORT_PLACEHOLDER.get(), 4444, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT1.get());
|
port.addValue(String.valueOf(uData.getPort1()));
|
commandBuilder.addArgument(port);
|
|
if (forceAddBindDN1)
|
{
|
StringArgument bindDN = new StringArgument("bindDN1",
|
OPTION_SHORT_BINDDN,
|
"bindDN1", false, false, true, INFO_BINDDN_PLACEHOLDER.get(),
|
"cn=Directory Manager", null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN1.get());
|
bindDN.addValue(uData.getBindDn1());
|
commandBuilder.addArgument(bindDN);
|
if (forceAddBindPwdFile1)
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"bindPasswordFile1",
|
null, "bindPasswordFile1", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE1.get());
|
bindPasswordFileArg.getNameToValueMap().put("{password file}",
|
"{password file}");
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
else
|
{
|
StringArgument bindPasswordArg = new StringArgument(
|
"bindPassword1",
|
null, "bindPassword1", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD1.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
}
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDDN))
|
{
|
StringArgument bindDN = new StringArgument("bindDN1",
|
OPTION_SHORT_BINDDN,
|
"bindDN1", false, false, true, INFO_BINDDN_PLACEHOLDER.get(),
|
"cn=Directory Manager", null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN1.get());
|
bindDN.addValue(uData.getBindDn1());
|
commandBuilder.addArgument(bindDN);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD))
|
{
|
if (useAdminUID)
|
{
|
adminInformationAdded = true;
|
StringArgument bindPasswordArg = new StringArgument("adminPassword",
|
OPTION_SHORT_BINDPWD, "adminPassword", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
else
|
{
|
StringArgument bindPasswordArg = new StringArgument("bindPassword1",
|
null, "bindPassword1", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD1.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD_FILE))
|
{
|
if (useAdminUID)
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"adminPasswordFile",
|
OPTION_SHORT_BINDPWD_FILE, "adminPasswordFile", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get());
|
bindPasswordFileArg.getNameToValueMap().putAll(
|
((FileBasedArgument)arg).getNameToValueMap());
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
else
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"bindPasswordFile1",
|
null, "bindPasswordFile1", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE1.get());
|
bindPasswordFileArg.getNameToValueMap().putAll(
|
((FileBasedArgument)arg).getNameToValueMap());
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
}
|
else
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_ADMIN_UID))
|
{
|
adminInformationAdded = true;
|
}
|
if (firstServerCommandBuilder.isObfuscated(arg))
|
{
|
commandBuilder.addObfuscatedArgument(arg);
|
}
|
else
|
{
|
commandBuilder.addArgument(arg);
|
}
|
}
|
}
|
}
|
|
|
if ((ci != null) && (ci.getCommandBuilder() != null))
|
{
|
CommandBuilder interactionBuilder = ci.getCommandBuilder();
|
boolean useAdminUID = false;
|
boolean hasBindDN = false;
|
for (Argument arg : interactionBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_ADMIN_UID))
|
{
|
useAdminUID = true;
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDDN))
|
{
|
hasBindDN = true;
|
}
|
if (useAdminUID && hasBindDN)
|
{
|
break;
|
}
|
}
|
// This is required when both the bindDN and the admin UID are provided
|
// in the command-line.
|
boolean forceAddBindDN2 = false;
|
boolean forceAddBindPwdFile2 = false;
|
if (useAdminUID)
|
{
|
String bindDN2 = uData.getBindDn2();
|
String adminUID = uData.getAdminUid();
|
if (bindDN2 != null && adminUID != null)
|
{
|
if (!Utils.areDnsEqual(ADSContext.getAdministratorDN(adminUID),
|
bindDN2))
|
{
|
forceAddBindDN2 = true;
|
|
for (Argument arg : interactionBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD_FILE))
|
{
|
forceAddBindPwdFile2 = true;
|
break;
|
}
|
}
|
}
|
}
|
}
|
ArrayList<Argument> argsToAnalyze = new ArrayList<Argument>();
|
for (Argument arg : interactionBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_HOST))
|
{
|
StringArgument host = new StringArgument("host2", 'O',
|
"host2", false, false, true, INFO_HOST_PLACEHOLDER.get(),
|
null,
|
null, INFO_DESCRIPTION_ENABLE_REPLICATION_HOST2.get());
|
host.addValue(uData.getHostName2());
|
commandBuilder.addArgument(host);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_PORT))
|
{
|
IntegerArgument port = new IntegerArgument("port2", null, "port2",
|
false, false, true, INFO_PORT_PLACEHOLDER.get(), 4444, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT2.get());
|
port.addValue(String.valueOf(uData.getPort2()));
|
commandBuilder.addArgument(port);
|
|
if (forceAddBindDN2)
|
{
|
StringArgument bindDN = new StringArgument("bindDN2",
|
OPTION_SHORT_BINDDN,
|
"bindDN2", false, false, true, INFO_BINDDN_PLACEHOLDER.get(),
|
"cn=Directory Manager", null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN2.get());
|
bindDN.addValue(uData.getBindDn2());
|
commandBuilder.addArgument(bindDN);
|
if (forceAddBindPwdFile2)
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"bindPasswordFile2",
|
null, "bindPasswordFile2", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE2.get());
|
bindPasswordFileArg.getNameToValueMap().put("{password file}",
|
"{password file}");
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
else
|
{
|
StringArgument bindPasswordArg = new StringArgument(
|
"bindPassword2",
|
null, "bindPassword2", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD2.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
}
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDDN))
|
{
|
StringArgument bindDN = new StringArgument("bindDN2", null,
|
"bindDN2", false, false, true, INFO_BINDDN_PLACEHOLDER.get(),
|
"cn=Directory Manager", null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN2.get());
|
bindDN.addValue(uData.getBindDn2());
|
commandBuilder.addArgument(bindDN);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD))
|
{
|
if (useAdminUID && !adminInformationAdded)
|
{
|
adminInformationAdded = true;
|
StringArgument bindPasswordArg = new StringArgument("adminPassword",
|
OPTION_SHORT_BINDPWD, "adminPassword", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
else if (hasBindDN)
|
{
|
StringArgument bindPasswordArg = new StringArgument("bindPassword2",
|
null, "bindPassword2", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD2.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD_FILE))
|
{
|
if (useAdminUID && !adminInformationAdded)
|
{
|
adminInformationAdded = true;
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"adminPasswordFile",
|
OPTION_SHORT_BINDPWD_FILE, "adminPasswordFile", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get());
|
bindPasswordFileArg.getNameToValueMap().putAll(
|
((FileBasedArgument)arg).getNameToValueMap());
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
else if (hasBindDN)
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"bindPasswordFile2",
|
null, "bindPasswordFile2", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE2.get());
|
bindPasswordFileArg.getNameToValueMap().putAll(
|
((FileBasedArgument)arg).getNameToValueMap());
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
}
|
else
|
{
|
argsToAnalyze.add(arg);
|
}
|
}
|
|
for (Argument arg : argsToAnalyze)
|
{
|
// Just check that the arguments have not already been added.
|
boolean found = false;
|
for (Argument a : commandBuilder.getArguments())
|
{
|
if (a.getLongIdentifier().equals(arg.getLongIdentifier()))
|
{
|
found = true;
|
break;
|
}
|
}
|
|
if (!found)
|
{
|
if (interactionBuilder.isObfuscated(arg))
|
{
|
commandBuilder.addObfuscatedArgument(arg);
|
}
|
else
|
{
|
commandBuilder.addArgument(arg);
|
}
|
}
|
}
|
}
|
|
// Try to add the new administration information.
|
if (!adminInformationAdded)
|
{
|
StringArgument adminUID = new StringArgument(OPTION_LONG_ADMIN_UID, 'I',
|
OPTION_LONG_ADMIN_UID, false, false, true,
|
INFO_ADMINUID_PLACEHOLDER.get(),
|
Constants.GLOBAL_ADMIN_UID, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_UID.get(
|
ReplicationCliArgumentParser.ENABLE_REPLICATION_SUBCMD_NAME));
|
if (uData.getAdminUid() != null)
|
{
|
adminUID.addValue(uData.getAdminUid());
|
commandBuilder.addArgument(adminUID);
|
}
|
|
if (userProvidedAdminPwdFile != null)
|
{
|
commandBuilder.addArgument(userProvidedAdminPwdFile);
|
}
|
else
|
{
|
Argument bindPasswordArg = new StringArgument("adminPassword",
|
OPTION_SHORT_BINDPWD, "adminPassword", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get());
|
if (uData.getAdminPwd() != null)
|
{
|
bindPasswordArg.addValue(uData.getAdminPwd());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
}
|
}
|
|
if (uData.configureReplicationServer1() &&
|
!uData.configureReplicationDomain1())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
argParser.onlyReplicationServer1Arg.getName(),
|
argParser.onlyReplicationServer1Arg.getShortIdentifier(),
|
argParser.onlyReplicationServer1Arg.getLongIdentifier(),
|
INFO_DESCRIPTION_ENABLE_REPLICATION_ONLY_REPLICATION_SERVER1.get()));
|
}
|
|
if (!uData.configureReplicationServer1() &&
|
uData.configureReplicationDomain1())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
argParser.noReplicationServer1Arg.getName(),
|
argParser.noReplicationServer1Arg.getShortIdentifier(),
|
argParser.noReplicationServer1Arg.getLongIdentifier(),
|
INFO_DESCRIPTION_ENABLE_REPLICATION_NO_REPLICATION_SERVER1.get()));
|
}
|
|
if (uData.configureReplicationServer1() &&
|
uData.getReplicationPort1() > 0)
|
{
|
IntegerArgument replicationPort1 = new IntegerArgument(
|
"replicationPort1", 'r',
|
"replicationPort1", false, false, true, INFO_PORT_PLACEHOLDER.get(),
|
8989, null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_PORT1.get());
|
replicationPort1.addValue(String.valueOf(uData.getReplicationPort1()));
|
commandBuilder.addArgument(replicationPort1);
|
}
|
if (uData.isSecureReplication1())
|
{
|
commandBuilder.addArgument(new BooleanArgument("secureReplication1", null,
|
"secureReplication1",
|
INFO_DESCRIPTION_ENABLE_SECURE_REPLICATION1.get()));
|
}
|
|
|
if (uData.configureReplicationServer2() &&
|
!uData.configureReplicationDomain2())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
argParser.onlyReplicationServer2Arg.getName(),
|
argParser.onlyReplicationServer2Arg.getShortIdentifier(),
|
argParser.onlyReplicationServer2Arg.getLongIdentifier(),
|
INFO_DESCRIPTION_ENABLE_REPLICATION_ONLY_REPLICATION_SERVER2.get()));
|
}
|
|
if (!uData.configureReplicationServer2() &&
|
uData.configureReplicationDomain2())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
argParser.noReplicationServer2Arg.getName(),
|
argParser.noReplicationServer2Arg.getShortIdentifier(),
|
argParser.noReplicationServer2Arg.getLongIdentifier(),
|
INFO_DESCRIPTION_ENABLE_REPLICATION_NO_REPLICATION_SERVER2.get()));
|
}
|
if (uData.configureReplicationServer2() &&
|
uData.getReplicationPort2() > 0)
|
{
|
IntegerArgument replicationPort2 = new IntegerArgument(
|
"replicationPort2", 'r',
|
"replicationPort2", false, false, true, INFO_PORT_PLACEHOLDER.get(),
|
uData.getReplicationPort2(), null,
|
INFO_DESCRIPTION_ENABLE_REPLICATION_PORT2.get());
|
replicationPort2.addValue(String.valueOf(uData.getReplicationPort2()));
|
commandBuilder.addArgument(replicationPort2);
|
}
|
if (uData.isSecureReplication2())
|
{
|
commandBuilder.addArgument(new BooleanArgument("secureReplication2", null,
|
"secureReplication2",
|
INFO_DESCRIPTION_ENABLE_SECURE_REPLICATION2.get()));
|
}
|
|
|
if (!uData.replicateSchema())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
"noschemareplication", null, "noSchemaReplication",
|
INFO_DESCRIPTION_ENABLE_REPLICATION_NO_SCHEMA_REPLICATION.get()));
|
}
|
if (argParser.skipReplicationPortCheck())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
"skipportcheck", 'S', "skipPortCheck",
|
INFO_DESCRIPTION_ENABLE_REPLICATION_SKIPPORT.get()));
|
}
|
if (argParser.useSecondServerAsSchemaSource())
|
{
|
commandBuilder.addArgument(new BooleanArgument(
|
"usesecondserverasschemasource", null,
|
"useSecondServerAsSchemaSource",
|
INFO_DESCRIPTION_ENABLE_REPLICATION_USE_SECOND_AS_SCHEMA_SOURCE.get(
|
"--"+argParser.noSchemaReplicationArg.getLongIdentifier())));
|
}
|
}
|
|
private void updateCommandBuilder(CommandBuilder commandBuilder,
|
InitializeReplicationUserData uData)
|
throws ArgumentException
|
{
|
// Update the arguments used in the console interaction with the
|
// actual arguments of dsreplication.
|
|
if (firstServerCommandBuilder != null)
|
{
|
for (Argument arg : firstServerCommandBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_HOST))
|
{
|
StringArgument host = new StringArgument("hostSource", 'O',
|
"hostSource", false, false, true,
|
INFO_HOST_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_SOURCE.get());
|
host.addValue(uData.getHostNameSource());
|
commandBuilder.addArgument(host);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_PORT))
|
{
|
IntegerArgument port = new IntegerArgument("portSource", null,
|
"portSource", false, false, true,
|
INFO_PORT_PLACEHOLDER.get(),
|
4444,
|
null,
|
INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_SOURCE.get());
|
port.addValue(String.valueOf(uData.getPortSource()));
|
commandBuilder.addArgument(port);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD))
|
{
|
StringArgument bindPasswordArg = new StringArgument("adminPassword",
|
OPTION_SHORT_BINDPWD, "adminPassword", false, false, true,
|
INFO_BINDPWD_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get());
|
bindPasswordArg.addValue(arg.getValue());
|
commandBuilder.addObfuscatedArgument(bindPasswordArg);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_BINDPWD_FILE))
|
{
|
FileBasedArgument bindPasswordFileArg = new FileBasedArgument(
|
"adminPasswordFile",
|
OPTION_SHORT_BINDPWD_FILE, "adminPasswordFile", false, false,
|
INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
|
INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get());
|
bindPasswordFileArg.getNameToValueMap().putAll(
|
((FileBasedArgument)arg).getNameToValueMap());
|
commandBuilder.addArgument(bindPasswordFileArg);
|
}
|
else
|
{
|
if (firstServerCommandBuilder.isObfuscated(arg))
|
{
|
commandBuilder.addObfuscatedArgument(arg);
|
}
|
else
|
{
|
commandBuilder.addArgument(arg);
|
}
|
}
|
}
|
}
|
|
|
if ((ci != null) && (ci.getCommandBuilder() != null))
|
{
|
CommandBuilder interactionBuilder = ci.getCommandBuilder();
|
for (Argument arg : interactionBuilder.getArguments())
|
{
|
if (arg.getLongIdentifier().equals(OPTION_LONG_HOST))
|
{
|
StringArgument host = new StringArgument("hostDestination", 'O',
|
"hostDestination", false, false, true,
|
INFO_HOST_PLACEHOLDER.get(),
|
null, null,
|
INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_DESTINATION.get());
|
host.addValue(uData.getHostNameDestination());
|
commandBuilder.addArgument(host);
|
}
|
else if (arg.getLongIdentifier().equals(OPTION_LONG_PORT))
|
{
|
IntegerArgument port = new IntegerArgument("portDestination", null,
|
"portDestination", false, false, true,
|
INFO_PORT_PLACEHOLDER.get(),
|
4444,
|
null,
|
INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_DESTINATION.get());
|
port.addValue(String.valueOf(uData.getPortDestination()));
|
commandBuilder.addArgument(port);
|
}
|
}
|
}
|
}
|
|
private void updateAvailableAndReplicatedSuffixesForOneDomain(
|
InitialLdapContext ctxDomain, InitialLdapContext ctxOther,
|
Collection<String> availableSuffixes,
|
Collection<String> alreadyReplicatedSuffixes)
|
{
|
Collection<ReplicaDescriptor> replicas = getReplicas(ctxDomain);
|
int replicationPort = getReplicationPort(ctxOther);
|
boolean isReplicationServerConfigured = replicationPort != -1;
|
String replicationServer = getReplicationServer(
|
ConnectionUtils.getHostName(ctxOther), replicationPort);
|
for (ReplicaDescriptor replica : replicas)
|
{
|
if (!isReplicationServerConfigured)
|
{
|
if (replica.isReplicated())
|
{
|
alreadyReplicatedSuffixes.add(replica.getSuffix().getDN());
|
}
|
availableSuffixes.add(replica.getSuffix().getDN());
|
}
|
if (!isReplicationServerConfigured)
|
{
|
availableSuffixes.add(replica.getSuffix().getDN());
|
}
|
else
|
{
|
if (!replica.isReplicated())
|
{
|
availableSuffixes.add(replica.getSuffix().getDN());
|
}
|
else
|
{
|
// Check if the replica is already configured with the replication
|
// server.
|
boolean alreadyReplicated = false;
|
Set<String> rServers = replica.getReplicationServers();
|
for (String rServer : rServers)
|
{
|
if (replicationServer.equalsIgnoreCase(rServer))
|
{
|
alreadyReplicated = true;
|
}
|
}
|
if (alreadyReplicated)
|
{
|
alreadyReplicatedSuffixes.add(replica.getSuffix().getDN());
|
}
|
else
|
{
|
availableSuffixes.add(replica.getSuffix().getDN());
|
}
|
}
|
}
|
}
|
}
|
|
private void updateAvailableAndReplicatedSuffixesForNoDomain(
|
InitialLdapContext ctx1, InitialLdapContext ctx2,
|
Collection<String> availableSuffixes,
|
Collection<String> alreadyReplicatedSuffixes)
|
{
|
int replicationPort1 = getReplicationPort(ctx1);
|
boolean isReplicationServer1Configured = replicationPort1 != -1;
|
String replicationServer1 = getReplicationServer(
|
ConnectionUtils.getHostName(ctx1), replicationPort1);
|
|
int replicationPort2 = getReplicationPort(ctx2);
|
boolean isReplicationServer2Configured = replicationPort2 != -1;
|
String replicationServer2 = getReplicationServer(
|
ConnectionUtils.getHostName(ctx2), replicationPort2);
|
|
TopologyCache cache1 = null;
|
TopologyCache cache2 = null;
|
|
if (isReplicationServer1Configured)
|
{
|
try
|
{
|
ADSContext adsContext = new ADSContext(ctx1);
|
if (adsContext.hasAdminData())
|
{
|
cache1 = new TopologyCache(adsContext, getTrustManager(),
|
getConnectTimeout());
|
cache1.getFilter().setSearchMonitoringInformation(false);
|
cache1.setPreferredConnections(
|
PreferredConnection.getPreferredConnections(ctx1));
|
cache1.reloadTopology();
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING, "Error loading topology cache in "+
|
ConnectionUtils.getLdapUrl(ctx1)+": "+t, t);
|
}
|
}
|
|
if (isReplicationServer2Configured)
|
{
|
try
|
{
|
ADSContext adsContext = new ADSContext(ctx2);
|
if (adsContext.hasAdminData())
|
{
|
cache2 = new TopologyCache(adsContext, getTrustManager(),
|
getConnectTimeout());
|
cache2.getFilter().setSearchMonitoringInformation(false);
|
cache2.setPreferredConnections(
|
PreferredConnection.getPreferredConnections(ctx2));
|
cache2.reloadTopology();
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING, "Error loading topology cache in "+
|
ConnectionUtils.getLdapUrl(ctx2)+": "+t, t);
|
}
|
}
|
|
if (cache1 != null && cache2 != null)
|
{
|
updateAvailableAndReplicatedSuffixesForNoDomainOneSense(cache1, cache2,
|
replicationServer1, replicationServer2, availableSuffixes,
|
alreadyReplicatedSuffixes);
|
updateAvailableAndReplicatedSuffixesForNoDomainOneSense(cache2, cache1,
|
replicationServer2, replicationServer1, availableSuffixes,
|
alreadyReplicatedSuffixes);
|
}
|
else if (cache1 != null)
|
{
|
Set<SuffixDescriptor> suffixes = cache1.getSuffixes();
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
for (String rServer : suffix.getReplicationServers())
|
{
|
if (rServer.equalsIgnoreCase(replicationServer1))
|
{
|
availableSuffixes.add(suffix.getDN());
|
}
|
}
|
}
|
}
|
else if (cache2 != null)
|
{
|
Set<SuffixDescriptor> suffixes = cache2.getSuffixes();
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
for (String rServer : suffix.getReplicationServers())
|
{
|
if (rServer.equalsIgnoreCase(replicationServer2))
|
{
|
availableSuffixes.add(suffix.getDN());
|
}
|
}
|
}
|
}
|
}
|
|
private void updateAvailableAndReplicatedSuffixesForNoDomainOneSense(
|
TopologyCache cache1, TopologyCache cache2, String replicationServer1,
|
String replicationServer2,
|
Collection<String> availableSuffixes,
|
Collection<String> alreadyReplicatedSuffixes)
|
{
|
Set<SuffixDescriptor> suffixes = cache1.getSuffixes();
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
for (String rServer : suffix.getReplicationServers())
|
{
|
if (rServer.equalsIgnoreCase(replicationServer1))
|
{
|
boolean isSecondReplicatedInSameTopology = false;
|
boolean isSecondReplicated = false;
|
boolean isFirstReplicated = false;
|
for (SuffixDescriptor suffix2 : cache2.getSuffixes())
|
{
|
if (Utils.areDnsEqual(suffix.getDN(), suffix2.getDN()))
|
{
|
for (String rServer2 : suffix2.getReplicationServers())
|
{
|
if (rServer2.equalsIgnoreCase(replicationServer2))
|
{
|
isSecondReplicated = true;
|
}
|
if (rServer.equalsIgnoreCase(replicationServer2))
|
{
|
isFirstReplicated = true;
|
}
|
if (isFirstReplicated && isSecondReplicated)
|
{
|
isSecondReplicatedInSameTopology = true;
|
break;
|
}
|
}
|
break;
|
}
|
}
|
if (!isSecondReplicatedInSameTopology)
|
{
|
availableSuffixes.add(suffix.getDN());
|
}
|
else
|
{
|
alreadyReplicatedSuffixes.add(suffix.getDN());
|
}
|
break;
|
}
|
}
|
}
|
}
|
|
private void updateBaseDnsWithNotEnoughReplicationServer(ADSContext adsCtx1,
|
ADSContext adsCtx2, EnableReplicationUserData uData,
|
Set<String> baseDNsWithNoReplicationServer,
|
Set<String> baseDNsWithOneReplicationServer)
|
{
|
if (uData.configureReplicationServer1() &&
|
uData.configureReplicationServer2())
|
{
|
return;
|
}
|
Set<SuffixDescriptor> suffixes = new HashSet<SuffixDescriptor>();
|
try
|
{
|
if (adsCtx1.hasAdminData())
|
{
|
TopologyCache cache = new TopologyCache(adsCtx1,
|
getTrustManager(), getConnectTimeout());
|
cache.getFilter().setSearchMonitoringInformation(false);
|
for (String dn : uData.getBaseDNs())
|
{
|
cache.getFilter().addBaseDNToSearch(dn);
|
}
|
cache.reloadTopology();
|
suffixes.addAll(cache.getSuffixes());
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING, "Error loading topology cache from "+
|
ConnectionUtils.getHostPort(adsCtx1.getDirContext())+": "+t, t);
|
}
|
|
try
|
{
|
if (adsCtx2.hasAdminData())
|
{
|
TopologyCache cache = new TopologyCache(adsCtx2,
|
getTrustManager(), getConnectTimeout());
|
cache.getFilter().setSearchMonitoringInformation(false);
|
cache.reloadTopology();
|
for (String dn : uData.getBaseDNs())
|
{
|
cache.getFilter().addBaseDNToSearch(dn);
|
}
|
suffixes.addAll(cache.getSuffixes());
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.WARNING, "Error loading topology cache from "+
|
ConnectionUtils.getHostPort(adsCtx2.getDirContext())+": "+t, t);
|
}
|
|
int repPort1 = getReplicationPort(adsCtx1.getDirContext());
|
String repServer1 = getReplicationServer(uData.getHostName1(), repPort1);
|
int repPort2 = getReplicationPort(adsCtx2.getDirContext());
|
String repServer2 = getReplicationServer(uData.getHostName2(), repPort2);
|
for (String baseDN : uData.getBaseDNs())
|
{
|
int nReplicationServers = 0;
|
for (SuffixDescriptor suffix : suffixes)
|
{
|
if (Utils.areDnsEqual(suffix.getDN(), baseDN))
|
{
|
Set<String> replicationServers = suffix.getReplicationServers();
|
nReplicationServers += replicationServers.size();
|
for (String repServer : replicationServers)
|
{
|
if (uData.configureReplicationServer1() &&
|
repServer.equalsIgnoreCase(repServer1))
|
{
|
nReplicationServers --;
|
}
|
if (uData.configureReplicationServer2() &&
|
repServer.equalsIgnoreCase(repServer2))
|
{
|
nReplicationServers --;
|
}
|
}
|
}
|
}
|
if (uData.configureReplicationServer1())
|
{
|
nReplicationServers ++;
|
}
|
if (uData.configureReplicationServer2())
|
{
|
nReplicationServers ++;
|
}
|
if (nReplicationServers == 1)
|
{
|
baseDNsWithOneReplicationServer.add(baseDN);
|
}
|
else if (nReplicationServers == 0)
|
{
|
baseDNsWithNoReplicationServer.add(baseDN);
|
}
|
}
|
}
|
|
/**
|
* Merge the contents of the two registries but only does it partially.
|
* Only one of the two ADSContext will be updated (in terms of data in
|
* cn=admin data), while the other registry's replication servers will have
|
* their truststore updated to be able to initialize all the contents.
|
*
|
* This method does NOT configure replication between topologies or initialize
|
* replication.
|
*
|
* @param adsCtx1 the ADSContext of the first registry.
|
* @param adsCtx2 the ADSContext of the second registry.
|
* @return <CODE>true</CODE> if the registry containing all the data is
|
* the first registry and <CODE>false</CODE> otherwise.
|
* @throws ReplicationCliException if there is a problem reading or updating
|
* the registries.
|
*/
|
private boolean mergeRegistries(ADSContext adsCtx1, ADSContext adsCtx2)
|
throws ReplicationCliException
|
{
|
PointAdder pointAdder = new PointAdder(this);
|
try
|
{
|
LinkedHashSet<PreferredConnection> cnx =
|
new LinkedHashSet<PreferredConnection>();
|
cnx.addAll(PreferredConnection.getPreferredConnections(
|
adsCtx1.getDirContext()));
|
cnx.addAll(PreferredConnection.getPreferredConnections(
|
adsCtx2.getDirContext()));
|
// Check that there are no errors. We do not allow to do the merge with
|
// errors.
|
TopologyCache cache1 = new TopologyCache(adsCtx1, getTrustManager(),
|
getConnectTimeout());
|
cache1.setPreferredConnections(cnx);
|
cache1.getFilter().setSearchBaseDNInformation(false);
|
try
|
{
|
cache1.reloadTopology();
|
}
|
catch (TopologyCacheException te)
|
{
|
LOG.log(Level.SEVERE, "Error reading topology cache of "+
|
ConnectionUtils.getHostPort(adsCtx1.getDirContext())+ " "+te, te);
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(te.getMessageObject()),
|
ERROR_UPDATING_ADS, te);
|
}
|
TopologyCache cache2 = new TopologyCache(adsCtx2, getTrustManager(),
|
getConnectTimeout());
|
cache2.setPreferredConnections(cnx);
|
cache2.getFilter().setSearchBaseDNInformation(false);
|
try
|
{
|
cache2.reloadTopology();
|
}
|
catch (TopologyCacheException te)
|
{
|
LOG.log(Level.SEVERE, "Error reading topology cache of "+
|
ConnectionUtils.getHostPort(adsCtx2.getDirContext())+ " "+te, te);
|
throw new ReplicationCliException(
|
ERR_REPLICATION_READING_ADS.get(te.getMessageObject()),
|
ERROR_UPDATING_ADS, te);
|
}
|
|
// Look for the cache with biggest number of replication servers:
|
// that one is going to be source.
|
int nRepServers1 = 0;
|
for (ServerDescriptor server : cache1.getServers())
|
{
|
if (server.isReplicationServer())
|
{
|
nRepServers1 ++;
|
}
|
}
|
|
int nRepServers2 = 0;
|
for (ServerDescriptor server : cache2.getServers())
|
{
|
if (server.isReplicationServer())
|
{
|
nRepServers2 ++;
|
}
|
}
|
|
InitialLdapContext ctxSource;
|
InitialLdapContext ctxDestination;
|
if (nRepServers1 >= nRepServers2)
|
{
|
ctxSource = adsCtx1.getDirContext();
|
ctxDestination = adsCtx2.getDirContext();
|
}
|
else
|
{
|
ctxSource = adsCtx2.getDirContext();
|
ctxDestination = adsCtx1.getDirContext();
|
}
|
|
if (isInteractive())
|
{
|
Message msg = INFO_REPLICATION_MERGING_REGISTRIES_CONFIRMATION.get(
|
ConnectionUtils.getHostPort(ctxSource),
|
ConnectionUtils.getHostPort(ctxDestination),
|
ConnectionUtils.getHostPort(ctxSource),
|
ConnectionUtils.getHostPort(ctxDestination));
|
try
|
{
|
if (!askConfirmation(msg, true, LOG))
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
catch (CLIException ce)
|
{
|
println(ce.getMessageObject());
|
throw new ReplicationCliException(
|
ERR_REPLICATION_USER_CANCELLED.get(),
|
ReplicationCliReturnCode.USER_CANCELLED, null);
|
}
|
}
|
else
|
{
|
Message msg = INFO_REPLICATION_MERGING_REGISTRIES_DESCRIPTION.get(
|
ConnectionUtils.getHostPort(ctxSource),
|
ConnectionUtils.getHostPort(ctxDestination),
|
ConnectionUtils.getHostPort(ctxSource),
|
ConnectionUtils.getHostPort(ctxDestination));
|
println(msg);
|
println();
|
}
|
|
printProgress(INFO_REPLICATION_MERGING_REGISTRIES_PROGRESS.get());
|
pointAdder.start();
|
|
Collection<Message> cache1Errors = cache1.getErrorMessages();
|
if (!cache1Errors.isEmpty())
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_CANNOT_MERGE_WITH_ERRORS.get(
|
ConnectionUtils.getHostPort(adsCtx1.getDirContext()),
|
Utils.getMessageFromCollection(cache1Errors,
|
Constants.LINE_SEPARATOR)),
|
ERROR_READING_ADS, null);
|
}
|
|
Collection<Message> cache2Errors = cache2.getErrorMessages();
|
if (!cache2Errors.isEmpty())
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_CANNOT_MERGE_WITH_ERRORS.get(
|
ConnectionUtils.getHostPort(adsCtx2.getDirContext()),
|
Utils.getMessageFromCollection(cache2Errors,
|
Constants.LINE_SEPARATOR)),
|
ERROR_READING_ADS, null);
|
}
|
|
Set<Message> commonRepServerIDErrors = new HashSet<Message>();
|
for (ServerDescriptor server1 : cache1.getServers())
|
{
|
if (server1.isReplicationServer())
|
{
|
int replicationID1 = server1.getReplicationServerId();
|
boolean found = false;
|
for (ServerDescriptor server2 : cache2.getServers())
|
{
|
if (server2.isReplicationServer())
|
{
|
int replicationID2 = server2.getReplicationServerId();
|
found = replicationID2 == replicationID1;
|
if (found)
|
{
|
commonRepServerIDErrors.add(
|
ERR_REPLICATION_ENABLE_COMMON_REPLICATION_SERVER_ID_ARG.get(
|
server1.getHostPort(true),
|
server2.getHostPort(true),
|
replicationID1));
|
found = true;
|
break;
|
}
|
}
|
}
|
if (found)
|
{
|
break;
|
}
|
}
|
}
|
Set<Message> commonDomainIDErrors = new HashSet<Message>();
|
for (SuffixDescriptor suffix1 : cache1.getSuffixes())
|
{
|
for (ReplicaDescriptor replica1 : suffix1.getReplicas())
|
{
|
if (replica1.isReplicated())
|
{
|
int domain1 = replica1.getReplicationId();
|
boolean found = false;
|
for (SuffixDescriptor suffix2 : cache2.getSuffixes())
|
{
|
if (!Utils.areDnsEqual(suffix2.getDN(),
|
replica1.getSuffix().getDN()))
|
{
|
// Conflicting domain names must apply to same suffix.
|
continue;
|
}
|
for (ReplicaDescriptor replica2 : suffix2.getReplicas())
|
{
|
if (replica2.isReplicated())
|
{
|
int domain2 = replica2.getReplicationId();
|
if (domain1 == domain2)
|
{
|
commonDomainIDErrors.add(
|
ERR_REPLICATION_ENABLE_COMMON_DOMAIN_ID_ARG.get(
|
replica1.getServer().getHostPort(true),
|
suffix1.getDN(),
|
replica2.getServer().getHostPort(true),
|
suffix2.getDN(),
|
domain1));
|
found = true;
|
break;
|
}
|
}
|
}
|
if (found)
|
{
|
break;
|
}
|
}
|
}
|
}
|
}
|
if (!commonRepServerIDErrors.isEmpty() || !commonDomainIDErrors.isEmpty())
|
{
|
MessageBuilder mb = new MessageBuilder();
|
if (!commonRepServerIDErrors.isEmpty())
|
{
|
mb.append(ERR_REPLICATION_ENABLE_COMMON_REPLICATION_SERVER_ID.get(
|
Utils.getMessageFromCollection(commonRepServerIDErrors,
|
Constants.LINE_SEPARATOR)));
|
}
|
if (!commonDomainIDErrors.isEmpty())
|
{
|
if (mb.length() > 0)
|
{
|
mb.append(Constants.LINE_SEPARATOR);
|
}
|
mb.append(ERR_REPLICATION_ENABLE_COMMON_DOMAIN_ID.get(
|
Utils.getMessageFromCollection(commonDomainIDErrors,
|
Constants.LINE_SEPARATOR)));
|
}
|
throw new ReplicationCliException(mb.toMessage(),
|
ReplicationCliReturnCode.REPLICATION_ADS_MERGE_NOT_SUPPORTED,
|
null);
|
}
|
|
ADSContext adsCtxSource;
|
ADSContext adsCtxDestination;
|
TopologyCache cacheDestination;
|
if (nRepServers1 >= nRepServers2)
|
{
|
adsCtxSource = adsCtx1;
|
adsCtxDestination = adsCtx2;
|
cacheDestination = cache2;
|
}
|
else
|
{
|
adsCtxSource = adsCtx2;
|
adsCtxDestination = adsCtx1;
|
cacheDestination = cache1;
|
}
|
|
try
|
{
|
adsCtxSource.mergeWithRegistry(adsCtxDestination);
|
}
|
catch (ADSContextException adce)
|
{
|
LOG.log(Level.SEVERE, "Error merging registry of "+
|
ConnectionUtils.getHostPort(adsCtxSource.getDirContext())+
|
" with registry of "+
|
ConnectionUtils.getHostPort(adsCtxDestination.getDirContext())+" "+
|
adce, adce);
|
if (adce.getError() == ADSContextException.ErrorType.ERROR_MERGING)
|
{
|
throw new ReplicationCliException(adce.getMessageObject(),
|
REPLICATION_ADS_MERGE_NOT_SUPPORTED, adce);
|
}
|
else
|
{
|
throw new ReplicationCliException(
|
ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
|
ERROR_UPDATING_ADS, adce);
|
}
|
}
|
|
try
|
{
|
for (ServerDescriptor server : cacheDestination.getServers())
|
{
|
if (server.isReplicationServer())
|
{
|
LOG.log(Level.INFO, "Seeding to replication server on "+
|
server.getHostPort(true)+" with certificates of "+
|
ConnectionUtils.getHostPort(adsCtxSource.getDirContext()));
|
InitialLdapContext ctx = null;
|
try
|
{
|
ctx = getDirContextForServer(cacheDestination, server);
|
ServerDescriptor.seedAdsTrustStore(ctx,
|
adsCtxSource.getTrustedCertificates());
|
}
|
finally
|
{
|
if (ctx != null)
|
{
|
ctx.close();
|
}
|
}
|
}
|
}
|
}
|
catch (Throwable t)
|
{
|
LOG.log(Level.SEVERE, "Error seeding truststore: "+t, t);
|
String arg = (t instanceof OpenDsException) ?
|
((OpenDsException)t).getMessageObject().toString() : t.toString();
|
throw new ReplicationCliException(
|
ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(
|
ConnectionUtils.getHostPort(adsCtx2.getDirContext()),
|
ConnectionUtils.getHostPort(adsCtx1.getDirContext()),
|
arg),
|
ERROR_SEEDING_TRUSTORE, t);
|
}
|
pointAdder.stop();
|
printProgress(formatter.getSpace());
|
printProgress(formatter.getFormattedDone());
|
printlnProgress();
|
|
return adsCtxSource == adsCtx1;
|
}
|
finally
|
{
|
pointAdder.stop();
|
}
|
}
|
|
private InitialLdapContext getDirContextForServer(TopologyCache cache,
|
ServerDescriptor server) throws NamingException
|
{
|
String dn = ConnectionUtils.getBindDN(
|
cache.getAdsContext().getDirContext());
|
String pwd = ConnectionUtils.getBindPassword(
|
cache.getAdsContext().getDirContext());
|
TopologyCacheFilter filter = new TopologyCacheFilter();
|
filter.setSearchMonitoringInformation(false);
|
filter.setSearchBaseDNInformation(false);
|
ServerLoader loader = new ServerLoader(server.getAdsProperties(),
|
dn, pwd, getTrustManager(), getConnectTimeout(),
|
cache.getPreferredConnections(), filter);
|
return loader.createContext();
|
}
|
|
/**
|
* Returns <CODE>true</CODE> if the provided baseDN is replicated in the
|
* provided server, <CODE>false</CODE> otherwise.
|
* @param server the server.
|
* @param baseDN the base DN.
|
* @return <CODE>true</CODE> if the provided baseDN is replicated in the
|
* provided server, <CODE>false</CODE> otherwise.
|
*/
|
private boolean isBaseDNReplicated(ServerDescriptor server, String baseDN)
|
{
|
boolean isReplicated = false;
|
for (ReplicaDescriptor replica : server.getReplicas())
|
{
|
if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
isReplicated = replica.isReplicated();
|
break;
|
}
|
}
|
return isReplicated;
|
}
|
|
/**
|
* Returns <CODE>true</CODE> if the provided baseDN is replicated between
|
* both servers, <CODE>false</CODE> otherwise.
|
* @param server1 the first server.
|
* @param server2 the second server.
|
* @param baseDN the base DN.
|
* @return <CODE>true</CODE> if the provided baseDN is replicated between
|
* both servers, <CODE>false</CODE> otherwise.
|
*/
|
private boolean isBaseDNReplicated(ServerDescriptor server1,
|
ServerDescriptor server2, String baseDN)
|
{
|
boolean isReplicatedInBoth = false;
|
ReplicaDescriptor replica1 = null;
|
ReplicaDescriptor replica2 = null;
|
for (ReplicaDescriptor replica : server1.getReplicas())
|
{
|
if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
replica1 = replica;
|
break;
|
}
|
}
|
if (replica1 != null && replica1.isReplicated())
|
{
|
for (ReplicaDescriptor replica : server2.getReplicas())
|
{
|
if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
|
{
|
replica2 = replica;
|
if (replica2.isReplicated())
|
{
|
Set<String> replServers1 =
|
replica1.getSuffix().getReplicationServers();
|
Set<String> replServers2 =
|
replica1.getSuffix().getReplicationServers();
|
for (String replServer1 : replServers1)
|
{
|
for (String replServer2 : replServers2)
|
{
|
if (replServer1.equalsIgnoreCase(replServer2))
|
{
|
isReplicatedInBoth = true;
|
break;
|
}
|
}
|
if (isReplicatedInBoth)
|
{
|
break;
|
}
|
}
|
}
|
break;
|
}
|
}
|
}
|
return isReplicatedInBoth;
|
}
|
|
private boolean displayLogFileAtEnd(String subCommand)
|
{
|
String[] subCommands =
|
{
|
ReplicationCliArgumentParser.ENABLE_REPLICATION_SUBCMD_NAME,
|
ReplicationCliArgumentParser.DISABLE_REPLICATION_SUBCMD_NAME,
|
ReplicationCliArgumentParser.INITIALIZE_ALL_REPLICATION_SUBCMD_NAME,
|
ReplicationCliArgumentParser.INITIALIZE_REPLICATION_SUBCMD_NAME};
|
for (String sub : subCommands)
|
{
|
if (sub.equals(subCommand))
|
{
|
return true;
|
}
|
}
|
return false;
|
}
|
|
/**
|
* Returns the timeout to be used to connect in milliseconds. The method
|
* must be called after parsing the arguments.
|
* @return the timeout to be used to connect in milliseconds. Returns
|
* {@code 0} if there is no timeout.
|
*/
|
private int getConnectTimeout()
|
{
|
return argParser.getConnectTimeout();
|
}
|
|
private String binDir;
|
/**
|
* Returns the binary/script directory.
|
* @return the binary/script directory.
|
*/
|
private String getBinaryDir()
|
{
|
if (binDir == null)
|
{
|
File f = Installation.getLocal().getBinariesDirectory();
|
try
|
{
|
binDir = f.getCanonicalPath();
|
}
|
catch (Throwable t)
|
{
|
binDir = f.getAbsolutePath();
|
}
|
if (binDir.lastIndexOf(File.separatorChar) != (binDir.length() - 1))
|
{
|
binDir += File.separatorChar;
|
}
|
}
|
|
return binDir;
|
}
|
|
/**
|
* Returns the full path of the command-line for a given script name.
|
* @param scriptBasicName the script basic name (with no extension).
|
* @return the full path of the command-line for a given script name.
|
*/
|
private String getCommandLinePath(String scriptBasicName)
|
{
|
String cmdLineName;
|
if (Utilities.isWindows())
|
{
|
cmdLineName = getBinaryDir()+scriptBasicName+".bat";
|
}
|
else
|
{
|
cmdLineName = getBinaryDir()+scriptBasicName;
|
}
|
return cmdLineName;
|
}
|
}
|
|
|
|
/**
|
* Class used to compare replication servers.
|
*
|
*/
|
class ReplicationServerComparator implements Comparator<ServerDescriptor>
|
{
|
/**
|
* {@inheritDoc}
|
*/
|
public int compare(ServerDescriptor s1, ServerDescriptor s2)
|
{
|
int compare = s1.getHostName().compareTo(s2.getHostName());
|
if (compare == 0)
|
{
|
if (s1.getReplicationServerPort() > s2.getReplicationServerPort())
|
{
|
compare = 1;
|
}
|
else if (s1.getReplicationServerPort() < s2.getReplicationServerPort())
|
{
|
compare = -1;
|
}
|
}
|
return compare;
|
}
|
}
|
|
/**
|
* Class used to compare suffixes.
|
*
|
*/
|
class SuffixComparator implements Comparator<SuffixDescriptor>
|
{
|
/**
|
* {@inheritDoc}
|
*/
|
public int compare(SuffixDescriptor s1, SuffixDescriptor s2)
|
{
|
return s1.getId().compareTo(s2.getId());
|
}
|
}
|
|
/**
|
* Class used to compare servers.
|
*
|
*/
|
class ServerComparator implements Comparator<ServerDescriptor>
|
{
|
/**
|
* {@inheritDoc}
|
*/
|
public int compare(ServerDescriptor s1, ServerDescriptor s2)
|
{
|
return s1.getId().compareTo(s2.getId());
|
}
|
}
|