InstallerHelper.java revision f0a048d41a13eca4cba405da9403c2469ca3d1ea
0N/A/*
2362N/A * CDDL HEADER START
0N/A *
0N/A * The contents of this file are subject to the terms of the
0N/A * Common Development and Distribution License, Version 1.0 only
0N/A * (the "License"). You may not use this file except in compliance
2362N/A * with the License.
0N/A *
2362N/A * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
0N/A * or http://forgerock.org/license/CDDLv1.0.html.
0N/A * See the License for the specific language governing permissions
0N/A * and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL HEADER in each
0N/A * file and include the License file at legal-notices/CDDLv1_0.txt.
0N/A * If applicable, add the following below this CDDL HEADER, with the
0N/A * fields enclosed by brackets "[]" replaced with your own identifying
0N/A * information:
0N/A * Portions Copyright [yyyy] [name of copyright owner]
0N/A *
2362N/A * CDDL HEADER END
2362N/A *
2362N/A *
0N/A * Copyright 2006-2010 Sun Microsystems, Inc.
0N/A * Portions Copyright 2011-2015 ForgeRock AS
0N/A */
0N/A
0N/Apackage org.opends.quicksetup.installer;
0N/A
0N/Aimport static org.opends.messages.QuickSetupMessages.*;
0N/Aimport static org.opends.quicksetup.util.Utils.*;
0N/A
0N/Aimport static com.forgerock.opendj.cli.Utils.*;
217N/Aimport static com.forgerock.opendj.util.OperatingSystem.*;
0N/A
0N/Aimport java.io.BufferedReader;
0N/Aimport java.io.BufferedWriter;
0N/Aimport java.io.Closeable;
0N/Aimport java.io.File;
0N/Aimport java.io.FileInputStream;
0N/Aimport java.io.FileReader;
0N/Aimport java.io.FileWriter;
0N/Aimport java.io.IOException;
0N/Aimport java.io.InputStreamReader;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.Arrays;
0N/Aimport java.util.HashMap;
0N/Aimport java.util.HashSet;
0N/Aimport java.util.List;
0N/Aimport java.util.Map;
0N/Aimport java.util.Properties;
0N/Aimport java.util.Random;
0N/Aimport java.util.Set;
0N/Aimport java.util.TreeSet;
0N/A
0N/Aimport javax.naming.ldap.InitialLdapContext;
0N/A
0N/Aimport org.forgerock.i18n.LocalizableMessage;
0N/Aimport org.forgerock.i18n.slf4j.LocalizedLogger;
0N/Aimport org.forgerock.opendj.config.server.ConfigException;
217N/Aimport org.opends.guitools.controlpanel.util.Utilities;
217N/Aimport org.opends.messages.CoreMessages;
0N/Aimport org.opends.messages.BackendMessages;
0N/Aimport org.opends.messages.ReplicationMessages;
0N/Aimport org.opends.quicksetup.Application;
0N/Aimport org.opends.quicksetup.ApplicationException;
217N/Aimport org.opends.quicksetup.Installation;
0N/Aimport org.opends.quicksetup.JavaArguments;
0N/Aimport org.opends.quicksetup.ReturnCode;
0N/Aimport org.opends.quicksetup.UserData;
0N/Aimport org.opends.quicksetup.util.OutputReader;
217N/Aimport org.opends.quicksetup.util.Utils;
217N/Aimport org.opends.server.admin.ManagedObjectNotFoundException;
217N/Aimport org.opends.server.admin.PropertyException;
217N/Aimport org.opends.server.admin.client.ManagementContext;
217N/Aimport org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
217N/Aimport org.opends.server.admin.client.ldap.LDAPManagementContext;
217N/Aimport org.opends.server.admin.std.client.BackendCfgClient;
217N/Aimport org.opends.server.admin.std.client.CryptoManagerCfgClient;
217N/Aimport org.opends.server.admin.std.client.LocalDBBackendCfgClient;
217N/Aimport org.opends.server.admin.std.client.ReplicationDomainCfgClient;
217N/Aimport org.opends.server.admin.std.client.ReplicationServerCfgClient;
217N/Aimport org.opends.server.admin.std.client.ReplicationSynchronizationProviderCfgClient;
217N/Aimport org.opends.server.admin.std.client.RootCfgClient;
0N/Aimport org.opends.server.admin.std.meta.BackendCfgDefn;
0N/Aimport org.opends.server.admin.std.meta.LocalDBBackendCfgDefn;
0N/Aimport org.opends.server.admin.std.meta.ReplicationDomainCfgDefn;
0N/Aimport org.opends.server.admin.std.meta.ReplicationServerCfgDefn;
0N/Aimport org.opends.server.admin.std.meta.ReplicationSynchronizationProviderCfgDefn;
0N/Aimport org.opends.server.backends.task.TaskState;
0N/Aimport org.opends.server.core.DirectoryServer;
0N/Aimport org.opends.server.tools.ConfigureDS;
0N/Aimport org.opends.server.tools.ConfigureWindowsService;
0N/Aimport org.opends.server.tools.JavaPropertiesTool;
0N/Aimport org.opends.server.types.DN;
0N/Aimport org.opends.server.types.DirectoryException;
0N/Aimport org.opends.server.types.Entry;
0N/Aimport org.opends.server.types.ExistingFileBehavior;
0N/Aimport org.opends.server.types.LDIFExportConfig;
0N/Aimport org.opends.server.types.OpenDsException;
0N/Aimport org.opends.server.util.LDIFException;
0N/Aimport org.opends.server.util.LDIFWriter;
0N/Aimport org.opends.server.util.SetupUtils;
0N/Aimport org.opends.server.util.StaticUtils;
0N/A
0N/A/**
0N/A * This is the only class that uses classes in org.opends.server (excluding the
0N/A * case of DynamicConstants, SetupUtils and CertificateManager
0N/A * which are already included in quicksetup.jar).
0N/A *
0N/A * Important note: do not include references to this class until OpenDS.jar has
0N/A * been loaded. These classes must be loaded during Runtime.
0N/A * The code is written in a way that when we execute the code that uses these
0N/A * classes the required jar files are already loaded. However these jar files
0N/A * are not necessarily loaded when we create this class.
0N/A */
0N/Apublic class InstallerHelper {
0N/A private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
0N/A
0N/A private static final int MAX_ID_VALUE = Short.MAX_VALUE;
0N/A private static final long ONE_MEGABYTE = 1024L * 1024;
0N/A /**
0N/A * Invokes the method ConfigureDS.configMain with the provided parameters.
0N/A * @param args the arguments to be passed to ConfigureDS.configMain.
217N/A * @return the return code of the ConfigureDS.configMain method.
0N/A * @throws ApplicationException if something goes wrong.
0N/A * @see org.opends.server.tools.ConfigureDS#configMain(String[],
0N/A * java.io.OutputStream, java.io.OutputStream)
0N/A */
0N/A public int invokeConfigureServer(String[] args) throws ApplicationException {
217N/A return ConfigureDS.configMain(args, System.out, System.err);
217N/A }
217N/A
217N/A /**
217N/A * Invokes the import-ldif command-line with the provided parameters.
217N/A *
0N/A * @param application
217N/A * the application that is launching this.
0N/A * @param args
0N/A * the arguments to be passed to import-ldif.
0N/A * @return the return code of the import-ldif call.
0N/A * @throws IOException
0N/A * if the process could not be launched.
0N/A * @throws InterruptedException
0N/A * if the process was interrupted.
0N/A */
217N/A public int invokeImportLDIF(final Application application, String[] args) throws IOException, InterruptedException
217N/A {
217N/A final File installPath = new File(application.getInstallationPath());
217N/A final File binPath = new File(installPath, isWindows() ? Installation.WINDOWS_BINARIES_PATH_RELATIVE
217N/A : Installation.UNIX_BINARIES_PATH_RELATIVE);
0N/A final File importLDIFPath = new File(binPath, isWindows() ? Installation.WINDOWS_IMPORT_LDIF
0N/A : Installation.UNIX_IMPORT_LDIF);
217N/A
217N/A final ArrayList<String> argList = new ArrayList<String>();
0N/A argList.add(Utils.getScriptPath(importLDIFPath.getAbsolutePath()));
0N/A argList.addAll(Arrays.asList(args));
0N/A logger.info(LocalizableMessage.raw("import-ldif arg list: " + argList));
0N/A
0N/A final ProcessBuilder processBuilder = new ProcessBuilder(argList.toArray(new String[argList.size()]));
0N/A final Map<String, String> env = processBuilder.environment();
0N/A env.remove(SetupUtils.OPENDJ_JAVA_HOME);
0N/A env.remove(SetupUtils.OPENDJ_JAVA_ARGS);
0N/A env.remove("CLASSPATH");
0N/A processBuilder.directory(installPath);
0N/A
0N/A Process process = null;
0N/A try
0N/A {
0N/A process = processBuilder.start();
0N/A final BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
217N/A new OutputReader(err)
0N/A {
0N/A @Override
0N/A public void processLine(final String line)
217N/A {
0N/A logger.warn(LocalizableMessage.raw("import-ldif error log: " + line));
217N/A application.notifyListeners(LocalizableMessage.raw(line));
217N/A application.notifyListeners(application.getLineBreak());
217N/A }
217N/A };
0N/A
217N/A final BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream()));
217N/A new OutputReader(out)
0N/A {
0N/A @Override
217N/A public void processLine(final String line)
217N/A {
217N/A logger.info(LocalizableMessage.raw("import-ldif out log: " + line));
217N/A application.notifyListeners(LocalizableMessage.raw(line));
217N/A application.notifyListeners(application.getLineBreak());
0N/A }
0N/A };
0N/A
0N/A return process.waitFor();
0N/A }
0N/A finally
0N/A {
0N/A if (process != null)
0N/A {
0N/A closeProcessStream(process.getErrorStream(), "error");
0N/A closeProcessStream(process.getOutputStream(), "output");
217N/A }
0N/A }
0N/A }
0N/A
217N/A private void closeProcessStream(final Closeable stream, final String streamName)
0N/A {
217N/A try
217N/A {
217N/A stream.close();
217N/A }
0N/A catch (Throwable t)
217N/A {
217N/A logger.warn(LocalizableMessage.raw("Error closing " + streamName + " stream: " + t, t));
0N/A }
0N/A }
217N/A
217N/A /**
217N/A * Returns the LocalizableMessage ID that corresponds to a successfully started server.
217N/A * @return the LocalizableMessage ID that corresponds to a successfully started server.
217N/A */
0N/A public String getStartedId()
217N/A {
217N/A return String.valueOf(CoreMessages.NOTE_DIRECTORY_SERVER_STARTED.ordinal());
217N/A }
217N/A
217N/A /**
0N/A * This methods enables this server as a Windows service.
0N/A * @throws ApplicationException if something goes wrong.
0N/A */
0N/A public void enableWindowsService() throws ApplicationException {
0N/A int code = ConfigureWindowsService.enableService(System.out, System.err);
0N/A
0N/A LocalizableMessage errorMessage = INFO_ERROR_ENABLING_WINDOWS_SERVICE.get();
0N/A
0N/A switch (code) {
0N/A case
0N/A ConfigureWindowsService.SERVICE_ENABLE_SUCCESS:
0N/A break;
0N/A case
0N/A ConfigureWindowsService.SERVICE_ALREADY_ENABLED:
0N/A break;
0N/A default:
0N/A throw new ApplicationException(
0N/A ReturnCode.WINDOWS_SERVICE_ERROR,
0N/A errorMessage, null);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This method disables this server as a Windows service.
0N/A * @throws ApplicationException if something goes worong.
0N/A */
0N/A public void disableWindowsService() throws ApplicationException
0N/A {
0N/A int code = ConfigureWindowsService.disableService(System.out, System.err);
0N/A if (code == ConfigureWindowsService.SERVICE_DISABLE_ERROR) {
0N/A throw new ApplicationException(
0N/A // TODO: fix this message's format string
0N/A ReturnCode.WINDOWS_SERVICE_ERROR,
0N/A INFO_ERROR_DISABLING_WINDOWS_SERVICE.get(""), null);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a template LDIF file with an entry that has as dn the provided
0N/A * baseDn.
0N/A * @param baseDn the dn of the entry that will be created in the LDIF file.
0N/A * @return the File object pointing to the created temporary file.
0N/A * @throws ApplicationException if something goes wrong.
0N/A */
0N/A public File createBaseEntryTempFile(String baseDn)
0N/A throws ApplicationException {
0N/A File ldifFile;
0N/A try
0N/A {
0N/A ldifFile = File.createTempFile("opendj-base-entry", ".ldif");
0N/A ldifFile.deleteOnExit();
0N/A } catch (IOException ioe)
0N/A {
0N/A LocalizableMessage failedMsg =
0N/A getThrowableMsg(INFO_ERROR_CREATING_TEMP_FILE.get(), ioe);
0N/A throw new ApplicationException(
0N/A ReturnCode.FILE_SYSTEM_ACCESS_ERROR,
0N/A failedMsg, ioe);
0N/A }
0N/A
0N/A try
0N/A {
0N/A LDIFExportConfig exportConfig = new LDIFExportConfig(
0N/A ldifFile.getAbsolutePath(), ExistingFileBehavior.OVERWRITE);
0N/A
0N/A LDIFWriter writer = new LDIFWriter(exportConfig);
0N/A
0N/A DN dn = DN.valueOf(baseDn);
0N/A Entry entry = StaticUtils.createEntry(dn);
0N/A
0N/A writer.writeEntry(entry);
0N/A writer.close();
0N/A } catch (DirectoryException de) {
0N/A throw new ApplicationException(
0N/A ReturnCode.CONFIGURATION_ERROR,
0N/A getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), de), de);
0N/A } catch (LDIFException le) {
0N/A throw new ApplicationException(
0N/A ReturnCode.CONFIGURATION_ERROR,
0N/A getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), le), le);
0N/A } catch (IOException ioe) {
0N/A throw new ApplicationException(
0N/A ReturnCode.CONFIGURATION_ERROR,
0N/A getThrowableMsg(INFO_ERROR_IMPORTING_LDIF.get(), ioe), ioe);
0N/A } catch (Throwable t) {
0N/A throw new ApplicationException(
0N/A ReturnCode.BUG, getThrowableMsg(
0N/A INFO_BUG_MSG.get(), t), t);
0N/A }
0N/A return ldifFile;
0N/A }
0N/A
0N/A /**
0N/A * Deletes a backend on the server.
0N/A * @param ctx the connection to the server.
0N/A * @param backendName the name of the backend to be deleted.
0N/A * @param serverDisplay the server display.
0N/A * @throws ApplicationException if something goes wrong.
0N/A */
0N/A public void deleteBackend(InitialLdapContext ctx, String backendName,
0N/A String serverDisplay)
0N/A throws ApplicationException
0N/A {
0N/A try
0N/A {
0N/A ManagementContext mCtx = LDAPManagementContext.createFromContext(
0N/A JNDIDirContextAdaptor.adapt(ctx));
0N/A RootCfgClient root = mCtx.getRootConfiguration();
0N/A root.removeBackend(backendName);
}
catch (Throwable t)
{
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR,
INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(serverDisplay, t),
t);
}
}
/**
* Deletes a backend on the server. It assumes the server is stopped.
* @param backendName the name of the backend to be deleted.
* @throws ApplicationException if something goes wrong.
*/
public void deleteBackend(String backendName)
throws ApplicationException
{
try
{
// Read the configuration file.
String dn = Utilities.getRDNString("ds-cfg-backend-id",
backendName)+",cn=Backends,cn=config";
Utilities.deleteConfigSubtree(
DirectoryServer.getConfigHandler(), DN.valueOf(dn));
}
catch (OpenDsException ode)
{
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR, ode.getMessageObject(), ode);
}
catch(ConfigException ce)
{
throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, ce.getMessageObject(), ce);
}
}
/**
* Creates a local database backend on the server.
* @param ctx the connection to the server.
* @param backendName the name of the backend to be created.
* @param baseDNs the list of base DNs to be defined on the server.
* @param serverDisplay the server display.
* @throws ApplicationException if something goes wrong.
*/
public void createLocalDBBackend(InitialLdapContext ctx,
String backendName,
Set<String> baseDNs,
String serverDisplay)
throws ApplicationException
{
try
{
ManagementContext mCtx = LDAPManagementContext.createFromContext(
JNDIDirContextAdaptor.adapt(ctx));
RootCfgClient root = mCtx.getRootConfiguration();
LocalDBBackendCfgDefn provider = LocalDBBackendCfgDefn.getInstance();
LocalDBBackendCfgClient backend = root.createBackend(provider,
backendName, null);
backend.setEnabled(true);
Set<DN> setBaseDNs = new HashSet<DN>();
for (String baseDN : baseDNs)
{
setBaseDNs.add(DN.valueOf(baseDN));
}
backend.setBaseDN(setBaseDNs);
backend.setBackendId(backendName);
backend.setWritabilityMode(BackendCfgDefn.WritabilityMode.ENABLED);
backend.commit();
}
catch (Throwable t)
{
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR,
INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(serverDisplay, t),
t);
}
}
/**
* Sets the base DNs on a given backend.
* @param ctx the connection to the server.
* @param backendName the name of the backend where the base Dns must be
* defined.
* @param baseDNs the list of base DNs to be defined on the server.
* @param serverDisplay the server display.
* @throws ApplicationException if something goes wrong.
*/
public void setBaseDns(InitialLdapContext ctx,
String backendName,
Set<String> baseDNs,
String serverDisplay)
throws ApplicationException
{
try
{
ManagementContext mCtx = LDAPManagementContext.createFromContext(
JNDIDirContextAdaptor.adapt(ctx));
RootCfgClient root = mCtx.getRootConfiguration();
BackendCfgClient backend = root.getBackend(backendName);
Set<DN> setBaseDNs = new HashSet<DN>();
for (String baseDN : baseDNs)
{
setBaseDNs.add(DN.valueOf(baseDN));
}
backend.setBaseDN(setBaseDNs);
backend.commit();
}
catch (Throwable t)
{
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR,
INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(serverDisplay, t),
t);
}
}
/**
* Configures the replication on a given server.
* @param remoteCtx the connection to the server where we want to configure
* the replication.
* @param replicationServers a Map where the key value is the base dn and
* the value is the list of replication servers for that base dn (or domain).
* @param replicationPort the replicationPort of the server that is being
* configured (it might not exist and the user specified it in the setup).
* @param useSecureReplication whether to encrypt connections with the
* replication port or not.
* @param serverDisplay the server display.
* @param usedReplicationServerIds the list of replication server ids that
* are already used.
* @param usedServerIds the list of server ids (domain ids) that
* are already used.
* @throws ApplicationException if something goes wrong.
* @return a ConfiguredReplication object describing what has been configured.
*/
public ConfiguredReplication configureReplication(
InitialLdapContext remoteCtx, Map<String,Set<String>> replicationServers,
int replicationPort, boolean useSecureReplication, String serverDisplay,
Set<Integer> usedReplicationServerIds, Set<Integer> usedServerIds)
throws ApplicationException
{
boolean synchProviderCreated;
boolean synchProviderEnabled;
boolean replicationServerCreated;
boolean secureReplicationEnabled;
try
{
ManagementContext mCtx = LDAPManagementContext.createFromContext(
JNDIDirContextAdaptor.adapt(remoteCtx));
RootCfgClient root = mCtx.getRootConfiguration();
/*
* Configure Synchronization plugin.
*/
ReplicationSynchronizationProviderCfgClient sync = null;
try
{
sync = (ReplicationSynchronizationProviderCfgClient)
root.getSynchronizationProvider("Multimaster Synchronization");
}
catch (ManagedObjectNotFoundException monfe)
{
// It does not exist.
}
if (sync == null)
{
ReplicationSynchronizationProviderCfgDefn provider =
ReplicationSynchronizationProviderCfgDefn.getInstance();
sync = root.createSynchronizationProvider(provider,
"Multimaster Synchronization",
new ArrayList<PropertyException>());
sync.setJavaClass(
org.opends.server.replication.plugin.MultimasterReplication.class.
getName());
sync.setEnabled(Boolean.TRUE);
synchProviderCreated = true;
synchProviderEnabled = false;
}
else
{
synchProviderCreated = false;
if (!sync.isEnabled())
{
sync.setEnabled(Boolean.TRUE);
synchProviderEnabled = true;
}
else
{
synchProviderEnabled = false;
}
}
sync.commit();
/*
* Configure the replication server.
*/
ReplicationServerCfgClient replicationServer;
if (!sync.hasReplicationServer())
{
if (useSecureReplication)
{
CryptoManagerCfgClient crypto = root.getCryptoManager();
if (!crypto.isSSLEncryption())
{
crypto.setSSLEncryption(true);
crypto.commit();
secureReplicationEnabled = true;
}
else
{
// Only mark as true if we actually change the configuration
secureReplicationEnabled = false;
}
}
else
{
secureReplicationEnabled = false;
}
int id = getReplicationId(usedReplicationServerIds);
usedReplicationServerIds.add(id);
replicationServer = sync.createReplicationServer(
ReplicationServerCfgDefn.getInstance(),
new ArrayList<PropertyException>());
replicationServer.setReplicationServerId(id);
replicationServer.setReplicationPort(replicationPort);
replicationServerCreated = true;
}
else
{
secureReplicationEnabled = false;
replicationServer = sync.getReplicationServer();
usedReplicationServerIds.add(
replicationServer.getReplicationServerId());
replicationServerCreated = false;
}
Set<String> servers = replicationServer.getReplicationServer();
if (servers == null)
{
servers = new HashSet<String>();
}
Set<String> oldServers = new HashSet<String>(servers);
for (Set<String> rs : replicationServers.values())
{
servers.addAll(rs);
}
replicationServer.setReplicationServer(servers);
replicationServer.commit();
Set<String> newReplicationServers = intersect(servers, oldServers);
/*
* Create the domains
*/
String[] domainNames = sync.listReplicationDomains();
if (domainNames == null)
{
domainNames = new String[]{};
}
Set<ConfiguredDomain> domainsConf = new HashSet<ConfiguredDomain>();
ReplicationDomainCfgClient[] domains =
new ReplicationDomainCfgClient[domainNames.length];
for (int i=0; i<domains.length; i++)
{
domains[i] = sync.getReplicationDomain(domainNames[i]);
}
for (String dn : replicationServers.keySet())
{
ReplicationDomainCfgClient domain = null;
boolean isCreated;
String domainName = null;
for (int i = 0; i < domains.length && domain == null; i++)
{
if (areDnsEqual(dn,
domains[i].getBaseDN().toString()))
{
domain = domains[i];
domainName = domainNames[i];
}
}
if (domain == null)
{
int domainId = getReplicationId(usedServerIds);
usedServerIds.add(domainId);
domainName = getDomainName(domainNames, domainId, dn);
domain = sync.createReplicationDomain(
ReplicationDomainCfgDefn.getInstance(), domainName,
new ArrayList<PropertyException>());
domain.setServerId(domainId);
domain.setBaseDN(DN.valueOf(dn));
isCreated = true;
}
else
{
isCreated = false;
}
oldServers = domain.getReplicationServer();
if (oldServers == null)
{
oldServers = new TreeSet<String>();
}
servers = replicationServers.get(dn);
domain.setReplicationServer(servers);
usedServerIds.add(domain.getServerId());
domain.commit();
Set<String> addedServers = intersect(servers, oldServers);
ConfiguredDomain domainConf = new ConfiguredDomain(domainName,
isCreated, addedServers);
domainsConf.add(domainConf);
}
return new ConfiguredReplication(synchProviderCreated,
synchProviderEnabled, replicationServerCreated,
secureReplicationEnabled, newReplicationServers,
domainsConf);
}
catch (Throwable t)
{
throw new ApplicationException(
ReturnCode.CONFIGURATION_ERROR,
INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(serverDisplay, t),
t);
}
}
private Set<String> intersect(Set<String> set1, Set<String> set2)
{
Set<String> result = new TreeSet<String>(set1);
result.removeAll(set2);
return result;
}
/**
* Configures the replication on a given server.
*
* @param remoteCtx
* the connection to the server where we want to configure the
* replication.
* @param replConf
* the object describing what was configured.
* @param serverDisplay
* the server display.
* @throws ApplicationException
* if something goes wrong.
*/
public void unconfigureReplication(InitialLdapContext remoteCtx, ConfiguredReplication replConf, String serverDisplay)
throws ApplicationException
{
try
{
ManagementContext mCtx = LDAPManagementContext.createFromContext(JNDIDirContextAdaptor.adapt(remoteCtx));
RootCfgClient root = mCtx.getRootConfiguration();
final String syncProvider = "Multimaster Synchronization";
// Unconfigure Synchronization plugin.
if (replConf.isSynchProviderCreated())
{
try
{
root.removeSynchronizationProvider(syncProvider);
}
catch (ManagedObjectNotFoundException monfe)
{
// It does not exist.
}
}
else
{
try
{
ReplicationSynchronizationProviderCfgClient sync =
(ReplicationSynchronizationProviderCfgClient) root.getSynchronizationProvider(syncProvider);
if (replConf.isSynchProviderEnabled())
{
sync.setEnabled(Boolean.FALSE);
}
if (replConf.isReplicationServerCreated())
{
sync.removeReplicationServer();
}
else if (sync.hasReplicationServer())
{
ReplicationServerCfgClient replicationServer = sync.getReplicationServer();
Set<String> replServers = replicationServer.getReplicationServer();
if (replServers != null)
{
replServers.removeAll(replConf.getNewReplicationServers());
replicationServer.setReplicationServer(replServers);
replicationServer.commit();
}
}
for (ConfiguredDomain domain : replConf.getDomainsConf())
{
if (domain.isCreated())
{
sync.removeReplicationDomain(domain.getDomainName());
}
else
{
try
{
ReplicationDomainCfgClient d = sync.getReplicationDomain(domain.getDomainName());
Set<String> replServers = d.getReplicationServer();
if (replServers != null)
{
replServers.removeAll(domain.getAddedReplicationServers());
d.setReplicationServer(replServers);
d.commit();
}
}
catch (ManagedObjectNotFoundException monfe)
{
// It does not exist.
}
}
}
sync.commit();
}
catch (ManagedObjectNotFoundException monfe)
{
// It does not exist.
}
}
if (replConf.isSecureReplicationEnabled())
{
CryptoManagerCfgClient crypto = root.getCryptoManager();
if (crypto.isSSLEncryption())
{
crypto.setSSLEncryption(false);
crypto.commit();
}
}
}
catch (Throwable t)
{
throw new ApplicationException(ReturnCode.CONFIGURATION_ERROR, INFO_ERROR_CONFIGURING_REMOTE_GENERIC.get(
serverDisplay, t), t);
}
}
/**
* For the given state provided by a Task tells if the task is done or not.
*
* @param sState
* the String representing the task state.
* @return <CODE>true</CODE> if the task is done and <CODE>false</CODE>
* otherwise.
*/
public boolean isDone(String sState)
{
return TaskState.isDone(TaskState.fromString(sState));
}
/**
* For the given state provided by a Task tells if the task is successful or
* not.
*
* @param sState
* the String representing the task state.
* @return <CODE>true</CODE> if the task is successful and <CODE>false</CODE>
* otherwise.
*/
public boolean isSuccessful(String sState)
{
return TaskState.isSuccessful(TaskState.fromString(sState));
}
/**
* For the given state provided by a Task tells if the task is complete with
* errors or not.
*
* @param sState
* the String representing the task state.
* @return <CODE>true</CODE> if the task is complete with errors and
* <CODE>false</CODE> otherwise.
*/
public boolean isCompletedWithErrors(String sState)
{
return TaskState.COMPLETED_WITH_ERRORS == TaskState.fromString(sState);
}
/**
* For the given state provided by a Task tells if the task is stopped by
* error or not.
*
* @param sState
* the String representing the task state.
* @return <CODE>true</CODE> if the task is stopped by error and
* <CODE>false</CODE> otherwise.
*/
public boolean isStoppedByError(String sState)
{
return TaskState.STOPPED_BY_ERROR == TaskState.fromString(sState);
}
/**
* Tells whether the provided log message corresponds to a peers not found
* error during the initialization of a replica or not.
*
* @param logMsg
* the log message.
* @return <CODE>true</CODE> if the log message corresponds to a peers not
* found error during initialization and <CODE>false</CODE> otherwise.
*/
public boolean isPeersNotFoundError(String logMsg)
{
return logMsg.contains("=" + ReplicationMessages.ERR_NO_REACHABLE_PEER_IN_THE_DOMAIN.ordinal());
}
/**
* Returns the ID to be used for a new replication server or domain.
* @param usedIds the list of already used ids.
* @return the ID to be used for a new replication server or domain.
*/
public static int getReplicationId(Set<Integer> usedIds)
{
Random r = new Random();
int id = 0;
while (id == 0 || usedIds.contains(id))
{
id = r.nextInt(MAX_ID_VALUE);
}
return id;
}
/**
* Returns the name to be used for a new replication domain.
* @param existingDomains the existing domains names.
* @param newDomainId the new domain replication id.
* @param baseDN the base DN of the domain.
* @return the name to be used for a new replication domain.
*/
public static String getDomainName(String[] existingDomains, int newDomainId,
String baseDN)
{
String domainName = baseDN;
boolean nameExists = true;
int j = 0;
while (nameExists)
{
boolean found = false;
for (int i=0; i<existingDomains.length && !found; i++)
{
found = existingDomains[i].equalsIgnoreCase(domainName);
}
if (found)
{
domainName = baseDN+"-"+j;
}
else
{
nameExists = false;
}
j++;
}
return domainName;
}
/**
* Writes the set-java-home file that is used by the scripts to set the java
* home and the java arguments.
*
* @param uData
* the data provided by the user.
* @param installPath
* where the server is installed.
* @throws IOException
* if an error occurred writing the file.
*/
public void writeSetOpenDSJavaHome(UserData uData, String installPath) throws IOException
{
String javaHome = System.getProperty("java.home");
if (javaHome == null || javaHome.length() == 0)
{
javaHome = System.getenv(SetupUtils.OPENDJ_JAVA_HOME);
}
// Try to transform things if necessary. The following map has as key
// the original JavaArgument object and as value the 'transformed' JavaArgument.
Map<JavaArguments, JavaArguments> hmJavaArguments = new HashMap<JavaArguments, JavaArguments>();
for (String script : uData.getScriptNamesForJavaArguments())
{
JavaArguments origJavaArguments = uData.getJavaArguments(script);
if (hmJavaArguments.get(origJavaArguments) == null)
{
if (Utils.supportsOption(origJavaArguments.getStringArguments(), javaHome, installPath))
{
// The argument works, so just use it.
hmJavaArguments.put(origJavaArguments, origJavaArguments);
}
else
{
// We have to fix it somehow: test separately memory and other
// arguments to see if something works.
JavaArguments transformedArguments = getBestEffortArguments(origJavaArguments, javaHome, installPath);
hmJavaArguments.put(origJavaArguments, transformedArguments);
}
}
// else, support is already checked.
}
Properties fileProperties = getJavaPropertiesFileContents(getPropertiesFileName(installPath));
Map<String, JavaArguments> args = new HashMap<String, JavaArguments>();
Map<String, String> otherProperties = new HashMap<String, String>();
for (String script : uData.getScriptNamesForJavaArguments())
{
JavaArguments origJavaArgument = uData.getJavaArguments(script);
JavaArguments transformedJavaArg = hmJavaArguments.get(origJavaArgument);
JavaArguments defaultJavaArg = uData.getDefaultJavaArguments(script);
// Apply the following policy: overwrite the values in the file only
// if the values provided by the user are not the default ones.
String propertiesKey = getJavaArgPropertyForScript(script);
if (origJavaArgument.equals(defaultJavaArg) && fileProperties.containsKey(propertiesKey))
{
otherProperties.put(propertiesKey, fileProperties.getProperty(propertiesKey));
}
else
{
args.put(script, transformedJavaArg);
}
}
putBooleanPropertyFrom("overwrite-env-java-home", fileProperties, otherProperties);
putBooleanPropertyFrom("overwrite-env-java-args", fileProperties, otherProperties);
if (!fileProperties.containsKey("default.java-home"))
{
otherProperties.put("default.java-home", javaHome);
}
writeSetOpenDSJavaHome(installPath, javaHome, args, otherProperties);
}
private void putBooleanPropertyFrom(
final String propertyName, final Properties propertiesSource, final Map<String, String> destMap)
{
final String propertyValue = propertiesSource.getProperty(propertyName);
if (propertyValue == null || !("true".equalsIgnoreCase(propertyValue) || "false".equalsIgnoreCase(propertyValue)))
{
destMap.put(propertyName, "false");
}
else
{
destMap.put("overwrite-env-java-home", propertyValue.toLowerCase());
}
}
/**
* Tries to figure out a new JavaArguments object that works, based on the
* provided JavaArguments. It is more efficient to call this method if we are
* sure that the provided JavaArguments object does not work.
*
* @param origJavaArguments
* the java arguments that does not work.
* @param javaHome
* the java home to be used to test the java arguments.
* @param installPath
* the install path.
* @return a working JavaArguments object.
*/
private JavaArguments getBestEffortArguments(JavaArguments origJavaArguments, String javaHome, String installPath)
{
JavaArguments memArgs = new JavaArguments();
memArgs.setInitialMemory(origJavaArguments.getInitialMemory());
memArgs.setMaxMemory(origJavaArguments.getMaxMemory());
String m = memArgs.getStringArguments();
boolean supportsMemory = false;
if (m.length() > 0)
{
supportsMemory = Utils.supportsOption(m, javaHome, installPath);
}
JavaArguments additionalArgs = new JavaArguments();
additionalArgs.setAdditionalArguments(origJavaArguments.getAdditionalArguments());
String a = additionalArgs.getStringArguments();
boolean supportsAdditional = false;
if (a.length() > 0)
{
supportsAdditional = Utils.supportsOption(a, javaHome, installPath);
}
JavaArguments javaArgs = new JavaArguments();
if (supportsMemory)
{
javaArgs.setInitialMemory(origJavaArguments.getInitialMemory());
javaArgs.setMaxMemory(origJavaArguments.getMaxMemory());
}
else
{
// Try to figure out a smaller amount of memory.
long currentMaxMemory = Runtime.getRuntime().maxMemory();
int maxMemory = origJavaArguments.getMaxMemory();
if (maxMemory != -1)
{
maxMemory = maxMemory / 2;
while (ONE_MEGABYTE * maxMemory < currentMaxMemory
&& !Utils.supportsOption(JavaArguments.getMaxMemoryArgument(maxMemory), javaHome, installPath))
{
maxMemory = maxMemory / 2;
}
if (ONE_MEGABYTE * maxMemory > currentMaxMemory)
{
// Supports this option.
javaArgs.setMaxMemory(maxMemory);
}
}
}
if (supportsAdditional)
{
javaArgs.setAdditionalArguments(origJavaArguments.getAdditionalArguments());
}
return javaArgs;
}
private List<String> getJavaPropertiesFileComments(String propertiesFile) throws IOException
{
ArrayList<String> commentLines = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new FileReader(propertiesFile));
String line;
while ((line = reader.readLine()) != null)
{
String trimmedLine = line.trim();
if (trimmedLine.startsWith("#") || trimmedLine.length() == 0)
{
commentLines.add(line);
}
else
{
break;
}
}
return commentLines;
}
private Properties getJavaPropertiesFileContents(String propertiesFile) throws IOException
{
FileInputStream fs = null;
Properties fileProperties = new Properties();
try
{
fs = new FileInputStream(propertiesFile);
fileProperties.load(fs);
}
catch (Throwable t)
{ /* do nothing */
}
finally
{
StaticUtils.close(fs);
}
return fileProperties;
}
private String getPropertiesFileName(String installPath)
{
String configDir = Utils.getPath(
Utils.getInstancePathFromInstallPath(installPath), Installation.CONFIG_PATH_RELATIVE);
return Utils.getPath(configDir, Installation.DEFAULT_JAVA_PROPERTIES_FILE);
}
/**
* Writes the set-java-home file that is used by the scripts to set the java
* home and the java arguments. Since the set-java-home file is created and
* may be changed, it's created under the instancePath.
*
* @param installPath
* the install path of the server.
* @param javaHome
* the java home to be used.
* @param arguments
* a Map containing as key the name of the script and as value, the
* java arguments to be set for the script.
* @param otherProperties
* other properties that must be set in the file.
* @throws IOException
* if an error occurred writing the file.
*/
private void writeSetOpenDSJavaHome(String installPath, String javaHome, Map<String, JavaArguments> arguments,
Map<String, String> otherProperties) throws IOException
{
String propertiesFile = getPropertiesFileName(installPath);
List<String> commentLines = getJavaPropertiesFileComments(propertiesFile);
BufferedWriter writer = new BufferedWriter(new FileWriter(propertiesFile, false));
for (String line: commentLines)
{
writer.write(line);
writer.newLine();
}
for (String key : otherProperties.keySet())
{
writer.write(key + "=" + otherProperties.get(key));
writer.newLine();
}
for (String scriptName : arguments.keySet())
{
String argument = arguments.get(scriptName).getStringArguments();
writer.newLine();
writer.write(getJavaArgPropertyForScript(scriptName) + "=" + argument);
}
writer.close();
String libDir = Utils.getPath(
Utils.getInstancePathFromInstallPath(installPath), Installation.LIBRARIES_PATH_RELATIVE);
// Create directory if it doesn't exist yet
File fLib = new File(libDir);
if (!fLib.exists())
{
fLib.mkdir();
}
final String destinationFile = Utils.getPath(libDir, isWindows() ? Installation.SET_JAVA_PROPERTIES_FILE_WINDOWS
: Installation.SET_JAVA_PROPERTIES_FILE_UNIX);
// Launch the script
String[] args =
{
"--propertiesFile", propertiesFile,
"--destinationFile", destinationFile,
"--quiet"
};
int returnValue = JavaPropertiesTool.mainCLI(args);
if (JavaPropertiesTool.ErrorReturnCode.SUCCESSFUL.getReturnCode() != returnValue &&
JavaPropertiesTool.ErrorReturnCode.SUCCESSFUL_NOP.getReturnCode() != returnValue)
{
logger.warn(LocalizableMessage.raw("Error creating java home scripts, error code: " + returnValue));
throw new IOException(ERR_ERROR_CREATING_JAVA_HOME_SCRIPTS.get(returnValue).toString());
}
}
/**
* Returns the java argument property for a given script.
*
* @param scriptName
* the script name.
* @return the java argument property for a given script.
*/
private static String getJavaArgPropertyForScript(String scriptName)
{
return scriptName + ".java-args";
}
/**
* If the log message is of type "[03/Apr/2008:21:25:43 +0200] category=JEB
* severity=NOTICE msgID=8847454 Processed 1 entries, imported 0, skipped 1,
* rejected 0 and migrated 0 in 1 seconds (average rate 0.0/sec)" returns the
* message part. Returns <CODE>null</CODE> otherwise.
*
* @param msg
* the message to be parsed.
* @return the parsed import message.
*/
public String getImportProgressMessage(String msg)
{
if (msg != null && (msg.contains("msgID=" + BackendMessages.NOTE_IMPORT_FINAL_STATUS.ordinal())
|| msg.contains("msgID=" + BackendMessages.NOTE_IMPORT_PROGRESS_REPORT.ordinal())))
{
int index = msg.indexOf("msg=");
if (index != -1)
{
return msg.substring(index + 4);
}
}
return null;
}
}