/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2009 Sun Microsystems, Inc. */ package org.opends.quicksetup.upgrader; import org.opends.quicksetup.CliApplication; import org.opends.quicksetup.LicenseFile; import static org.opends.quicksetup.Installation.*; import static org.opends.messages.QuickSetupMessages.*; import org.opends.admin.ads.ADSContext; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.quicksetup.ReturnCode; import org.opends.quicksetup.WizardStep; import org.opends.quicksetup.ProgressStep; import org.opends.quicksetup.ApplicationException; import org.opends.quicksetup.Installation; import org.opends.quicksetup.QuickSetupLog; import org.opends.quicksetup.UserData; import org.opends.quicksetup.ButtonName; import org.opends.quicksetup.UserDataException; import org.opends.quicksetup.BuildInformation; import org.opends.quicksetup.UserInteraction; import org.opends.quicksetup.Constants; import org.opends.quicksetup.Launcher; import org.opends.quicksetup.HistoricalRecord; import org.opends.quicksetup.webstart.WebStartDownloader; import org.opends.quicksetup.util.Utils; import org.opends.quicksetup.util.ZipExtractor; import org.opends.quicksetup.util.ServerController; import org.opends.quicksetup.util.InProcessServerController; import org.opends.quicksetup.util.ServerHealthChecker; import org.opends.quicksetup.util.FileManager; import org.opends.quicksetup.util.ExternalTools; import org.opends.quicksetup.util.OperationOutput; import org.opends.quicksetup.ui.FinishedPanel; import org.opends.quicksetup.ui.GuiApplication; import org.opends.quicksetup.ui.QuickSetupDialog; import org.opends.quicksetup.ui.ProgressPanel; import org.opends.quicksetup.ui.QuickSetupStepPanel; import org.opends.quicksetup.ui.QuickSetup; import org.opends.quicksetup.ui.FieldName; import org.opends.quicksetup.upgrader.ui.UpgraderReviewPanel; import org.opends.quicksetup.upgrader.ui.WelcomePanel; import org.opends.server.tools.JavaPropertiesTool; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.Proxy; import java.net.SocketAddress; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.opends.server.util.DynamicConstants; /** * QuickSetup application of upgrading the bits of an installation of * OpenDS. */ public class Upgrader extends GuiApplication implements CliApplication { static private final Logger LOG = Logger.getLogger(Upgrader.class.getName()); /** * Passed in from the shell script if the root is known at the time * of invocation. */ static private final String SYS_PROP_INSTALL_ROOT = "org.opends.quicksetup.upgrader.Root"; /** * Passed in from the shell script if the root is known at the time * of invocation. */ static private final String SYS_PROP_INSTANCE_ROOT = "org.opends.quicksetup.upgrader.Instance"; /** * If set to true, an error is introduced during the * upgrade process for testing. */ static private final String SYS_PROP_CREATE_ERROR = "org.opends.quicksetup.upgrader.CreateError"; /** * If set to true, an error is introduced during the * upgrade verification process. */ static private final String SYS_PROP_CREATE_VERIFY_ERROR = "org.opends.quicksetup.upgrader.VerifyError"; /** * If set to true, if the upgrader encounters an error * during upgrade, the abort method that backs out * changes is made a no-op leaving the server in the * erroneous state. */ static final String SYS_PROP_NO_ABORT = "org.opends.quicksetup.upgrader.NoAbort"; // Root files that will be ignored during backup static final String[] ROOT_FILES_TO_IGNORE_DURING_BACKUP = { CHANGELOG_PATH_RELATIVE, // changelogDb DATABASES_PATH_RELATIVE, // db LOGS_PATH_RELATIVE, // logs LOCKS_PATH_RELATIVE, // locks HISTORY_PATH_RELATIVE, // history TMP_PATH_RELATIVE, // tmp INSTANCE_LOCATION_PATH_RELATIVE //instance.loc }; // Files that should be located into the install directory static final String[] ROOT_FILE_FOR_INSTALL_DIR= { "bin", "lib", "bat", "config" + File.separator + "schema", "setup", "setup.bat", "uninstall", "uninstall.bat", "install.html", "install.txt", "legal-notices", "opends_logo.png", "README", "upgrade", "upgrade.bat", "QuickSetup.app", "Uninstall.app", "tmpl_instance" }; // Files that will be ignored during backup static final String[] FILES_TO_IGNORE_DURING_BACKUP = { TOOLS_PROPERTIES, // tools.properties RELATIVE_JAVA_PROPERTIES_FILE, // java.properties ADSContext.getAdminLDIFFile() // admin-backend.ldif }; private ProgressStep currentProgressStep = UpgradeProgressStep.NOT_STARTED; /** * Assigned if an exception occurs during run(). */ private ApplicationException runError = null; /** * Assigned if a non-fatal error happened during the upgrade that the * user needs to be warned about during run(). */ private ApplicationException runWarning = null; /** * Directory where backup is kept in case the upgrade needs reversion. */ private File backupDirectory = null; /** * ID that uniquely identifieds this invocation of the Upgrader in the * historical logs. */ private Long historicalOperationId; /** * Information on the current build. */ protected BuildInformation currentVersion = null; /** * Information on the current instance. */ protected BuildInformation currentInstanceVersion = null; /** * Information on the staged build. */ private BuildInformation stagedVersion = null; /** * New OpenDS bits. */ private Installation stagedInstallation = null; // TODO: remove dead code private RemoteBuildManager remoteBuildManager = null; /** * Represents staged files for upgrade. */ private Stage stage = null; /** Set to true if the user decides to close the window while running. */ private boolean abort = false; /** * Creates a default instance. */ public Upgrader() { // Initialize the logs if necessary try { if (!QuickSetupLog.isInitialized()) QuickSetupLog.initLogFileHandler( File.createTempFile( UpgradeLauncher.LOG_FILE_PREFIX, QuickSetupLog.LOG_FILE_SUFFIX)); } catch (IOException e) { System.err.println(INFO_ERROR_INITIALIZING_LOG.get()); e.printStackTrace(); } // Get started on downloading the web start jars if (Utils.isWebStart()) { initLoader(); } final String installRootFromSystem = System.getProperty(SYS_PROP_INSTALL_ROOT); final String instanceRootFromSystem = System.getProperty(SYS_PROP_INSTANCE_ROOT); if (installRootFromSystem != null) { if (instanceRootFromSystem != null) { setInstallation(new Installation(installRootFromSystem, instanceRootFromSystem)); } else { setInstallation(new Installation(installRootFromSystem, installRootFromSystem)); } } } /** * {@inheritDoc} */ public Message getFrameTitle() { return Utils.getCustomizedObject("INFO_FRAME_UPGRADE_TITLE", INFO_FRAME_UPGRADE_TITLE.get(DynamicConstants.PRODUCT_NAME), Message.class); } /** * {@inheritDoc} */ public WizardStep getFirstWizardStep() { return UpgradeWizardStep.WELCOME; } /** * {@inheritDoc} */ public void setWizardDialogState(QuickSetupDialog dlg, UserData userData, WizardStep step) { // Set the default button for the frame if (step == UpgradeWizardStep.REVIEW) { dlg.setFocusOnButton(ButtonName.FINISH); dlg.setDefaultButton(ButtonName.FINISH); } else if (step == UpgradeWizardStep.WELCOME) { dlg.setDefaultButton(ButtonName.NEXT); dlg.setFocusOnButton(ButtonName.NEXT); } else if ((step == UpgradeWizardStep.PROGRESS) || (step == UpgradeWizardStep.FINISHED)) { dlg.setDefaultButton(ButtonName.CLOSE); dlg.setFocusOnButton(ButtonName.CLOSE); } } /** * Gets a remote build manager that this class can use to find * out about and download builds for upgrading. * * @return RemoteBuildManager to use for builds */ public RemoteBuildManager getRemoteBuildManager() { if (remoteBuildManager == null) { try { String listUrlString = System.getProperty("org.opends.quicksetup.upgrader.BuildList"); if (listUrlString == null) { listUrlString = "http://www.opends.org/upgrade-builds"; } URL buildRepo = new URL(listUrlString); // See if system properties dictate use of a proxy Proxy proxy = null; String proxyHost = System.getProperty("http.proxyHost"); String proxyPort = System.getProperty("http.proxyPort"); if (proxyHost != null && proxyPort != null) { try { SocketAddress addr = new InetSocketAddress(proxyHost, new Integer(proxyPort)); proxy = new Proxy(Proxy.Type.HTTP, addr); } catch (NumberFormatException nfe) { LOG.log(Level.INFO, "Illegal proxy port number " + proxyPort); } } remoteBuildManager = new RemoteBuildManager(this, buildRepo, proxy); } catch (MalformedURLException e) { LOG.log(Level.INFO, "", e); } } return remoteBuildManager; } /** * {@inheritDoc} */ public int getExtraDialogHeight() { // Makes dialog height same as QuickSetup return 177; } /** * {@inheritDoc} */ public String getInstallationPath() { // The upgrader runs from the bits extracted by BuildExtractor // in the staging directory. However // we still want the Installation to point at the build being // upgraded so the install path reported in [installroot]. String installationPath = System.getProperty("INSTALL_ROOT"); if (installationPath == null) { String path = Utils.getInstallPathFromClasspath(); if (path != null) { File f = new File(path); if (f.getParentFile() != null && f.getParentFile().getParentFile() != null && new File(f.getParentFile().getParentFile(), Installation.LOCKS_PATH_RELATIVE).exists()) { installationPath = Utils.getPath(f.getParentFile().getParentFile()); } else { installationPath = path; } } } return installationPath; } /** * {@inheritDoc} */ public String getInstancePath() { String installPath = getInstallationPath(); if (installPath == null) { return null; } return Utils.getInstancePathFromClasspath(installPath); } /** * {@inheritDoc} */ public ProgressStep getCurrentProgressStep() { return currentProgressStep; } /** * {@inheritDoc} */ public Integer getRatio(ProgressStep step) { return ((UpgradeProgressStep) step).getProgress(); } /** * {@inheritDoc} */ public Message getSummary(ProgressStep step) { Message txt; if (step == UpgradeProgressStep.FINISHED) { txt = getFinalSuccessMessage(); } else if (step == UpgradeProgressStep.FINISHED_CANCELED) { txt = getFinalCanceledMessage(); } else if (step == UpgradeProgressStep.FINISHED_WITH_ERRORS) { txt = getFinalErrorMessage(); } else if (step == UpgradeProgressStep.FINISHED_WITH_WARNINGS) { txt = getFinalWarningMessage(); } else { txt = (((UpgradeProgressStep) step).getSummaryMessage()); } return txt; } /** * {@inheritDoc} */ public void windowClosing(QuickSetupDialog dlg, WindowEvent evt) { if ((dlg.getDisplayedStep() == UpgradeWizardStep.PROGRESS) || (dlg.getDisplayedStep() == UpgradeWizardStep.FINISHED)) { // Simulate a close button event dlg.notifyButtonEvent(ButtonName.CLOSE); } else { // Simulate a quit button event dlg.notifyButtonEvent(ButtonName.QUIT); } } /** * Returns the progress message for a given progress step. * @param step the progress step. * @return the progress message for the provided step. */ private Message getLogMsg(UpgradeProgressStep step) { Message txt; if (step == UpgradeProgressStep.FINISHED) { txt = getFinalSuccessMessage(); } else if (step == UpgradeProgressStep.FINISHED_CANCELED) { txt = getFinalCanceledMessage(); } else if (step == UpgradeProgressStep.FINISHED_WITH_ERRORS) { txt = getFinalErrorMessage(); } else if (step == UpgradeProgressStep.FINISHED_WITH_WARNINGS) { txt = getFinalWarningMessage(); } else { txt = step.getLogMsg(isVerbose()); } return txt; } /** * {@inheritDoc} */ public ButtonName getInitialFocusButtonName() { // TODO return null; } /** * {@inheritDoc} */ public Set getWizardSteps() { return Collections.unmodifiableSet(EnumSet.allOf(UpgradeWizardStep.class)); } /** * {@inheritDoc} */ public QuickSetupStepPanel createWizardStepPanel(WizardStep step) { QuickSetupStepPanel pnl = null; if (UpgradeWizardStep.WELCOME.equals(step)) { pnl = new WelcomePanel(this); } else if (UpgradeWizardStep.REVIEW.equals(step)) { pnl = new UpgraderReviewPanel(this); } else if (UpgradeWizardStep.PROGRESS.equals(step)) { pnl = new ProgressPanel(this); } else if (UpgradeWizardStep.FINISHED.equals(step)) { pnl = new FinishedPanel(this); } return pnl; } /** * {@inheritDoc} */ public WizardStep getNextWizardStep(WizardStep step) { WizardStep next = null; if (UpgradeWizardStep.WELCOME.equals(step)) { next = UpgradeWizardStep.REVIEW; } else if (UpgradeWizardStep.REVIEW.equals(step)) { next = UpgradeWizardStep.PROGRESS; } else if (UpgradeWizardStep.PROGRESS.equals(step)) { next = UpgradeWizardStep.FINISHED; } return next; } /** * {@inheritDoc} */ public WizardStep getPreviousWizardStep(WizardStep step) { WizardStep prev = null; if (UpgradeWizardStep.FINISHED.equals(step)) { prev = UpgradeWizardStep.PROGRESS; } else if (UpgradeWizardStep.PROGRESS.equals(step)) { prev = UpgradeWizardStep.REVIEW; } else if (UpgradeWizardStep.REVIEW.equals(step)) { prev = UpgradeWizardStep.WELCOME; } return prev; } /** * {@inheritDoc} */ public WizardStep getFinishedStep() { return UpgradeWizardStep.FINISHED; } /** * {@inheritDoc} */ public boolean canQuit(WizardStep step) { return UpgradeWizardStep.WELCOME == step || UpgradeWizardStep.REVIEW == step; } /** * {@inheritDoc} */ public Message getFinishButtonToolTip() { return INFO_FINISH_BUTTON_UPGRADE_TOOLTIP.get(); } /** * {@inheritDoc} */ public Message getQuitButtonToolTip() { return INFO_QUIT_BUTTON_UPGRADE_TOOLTIP.get(); } /** * {@inheritDoc} */ public void cancel() { // The run() method checks that status of this variable // occasionally and aborts the operation if it discovers // a 'true' value. abort = true; } /** * {@inheritDoc} */ public boolean confirmCancel(QuickSetup qs) { return qs.displayConfirmation( INFO_CONFIRM_CANCEL_UPGRADE_MSG.get(), INFO_CONFIRM_CANCEL_UPGRADE_TITLE.get()); } /** * {@inheritDoc} */ public boolean isFinished() { return getCurrentProgressStep() == UpgradeProgressStep.FINISHED || getCurrentProgressStep() == UpgradeProgressStep.FINISHED_WITH_ERRORS || getCurrentProgressStep() == UpgradeProgressStep.FINISHED_WITH_WARNINGS || getCurrentProgressStep() == UpgradeProgressStep.FINISHED_CANCELED; } /** * {@inheritDoc} */ public boolean isCancellable() { return true; } /** * {@inheritDoc} */ public void quitClicked(WizardStep cStep, final QuickSetup qs) { if (cStep == UpgradeWizardStep.PROGRESS) { throw new IllegalStateException( "Cannot click on quit from progress step"); } else if (isFinished()) { qs.quit(); } else if (qs.displayConfirmation( INFO_CONFIRM_QUIT_UPGRADE_MSG.get(), INFO_CONFIRM_QUIT_UPGRADE_TITLE.get())) { qs.quit(); } } /** * {@inheritDoc} */ public void updateUserData(WizardStep cStep, QuickSetup qs) throws UserDataException { List errorMsgs = new ArrayList(); UpgradeUserData uud = getUpgradeUserData(); if (cStep == UpgradeWizardStep.WELCOME) { // User can only select the installation to upgrade // in the webstart version of this tool. Otherwise // the fields are readonly. if (Utils.isWebStart()) { String serverLocationString = qs.getFieldStringValue(FieldName.SERVER_TO_UPGRADE_LOCATION); if ((serverLocationString == null) || ("".equals(serverLocationString.trim()))) { errorMsgs.add(INFO_EMPTY_SERVER_LOCATION.get()); qs.displayFieldInvalid(FieldName.SERVER_TO_UPGRADE_LOCATION, true); } else { try { File serverLocation = new File(serverLocationString); Installation.validateRootDirectory(serverLocation); // If we get here the value is acceptable and not null Installation currentInstallation = getInstallation(); if (currentInstallation == null || !serverLocation.equals(getInstallation().getRootDirectory())) { LOG.log(Level.INFO, "user changed server root from " + (currentInstallation == null ? "'null'" : currentInstallation.getRootDirectory()) + " to " + serverLocation); Installation installation = new Installation(serverLocation, serverLocation); setInstallation(installation); try { // Try to see if there is a problem with the build information, // we might be trying to do the upgrade with a JVM that is not // compatible with the java arguments used by the server // scripts (see issue ). installation.getBuildInformation(true); } catch (ApplicationException ae) { if (ae.getMessageObject().getDescriptor().equals( INFO_ERROR_CREATING_BUILD_INFO_MSG)) { // This is the message thrown when there was a problem with // the binary. The details content is on the scripts and not // localized, we can assume that if there is a mention to // OPENDS_JAVA_HOME in the message there is an error with the // script. if (ae.getMessageObject().toString().indexOf( "OPENDS_JAVA_HOME") != -1) { String javaBin = System.getProperty("java.home")+ File.separator+ "bin"+File.separator+"java"; String setJavaHome = installation.getSetJavaHomeFile().getAbsolutePath(); String dsJavaProperties = installation.getJavaPropertiesCommandFile(). getAbsolutePath(); errorMsgs.add(ERR_INVALID_JAVA_ARGS.get( serverLocationString, javaBin, setJavaHome, dsJavaProperties)); } } } } uud.setServerLocation(serverLocationString); qs.displayFieldInvalid(FieldName.SERVER_TO_UPGRADE_LOCATION, false); } catch (IllegalArgumentException iae) { LOG.log(Level.INFO, "illegal OpenDS installation directory selected", iae); errorMsgs.add(INFO_ERROR_INVALID_SERVER_LOCATION.get( serverLocationString)); qs.displayFieldInvalid(FieldName.SERVER_TO_UPGRADE_LOCATION, true); } } } else { // do nothing; all fields are read-only } } else if (cStep == UpgradeWizardStep.REVIEW) { Boolean startServer = (Boolean) qs.getFieldValue(FieldName.SERVER_START_UPGRADER); uud.setStartServer(startServer); } if (errorMsgs.size() > 0) { throw new UserDataException(UpgradeWizardStep.WELCOME, Utils.getMessageFromCollection(errorMsgs, "\n")); } } /** * {@inheritDoc} */ public void previousClicked(WizardStep cStep, QuickSetup qs) { } /** * {@inheritDoc} */ public boolean finishClicked(final WizardStep cStep, final QuickSetup qs) { return true; } /** * {@inheritDoc} */ public void nextClicked(WizardStep cStep, QuickSetup qs) { } /** * {@inheritDoc} */ public boolean canFinish(WizardStep step) { return UpgradeWizardStep.REVIEW.equals(step); } /** * {@inheritDoc} */ public boolean canGoBack(WizardStep step) { return super.canGoBack(step) && !step.equals(UpgradeWizardStep.PROGRESS) && !step.equals(UpgradeWizardStep.FINISHED); } /** * {@inheritDoc} */ public void run() { // Reset exception just in case this application is rerun // for some reason runError = null; try { if (Utils.isWebStart()) { ZipExtractor extractor; setCurrentProgressStep(UpgradeProgressStep.DOWNLOADING); try { LOG.log(Level.INFO, "Waiting for Java Web Start jar download"); waitForLoader(UpgradeProgressStep.EXTRACTING.getProgress()); LOG.log(Level.INFO, "Downloaded build file"); String zipName = WebStartDownloader.getZipFileName(); InputStream in = Upgrader.class.getClassLoader().getResourceAsStream(zipName); extractor = new ZipExtractor(in, UpgradeProgressStep.EXTRACTING.getProgress(), UpgradeProgressStep.INITIALIZING.getProgress(), Utils.getNumberZipEntries(), zipName, this); } catch (ApplicationException e) { LOG.log(Level.SEVERE, "Error downloading Web Start jars", e); throw e; } notifyListeners(getFormattedDoneWithLineBreak()); checkAbort(); try { setCurrentProgressStep(UpgradeProgressStep.EXTRACTING); if (isVerbose()) { notifyListeners(getLineBreak()); } extractor.extract(getStageDirectory()); if (!isVerbose()) { notifyListeners(getFormattedDoneWithLineBreak()); } else { notifyListeners(getLineBreak()); } LOG.log(Level.INFO, "extraction finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error extracting build file", e); throw e; } } checkAbort(); // Check license if (!LicenseFile.isAlreadyApproved()) { String currentInstallRoot = System.getProperty("INSTALL_ROOT"); System.setProperty("INSTALL_ROOT", getStageDirectory().getAbsolutePath()); if (LicenseFile.exists()) { String licenseString = LicenseFile.getText(); System.out.println(licenseString); if (getUserData().isInteractive()) { // If the user asks for no-prompt. We just display the license text. // User doesn't asks for no-prompt. We just display the license text // and force to accept it. String yes = INFO_LICENSE_CLI_ACCEPT_YES.get().toString(); String no = INFO_LICENSE_CLI_ACCEPT_NO.get().toString(); System.out.println(INFO_LICENSE_DETAILS_CLI_LABEL.get().toString()); BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); while (true) { System.out.print(INFO_LICENSE_CLI_ACCEPT_QUESTION .get(yes, no, no).toString()); try { String response = in.readLine(); if ((response == null) || (response.toLowerCase().equals(no.toLowerCase())) || (response.length() == 0)) { System.exit(ReturnCode.CANCELED.getReturnCode()); } else if (response.toLowerCase().equals(yes.toLowerCase())) { // create the file LicenseFile.setApproval(true); LicenseFile.createFileLicenseApproved(); break; } else { System.out.println(INFO_LICENSE_CLI_ACCEPT_INVALID_RESPONSE .get().toString()); } } catch (IOException e) { System.out.println(INFO_LICENSE_CLI_ACCEPT_INVALID_RESPONSE .get().toString()); } } } } if (currentInstallRoot != null) { System.setProperty("INSTALL_ROOT", currentInstallRoot); } else { System.clearProperty("INSTALL_ROOT"); } } if (!Utils.isWebStart()) { // The command-line upgrade has not the option of leaving the server // started or stopped, so we must leave it as it was at the beginning of // the upgrade. getUserData().setStartServer( getInstallation().getStatus().isServerRunning()); } try { LOG.log(Level.INFO, "initializing upgrade"); setCurrentProgressStep(UpgradeProgressStep.INITIALIZING); initialize(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "initialization finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error initializing upgrader", e); throw e; } checkAbort(); MigrationManager migration = new MigrationManager(getInstallation(), getUpgradeBackupDirectory(), userInteraction()); try { LOG.log(Level.INFO, "checking for schema customizations"); setCurrentProgressStep( UpgradeProgressStep.CALCULATING_SCHEMA_CUSTOMIZATIONS); migration.calculateSchemaCustomizations(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "check for schema customizations finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error calculating schema customizations", e); throw e; } checkAbort(); try { LOG.log(Level.INFO, "checking for config customizations"); setCurrentProgressStep( UpgradeProgressStep.CALCULATING_CONFIGURATION_CUSTOMIZATIONS); migration.calculateConfigCustomizations(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "check for config customizations finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error calculating config customizations", e); throw e; } checkAbort(); if (getUpgradeUserData().getPerformDatabaseBackup()) { try { LOG.log(Level.INFO, "backing up databases"); setCurrentProgressStep(UpgradeProgressStep.BACKING_UP_DATABASES); backupDatabases(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "database backup finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error backing up databases", e); throw e; } } checkAbort(); try { LOG.log(Level.INFO, "backing up filesystem"); setCurrentProgressStep(UpgradeProgressStep.BACKING_UP_FILESYSTEM); backupFilesystem(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "filesystem backup finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error backing up files", e); throw e; } checkAbort(); try { LOG.log(Level.INFO, "upgrading components"); setCurrentProgressStep( UpgradeProgressStep.UPGRADING_COMPONENTS); upgradeComponents(); updateConfigDirectory(); updateExtensionsDirectory(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "component upgrade finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error upgrading components", e); throw e; } checkAbort(); //******************************************** //* The two steps following this step require //* the server to be started 'in process'. // ******************************************* LOG.log(Level.INFO, "schema customization " + (migration.isSchemaCustomized() ? "":"not ") + "present"); LOG.log(Level.INFO, "config customization " + (migration.isConfigurationCustomized() ? "":"not ") + "present"); if (migration.isSchemaCustomized() || migration.isConfigurationCustomized()) { try { LOG.log(Level.INFO, "starting server"); setCurrentProgressStep( UpgradeProgressStep.PREPARING_CUSTOMIZATIONS); InProcessServerController ipsc = new InProcessServerController(getInstallation()); InProcessServerController.disableConnectionHandlers(true); InProcessServerController.disableAdminDataSynchronization(true); InProcessServerController.disableSynchronization(true); ipsc.startServer(); LOG.log(Level.INFO, "start server finished"); notifyListeners(getFormattedDoneWithLineBreak()); } catch (Exception e) { LOG.log(Level.INFO, "Error starting server in order to apply custom" + "schema and/or configuration", e); throw new ApplicationException( ReturnCode.APPLICATION_ERROR, INFO_ERROR_STARTING_SERVER.get(), e); } checkAbort(); if (migration.isSchemaCustomized()) { try { LOG.log(Level.INFO, "Applying schema customizations"); setCurrentProgressStep( UpgradeProgressStep.APPLYING_SCHEMA_CUSTOMIZATIONS); migration.migrateSchema(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "custom schema application finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error applying schema customizations", e); throw e; } } checkAbort(); if (migration.isConfigurationCustomized()) { try { LOG.log(Level.INFO, "Applying config customizations"); setCurrentProgressStep( UpgradeProgressStep.APPLYING_CONFIGURATION_CUSTOMIZATIONS); migration.migrateConfiguration(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "custom config application finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error applying configuration customizations", e); throw e; } } checkAbort(); if (migration.mustMigrateADS()) { try { LOG.log(Level.INFO, "Applying registration changes"); if (isVerbose()) { setCurrentProgressStep( UpgradeProgressStep.APPLYING_ADS_CUSTOMIZATIONS); } migration.migrateADS( getStagedInstallation().getADSBackendFile()); if (isVerbose()) { notifyListeners(getFormattedDone()); } LOG.log(Level.INFO, "custom registration application finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error applying registration customizations", e); throw e; } } checkAbort(); if (migration.mustMigrateToolProperties()) { try { LOG.log(Level.INFO, "Applying tools properties"); migration.migrateToolPropertiesFile( getStagedInstallation().getToolsPropertiesFile()); LOG.log(Level.INFO, "tools properties application finished"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error applying tools properties changes", e); throw e; } } if (migration.mustRunDSJavaProperties()) { try { LOG.log(Level.INFO, "Upgrading script with java properties"); // Launch the script String propertiesFile = new File( getInstallation().getConfigurationDirectory(), Installation.DEFAULT_JAVA_PROPERTIES_FILE).getAbsolutePath(); String setJavaFile = getInstallation().getSetJavaHomeFile().getAbsolutePath(); String[] args = { "--propertiesFile", propertiesFile, "--destinationFile", setJavaFile, "--quiet" }; int returnValue = JavaPropertiesTool.mainCLI(args); if ((returnValue != JavaPropertiesTool.ErrorReturnCode.SUCCESSFUL.getReturnCode()) && returnValue != JavaPropertiesTool.ErrorReturnCode.SUCCESSFUL_NOP.getReturnCode()) { throw new ApplicationException(ReturnCode.APPLICATION_ERROR, ERR_ERROR_CREATING_JAVA_HOME_SCRIPTS.get(returnValue), null); } LOG.log(Level.INFO, "scripts successfully upgraded"); } catch (ApplicationException e) { LOG.log(Level.INFO, "Error upgrading scripts", e); throw e; } } checkAbort(); try { LOG.log(Level.INFO, "stopping server"); // This class imports classes from the server if (isVerbose()) { notifyListeners(INFO_PROGRESS_UPGRADE_INTERNAL_STOP.get()); } new InProcessServerController( getInstallation()).stopServer(); InProcessServerController.disableConnectionHandlers(false); if (isVerbose()) { notifyListeners(getFormattedDone()); } LOG.log(Level.INFO, "server stopped"); } catch (Throwable t) { LOG.log(Level.INFO, "Error stopping server", t); throw new ApplicationException(ReturnCode.BUG, INFO_ERROR_STOPPING_SERVER.get(), t); } } checkAbort(); // This allows you to test whether or not he upgrader can successfully // abort an upgrade once changes have been made to the installation // path's filesystem. if ("true".equals( System.getProperty(SYS_PROP_CREATE_ERROR))) { LOG.log(Level.WARNING, "creating artificial error"); throw new ApplicationException( null, INFO_ERROR_ARTIFICIAL.get(), null); } List errors; try { LOG.log(Level.INFO, "verifying upgrade"); setCurrentProgressStep(UpgradeProgressStep.VERIFYING); Installation installation = getInstallation(); ServerHealthChecker healthChecker = new ServerHealthChecker(installation); healthChecker.checkServer(); errors = healthChecker.getProblemMessages(); } catch (Exception e) { LOG.log(Level.INFO, "error performing server health check", e); throw e; } // For testing if ("true".equals( System.getProperty(SYS_PROP_CREATE_VERIFY_ERROR))) { LOG.log(Level.WARNING, "creating artificial verification error"); if (errors == null || errors.size() == 0) { errors = new ArrayList(); errors.add(Message.raw("Artificial verification error for testing")); } } if (errors != null && errors.size() > 0) { notifyListeners(getFormattedErrorWithLineBreak()); Message formattedDetails = Utils.listToMessage(errors, Constants.LINE_SEPARATOR, /*bullet=*/"\u2022 ", ""); ApplicationException ae = new ApplicationException( ReturnCode.APPLICATION_ERROR, INFO_ERROR_UPGRADED_SERVER_STARTS_WITH_ERRORS.get( Constants.LINE_SEPARATOR + formattedDetails), null); UserInteraction ui = userInteraction(); if (ui != null) { // We are about to present the problems with the upgrade to the // user and ask if they would like to continue. Regardless of // whether or not they continue at this point, since they will // have seen the errors we consider the errors as warnings. runWarning = ae; // Ask the user if they would like to continue. Message cancel = INFO_UPGRADE_VERIFICATION_FAILURE_CANCEL.get(); if (cancel.equals(ui.confirm( INFO_UPGRADE_VERIFICATION_FAILURE_TITLE.get(), INFO_UPGRADE_VERIFICATION_FAILURE_PROMPT.get(), formattedDetails, INFO_UPGRADE_VERIFICATION_FAILURE_TITLE.get(), UserInteraction.MessageType.ERROR, new Message[]{INFO_CONTINUE_BUTTON_LABEL.get(), cancel}, cancel, INFO_UPGRADE_VERIFICATION_FAILURE_VIEW_DETAILS.get()))) { // User indicated cancel cancel(); checkAbort(); } else { // User wants to continue; nothing to do } } else { // We can't ask the user if they want to continue so we // just bail on the upgrade by throwing an exception which // will cause upgrader to exit unsuccessfully throw ae; } } else { notifyListeners(getFormattedDoneWithLineBreak()); } LOG.log(Level.INFO, "upgrade verification complete"); // Leave the server in the state requested by the user via the // checkbox on the review panel. The upgrade has already been // verified at this point to in the unlikely event of an error, // we call this a warning instead of an error. try { ServerController control = new ServerController(getInstallation()); boolean serverRunning = getInstallation().getStatus().isServerRunning(); boolean userRequestsStart = getUserData().getStartServer(); if (userRequestsStart && !serverRunning) { try { LOG.log(Level.INFO, "starting server"); setCurrentProgressStep(UpgradeProgressStep.STARTING_SERVER); if (isVerbose()) { notifyListeners(getTaskSeparator()); } else { notifyListeners(getFormattedWithPoints( INFO_PROGRESS_STARTING_NON_VERBOSE.get())); } int port = getInstallation().getCurrentConfiguration().getPort(); if (port != -1 && !Utils.canUseAsPort(port)) { throw new ApplicationException( ReturnCode.APPLICATION_ERROR, INFO_ERROR_PORT_IN_USE.get(Integer.toString(port)), null); } control.startServer(!isVerbose()); if (!isVerbose()) { notifyListeners(getFormattedDoneWithLineBreak()); } else { notifyListeners(getLineBreak()); } } catch (ApplicationException e) { if (isVerbose()) { notifyListeners(getLineBreak()); } notifyListeners(getFormattedErrorWithLineBreak()); LOG.log(Level.INFO, "error starting server"); this.runWarning = e; } } else if (!userRequestsStart && serverRunning) { try { LOG.log(Level.INFO, "stopping server"); if (isVerbose()) { notifyListeners(getTaskSeparator()); } else { notifyListeners(getFormattedWithPoints( INFO_PROGRESS_STOPPING_NON_VERBOSE.get())); } setCurrentProgressStep(UpgradeProgressStep.STOPPING_SERVER); control.stopServer(!isVerbose()); if (!isVerbose()) { notifyListeners(getFormattedDoneWithLineBreak()); } else { notifyListeners(getLineBreak()); } } catch (ApplicationException e) { if (isVerbose()) { notifyListeners(getLineBreak()); } notifyListeners(getFormattedErrorWithLineBreak()); LOG.log(Level.INFO, "error stopping server"); this.runWarning = e; } } } catch (IOException ioe) { LOG.log(Level.INFO, "error determining if server running"); this.runWarning = new ApplicationException( ReturnCode.TOOL_ERROR, INFO_ERROR_SERVER_STATUS.get(), ioe); } } catch (ApplicationException ae) { // We don't consider a user cancelation exception // to be an error. if (ae.getType() != ReturnCode.CANCELED) { this.runError = ae; } else { this.abort = true; } } catch (Throwable t) { this.runError = new ApplicationException(ReturnCode.BUG, INFO_BUG_MSG.get(), t); } finally { try { HistoricalRecord.Status status; String note = null; if (runError == null && !abort) { status = HistoricalRecord.Status.SUCCESS; backupWindowsUpgradeFile(); } else { if (abort) { status = HistoricalRecord.Status.CANCEL; } else { status = HistoricalRecord.Status.FAILURE; note = runError.getLocalizedMessage(); } if (runError != null) { notifyListeners(getFormattedErrorWithLineBreak()); Message msg; if (runError.getCause() != null) { msg = getFormattedError( Utils.getThrowableMsg(runError.getMessageObject(), runError.getCause()), true); } else { msg = getFormattedError(runError, true); } notifyListeners(msg); if (Utils.isCli()) { notifyListeners(getLineBreak()); notifyListeners(getLineBreak()); } } // Abort the upgrade and put things back like we found it LOG.log(Level.INFO, "canceling upgrade"); ProgressStep lastProgressStep = getCurrentProgressStep(); setCurrentProgressStep(UpgradeProgressStep.ABORT); abort(lastProgressStep); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "cancelation complete"); } LOG.log(Level.INFO, "cleaning up after upgrade"); setCurrentProgressStep(UpgradeProgressStep.CLEANUP); cleanup(); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "clean up complete"); // Write a record in the log file indicating success/failure LOG.log(Level.INFO, "recording upgrade history"); setCurrentProgressStep(UpgradeProgressStep.RECORDING_HISTORY); writeHistoricalRecord(historicalOperationId, getCurrentBuildInformation(), getStagedBuildInformation(), status, note); notifyListeners(getFormattedDoneWithLineBreak()); LOG.log(Level.INFO, "history recorded"); notifyListeners( new MessageBuilder().append( INFO_GENERAL_SEE_FOR_HISTORY.get( Utils.getPath(getInstallation().getHistoryLogFile()))) .append(formatter.getLineBreak()) .toMessage()); try { Stage stage = getStage(); List stageMessages = stage.getMessages(); for (Message m : stageMessages) { notifyListeners(m); } } catch (IOException e) { LOG.log(Level.INFO, "failed to access stage", e); } } catch (ApplicationException e) { notifyListeners(getFormattedErrorWithLineBreak()); Message msg; if (e.getCause() != null) { msg = getFormattedError( Utils.getThrowableMsg(e.getMessageObject(), e.getCause()), true); } else { msg = getFormattedError(e, true); } notifyListeners(msg); if (Utils.isCli()) { notifyListeners(getLineBreak()); } LOG.log(Level.INFO, "Error cleaning up after upgrade.", e); } // Decide final status based on presence of error // WARNING: change this code at your own risk! The ordering // of these statements is important. There are differences // in how the CLI and GUI application's processes exit. // Changing the ordering here may result in messages being // skipped because the process has already exited by the time // processing messages has finished. Need to resolve these // issues. if (abort) { LOG.log(Level.INFO, "upgrade canceled by user"); if (!Utils.isCli()) { notifyListenersOfLog(); this.currentProgressStep = UpgradeProgressStep.FINISHED_CANCELED; notifyListeners(null); } else { setCurrentProgressStep(UpgradeProgressStep.FINISHED_CANCELED); notifyListeners(getLineBreak()); } } else if (runError != null) { LOG.log(Level.INFO, "upgrade completed with errors", runError); if (!Utils.isCli()) { notifyListenersOfLog(); this.currentProgressStep = UpgradeProgressStep.FINISHED_WITH_ERRORS; } else { setCurrentProgressStep(UpgradeProgressStep.FINISHED_WITH_ERRORS); notifyListeners(getLineBreak()); } } else if (runWarning != null) { LOG.log(Level.INFO, "upgrade completed with warnings"); Message warningText = runWarning.getMessageObject(); // By design, the warnings are written as errors to the details section // as errors. Warning markup is used surrounding the main message // at the end of progress. if (!Utils.isCli()) { notifyListenersOfLog(); this.currentProgressStep = UpgradeProgressStep.FINISHED_WITH_WARNINGS; notifyListeners(getFormattedError(warningText, true)); } else { notifyListeners(getFormattedErrorWithLineBreak(warningText, true)); notifyListeners(getLineBreak()); setCurrentProgressStep(UpgradeProgressStep.FINISHED_WITH_WARNINGS); notifyListeners(getLineBreak()); } } else { LOG.log(Level.INFO, "upgrade completed successfully"); if (!Utils.isCli()) { notifyListenersOfLog(); this.currentProgressStep = UpgradeProgressStep.FINISHED; notifyListeners(null); } else { setCurrentProgressStep(UpgradeProgressStep.FINISHED); notifyListeners(getLineBreak()); } } } } /** * Checks the value of aborted field and throws an * ApplicationException if true. This indicates that the user has * aborted this operation and the process of aborting should begin * as soon as possible. * * @throws ApplicationException thrown if aborted */ public void checkAbort() throws ApplicationException { if (abort) throw new ApplicationException( ReturnCode.CANCELED, INFO_UPGRADE_CANCELED.get(), null); } /** * Abort this upgrade and repair the installation. * * @param lastStep ProgressStep indicating how much work we will have to * do to get the installation back like we left it * @throws ApplicationException of something goes wrong */ private void abort(ProgressStep lastStep) throws ApplicationException { // This can be used to bypass the aborted upgrade cleanup // process so that an autopsy can be performed on the // crippled server. if ("true".equals(System.getProperty(SYS_PROP_NO_ABORT))) { return; } UpgradeProgressStep lastUpgradeStep = (UpgradeProgressStep) lastStep; EnumSet stepsStarted = EnumSet.range(UpgradeProgressStep.NOT_STARTED, lastUpgradeStep); if (stepsStarted.contains(UpgradeProgressStep.BACKING_UP_FILESYSTEM)) { // Files were copied from the stage directory to the current // directory. Repair things by overwriting file in the // root with those that were copied to the backup directory // during backupFiles() File root = getInstallation().getRootDirectory(); File backupDirectory; try { backupDirectory = getFilesInstallBackupDirectory(); FileManager fm = new FileManager(); boolean restoreError = false; for (String fileName : backupDirectory.list()) { File f = new File(backupDirectory, fileName); // Do our best to restore the filesystem like // we found it. Just report potential problems // to the user. try { fm.move(f, root, null); } catch (Throwable t) { restoreError = true; notifyListeners(INFO_ERROR_RESTORING_FILE.get(Utils.getPath(f), Utils.getPath(root))); } } if (!restoreError) { fm.deleteRecursively(backupDirectory); } if (! instanceAndInstallInSameDir()) { root = getInstallation().getInstanceDirectory(); backupDirectory = getFilesInstanceBackupDirectory(); fm = new FileManager(); for (String fileName : backupDirectory.list()) { File f = new File(backupDirectory, fileName); // Do our best to restore the filesystem like // we found it. Just report potential problems // to the user. try { fm.move(f, root, null); } catch (Throwable t) { restoreError = true; notifyListeners(INFO_ERROR_RESTORING_FILE.get(Utils.getPath(f), Utils.getPath(root))); } } if (!restoreError) { fm.deleteRecursively(backupDirectory); } } // Restart the server after putting the files // back like we found them. ServerController sc = new ServerController(getInstallation()); sc.stopServer(true); sc.startServer(true); } catch (IOException e) { LOG.log(Level.INFO, "Error getting backup directory", e); } } } /** * Returns the directory used to stage files for upgrade or reversion. * @return the directory used to stage files for upgrade or reversion * @throws IOException if errors occurs while accessing stage files * @throws org.opends.quicksetup.ApplicationException * if retrieval of stage files path fails */ protected Stage getStage() throws IOException, ApplicationException { if (this.stage == null) { this.stage = new Stage(getStageDirectory()); } return this.stage; } /** * Upgrade components. * @throws ApplicationException if upgrade fails */ protected void upgradeComponents() throws ApplicationException { try { Stage stage = getStage(); Installation installation = getInstallation(); File root = installation.getRootDirectory(); if (instanceAndInstallInSameDir()) { stage.move(root, new UpgradeFileFilter(getStageDirectory())); } else { stage.move(root, new UpgradeFileFilter(getStageDirectory(),true)); root = installation.getInstanceDirectory(); stage.move(root, new UpgradeFileFilter(getStageDirectory(),false)); } // Check if instance.loc exits File instanceFile = new File (installation.getRootDirectory(), Installation.INSTANCE_LOCATION_PATH_RELATIVE); if (! instanceFile.exists()) { BufferedWriter instanceLoc = new BufferedWriter(new FileWriter(instanceFile)); instanceLoc.append( installation.getInstanceDirectory().getAbsolutePath()); instanceLoc.close(); } // The bits should now be of the new version. Have // the installation update the build information so // that it is correct. LOG.log(Level.INFO, "upgraded bits to " + installation.getBuildInformation(false)); } catch (IOException e) { throw ApplicationException.createFileSystemException( INFO_ERROR_UPGRADING_COMPONENTS.get(), e); } } private void updateConfigDirectory() throws IOException,ApplicationException { // The config directory may contain files that are needed // by the new installation (e.g. SSL config files and tasks) File oldInstallConfigDir = new File(getFilesInstallBackupDirectory(), Installation.CONFIG_PATH_RELATIVE); File oldInstanceConfigDir = new File(getFilesInstanceBackupDirectory(), Installation.CONFIG_PATH_RELATIVE); File newInstallConfigDir = getInstallation().getInstallConfigurationDirectory(); File newInstanceConfigDir = getInstallation().getConfigurationDirectory(); FileManager fm = new FileManager(); // Define a filter for files that we don't want to copy over // from the old config directory. { final File oldConfigUpgradeDir = new File(oldInstallConfigDir, "upgrade"); final File oldConfigSchemaDir = new File(oldInstallConfigDir, "schema"); FileFilter filter = new FileFilter() { public boolean accept(File f) { return !Utils.isDescendant(f, oldConfigUpgradeDir) && !Utils.isDescendant(f, oldConfigSchemaDir); } }; fm.synchronize(oldInstallConfigDir, newInstallConfigDir, filter); } { final File oldConfigUpgradeDir = new File(oldInstanceConfigDir, "upgrade"); FileFilter filter = new FileFilter() { public boolean accept(File f) { return !Utils.isDescendant(f, oldConfigUpgradeDir); } }; fm.synchronize(oldInstanceConfigDir, newInstanceConfigDir, filter); } } private void updateExtensionsDirectory() throws IOException,ApplicationException { // Get extensions back File savedDir = new File(getFilesInstanceBackupDirectory(), Installation.LIBRARIES_PATH_RELATIVE); File destDir = getInstallation().getInstanceDirectory(); FileManager fm = new FileManager(); fm.copyRecursively(savedDir, destDir); // Get classes back savedDir = new File(getFilesInstanceBackupDirectory(), Installation.CLASSES_PATH_RELATIVE); destDir = getInstallation().getInstanceDirectory(); fm.copyRecursively(savedDir, destDir); } /** * Backup files to be able to revert if upgrdae fails. * @throws ApplicationException if backup fails */ protected void backupFilesystem() throws ApplicationException { try { // Backup first install (potentially everything if install and instance // are in the same dir File filesBackupDirectory = getFilesInstallBackupDirectory(); FileManager fm = new FileManager(); File root = getInstallation().getRootDirectory(); FileFilter filter = new UpgradeFileFilter(root); for (String fileName : root.list()) { File f = new File(root, fileName); // Replacing a Windows bat file while it is running with a different // version leads to unpredictable behavior so we make a special case // here and during the upgrade components step. This file will only // be backed up at the end of the process if everything went fine. if (Utils.isWindows() && fileName.equals(Installation.WINDOWS_UPGRADE_FILE_NAME)) { continue; } fm.move(f, filesBackupDirectory, filter); } if (!instanceAndInstallInSameDir()) { filesBackupDirectory = getFilesInstanceBackupDirectory(); root = getInstallation().getInstanceDirectory(); filter = new UpgradeFileFilter(root); for (String fileName : root.list()) { File f = new File(root, fileName); // Replacing a Windows bat file while it is running with a different // version leads to unpredictable behavior so we make a special case // here and during the upgrade components step. This file will only // be backed up at the end of the process if everything went fine. if (Utils.isWindows() && fileName.equals(Installation.WINDOWS_UPGRADE_FILE_NAME)) { continue; } fm.move(f, filesBackupDirectory, filter); } } } catch (ApplicationException ae) { throw ae; } catch (Exception e) { throw new ApplicationException( ReturnCode.FILE_SYSTEM_ACCESS_ERROR, INFO_ERROR_BACKUP_FILESYSTEM.get(), e); } } /** * This method is called at the end of the upgrade process if everything went * fine since the reverter requires to have the upgrade file to properly * complete (see issue 2784). * @throws ApplicationException if there was an error backing up the upgrade * file. */ private void backupWindowsUpgradeFile() throws ApplicationException { try { if (Utils.isWindows()) { File filesBackupDirectory = getFilesInstallBackupDirectory(); FileManager fm = new FileManager(); File root = getInstallation().getRootDirectory(); File f = new File(root, Installation.WINDOWS_UPGRADE_FILE_NAME); fm.copy(f, filesBackupDirectory); } } catch (ApplicationException ae) { throw ae; } catch (Exception e) { throw new ApplicationException( ReturnCode.FILE_SYSTEM_ACCESS_ERROR, INFO_ERROR_BACKUP_FILESYSTEM.get(), e); } } private void backupDatabases() throws ApplicationException { try { ExternalTools et = new ExternalTools(getInstallation()); OperationOutput output = et.backup(getUpgradeBackupDirectory()); int ret = output.getReturnCode(); if (ret != 0) { throw new ApplicationException( ReturnCode.TOOL_ERROR, INFO_ERROR_BACKUP_DB_TOOL_RETURN_CODE.get( Integer.toString(ret)), null); } } catch (ApplicationException ae) { throw ae; } catch (Exception e) { throw new ApplicationException( ReturnCode.TOOL_ERROR, INFO_ERROR_BACKUP_DB.get(), e); } } /** * Cleanup to done executed once upgrade is done. * @throws org.opends.quicksetup.ApplicationException * if cleanup fails */ protected void cleanup() throws ApplicationException { deleteStagingDirectory(); } private void deleteStagingDirectory() throws ApplicationException { File stagingDir = null; try { stagingDir = getStageDirectory(); FileManager fm = new FileManager(); // On Linux at least the deleteOnExit seems not to work very well // for directories that contain files, even if they have been marked // for deletion upon exit as well. Note that on Windows there are // file locking issues so we mark files for deletion after this JVM exits. if (stagingDir.exists()) { fm.deleteRecursively(stagingDir, null, FileManager.DeletionPolicy.DELETE_ON_EXIT_IF_UNSUCCESSFUL); } } catch (IOException e) { throw ApplicationException.createFileSystemException( INFO_ERROR_DELETING_STAGE_DIRECTORY.get( Utils.getPath(stagingDir)), e); } } /** * Implements the initialization phase of the upgrade. * @throws ApplicationException if upgrade is not possible */ protected void initialize() throws ApplicationException { try { BuildInformation fromVersion = getCurrentInstanceBuildInformation(); BuildInformation toVersion = getStagedBuildInformation(); if (fromVersion.equals(toVersion)) { // Only possible if product differs String fromProductName = getCurrentBuildInformation().getName(); String toProductName = toVersion.getName(); LOG.log(Level.FINEST, "fromProductName=" + fromProductName); LOG.log(Level.FINEST, "toProductName=" + toProductName); if ((fromProductName != null) && (toProductName != null) && fromProductName.equals(toProductName)) { throw new ApplicationException(ReturnCode.APPLICATION_ERROR, INFO_UPGRADE_ORACLE_SAME_VERSION.get( toVersion.toString()), null); } } if (getInstallation().getStatus().isServerRunning()) { new ServerController(getInstallation()).stopServer(true); } this.historicalOperationId = writeInitialHistoricalRecord(fromVersion, toVersion); insureUpgradability(); } catch (ApplicationException ae) { throw ae; } catch (Exception e) { throw new ApplicationException( ReturnCode.FILE_SYSTEM_ACCESS_ERROR, INFO_ERROR_INITIALIZING_UPGRADE.get(), e); } } /** * Given the current information, determines whether or not * an upgrade from the current version to the next version * is possible. Upgrading may not be possible due to 'flag * day' types of changes to the codebase. * @throws org.opends.quicksetup.ApplicationException if upgradability * cannot be insured. */ private void insureUpgradability() throws ApplicationException { BuildInformation newVersion; currentVersion = getCurrentInstanceBuildInformation(); try { newVersion = getStagedInstallation().getBuildInformation(); } catch (ApplicationException ae) { throw ae; } catch (Exception e) { LOG.log(Level.INFO, "error getting build information for " + "staged installation", e); throw ApplicationException.createFileSystemException( INFO_ERROR_DETERMINING_UPGRADE_BUILD.get(), e); } UpgradeIssueNotifier uo = new UpgradeIssueNotifier( userInteraction(), currentVersion, newVersion); uo.notifyUser(); if (uo.noServerStartFollowingOperation()) { // Some issue dictates that we don't try and restart the server // after this operation. It may be that the databases are no // longer readable after the upgrade or something equally earth // shattering. getUserData().setStartServer(false); } } /** * Returns the path of the new OpenDS bits. * @return the path of the new OpenDS bits. * @throws java.io.IOException if an error occurs while accessing the * new bits * @throws org.opends.quicksetup.ApplicationException if upgradability * cannot be insured. */ protected Installation getStagedInstallation() throws IOException, ApplicationException { if (stagedInstallation == null) { File stageDir = getStageDirectory(); try { Installation.validateRootDirectory(stageDir); stagedInstallation = new Installation(getStageDirectory(), getStageDirectory()); } catch (IllegalArgumentException e) { Message msg = INFO_ERROR_BAD_STAGE_DIRECTORY.get( Utils.getPath(getStageDirectory())); throw ApplicationException.createFileSystemException(msg, e); } } return stagedInstallation; } /** * {@inheritDoc} */ public UserData createUserData() { UpgradeUserData uud = new UpgradeUserData(); String instanceRootFromSystem = System.getProperty(SYS_PROP_INSTALL_ROOT); if (instanceRootFromSystem != null) { uud.setServerLocation(instanceRootFromSystem); } return uud; } /** * {@inheritDoc} */ public UserData createUserData(Launcher launcher) throws UserDataException { return new UpgraderCliHelper((UpgradeLauncher) launcher). createUserData(launcher.getArguments()); } /** * {@inheritDoc} */ public ApplicationException getRunError() { return runError; } /** * {@inheritDoc} */ public ReturnCode getReturnCode() { return null; } private void setCurrentProgressStep(UpgradeProgressStep step) { this.currentProgressStep = step; int progress = step.getProgress(); Message msg = getSummary(step); Message log = getLogMsg(step); if (step.logRequiresPoints(isVerbose()) && (log != null)) { log = getFormattedWithPoints(log); } notifyListeners(progress, msg, log); } private Message getFinalSuccessMessage() { Message txt; String installPath = Utils.getPath(getInstallation().getRootDirectory()); String newVersion; try { BuildInformation bi = getInstallation().getBuildInformation(); if (bi != null) { newVersion = bi.toString(); } else { newVersion = INFO_UPGRADE_BUILD_ID_UNKNOWN.get().toString(); } } catch (ApplicationException e) { newVersion = INFO_UPGRADE_BUILD_ID_UNKNOWN.get().toString(); } if (Utils.isCli()) { txt = INFO_SUMMARY_UPGRADE_FINISHED_SUCCESSFULLY_CLI.get( DynamicConstants.PRODUCT_NAME, formatter.getFormattedText(Message.raw(installPath)), newVersion); } else { String formattedPath = Utils.addWordBreaks( formatter.getFormattedText(Message.raw(installPath)).toString(), 60, 5); txt = getFormattedSuccess( INFO_SUMMARY_UPGRADE_FINISHED_SUCCESSFULLY.get( formattedPath, newVersion)); } return txt; } private Message getFinalCanceledMessage() { Message txt; if (Utils.isCli()) { txt = INFO_SUMMARY_UPGRADE_FINISHED_CANCELED_CLI.get(); } else { txt = getFormattedSuccess( INFO_SUMMARY_UPGRADE_FINISHED_CANCELED.get()); } return txt; } private Message getFinalErrorMessage() { Message txt; if (Utils.isCli()) { txt = INFO_SUMMARY_UPGRADE_FINISHED_WITH_ERRORS_CLI.get(); } else { txt = getFormattedError( INFO_SUMMARY_UPGRADE_FINISHED_WITH_ERRORS.get()); } return txt; } private Message getFinalWarningMessage() { Message txt; if (Utils.isCli()) { txt = INFO_SUMMARY_UPGRADE_FINISHED_WITH_WARNINGS_CLI.get(); } else { txt = getFormattedWarning( INFO_SUMMARY_UPGRADE_FINISHED_WITH_WARNINGS.get()); } return txt; } /** * Returns the path of the new OpenDS bits. * @return the path of the new OpenDS bits. * @throws org.opends.quicksetup.ApplicationException * if retrieval of stage files path fails * @throws java.io.IOException if errors occurs while accessing stage files */ protected File getStageDirectory() throws ApplicationException, IOException { return getInstallation().getTemporaryUpgradeDirectory(); } private UpgradeUserData getUpgradeUserData() { return (UpgradeUserData) getUserData(); } private boolean instanceAndInstallInSameDir() { Installation installation = getInstallation() ; File installDir = installation.getRootDirectory(); try { installDir = installDir.getCanonicalFile(); } catch (Exception e) { installDir = installation.getRootDirectory(); } File instanceDir = installation.getInstanceDirectory(); try { instanceDir = instanceDir.getCanonicalFile(); } catch (Exception e) { instanceDir = installation.getInstanceDirectory(); } return installDir.getAbsolutePath().equals(instanceDir.getAbsolutePath()); } /** * Returns the path where to backup instance files. * @return the path where to backup instance files. * @throws java.io.IOException if retrieval of backup files fails */ protected File getFilesInstanceBackupDirectory() throws IOException { if (instanceAndInstallInSameDir()) { return getFilesBackupDirectory(); } else { return new File(getFilesBackupDirectory(), Installation.HISTORY_BACKUP_FILES_DIR_INSTANCE); } } private File getFilesInstallBackupDirectory() throws IOException { if (instanceAndInstallInSameDir()) { return getFilesBackupDirectory(); } else { return new File(getFilesBackupDirectory(), Installation.HISTORY_BACKUP_FILES_DIR_INSTALL); } } private File getFilesBackupDirectory() throws IOException { File files = new File(getUpgradeBackupDirectory(), Installation.HISTORY_BACKUP_FILES_DIR_NAME); if (!files.exists()) { if (!files.mkdirs()) { throw new IOException("error creating files backup directory"); } } // Check if instance and instance are in the same dir if ( ! instanceAndInstallInSameDir()) { File install = new File(files, Installation.HISTORY_BACKUP_FILES_DIR_INSTALL); if (!install.exists()) { if (!install.mkdirs()) { throw new IOException("error creating files backup directory"); } } File instance = new File(files, Installation.HISTORY_BACKUP_FILES_DIR_INSTANCE); if (!instance.exists()) { if (!instance.mkdirs()) { throw new IOException("error creating files backup directory"); } } } return files; } private File getUpgradeBackupDirectory() throws IOException { if (backupDirectory == null) { backupDirectory = getInstallation().createHistoryBackupDirectory(); } return backupDirectory; } /** * Returns the BuildInformation of the current OpenDS bits. * @return the BuildInformation of the current OpenDS bits. */ private BuildInformation getCurrentBuildInformation() { if (this.currentVersion == null) { try { currentVersion = getInstallation().getBuildInformation(); } catch (Exception e) { LOG.log(Level.INFO, "error trying to determine current version", e); } } return currentVersion; } /** * Returns the BuildInformation of the OpenDS instance. * @return the BuildInformation of the OpenDS instance. */ private BuildInformation getCurrentInstanceBuildInformation() { if (this.currentInstanceVersion == null) { currentInstanceVersion = getInstallation().getInstanceBuildInformation(); } return currentInstanceVersion; } private BuildInformation getStagedBuildInformation() { if (stagedVersion == null) { try { stagedVersion = getStagedInstallation().getBuildInformation(); } catch (Exception e) { LOG.log(Level.INFO, "error getting build info for staged installation", e); } } return stagedVersion; } }