/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2010 Sun Microsystems, Inc. * Portions copyright 2012 ForgeRock AS. */ package org.opends.quicksetup.upgrader; import org.opends.messages.Message; import org.opends.quicksetup.BuildInformation; import org.opends.quicksetup.ApplicationException; import org.opends.quicksetup.Constants; import org.opends.quicksetup.UserInteraction; import org.opends.server.util.VersionCompatibilityIssue; import org.opends.server.util.BuildVersion; import static org.opends.messages.QuickSetupMessages.*; import static org.opends.server.util.VersionCompatibilityIssue.*; import java.util.List; import java.util.Set; import java.util.ArrayList; import java.util.Collections; import java.util.logging.Logger; import java.util.logging.Level; /** * This class can answer questions important upgrade/reversion questions * like 'can I upgrade from verion X to version Y?' and 'if not then why?'. * This is also responsible for obtaining and translating any applicable * {@link org.opends.server.util.VersionCompatibilityIssue}s and * interacting with the user to inform them of an actions or information * that they dictate. */ public abstract class VersionIssueNotifier { static private final Logger LOG = Logger.getLogger(VersionIssueNotifier.class.getName()); /** * End Of Line. */ public static String EOL = System.getProperty("line.separator"); /** Descriptor for a directive. */ protected enum DirectiveType { /** Causes the tools to refuse to continue. */ NOT_SUPPORTED, /** Causes the tools to display an action dialog. */ ACTION, /** Causes the tools to display an informational dialog. */ INFO, /** Causes the tools to display a warning dialog. */ WARNING } /** * Holds information that directs tool behavior. */ protected class Directive { DirectiveType type; Message msg; /** * Creates a parameterized instance. * * @param type of directive * @param localizedMsg for displaying to the user */ public Directive(DirectiveType type, Message localizedMsg) { this.type = type; this.msg = localizedMsg; } /** * Gets the type of issue. * @return type of issue */ public DirectiveType getType() { return this.type; } /** * Gets the issue's message. * @return string message */ public Message getMessage() { return this.msg; } } /** Used for interacting with the user. */ protected UserInteraction ui; /** Version issues applicable to this operation. */ protected List directives; /** Information about the current build version. */ protected BuildInformation currentBuildInfo; /** Information about the proposed new build version. */ protected BuildInformation newBuildInfo; private boolean isSupported = true; private boolean noServerStart = false; /** * Creates a parameterized instance. * @param ui for interacting with the user * @param current build version * @param neu build version */ public VersionIssueNotifier(UserInteraction ui, BuildInformation current, BuildInformation neu) { this.ui = ui; this.currentBuildInfo = current; this.newBuildInfo = neu; // Get the list of possible version incompatibility events (aka flag days) List compatibilityIssues; Set excludeIds ; boolean isUpgrade = neu.compareTo(current) >= 0; if (isUpgrade) { excludeIds = current.getIncompatibilityEventIds(); } else { excludeIds = neu.getIncompatibilityEventIds(); } if (excludeIds != null) { if (isUpgrade) { compatibilityIssues = getEvents(excludeIds, current, neu); } else { compatibilityIssues = getEvents(excludeIds, neu, current); } } else { // This method is only used as a fallback for pre 1.0.0 servers which // do not advertise incompatible version events. LOG.log(Level.INFO, "Legacy method for obtaining compatibility issues"); BuildVersion bv = new BuildVersion( current.getMajorVersion(), current.getMinorVersion(), current.getPointVersion(), current.getRevisionNumber()); compatibilityIssues = getEvents(bv); } directives = processEvents(compatibilityIssues); } /** * Interacts with the user to let them know about any * version issues applicable to operations between the * builds supplied in the constructor. * * @throws ApplicationException if something goes wrong or * the user cancels the operation. */ public abstract void notifyUser() throws ApplicationException; /** * Indicates whether or not this operation would be considered an * upgrade (as opposed to a reversion). * * @return boolean where true indicates that this would be an upgrade; * false indicates that this would be a reversion. */ public boolean isUpgrade() { return currentBuildInfo.compareTo(newBuildInfo) < 0; } /** * Indicates whether or not this operation would be considered an * reversion (as opposed to an upgrade). * * @return boolean where true indicates that this would be a reversion; * false indicates that this would be an upgrade. */ public boolean isReversion() { return currentBuildInfo.compareTo(newBuildInfo) > 0; } /** * Returns whether or not this operation is supported. * @return true to indicate this operation is supported; false otherwise */ public boolean isSupported() { return isSupported; } /** * Indicates whether the set of version issues dictates that the server * not be restarted afterward. * * @return true meaning the server won't be restarted; false otherwise */ public boolean noServerStartFollowingOperation() { return noServerStart; } /** * Gets a list of issues applicable to this operation. * @return list of issues */ protected List getIssues() { return directives; } /** * Indicates whether or not there are issues with this operation. * @return true indicating there are issues; false otherwise */ protected boolean hasIssues() { return (directives != null && directives.size() > 0); } /** * Given a particular cause return a detail message appropriate * for this operation. * * @param cause of issue * @return message for presenting to the user */ protected abstract Message getLocalizedDetailMessage( VersionCompatibilityIssue.Cause cause); /** * Given a particular cause indicates whether or not the user * will be confronted with verbage explaining that they will * have to perform extra actions for this operation. * * @param cause of issue * @return message for presenting to the user */ protected abstract boolean isActionRequired( VersionCompatibilityIssue.Cause cause); /** * Given a particular cause indicates whether or not this * operation should be allowed to continue. * * @param cause of issue * @return message for presenting to the user */ protected abstract boolean isUnsupported( VersionCompatibilityIssue.Cause cause); /** * Given a particular cause indicates whether or not this * the user will be shown a warning dialog containing * a warning message regarding this operation. * * @param cause of issue * @return message for presenting to the user */ protected abstract boolean isWarning( VersionCompatibilityIssue.Cause cause); /** * Given a particular cause indicates whether or not this * the user will be shown some verbage that may contain * information about this operation. * * @param cause of issue * @return message for presenting to the user */ protected boolean isNotification(Cause cause) { boolean isNotification = false; if (cause != null) { Message msg = getLocalizedDetailMessage(cause); if (msg != null && !isWarning(cause) && !isActionRequired(cause)) { isNotification = true; } } return isNotification; } /** * Gets a list of strings representing the steps neccessary * to export and then reimport the data. * * @return List containing strings representing intruction steps */ protected List getExportImportInstructions() { List instructions = new ArrayList(); if (ui.isCLI()) { instructions.add(INFO_ORACLE_EI_ACTION_STEP1_CLI.get()); } else { instructions.add(INFO_ORACLE_EI_ACTION_STEP1.get()); } instructions.add(INFO_ORACLE_EI_ACTION_STEP2.get()); instructions.add(INFO_ORACLE_EI_ACTION_STEP3.get()); instructions.add(INFO_ORACLE_EI_ACTION_STEP4.get()); return instructions; } /** * Converts a set of compatibility issues into a set of set of * action oriented issues for directing tool behavior. * * @param compatibilityIssues list of issues * @return list of directives */ private List processEvents( List compatibilityIssues) { List directives = new ArrayList(); if (compatibilityIssues != null) { for (VersionCompatibilityIssue evt : compatibilityIssues) { VersionCompatibilityIssue.Cause cause = evt.getCause(); Set effects = cause.getEffects(); Message msg = getLocalizedDetailMessage(cause); if (isUnsupported(cause)) { isSupported = false; directives.add(new Directive(DirectiveType.NOT_SUPPORTED, msg)); } else if (isActionRequired(cause)) { directives.add(new Directive(DirectiveType.ACTION, msg)); } else if (isWarning(cause)) { directives.add(new Directive(DirectiveType.WARNING, msg)); } else if (isNotification(cause)) { directives.add(new Directive(DirectiveType.INFO, msg)); } if ((effects.contains( Effect.NO_SERVER_RESTART_FOLLOWING_REVERSION) || effects.contains( Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED) || effects.contains( Effect.UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED))) { noServerStart = true; } } } return Collections.unmodifiableList(directives); } /** * Creates a list appropriate for the presentation implementation. * * @param list to format * @return String representing the list */ protected String createUnorderedList(List list) { StringBuilder sb = new StringBuilder(); if (list != null) { for (Object o : list) { sb.append(/*bullet=*/"* "); sb.append(o.toString()); sb.append(Constants.LINE_SEPARATOR); } } return sb.toString(); } }