StatusPanelController.java revision 3bd997f0d659b0b5280791733d0101a588b01da5
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/*
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * CDDL HEADER START
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * The contents of this file are subject to the terms of the
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Common Development and Distribution License, Version 1.0 only
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * (the "License"). You may not use this file except in compliance
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * with the License.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * You can obtain a copy of the license at
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * trunk/opends/resource/legal-notices/OpenDS.LICENSE
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * See the License for the specific language governing permissions
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * and limitations under the License.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * When distributing Covered Code, include this CDDL HEADER in each
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * file and include the License file at
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * add the following below this CDDL HEADER, with the fields enclosed
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * by brackets "[]" replaced with your own identifying information:
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Portions Copyright [yyyy] [name of copyright owner]
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * CDDL HEADER END
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Portions Copyright 2006-2007 Sun Microsystems, Inc.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkpackage org.opends.guitools.statuspanel;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.awt.event.WindowAdapter;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.awt.event.WindowEvent;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.io.BufferedReader;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.io.IOException;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.io.InputStreamReader;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.util.ArrayList;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport java.util.Map;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport javax.swing.SwingUtilities;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.server.core.DirectoryServer;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.admin.ads.util.ApplicationTrustManager;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.guitools.statuspanel.event.ServerStatusChangeEvent;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.guitools.statuspanel.event.ServerStatusChangeListener;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.guitools.statuspanel.event.StatusPanelButtonListener;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.guitools.statuspanel.ui.LoginDialog;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.guitools.statuspanel.ui.StatusPanelDialog;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.Installation;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.ui.ProgressDialog;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.ui.UIFactory;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.ui.Utilities;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.util.BackgroundTask;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.util.HtmlProgressMessageFormatter;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.quicksetup.util.Utils;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.messages.Message;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.messages.MessageBuilder;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport org.opends.messages.MessageDescriptor;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport static org.opends.messages.AdminToolMessages.*;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkimport static org.opends.messages.QuickSetupMessages.*;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/**
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * This is the main class of the status panel.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * It is in charge of all the logic behind the displaying of the dialogs and
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * the one that initializes everything. This is also the class that ultimately
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * listens to user events (notably button clicks) and executes the associated
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * operations with these user events.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkpublic class StatusPanelController implements ServerStatusChangeListener,
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk StatusPanelButtonListener
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk{
private LoginDialog loginDialog;
private StatusPanelDialog controlPanelDialog;
private ProgressDialog progressDialog;
private ServerStatusPooler serverStatusPooler;
private HtmlProgressMessageFormatter formatter =
new HtmlProgressMessageFormatter();
private boolean isStarting;
private boolean isStopping;
private boolean isRestarting;
private boolean mustDisplayAuthenticateDialog;
private ServerStatusDescriptor desc;
private Message lastDetail;
private Message lastSummary;
private Thread progressUpdater;
private ApplicationTrustManager trustManager;
//Update period of the progress dialog.
private static final int UPDATE_PERIOD = 500;
private static final ConnectionProtocolPolicy CONNECTION_POLICY =
ConnectionProtocolPolicy.USE_MOST_SECURE_AVAILABLE;
/**
* This method creates the control panel dialogs and to check the current
* install status. This method must be called outside the event thread because
* it can perform long operations which can make the user think that the UI is
* blocked.
*
* Note that there is no synchronization code between threads. The
* synchronization code is not required as all the start/stop/restart actions
* are launched in the event thread so just using booleans that are updated
* in the event thread is enough to guarantee that there are no multiple
* operations launched at the same time.
*
* @param args for the moment this parameter is not used but we keep it in
* order to (in case of need) pass parameters through the command line.
*/
public void initialize(String[] args)
{
DirectoryServer.bootstrapClient();
initLookAndFeel();
trustManager = new ApplicationTrustManager(null);
/* Call this methods to create the dialogs (the control panel dialog
* is generated when we call getLoginDialog()). */
getLoginDialog();
getProgressDialog();
serverStatusPooler = new ServerStatusPooler(CONNECTION_POLICY);
serverStatusPooler.addServerStatusChangeListener(this);
serverStatusPooler.startPooling();
desc = serverStatusPooler.getLastDescriptor();
while (desc == null)
{
try
{
Thread.sleep(100);
}
catch (Exception ex)
{
}
desc = serverStatusPooler.getLastDescriptor();
}
}
/**
* This method displays the required dialog. This method must be called from
* the event thread.
*/
public void display()
{
getStatusPanelDialog().packAndShow();
if (!isAuthenticated())
{
if (desc.getStatus() == ServerStatusDescriptor.ServerStatus.STARTED)
{
authenticateClicked();
}
}
}
/**
* ServerStatusChangeListener implementation. This method is called when
* a new ServerStatusDescriptor has been generated by the ServerStatusPooler.
* @param ev the event we receive.
*/
public void statusChanged(final ServerStatusChangeEvent ev)
{
/* Here we assume that this events are not very frequent (not frequent
* at least to generate flickering). This is acceptable since the
* ServerStatusPooler does pooling every second.
*/
if (SwingUtilities.isEventDispatchThread())
{
getStatusPanelDialog().updateContents(ev.getStatusDescriptor());
}
else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
getStatusPanelDialog().updateContents(ev.getStatusDescriptor());
}
});
}
}
/**
* Method called when user clicks on Quit button.
* StatusPanelButtonListener implementation.
*/
public void quitClicked()
{
serverStatusPooler.stopPooling();
System.exit(0);
}
/**
* Method called when user clicks on Start button.
* StatusPanelButtonListener implementation.
*/
public void startClicked()
{
if (isStarting)
{
if (!getProgressDialog().isVisible())
{
getProgressDialog().setVisible(true);
}
}
else if (isStopping)
{
/* Should not happen */
Thread.dumpStack();
}
else if (isRestarting)
{
/* Should not happen */
Thread.dumpStack();
}
else
{
isStarting = true;
lastDetail = null;
getProgressDialog().setSummary(
getFormattedSummary(INFO_SUMMARY_STARTING.get()));
getProgressDialog().setDetails(Message.EMPTY);
serverStatusPooler.beginServerStart();
getProgressDialog().setCloseButtonEnabled(false);
getStatusPanelDialog().setStartButtonEnabled(false);
getStatusPanelDialog().setStopButtonEnabled(false);
getStatusPanelDialog().setRestartButtonEnabled(false);
getStatusPanelDialog().setAuthenticateButtonEnabled(false);
if (!getProgressDialog().isVisible())
{
getProgressDialog().pack();
Utilities.centerOnComponent(getProgressDialog(),
getStatusPanelDialog());
getProgressDialog().setVisible(true);
}
BackgroundTask task = new BackgroundTask()
{
public Object processBackgroundTask()
{
if (progressUpdater == null)
{
runProgressUpdater();
}
mustDisplayAuthenticateDialog = startServer() && !isAuthenticated();
serverStatusPooler.endServerStart();
return null;
}
public void backgroundTaskCompleted(Object value, Throwable t)
{
if (t != null)
{
// Bug
t.printStackTrace();
}
getStatusPanelDialog().setStartButtonEnabled(true);
getStatusPanelDialog().setStopButtonEnabled(true);
getStatusPanelDialog().setRestartButtonEnabled(true);
getStatusPanelDialog().setAuthenticateButtonEnabled(
!isAuthenticated());
getProgressDialog().setCloseButtonEnabled(true);
isStarting = false;
}
};
task.startBackgroundTask();
}
}
/**
* Method called when user clicks on Stop button.
* StatusPanelButtonListener implementation.
*/
public void stopClicked()
{
if (isStopping)
{
if (!getProgressDialog().isVisible())
{
getProgressDialog().setVisible(true);
}
}
else if (isStarting)
{
/* Should not happen */
Thread.dumpStack();
}
else if (isRestarting)
{
/* Should not happen */
Thread.dumpStack();
}
else
{
boolean stopServer = confirmStop();
if (stopServer)
{
isStopping = true;
lastDetail = null;
getProgressDialog().setSummary(
getFormattedSummary(INFO_SUMMARY_STOPPING.get()));
getProgressDialog().setDetails(Message.EMPTY);
serverStatusPooler.beginServerStop();
getProgressDialog().setCloseButtonEnabled(false);
getStatusPanelDialog().setStartButtonEnabled(false);
getStatusPanelDialog().setStopButtonEnabled(false);
getStatusPanelDialog().setRestartButtonEnabled(false);
getStatusPanelDialog().setAuthenticateButtonEnabled(false);
if (!getProgressDialog().isVisible())
{
getProgressDialog().pack();
Utilities.centerOnComponent(getProgressDialog(),
getStatusPanelDialog());
getProgressDialog().setVisible(true);
}
BackgroundTask task = new BackgroundTask()
{
public Object processBackgroundTask()
{
if (progressUpdater == null)
{
runProgressUpdater();
}
stopServer();
serverStatusPooler.endServerStop();
mustDisplayAuthenticateDialog = false;
return null;
}
public void backgroundTaskCompleted(Object value, Throwable t)
{
if (t != null)
{
// Bug
t.printStackTrace();
}
getStatusPanelDialog().setStartButtonEnabled(true);
getStatusPanelDialog().setStopButtonEnabled(true);
getStatusPanelDialog().setRestartButtonEnabled(true);
getStatusPanelDialog().setAuthenticateButtonEnabled(false);
getProgressDialog().setCloseButtonEnabled(true);
isStopping = false;
}
};
task.startBackgroundTask();
}
}
}
/**
* Method called when user clicks on Restart button.
* StatusPanelButtonListener implementation.
*/
public void restartClicked()
{
if (isRestarting)
{
if (!getProgressDialog().isVisible())
{
getProgressDialog().setVisible(true);
}
}
else if (isStopping)
{
/* Should not happen */
Thread.dumpStack();
}
else if (isStarting)
{
/* Should not happen */
Thread.dumpStack();
}
else
{
boolean restartServer = confirmRestart();
if (restartServer)
{
isRestarting = true;
lastDetail = null;
getProgressDialog().setSummary(
getFormattedSummary(INFO_SUMMARY_STOPPING.get()));
getProgressDialog().setDetails(Message.EMPTY);
serverStatusPooler.beginServerStop();
getProgressDialog().setCloseButtonEnabled(false);
getStatusPanelDialog().setStartButtonEnabled(false);
getStatusPanelDialog().setStopButtonEnabled(false);
getStatusPanelDialog().setRestartButtonEnabled(false);
getStatusPanelDialog().setAuthenticateButtonEnabled(false);
if (!getProgressDialog().isVisible())
{
getProgressDialog().pack();
Utilities.centerOnComponent(getProgressDialog(),
getStatusPanelDialog());
getProgressDialog().setVisible(true);
}
BackgroundTask task = new BackgroundTask()
{
public Object processBackgroundTask()
{
if (progressUpdater == null)
{
runProgressUpdater();
}
if (stopServer())
{
serverStatusPooler.endServerStop();
serverStatusPooler.beginServerStart();
mustDisplayAuthenticateDialog = startServer() &&
!isAuthenticated();
serverStatusPooler.endServerStart();
}
else
{
serverStatusPooler.endServerStop();
mustDisplayAuthenticateDialog = false;
}
return null;
}
public void backgroundTaskCompleted(Object value, Throwable t)
{
if (t != null)
{
// Bug
t.printStackTrace();
}
getStatusPanelDialog().setStartButtonEnabled(true);
getStatusPanelDialog().setStopButtonEnabled(true);
getStatusPanelDialog().setRestartButtonEnabled(true);
getStatusPanelDialog().setAuthenticateButtonEnabled(
!isAuthenticated());
getProgressDialog().setCloseButtonEnabled(true);
isRestarting = false;
}
};
task.startBackgroundTask();
}
}
}
/**
* Method called when user clicks on Authenticate button.
* StatusPanelButtonListener implementation.
*/
public void authenticateClicked()
{
getLoginDialog().pack();
Utilities.centerOnComponent(getLoginDialog(), getStatusPanelDialog());
getLoginDialog().setVisible(true);
if (!getLoginDialog().isCancelled())
{
try
{
serverStatusPooler.setAuthentication(
getLoginDialog().getDirectoryManagerDn(),
getLoginDialog().getDirectoryManagerPwd(),
trustManager);
}
catch (ConfigException ce)
{
Utilities.displayError(getLoginDialog(), ce.getMessageObject(),
INFO_ERROR_TITLE.get());
getLoginDialog().toFront();
}
}
}
/**
* A method to initialize the look and feel.
*
*/
private void initLookAndFeel()
{
UIFactory.initialize();
}
/**
* Returns the login dialog and creates it if it does not exist.
* @return the login dialog.
*/
private LoginDialog getLoginDialog()
{
if (loginDialog == null)
{
loginDialog = new LoginDialog(getStatusPanelDialog(), trustManager,
CONNECTION_POLICY);
loginDialog.setModal(true);
}
return loginDialog;
}
/**
* Returns the progress dialog and creates it if it does not exist.
* As we only can run an operation at a time (considering the nature of the
* operations we provide today) having a single progress dialog is enough.
* @return the progress dialog.
*/
private ProgressDialog getProgressDialog()
{
if (progressDialog == null)
{
progressDialog = new ProgressDialog(getStatusPanelDialog());
progressDialog.addWindowListener(new WindowAdapter()
{
public void windowClosed(WindowEvent ev)
{
if (mustDisplayAuthenticateDialog)
{
mustDisplayAuthenticateDialog = false;
authenticateClicked();
}
}
});
}
return progressDialog;
}
/**
* Returns the status panel dialog and creates it if it does not exist. This
* is the dialog that displays the status information to the user.
* @return the status panel dialog.
*/
private StatusPanelDialog getStatusPanelDialog()
{
if (controlPanelDialog == null)
{
controlPanelDialog = new StatusPanelDialog();
controlPanelDialog.addButtonListener(this);
}
return controlPanelDialog;
}
/**
* This methods starts the server and updates the progress with the start
* messages.
* @return <CODE>true</CODE> if the server started successfully and
* <CODE>false</CODE> otherwise.
*/
protected boolean startServer()
{
boolean started = false;
if (isRestarting)
{
updateProgress(
getFormattedSummary(INFO_SUMMARY_STARTING.get()),
getTaskSeparator());
}
updateProgress(
getFormattedSummary(INFO_SUMMARY_STARTING.get()),
getFormattedProgressWithLineBreak(INFO_PROGRESS_STARTING.get()));
ArrayList<String> argList = new ArrayList<String>();
Installation installation = Installation.getLocal();
argList.add(Utils.getPath(installation.getServerStartCommandFile()));
String[] args = new String[argList.size()];
argList.toArray(args);
ProcessBuilder pb = new ProcessBuilder(args);
Map<String, String> env = pb.environment();
env.put("JAVA_HOME", System.getProperty("java.home"));
/* Remove JAVA_BIN to be sure that we use the JVM running the installer
* JVM to start the server.
*/
env.remove("JAVA_BIN");
try
{
Process process = pb.start();
BufferedReader err =
new BufferedReader(new InputStreamReader(process.getErrorStream()));
BufferedReader out =
new BufferedReader(new InputStreamReader(process.getInputStream()));
/* Create these objects to resend the stop process output to the details
* area.
*/
new ProgressReader(err, true, true);
new ProgressReader(out, false, true);
int returnValue = process.waitFor();
if (returnValue == 0)
{
/*
* There are no exceptions from the readers and they are marked as
* finished. This means that the server has written in its output the
* message id informing that it started. So it seems that everything
* went fine.
*
* However we can have issues with the firewalls or do not have rights
* to connect. Just check if we can connect to the server.
* Try 5 times with an interval of 1 second between try.
*/
boolean running = false;
for (int i=0; i<5 && !running; i++)
{
running = Installation.getLocal().getStatus().isServerRunning();
}
if (!running)
{
try
{
Thread.sleep(1000);
}
catch (Throwable t)
{
}
}
if (!running)
{
updateProgress(getFormattedError(INFO_SUMMARY_START_ERROR.get()),
getFormattedError(ERR_STARTING_SERVER_GENERIC.get(),
true));
}
else
{
updateProgress(
getFormattedSuccess(INFO_SUMMARY_START_SUCCESS.get()),
Message.EMPTY);
started = true;
}
}
else
{
Message msg = INFO_ERROR_STARTING_SERVER_CODE
.get(String.valueOf(returnValue));
/*
* The return code is not the one expected, assume the server could
* not be started.
*/
updateProgress(
getFormattedError(INFO_SUMMARY_START_ERROR.get()),
msg);
}
} catch (IOException ioe)
{
Message msg =
Utils.getThrowableMsg(INFO_ERROR_STARTING_SERVER.get(), ioe);
updateProgress(
getFormattedError(INFO_SUMMARY_START_ERROR.get()),
msg);
}
catch (InterruptedException ie)
{
Message msg = Utils.getThrowableMsg(INFO_ERROR_STARTING_SERVER.get(), ie);
updateProgress(
getFormattedError(INFO_SUMMARY_START_ERROR.get()),
msg);
}
return started;
}
/**
* This methods stops the server and updates the progress with the stop
* messages.
* @return <CODE>true</CODE> if the server stopped successfully and
* <CODE>false</CODE> otherwise.
*/
private boolean stopServer()
{
boolean stopped = false;
updateProgress(
getFormattedSummary(INFO_SUMMARY_STOPPING.get()),
getFormattedProgressWithLineBreak(INFO_PROGRESS_STOPPING.get()));
ArrayList<String> argList = new ArrayList<String>();
Installation installation = Installation.getLocal();
argList.add(Utils.getPath(installation.getServerStopCommandFile()));
String[] args = new String[argList.size()];
argList.toArray(args);
ProcessBuilder pb = new ProcessBuilder(args);
Map<String, String> env = pb.environment();
env.put("JAVA_HOME", System.getProperty("java.home"));
/* Remove JAVA_BIN to be sure that we use the JVM running the uninstaller
* JVM to stop the server.
*/
env.remove("JAVA_BIN");
try
{
Process process = pb.start();
BufferedReader err =
new BufferedReader(new InputStreamReader(process.getErrorStream()));
BufferedReader out =
new BufferedReader(new InputStreamReader(process.getInputStream()));
/* Create these objects to resend the stop process output to the details
* area.
*/
new ProgressReader(err, true, false);
new ProgressReader(out, false, false);
int returnValue = process.waitFor();
int clientSideError =
org.opends.server.protocols.ldap.LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR;
if ((returnValue == clientSideError) || (returnValue == 0))
{
if (Utils.isWindows())
{
/*
* Sometimes the server keeps some locks on the files.
* TODO: remove this code once stop-ds returns properly when server
* is stopped.
*/
int nTries = 10;
for (int i=0; i<nTries && !stopped; i++)
{
stopped = !Installation.getLocal().getStatus()
.isServerRunning();
if (!stopped)
{
Message msg = new MessageBuilder(
getFormattedLog(INFO_PROGRESS_SERVER_WAITING_TO_STOP.get()))
.append(getLineBreak()).toMessage();
updateProgress(
getFormattedSummary(INFO_SUMMARY_STOPPING.get()),
msg);
try
{
Thread.sleep(5000);
}
catch (Exception ex)
{
}
}
}
if (!stopped)
{
returnValue = -1;
}
}
}
if (returnValue == clientSideError)
{
Message msg = new MessageBuilder(getLineBreak()).append(
getFormattedLog(INFO_PROGRESS_SERVER_ALREADY_STOPPED.get())).append(
getLineBreak()).toMessage();
if (!isRestarting)
{
updateProgress(
getFormattedSuccess(INFO_SUMMARY_STOP_SUCCESS.get()),
msg);
}
else
{
updateProgress(
getFormattedSummary(INFO_SUMMARY_STOP_SUCCESS.get()),
msg);
}
stopped = true;
}
else if (returnValue != 0)
{
Message msg = INFO_ERROR_STOPPING_SERVER_CODE
.get(String.valueOf(returnValue));
/*
* The return code is not the one expected, assume the server could
* not be stopped.
*/
updateProgress(
getFormattedError(INFO_SUMMARY_STOP_ERROR.get()),
msg);
}
else
{
Message msg = getFormattedLog(INFO_PROGRESS_SERVER_STOPPED.get());
if (!isRestarting)
{
updateProgress(
getFormattedSuccess(INFO_SUMMARY_STOP_SUCCESS.get()),
msg);
}
else
{
updateProgress(
getFormattedSummary(INFO_SUMMARY_STOP_SUCCESS.get()),
msg);
}
stopped = true;
}
} catch (IOException ioe)
{
Message msg = Utils.getThrowableMsg(
INFO_ERROR_STOPPING_SERVER.get(), ioe);
updateProgress(
getFormattedError(INFO_SUMMARY_STOP_ERROR.get()),
msg);
}
catch (InterruptedException ie)
{
Message msg = Utils.getThrowableMsg(INFO_ERROR_STOPPING_SERVER.get(), ie);
updateProgress(
getFormattedError(INFO_SUMMARY_STOP_ERROR.get()),
msg);
}
return stopped;
}
/**
* Updates the progress variables used to update the progress dialog during
* start/stop/restart.
*
* @param summary the summary for the start/stop/restart operation.
* @param newDetail the new detail for the start/stop/restart operation.
*/
private synchronized void updateProgress(final Message summary,
final Message newDetail)
{
if (lastDetail == null)
{
lastDetail = newDetail;
}
else
{
lastDetail = new MessageBuilder(lastDetail)
.append(newDetail).toMessage();
}
lastSummary = summary;
}
/**
* This method is used to update the progress dialog.
*
* We are receiving notifications from the installer and uninstaller (this
* class is a ProgressListener). However if we send lots of notifications
* updating the progress panel every time we get a progress update can result
* of a lot of flickering. So the idea here is to have a minimal time between
* 2 updates of the progress dialog (specified by UPDATE_PERIOD).
*/
private void runProgressUpdater()
{
progressUpdater = new Thread()
{
public void run()
{
try
{
Message lastDisplayedSummary = null;
Message lastDisplayedDetail = null;
while (true)
{
if (lastSummary != null)
{
if (lastSummary != lastDisplayedSummary)
{
lastDisplayedSummary = lastSummary;
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
getProgressDialog().setSummary(lastSummary);
}
});
}
}
if (lastDetail != null)
{
if (lastDetail != lastDisplayedDetail)
{
lastDisplayedDetail = lastDetail;
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
getProgressDialog().setDetails(lastDetail);
}
});
}
}
try
{
Thread.sleep(UPDATE_PERIOD);
} catch (Exception ex)
{
}
}
} catch (Throwable t)
{
// Bug
t.printStackTrace();
}
}
};
progressUpdater.start();
}
/**
* Returns the formatted representation of the text that is the summary of the
* installation process (the one that goes in the UI next to the progress
* bar).
* @param text the source text from which we want to get the formatted
* representation
* @return the formatted representation of an error for the given text.
*/
private Message getFormattedSummary(Message text)
{
return formatter.getFormattedSummary(text);
}
/**
* Returns the formatted representation of a success message for a given text.
* @param text the source text from which we want to get the formatted
* representation.
* @return the formatted representation of an success message for the given
* text.
*/
private Message getFormattedSuccess(Message text)
{
return formatter.getFormattedSuccess(text);
}
/**
* Returns the formatted representation of an error for a given text.
* @param text the source text from which we want to get the formatted
* representation
* @return the formatted representation of an error for the given text.
*/
private Message getFormattedError(Message text)
{
return formatter.getFormattedError(text, false);
}
/**
* Returns the formatted representation of an error for a given text.
* @param text the source text from which we want to get the formatted
* representation
* @return the formatted representation of an error for the given text.
*/
private Message getFormattedError(Message text, boolean applyMargin)
{
return formatter.getFormattedError(text, applyMargin);
}
/**
* Returns the formatted representation of a log error message for a given
* text.
* @param text the source text from which we want to get the formatted
* representation
* @return the formatted representation of a log error message for the given
* text.
*/
private Message getFormattedLogError(Message text)
{
return formatter.getFormattedLogError(text);
}
/**
* Returns the formatted representation of a log message for a given text.
* @param text the source text from which we want to get the formatted
* representation
* @return the formatted representation of a log message for the given text.
*/
private Message getFormattedLog(Message text)
{
return formatter.getFormattedLog(text);
}
/**
* Returns the line break formatted.
* @return the line break formatted.
*/
private Message getLineBreak()
{
return formatter.getLineBreak();
}
/**
* Returns the task separator formatted.
* @return the task separator formatted.
*/
private Message getTaskSeparator()
{
return formatter.getTaskSeparator();
}
/**
* Returns the formatted representation of a progress message for a given
* text with a line feed at the end.
* @param text the source text from which we want to get the formatted
* representation
* @return the formatted representation of a progress message for the given
* text.
*/
private Message getFormattedProgressWithLineBreak(Message text) {
return new MessageBuilder(text).append(getLineBreak()).toMessage();
}
/**
* This class is used to read the standard error and standard output of the
* Stop/Start process.
*
* When a new log message is found notifies the progress listeners of it. If
* an error occurs it also notifies the listeners.
*
*/
private class ProgressReader
{
private boolean isFirstLine;
private Message errorMsg;
/**
* The protected constructor.
* @param reader the BufferedReader of the stop process.
* @param isError a boolean indicating whether the BufferedReader
* corresponds to the standard error or to the standard output.
* @param isStart a boolean indicating whether we are starting or stopping
* the server.
*/
public ProgressReader(final BufferedReader reader, final boolean isError,
final boolean isStart)
{
final MessageDescriptor.Arg0 errorTag =
isError ? INFO_ERROR_READING_ERROROUTPUT :
INFO_ERROR_READING_OUTPUT;
isFirstLine = true;
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
String line = reader.readLine();
while (line != null)
{
MessageBuilder buf = new MessageBuilder();
if (!isFirstLine)
{
buf.append(formatter.getLineBreak());
}
if (isError)
{
buf.append(getFormattedLogError(Message.raw(line)));
} else
{
buf.append(getFormattedLog(Message.raw(line)));
}
Message summary = isStart?
getFormattedSummary(INFO_SUMMARY_STARTING.get()):
getFormattedSummary(INFO_SUMMARY_STOPPING.get());
updateProgress(summary, buf.toMessage());
isFirstLine = false;
line = reader.readLine();
}
} catch (IOException ioe)
{
errorMsg = Utils.getThrowableMsg(errorTag.get(), ioe);
} catch (Throwable t)
{
errorMsg = Utils.getThrowableMsg(errorTag.get(), t);
}
}
});
t.start();
}
public Message getErrorMessage()
{
return errorMsg;
}
}
/**
* Displays a confirmation dialog asking the user whether to stop the server
* or not.
* @return <CODE>true</CODE> if the server confirms that (s)he wants to stop
* the server and <CODE>false</CODE> otherwise.
*/
private boolean confirmStop()
{
return Utilities.displayConfirmation(getStatusPanelDialog(),
INFO_CONFIRM_STOP_MESSAGE.get(),
INFO_CONFIRM_STOP_TITLE.get());
}
/**
* Displays a confirmation dialog asking the user whether to restart the
* server or not.
* @return <CODE>true</CODE> if the server confirms that (s)he wants to
* restart the server and <CODE>false</CODE> otherwise.
*/
private boolean confirmRestart()
{
return Utilities.displayConfirmation(getStatusPanelDialog(),
INFO_CONFIRM_RESTART_MESSAGE.get(),
INFO_CONFIRM_RESTART_TITLE.get());
}
/**
* Returns whether the user provided LDAP authentication or not.
* @return <CODE>true</CODE> if the server provided LDAP authentication and
* <CODE>false</CODE> otherwise.
*/
private boolean isAuthenticated()
{
return serverStatusPooler.isAuthenticated();
}
}