Installer.java revision d25372dc8e65a9ed019a88fdf659ca61313f1b31
/*
* 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
* 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 2006-2008 Sun Microsystems, Inc.
*/
/**
* This is an abstract class that is in charge of actually performing the
* installation.
*
* It just takes a UserData object and based on that installs OpenDS.
*
* When there is an update during the installation it will notify the
* ProgressUpdateListener objects that have been added to it. The
* notification will send a ProgressUpdateEvent.
*
* This class is supposed to be fully independent of the graphical layout.
*
* Note that we can use freely the class org.opends.server.util.SetupUtils as
* it is included in quicksetup.jar.
*
*/
public abstract class Installer extends GuiApplication {
private TopologyCache lastLoadedCache;
/** Indicates that we've detected that there is something installed. */
boolean forceToDisplaySetup = false;
/** When true indicates that the user has canceled this operation. */
protected boolean canceled = false;
private boolean javaVersionCheckFailed;
/** Map containing information about what has been configured remotely. */
// Constants used to do checks
private static final int MIN_DIRECTORY_MANAGER_PWD = 1;
/**
* The minimum integer value that can be used for a port.
*/
public static final int MIN_PORT_VALUE = 1;
/**
* The maximum integer value that can be used for a port.
*/
public static final int MAX_PORT_VALUE = 65535;
private static final int MIN_NUMBER_ENTRIES = 1;
private static final int MAX_NUMBER_ENTRIES = 10000;
/** Set of progress steps that have been completed. */
protected Set<InstallProgressStep>
{
}
private char[] selfSignedCertPw = null;
private boolean registeredNewServerOnRemote;
private boolean createdAdministrator;
private boolean createdRemoteAds;
private String lastImportProgress;
/**
* An static String that contains the class name of ConfigFileHandler.
*/
protected static final String DEFAULT_CONFIG_CLASS_NAME =
"org.opends.server.extensions.ConfigFileHandler";
/** Alias of a self-signed certificate. */
/** The thresold in minutes used to know whether we must display a warning
* informing that there is a server clock difference between two servers
* whose contents are being replicated. */
public static final int WARNING_CLOCK_DIFFERENCE_THRESOLD_MINUTES = 5;
/**
* Creates a default instance.
*/
public Installer() {
try {
if (!QuickSetupLog.isInitialized())
} catch (IOException e) {
}
}
/**
* {@inheritDoc}
*/
public boolean isCancellable() {
return true;
}
/**
* {@inheritDoc}
*/
public UserData createUserData() {
return ud;
}
/**
* {@inheritDoc}
*/
public void forceToDisplay() {
forceToDisplaySetup = true;
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
{
}
/**
* {@inheritDoc}
*/
{
boolean isVisible;
if (step == CREATE_GLOBAL_ADMINISTRATOR)
{
}
else if (step == NEW_SUFFIX_OPTIONS)
{
{
}
else
{
isVisible = false;
}
}
else if (step == SUFFIXES_OPTIONS)
{
{
}
else
{
isVisible = false;
}
}
else if (step == REMOTE_REPLICATION_PORTS)
{
}
else
{
isVisible = true;
}
return isVisible;
}
/**
* {@inheritDoc}
*/
{
}
/**
* {@inheritDoc}
*/
} else {
throw new IllegalStateException(
"Cannot click on finish when we are not in the Review window");
}
// Installer responsible for updating the user data and launching
return false;
}
/**
* {@inheritDoc}
*/
throw new IllegalStateException(
"Cannot click on next from progress step");
throw new IllegalStateException("Cannot click on next from review step");
throw new IllegalStateException(
"Cannot click on next from finished step");
}
}
/**
* {@inheritDoc}
*/
if (isFinished()
}
}
{
} else {
throw new IllegalStateException(
"Close only can be clicked on PROGRESS step");
}
}
/**
* {@inheritDoc}
*/
public boolean isFinished()
{
}
/**
* {@inheritDoc}
*/
public void cancel() {
this.canceled = true;
}
/**
* {@inheritDoc}
*/
{
}
throw new IllegalStateException(
"Cannot click on quit from progress step");
} else if (installStatus.isInstalled()) {
} else if (javaVersionCheckFailed)
{
}
}
/**
* {@inheritDoc}
*/
public ButtonName getInitialFocusButtonName() {
{
} else
{
{
}
else
{
}
}
return name;
}
/**
* {@inheritDoc}
*/
JPanel p;
javaVersionCheckFailed = true;
try
{
javaVersionCheckFailed = false;
p = dlg.getInstalledPanel();
} else {
p = super.createFramePanel(dlg);
}
}
catch (IncompatibleVersionException ijv)
{
new ButtonActionListener()
{
/**
* ButtonActionListener implementation. It assumes that we are
* called in the event thread.
*
* @param ev the ButtonEvent we receive.
*/
{
// Simulate a close button event
}
});
p = errPanel;
}
return p;
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
QuickSetupStepPanel p = null;
p = new InstallWelcomePanel(this);
} else if (step == SERVER_SETTINGS) {
p = new ServerSettingsPanel(this);
} else if (step == REPLICATION_OPTIONS) {
p = new DataReplicationPanel(this);
} else if (step == CREATE_GLOBAL_ADMINISTRATOR) {
p = new GlobalAdministratorPanel(this);
} else if (step == SUFFIXES_OPTIONS) {
p = new SuffixesToReplicatePanel(this);
} else if (step == REMOTE_REPLICATION_PORTS) {
p = new RemoteReplicationPortsPanel(this);
} else if (step == NEW_SUFFIX_OPTIONS) {
p = new DataOptionsPanel(this);
p = new InstallReviewPanel(this);
p = new ProgressPanel(this);
p = new FinishedPanel(this);
}
return p;
}
/**
* {@inheritDoc}
*/
// Simulate a close button event
} else {
// Simulate a close button event
} else {
// Simulate a quit button event
}
}
}
/**
* {@inheritDoc}
*/
public Message getCloseButtonToolTip() {
return INFO_CLOSE_BUTTON_INSTALL_TOOLTIP.get();
}
/**
* {@inheritDoc}
*/
public Message getQuitButtonToolTip() {
return INFO_QUIT_BUTTON_INSTALL_TOOLTIP.get();
}
/**
* {@inheritDoc}
*/
public Message getFinishButtonToolTip() {
return INFO_FINISH_BUTTON_INSTALL_TOOLTIP.get();
}
/**
* {@inheritDoc}
*/
public int getExtraDialogHeight() {
return UIFactory.EXTRA_DIALOG_HEIGHT;
}
/**
* {@inheritDoc}
*/
throw new IllegalStateException(
"Cannot click on previous from progress step");
throw new IllegalStateException(
"Cannot click on previous from progress step");
throw new IllegalStateException(
"Cannot click on previous from finished step");
}
}
/**
* {@inheritDoc}
*/
public Message getFrameTitle() {
return INFO_FRAME_INSTALL_TITLE.get();
}
/** Indicates the current progress step. */
private InstallProgressStep currentProgressStep =
/**
* {@inheritDoc}
*/
WizardStep step) {
// Set the default button for the frame
} else {
}
}
}
/**
* {@inheritDoc}
*/
public ProgressStep getCurrentProgressStep()
{
return currentProgressStep;
}
/**
* {@inheritDoc}
*/
public WizardStep getFirstWizardStep() {
return WELCOME;
}
/**
* {@inheritDoc}
*/
{
if (getUserData().mustCreateAdministrator())
{
}
else
{
{
case FIRST_IN_TOPOLOGY:
break;
case STANDALONE:
break;
default:
}
}
}
{
switch (getUserData().getSuffixesToReplicateOptions().
getType())
{
{
}
else
{
}
break;
default:
}
}
{
}
else
{
}
}
{
}
return next;
}
/**
* {@inheritDoc}
*/
{
return orderedSteps;
}
/**
* {@inheritDoc}
*/
// Try with the steps calculated in method getNextWizardStep.
{
if (i != -1 && i > 0) {
}
}
return prev;
}
/**
* {@inheritDoc}
*/
public WizardStep getFinishedStep() {
}
/**
* Uninstalls installed services. This is to be used when the user
* has elected to cancel an installation.
*/
protected void uninstallServices() {
try {
new InstallerHelper().disableWindowsService();
} catch (ApplicationException ae) {
}
}
}
/**
* Creates the template files based in the contents of the UserData object.
* These templates files are used to generate automatically data. To generate
* the template file the code will basically take into account the value of
* the base dn and the number of entries to be generated.
*
* @return a list of file objects pointing to the create template files.
* @throws ApplicationException if an error occurs.
*/
try
{
{
}
}
catch (IOException ioe)
{
throw new ApplicationException(
}
return files;
}
/**
* This methods configures the server based on the contents of the UserData
* object provided in the constructor.
* @throws ApplicationException if something goes wrong.
*/
protected void configureServer() throws ApplicationException {
if (Utils.isWebStart())
{
}
checkAbort();
// TODO: even if the user does not configure SSL maybe we should choose
// a secure port that is not being used and that we can actually use.
if (sec.getEnableSSL())
{
}
if (sec.getEnableStartTLS())
{
}
switch (sec.getCertificateType())
{
case SELF_SIGNED_CERTIFICATE:
break;
case JKS:
break;
case JCEKS:
break;
case PKCS12:
// We are going to import the PCKS12 certificate in a JKS truststore
break;
case PKCS11:
// We are going to import the PCKS11 certificate in a JKS truststore
break;
case NO_CERTIFICATE:
// Nothing to do.
break;
default:
throw new IllegalStateException("Unknown certificate type: "+
}
// For the moment do not enable JMX
{
}
if (createNotReplicatedSuffix())
{
{
}
}
else
{
{
}
}
boolean nextPassword = false;
{
{
}
if (nextPassword)
{
}
else
{
}
}
setNotifyListeners(false);
{
public void run()
{
int result = -1;
try
{
if (result != 0)
{
ae = new ApplicationException(
}
} catch (ApplicationException aex)
{
} catch (Throwable t)
{
ae = new ApplicationException(
}
finally
{
setNotifyListeners(true);
}
isOver = true;
}
public void abort()
{
// TODO: implement the abort
}
};
checkAbort();
try
{
{
}
File f;
switch (certType)
{
case NO_CERTIFICATE:
// Nothing to do
break;
case SELF_SIGNED_CERTIFICATE:
certManager = new CertificateManager(
pwd);
trustManager = new CertificateManager(
pwd);
new File(getTemporaryCertificatePath()));
f = new File(getTemporaryCertificatePath());
f.delete();
break;
case JKS:
certManager = new CertificateManager(
trustManager = new CertificateManager(
new File(getTemporaryCertificatePath()));
f = new File(getTemporaryCertificatePath());
f.delete();
break;
case JCEKS:
certManager = new CertificateManager(
trustManager = new CertificateManager(
new File(getTemporaryCertificatePath()));
f = new File(getTemporaryCertificatePath());
f.delete();
break;
case PKCS12:
certManager = new CertificateManager(
trustManager = new CertificateManager(
new File(getTemporaryCertificatePath()));
f = new File(getTemporaryCertificatePath());
f.delete();
break;
case PKCS11:
certManager = new CertificateManager(
trustManager = new CertificateManager(
new File(getTemporaryCertificatePath()));
break;
default:
}
{
}
}
catch (Throwable t)
{
throw new ApplicationException(
t), t);
}
}
/**
* This methods creates the base entry for the suffix based on the contents of
* the UserData object provided in the constructor.
* @throws ApplicationException if something goes wrong.
*/
private void createBaseEntry() throws ApplicationException {
{
}
else
{
}
{
}
checkAbort();
{
}
setNotifyListeners(false);
{
public void run()
{
try
{
if (result != 0)
{
ae = new ApplicationException(
}
} catch (Throwable t)
{
ae = new ApplicationException(
}
finally
{
setNotifyListeners(true);
}
isOver = true;
}
public void abort()
{
// TODO: implement the abort
}
};
}
/**
* This methods imports the contents of an LDIF file based on the contents of
* the UserData object provided in the constructor.
* @throws ApplicationException if something goes wrong.
*/
private void importLDIF() throws ApplicationException {
{
if (isVerbose())
{
}
else
{
}
}
else
{
if (isVerbose())
{
}
else
{
}
}
if (!isVerbose())
{
setNotifyListeners(false);
pointAdder.start();
}
{
}
if (rejectedFile != null)
{
}
if (skippedFile != null)
{
}
{
public void run()
{
try
{
if (result != 0)
{
ae = new ApplicationException(
}
} catch (Throwable t)
{
ae = new ApplicationException(
}
finally
{
if (!isVerbose())
{
pointAdder.stop();
setNotifyListeners(true);
}
}
isOver = true;
}
public void abort()
{
// TODO: implement the abort
}
};
try
{
} catch (ApplicationException ae)
{
if (!isVerbose())
{
if (lastImportProgress != null)
{
}
}
throw ae;
}
if (!isVerbose())
{
if (lastImportProgress == null)
{
}
else
{
}
}
}
/**
* This methods imports automatically generated data based on the contents
* of the UserData object provided in the constructor.
* @throws ApplicationException if something goes wrong.
*/
private void importAutomaticallyGenerated() throws ApplicationException {
if (isVerbose())
{
}
else
{
}
if (!isVerbose())
{
pointAdder.start();
}
{
if (!isVerbose())
{
setNotifyListeners(false);
}
// append: each file contains data for each base DN.
{
public void run()
{
try
{
if (result != 0)
{
ae = new ApplicationException(
}
} catch (Throwable t)
{
ae = new ApplicationException(
t);
}
finally
{
if (!isVerbose())
{
setNotifyListeners(true);
{
pointAdder.stop();
}
}
}
isOver = true;
}
public void abort()
{
// TODO: implement the abort
}
};
if (!isVerbose())
{
pointAdder.stop();
}
}
}
/**
* This method undoes the modifications made in other servers in terms of
* replication. This method assumes that we are aborting the Installer and
* that is why it does not call checkAbort.
*/
private void unconfigureRemote()
{
{
// Try to connect
if (isVerbose())
{
}
try
{
if (auth.useSecureConnection())
{
}
else
{
}
if (createdRemoteAds)
{
}
else
{
{
try
{
getUserData()));
}
catch (ADSContextException ace)
{
{
throw ace;
}
else
{
// Nothing to do: this may occur if the new server has been
// unregistered on another server and the modification has
// been already propagated by replication.
}
}
}
if (createdAdministrator)
{
getUserData()));
}
}
if (isVerbose())
{
}
}
catch (Throwable t)
{
notifyListeners(getFormattedError(t, true));
}
finally
{
{
try
{
}
catch (Throwable t)
{
}
}
}
}
{
getHostPort(server))));
try
{
}
catch (ApplicationException ae)
{
}
{
try
{
}
catch (Throwable t)
{
}
}
}
}
/**
* This method creates the replication configuration for the suffixes on the
* the local server (and eventually in the remote servers) to synchronize
* things.
* NOTE: this method assumes that the server is running.
* @throws ApplicationException if something goes wrong.
*/
protected void configureReplication() throws ApplicationException
{
if (lastLoadedCache != null)
{
{
{
}
}
{
if (v != null)
{
}
}
}
else
{
/* There is no ADS anywhere. Just use the SuffixDescriptors we found */
for (SuffixDescriptor suffix :
{
{
if (v != null)
{
}
}
}
}
/* For each suffix specified by the user, create a map from the suffix
DN to the set of replication servers. The initial instance in a topology
is a degenerate case. Also, collect a set of all observed replication
servers as the set of ADS suffix replicas (all instances hosting the
replication server also replicate ADS). */
{
h.add(getLocalReplicationServer());
{
}
}
else
{
{
h.add(getLocalReplicationServer());
{
{
}
}
}
}
long localTime = -1;
long localTimeMeasureTime = -1;
try
{
ctx = createLocalContext();
}
catch (ApplicationException ae)
{
throw ae;
}
catch (NamingException ne)
{
throw new ApplicationException(
}
finally
{
try
{
{
}
}
catch (Throwable t)
{
}
}
checkAbort();
{
for (SuffixDescriptor suffix :
{
{
{
}
}
}
{
getHostPort(server))));
int replicationPort;
boolean enableSecureReplication;
if (v != null)
{
replicationPort = v;
enableSecureReplication = false;
}
else
{
{
}
else
{
enableSecureReplication = false;
}
}
{
}
{
{
// Do the comparison manually
{
{
break;
}
}
}
{
}
else
{
dn);
}
}
{
{
}
}
try
{
}
catch (Throwable t)
{
}
checkAbort();
}
}
}
/**
* This methods enables this server as a Windows service.
* @throws ApplicationException if something goes wrong.
*/
protected void enableWindowsService() throws ApplicationException {
}
/**
* Updates the contents of the provided map with the localized summary
* strings.
* @param hmSummary the Map to be updated.
*/
protected void initSummaryMap(
{
cmd)));
cmd)));
}
/**
* Updates the messages in the summary with the state of the server.
* @param hmSummary the Map containing the messages.
*/
protected void updateSummaryWithServerState(
{
{
}
else
{
}
cmd)));
cmd)));
}
/**
* Checks the value of <code>canceled</code> field and throws an
* ApplicationException if true. This indicates that the user has
* canceled this operation and the process of aborting should begin
* as soon as possible.
*
* @throws ApplicationException thrown if <code>canceled</code>
*/
public void checkAbort() throws ApplicationException {
if (canceled) {
throw new ApplicationException(
}
}
/**
* Writes the java home that we are using for the setup in a file.
* This way we can use this java home even if the user has not set
* OPENDS_JAVA_HOME when running the different scripts.
*
*/
protected void writeOpenDSJavaHome()
{
try
{
// This isn't likely to happen, and it's not a serious problem even if
// it does.
} catch (Exception e) {
}
}
/**
* These methods validate the data provided by the user in the panels and
* update the userData object according to that content.
*
* @param cStep
* the current step of the wizard
* @param qs QuickStart controller
* @throws UserDataException if the data provided by the user is not
* valid.
*
*/
throws UserDataException
{
if (cStep == SERVER_SETTINGS)
{
}
else if (cStep == REPLICATION_OPTIONS)
{
}
else if (cStep == CREATE_GLOBAL_ADMINISTRATOR)
{
}
else if (cStep == SUFFIXES_OPTIONS)
{
}
else if (cStep == REMOTE_REPLICATION_PORTS)
{
}
else if (cStep == NEW_SUFFIX_OPTIONS)
{
}
{
}
}
/**
* Returns the default backend name (the one that will be created).
* @return the default backend name (the one that will be created).
*/
protected String getBackendName()
{
return "userRoot";
}
/**
* Sets the current progress step of the installation process.
* @param currentProgressStep the current progress step of the installation
* process.
*/
{
if (currentProgressStep != null) {
}
}
/**
* This methods updates the data on the server based on the contents of the
* UserData object provided in the constructor.
* @throws ApplicationException if something goes wrong.
*/
protected void createData() throws ApplicationException
{
if (createNotReplicatedSuffix())
{
{
case CREATE_BASE_ENTRY:
if (isVerbose())
{
}
break;
case IMPORT_FROM_LDIF_FILE:
if (isVerbose())
{
}
importLDIF();
break;
if (isVerbose())
{
}
break;
}
}
}
/**
* This method initialize the contents of the synchronized servers with the
* contents of the first server we find.
* @throws ApplicationException if something goes wrong.
*/
protected void initializeSuffixes() throws ApplicationException
{
try
{
ctx = createLocalContext();
}
catch (Throwable t)
{
try
{
{
}
}
{
}
throw new ApplicationException(
}
/* Initialize local ADS and schema contents using any replica. */
{
try
{
filter.setSearchMonitoringInformation(false);
{
{
}
{
}
}
}
catch (NamingException ne)
{
{
}
else
{
}
ne);
}
finally
{
catch (Throwable t){}
}
}
{
if(isADS)
{
if (isVerbose())
{
}
}
else if (isSchema)
{
if (isVerbose())
{
}
}
else
{
}
try
{
if (replicationId == -1)
{
/**
* This occurs if the remote server had not replication configured.
*/
try
{
filter.setSearchMonitoringInformation(false);
filter);
for (ReplicaDescriptor r : s.getReplicas())
{
{
replicationId = r.getReplicationId();
}
}
}
catch (NamingException ne)
{
{
}
else
{
}
ne);
}
finally
{
try
{
}
catch (Throwable t)
{
}
}
}
if (replicationId == -1)
{
throw new ApplicationException(
}
try
{
}
catch (Throwable t) {}
int nTries = 5;
boolean initDone = false;
while (!initDone)
{
try
{
hostPort);
initDone = true;
}
catch (PeerNotFoundException pnfe)
{
if (nTries == 1)
{
throw new ApplicationException(
}
try
{
}
catch (Throwable t)
{
}
}
nTries--;
}
}
catch (ApplicationException ae)
{
try
{
{
}
}
{
}
throw ae;
}
{
}
checkAbort();
}
}
/**
* This method updates the ADS contents (and creates the according suffixes).
* If the user specified an existing topology, the new instance is
* registered with that ADS (the ADS might need to be created), and the
* local ADS will be populated when the local server is added to the remote
* server's ADS replication domain in a subsequent step. Otherwise, an ADS
* is created on the new instance and the server is registered with the new
* ADS. NOTE: this method assumes that the local server and any remote server
* are running.
* @throws ApplicationException if something goes wrong.
*/
protected void updateADS() throws ApplicationException
{
boolean isRemoteServer =
: null;
/* Outer try-catch-finally to convert occurences of NamingException and
ADSContextException to ApplicationException and clean up JNDI contexts.*/
try
{
if (isRemoteServer)
{
/* In case the user specified an existing topology... */
if (auth.useSecureConnection())
{
}
else
{
}
/* Check the remote server for ADS. If it does not exist, create the
initial ADS there and register the server with itself. */
if (! adsContext.hasAdminData())
{
if (isVerbose())
{
}
filter.setSearchMonitoringInformation(false);
filter.setSearchBaseDNInformation(false);
createdRemoteAds = true;
if (isVerbose())
{
}
checkAbort();
}
}
/* Act on local server depending on if using remote or local ADS */
if (isVerbose())
{
}
// if (isRemoteServer)
// {
// /* Create an empty ADS suffix on the local server. */
// ADSContext localAdsContext = new ADSContext(localCtx);
// localAdsContext.createAdministrationSuffix(null);
// }
if (!isRemoteServer)
{
/* Configure local server to have an ADS */
}
/* Register new server in ADS. */
filter.setSearchMonitoringInformation(false);
filter.setSearchBaseDNInformation(false);
filter);
if (isRemoteServer) registeredNewServerOnRemote = true;
} else {
"server registration.");
}
if (isRemoteServer)
{
}
if (isVerbose())
{
}
checkAbort();
/* Add global administrator if the user specified one. */
if (getUserData().mustCreateAdministrator())
{
try
{
if (isVerbose())
{
}
getUserData()));
if (isVerbose())
{
}
checkAbort();
}
catch (ADSContextException ade)
{
{
}
else
{
throw ade;
}
}
}
}
catch (NoPermissionException ne)
{
if (isRemoteServer)
{
throw new ApplicationException(
}
else
{
// TODO: INFO for local PERMISSIONS exception?
throw new ApplicationException(
}
}
catch (NamingException ne)
{
if (isRemoteServer)
{
throw new ApplicationException(
}
else
{
throw new ApplicationException(
}
}
catch (ADSContextException ace)
{
throw new ApplicationException(
}
finally
{
}
}
/**
* Tells whether we must create a suffix that we are not going to replicate
* with other servers or not.
* @return <CODE>true</CODE> if we must create a new suffix and
* <CODE>false</CODE> otherwise.
*/
protected boolean createNotReplicatedSuffix()
{
boolean createSuffix;
return createSuffix;
}
/**
* Returns <CODE>true</CODE> if we must configure replication and
* <CODE>false</CODE> otherwise.
* @return <CODE>true</CODE> if we must configure replication and
* <CODE>false</CODE> otherwise.
*/
protected boolean mustConfigureReplication()
{
}
/**
* Returns <CODE>true</CODE> if we must create the ADS and
* <CODE>false</CODE> otherwise.
* @return <CODE>true</CODE> if we must create the ADS and
* <CODE>false</CODE> otherwise.
*/
protected boolean mustCreateAds()
{
}
/**
* Returns <CODE>true</CODE> if we must start the server and
* <CODE>false</CODE> otherwise.
* @return <CODE>true</CODE> if we must start the server and
* <CODE>false</CODE> otherwise.
*/
protected boolean mustStart()
{
}
/**
* Returns <CODE>true</CODE> if we must stop the server and
* <CODE>false</CODE> otherwise.
* The server might be stopped if the user asked not to start it at the
* end of the installation and it was started temporarily to update its
* configuration.
* @return <CODE>true</CODE> if we must stop the server and
* <CODE>false</CODE> otherwise.
*/
protected boolean mustStop()
{
}
/**
* Returns <CODE>true</CODE> if we must initialize suffixes and
* <CODE>false</CODE> otherwise.
* @return <CODE>true</CODE> if we must initialize suffixes and
* <CODE>false</CODE> otherwise.
*/
protected boolean mustInitializeSuffixes()
{
}
/**
* Returns the list of preferred URLs to connect to remote servers. In fact
* it returns only the URL to the remote server specified by the user in
* the replication options panel. The method returns a list for convenience
* with other interfaces.
* NOTE: this method assumes that the UserData object has already been updated
* with the host and port of the remote server.
* @return the list of preferred URLs to connect to remote servers.
*/
{
new LinkedHashSet<PreferredConnection>();
{
{
if (auth.useSecureConnection())
{
}
else
{
}
}
}
return cnx;
}
{
if (auth.useSecureConnection())
{
}
else
{
}
return ldapUrl;
}
{
}
{
userData.getHostName());
// TODO: even if the user does not configure SSL maybe we should choose
// a secure port that is not being used and that we can actually use.
if (sec.getEnableSSL())
{
}
else
{
}
if (sec.getEnableStartTLS())
{
}
else
{
}
if (isWebStart())
{
}
else
{
}
/* TODO: do we want to ask this specifically to the user? */
getOSString());
return serverProperties;
}
{
return adminProperties;
}
/**
* Validate the data provided by the user in the server settings panel and
* update the userData object according to that content.
*
* @throws UserDataException if the data provided by the user is not
* valid.
*
*/
throws UserDataException
{
if (isWebStart())
{
// Check the server location
{
}
else if (!parentDirectoryExists(serverLocation))
{
{
f = f.getParentFile();
{
if (f.isDirectory())
{
}
else
{
// The parent path is a file!
f = null;
}
}
}
if (existingParentDirectory == null)
{
}
else
{
if (!canWrite(existingParentDirectory))
{
}
else if (!hasEnoughSpace(existingParentDirectory,
{
}
else
{
}
}
} else if (fileExists(serverLocation))
{
} else if (directoryExistsAndIsNotEmpty(serverLocation))
{
} else if (!canWrite(serverLocation))
{
} else if (!hasEnoughSpace(serverLocation,
{
{
} else
{
}
}
// Check the host is not empty.
// TODO: check that the host name is valid...
{
}
else
{
}
// Check the port
int port = -1;
try
{
{
} else if (!canUseAsPort(port))
{
if (isPriviledgedPort(port))
{
} else
{
}
} else
{
}
} catch (NumberFormatException nfe)
{
}
// Check the admin connector port
int adminConnectorPort = -1;
try
{
if ((adminConnectorPort < MIN_PORT_VALUE) ||
{
} else if (!canUseAsPort(adminConnectorPort))
{
{
} else
{
}
} else
{
}
} catch (NumberFormatException nfe)
{
}
// Check the secure port
if (sec.getEnableSSL())
{
{
} else if (!canUseAsPort(securePort))
{
if (isPriviledgedPort(securePort))
{
} else
{
}
}
else if (port == securePort)
{
}
else
{
}
}
else
{
}
// Check the Directory Manager DN
{
{
} else if (isConfigurationDn(dmDn))
{
} else
{
}
// Check the provided passwords
{
pwd1 = "";
}
boolean pwdValid = true;
{
pwdValid = false;
}
{
{
}
pwdValid = false;
}
if (pwdValid)
{
}
// For the moment do not enable JMX
int defaultJMXPort =
if (defaultJMXPort != -1)
{
//getUserData().setServerJMXPort(defaultJMXPort);
}
{
}
if (confirmationMsg != null)
{
}
}
/**
* Validate the data provided by the user in the data options panel and update
* the userData object according to that content.
*
* @throws UserDataException if the data provided by the user is not
* valid.
*
*/
throws UserDataException {
boolean hasGlobalAdministrators = false;
boolean secureReplication = false;
{
// Check replication port
}
switch (type)
{
case IN_EXISTING_TOPOLOGY:
{
{
// Try to connect
boolean[] globalAdmin = {hasGlobalAdministrators};
try
{
}
catch (UserDataConfirmationException e)
{
confirmEx = e;
}
}
break;
}
case STANDALONE:
{
new HashSet<SuffixDescriptor>(),
new HashSet<SuffixDescriptor>()));
break;
}
case FIRST_IN_TOPOLOGY:
{
new HashSet<SuffixDescriptor>(),
new HashSet<SuffixDescriptor>()));
break;
}
default:
throw new IllegalStateException("Do not know what to do with type: "+
type);
}
{
{
}
auth.setUseSecureConnection(true);
switch (type)
{
case IN_EXISTING_TOPOLOGY:
{
break;
}
case STANDALONE:
{
break;
}
case FIRST_IN_TOPOLOGY:
{
break;
}
default:
throw new IllegalStateException("Do not know what to do with type: "+
type);
}
}
{
}
{
throw confirmEx;
}
}
{
int replicationPort = -1;
try
{
if ((replicationPort < MIN_PORT_VALUE) ||
{
} else if (!canUseAsPort(replicationPort))
{
{
} else
{
}
} else
{
/* Check that we did not chose this port for another protocol */
{
}
else
{
}
}
} catch (NumberFormatException nfe)
{
}
return replicationPort;
}
{
// Check host
{
}
else
{
}
// Check port
try
{
}
catch (Throwable t)
{
}
// Check dn
{
}
else
{
}
// Check password
{
}
else
{
}
}
boolean[] hasGlobalAdministrators,
{
try
{
try
{
}
catch (Throwable t)
{
if (!isCertificateException(t))
{
// Try using a global administrator
}
else
{
throw t;
}
}
if (adsContext.hasAdminData())
{
/* Check if there are already global administrators */
{
hasGlobalAdministrators[0] = true;
}
else
{
hasGlobalAdministrators[0] = false;
}
/* Check the exceptions and see if we throw them or not. */
for (TopologyCacheException e : exceptions)
{
switch (e.getType())
{
case NOT_GLOBAL_ADMINISTRATOR:
{
if (e.getTrustManager() != null)
{
}
{
}
else if (cause ==
{
}
else
{
}
{
String h;
int p;
try
{
}
catch (Throwable t)
{
"Error parsing ldap url of TopologyCacheException.", t);
p = -1;
}
throw new UserDataCertificateException(
e.getCause(), h, p,
}
}
}
}
{
}
}
else
{
}
}
catch (UserDataException ude)
{
throw ude;
}
catch (Throwable t)
{
if (isCertificateException(t))
{
{
}
{
}
else
{
}
{
}
else
{
}
}
else if (t instanceof AuthenticationException)
{
}
else if (t instanceof NoPermissionException)
{
}
else if (t instanceof NamingException)
{
}
else if (t instanceof ADSContextException)
{
}
else
{
}
}
finally
{
{
try
{
}
catch (Throwable t)
{
}
}
}
}
/**
* Validate the data provided by the user in the create global administrator
* panel and update the UserInstallData object according to that content.
*
* @throws
* UserDataException if the data provided by the user is not
* valid.
*
*/
throws UserDataException
{
// Check the Global Administrator UID
{
}
else
{
}
// Check the provided passwords
{
pwd1 = "";
}
boolean pwdValid = true;
{
pwdValid = false;
}
{
{
true);
}
pwdValid = false;
}
if (pwdValid)
{
}
{
}
}
/**
* Validate the data provided by the user in the replicate suffixes options
* panel and update the UserInstallData object according to that content.
*
* @throws
* UserDataException if the data provided by the user is not
* valid.
*
*/
throws UserDataException
{
{
if (s.size() == 0)
{
}
else
{
for (Object o: s)
{
}
chosen);
}
}
else
{
chosen);
}
{
}
}
/**
* Validate the data provided by the user in the remote server replication
* port panel and update the userData object according to that content.
*
* @throws UserDataException if the data provided by the user is not
* valid.
*/
throws UserDataException
{
{
int replicationPort = -1;
try
{
if ((replicationPort < MIN_PORT_VALUE) ||
{
}
{
int securePort = -1;
{
}
(replicationPort ==
(replicationPort == securePort))
{
}
}
} catch (NumberFormatException nfe)
{
}
}
{
}
else
{
}
}
/**
* Validate the data provided by the user in the new suffix data options panel
* and update the UserInstallData object according to that content.
*
* @throws UserDataException if the data provided by the user is not
* valid.
*
*/
throws UserDataException
{
// Check the base dn
boolean validBaseDn = false;
{
{
} else if (isConfigurationDn(baseDn))
{
} else
{
validBaseDn = true;
}
// Check the data options
switch (type)
{
case IMPORT_FROM_LDIF_FILE:
{
} else if (!fileExists(ldifPath))
{
} else if (validBaseDn)
{
}
break;
// variable used to know if everything went ok during these
// checks
// Check the number of entries
{
} else
{
boolean nEntriesValid = false;
try
{
} catch (NumberFormatException nfe)
{
}
if (!nEntriesValid)
{
} else
{
}
}
{
// No validation errors
}
break;
default:
if (validBaseDn)
{
{
}
else
{
}
}
}
if (dataOptions != null)
{
}
{
}
}
/**
* Update the userData object according to the content of the review
* panel.
*
*/
{
getUserData().setStartServer(b);
}
/**
* Returns the number of free disk space in bytes required to install Open DS
*
* For the moment we just return 15 Megabytes. TODO we might want to have
* something dynamic to calculate the required free disk space for the
* installation.
*
* @return the number of free disk space required to install Open DS.
*/
private long getRequiredInstallSpace()
{
return 15 * 1024 * 1024;
}
/**
* Update the UserInstallData with the contents we discover in the ADS.
*/
throws TopologyCacheException
{
new HashSet<TopologyCacheException>();
{
}
else
{
}
new LinkedHashSet<PreferredConnection>();
adsContext.getDirContext()));
// We cannot use getPreferredConnections since the user data has not been
// updated yet.
/* 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.
*/
{
if (e != null)
{
exceptions.add(e);
}
}
return exceptions;
}
/**
* Update the UserInstallData object with the contents of the server to which
* we are connected with the provided InitialLdapContext.
*/
throws NamingException
{
{
}
else
{
}
new TopologyCacheFilter());
{
}
}
/**
* Returns the keystore path to be used for generating a self-signed
* certificate.
* @return the keystore path to be used for generating a self-signed
* certificate.
*/
protected String getSelfSignedKeystorePath()
{
}
/**
* Returns the trustmanager path to be used for generating a self-signed
* certificate.
* @return the trustmanager path to be used for generating a self-signed
* certificate.
*/
private String getTrustManagerPath()
{
}
/**
* Returns the path of the self-signed that we export to be able to create
* a truststore.
* @return the path of the self-signed that is exported.
*/
private String getTemporaryCertificatePath()
{
}
/**
* Returns the path to be used to store the password of the keystore.
* @return the path to be used to store the password of the keystore.
*/
private String getKeystorePinPath()
{
}
/**
* Returns the validity period to be used to generate the self-signed
* certificate.
* @return the validity period to be used to generate the self-signed
* certificate.
*/
private int getSelfSignedCertificateValidity()
{
return 2 * 365;
}
/**
* Returns the Subject DN to be used to generate the self-signed certificate.
* @return the Subject DN to be used to generate the self-signed certificate.
*/
private String getSelfSignedCertificateSubjectDN()
{
",O=OpenDS Self-Signed Certificate";
}
/**
* Returns the self-signed certificate password used for this session. This
* method calls <code>createSelfSignedCertificatePwd()</code> the first time
* this method is called.
* @return the self-signed certificate password used for this session.
*/
protected String getSelfSignedCertificatePwd()
{
if (selfSignedCertPw == null) {
}
return new String(selfSignedCertPw);
}
{
{
{
{
authData.setUseSecureConnection(false);
}
}
}
return servers;
}
{
}
/**
* Gets an InitialLdapContext based on the information that appears on the
* provided ServerDescriptor.
* @param server the object describing the server.
* @param trustManager the trust manager to be used to establish the
* connection.
* @param preferredURLs the list of preferred LDAP URLs to be used to connect
* to the server.
* @return the InitialLdapContext to the remote server.
* @throws ApplicationException if something goes wrong.
*/
throws ApplicationException
{
if (!server.isRegistered())
{
/* Create adsProperties to be able to use the class ServerLoader to
* get the connection. Just update the connection parameters with what
* the user chose in the Topology Options panel (i.e. even if SSL
* is enabled on the remote server, use standard LDAP to connect to the
* server if the user specified the LDAP port: this avoids having an
* issue with the certificate if it has not been accepted previously
* by the user).
*/
server.getHostName());
if (auth.useSecureConnection())
{
}
else
{
}
}
trustManager, cnx);
}
/**
* Initializes a suffix with the contents of a replica that has a given
* replication id.
* @param ctx the connection to the server whose suffix we want to initialize.
* @param replicaId the replication ID of the replica we want to use to
* initialize the contents of the suffix.
* @param suffixDn the dn of the suffix.
* @param displayProgress whether we want to display progress or not.
* @param sourceServerDisplay the string to be used to represent the server
* that contains the data that will be used to initialize the suffix.
* @throws ApplicationException if an unexpected error occurs.
* @throws PeerNotFoundException if the replication mechanism cannot find
* a peer.
*/
{
boolean taskCreated = false;
int i = 1;
boolean isOver = false;
while (!taskCreated)
{
checkAbort();
try
{
taskCreated = true;
}
catch (NameAlreadyBoundException x)
{
}
catch (NamingException ne)
{
throw new ApplicationException(
}
i++;
}
// Wait until it is over
new String[] {
"ds-task-unprocessed-entry-count",
"ds-task-processed-entry-count",
"ds-task-log-message",
"ds-task-state"
});
long lastTimeMsgDisplayed = -1;
long lastTimeMsgLogged = -1;
int totalEntries = 0;
while (!isOver)
{
if (canceled)
{
// TODO: we should try to cleanly abort the initialize. As we have
// aborted the install, the server will be stopped and the remote
// server will receive a connect error.
checkAbort();
}
try
{
}
catch (Throwable t)
{
}
if (canceled)
{
// TODO: we should try to cleanly abort the initialize. As we have
// aborted the install, the server will be stopped and the remote
// server will receive a connect error.
checkAbort();
}
try
{
// Get the number of entries that have been handled and
// a percentage...
"ds-task-processed-entry-count");
"ds-task-unprocessed-entry-count");
int processed = -1;
int unprocessed = -1;
if (sProcessed != null)
{
}
if (sUnprocessed != null)
{
}
{
{
}
else
{
//msg = INFO_NO_ENTRIES_TO_INITIALIZE.get();
}
}
else if (processed != -1)
{
}
else if (unprocessed != -1)
{
}
else
{
}
{
/* 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 (displayProgress)
{
{
}
}
}
{
{
lastLogMsg = logMsg;
}
}
{
isOver = true;
{
}
if (lastLogMsg == null)
{
}
else
{
}
{
if (displayProgress)
{
}
}
{
null);
if ((lastLogMsg == null) ||
{
"Last Log Msg: "+lastLogMsg);
// Assume that this is a peer not found error.
throw new PeerNotFoundException(errorMsg);
}
else
{
throw ae;
}
}
else if (displayProgress)
{
}
}
}
catch (NameNotFoundException x)
{
isOver = true;
if (displayProgress)
{
}
}
catch (NamingException ne)
{
throw new ApplicationException(
}
}
}
/**
* Returns the configuration file path to be used when invoking the
* command-lines.
* @return the configuration file path to be used when invoking the
* command-lines.
*/
private String getConfigurationFile()
{
{
}
return file;
}
/**
* Returns the configuration class name to be used when invoking the
* command-lines.
* @return the configuration class name to be used when invoking the
* command-lines.
*/
private String getConfigurationClassName()
{
{
}
return className;
}
private String getLocalReplicationServer()
{
}
private String getLocalHostPort()
{
}
throws ApplicationException
{
boolean taskCreated = false;
int i = 1;
boolean isOver = false;
"org.opends.server.tasks.SetGenerationIdTask");
while (!taskCreated)
{
checkAbort();
try
{
taskCreated = true;
}
catch (NameAlreadyBoundException x)
{
}
catch (NamingException ne)
{
throw new ApplicationException(
}
i++;
}
// Wait until it is over
new String[] {
"ds-task-log-message",
"ds-task-state"
});
while (!isOver)
{
try
{
}
catch (Throwable t)
{
}
try
{
{
{
lastLogMsg = logMsg;
}
}
{
isOver = true;
if (lastLogMsg == null)
{
}
else
{
}
{
}
{
null);
throw ae;
}
}
}
catch (NameNotFoundException x)
{
isOver = true;
}
catch (NamingException ne)
{
throw new ApplicationException(
}
}
}
/**
* Invokes a long operation in a separate thread and checks whether the user
* canceled the operation or not.
* @param thread the Thread that must be launched.
* @throws ApplicationException if there was an error executing the task or
* if the user canceled the installer.
*/
throws ApplicationException
{
try
{
{
if (canceled)
{
// Try to abort the thread
try
{
}
catch (Throwable t)
{
}
}
{
throw thread.getException();
}
else
{
try
{
}
catch (Throwable t)
{
}
}
}
{
throw thread.getException();
}
if (canceled)
{
checkAbort();
}
}
catch (ApplicationException e)
{
throw e;
}
catch (Throwable t)
{
}
}
/**
* Returns the host port representation of the server to be used in progress
* and error messages. It takes into account the fact the host and port
* provided by the user in the replication options panel.
* NOTE: the code assumes that the user data with the contents of the
* replication options has already been updated.
* @param server the ServerDescriptor.
* @return the host port string representation of the provided server.
*/
{
{
{
}
{
}
}
{
}
return hostPort;
}
/**
* {@inheritDoc}
*/
{
if (parsedMessage != null)
{
}
}
}
/**
* Class used to be able to cancel long operations.
*/
{
protected boolean isOver = false;
protected ApplicationException ae;
/**
* Returns <CODE>true</CODE> if the thread is over and <CODE>false</CODE>
* otherwise.
* @return <CODE>true</CODE> if the thread is over and <CODE>false</CODE>
* otherwise.
*/
public boolean isOver()
{
return isOver;
}
/**
* Returns the exception that was encountered running the thread.
* @return the exception that was encountered running the thread.
*/
public ApplicationException getException()
{
return ae;
}
/**
* Runnable implementation.
*/
public abstract void run();
/**
* Abort this thread.
*/
public abstract void abort();
}