VersionCompatibilityIssue.java revision b8c6b80da1cb6118167a934daa480eb381c59e0e
/*
* 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 legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* 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 legal-notices/CDDLv1_0.txt.
* 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.
* Portions Copyright 2011-2015 ForgeRock AS
*/
package org.opends.server.util;
import static org.opends.messages.VersionMessages.*;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.quicksetup.BuildInformation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Record for version compatibility issues (also known as 'flag days') which
* are events associated with particular builds or builds between which upgrade
* or reversion may required additional steps, notification of issues, or
* be prohibited altogether.
*/
@org.opends.server.types.PublicAPI(
stability=org.opends.server.types.StabilityLevel.VOLATILE,
mayInstantiate=false,
mayExtend=false,
mayInvoke=true)
public final class VersionCompatibilityIssue {
//***************************************************
//
// TO DEFINE A NEW ISSUE:
//
// Step 1: Select (or add to) effects from the list
// below that will cause the upgrade or
// reversion tools to behave in particular
// ways. If you add to this list you will
// likely need to update the UpgradeOracle
// and ReversionOracle code.
//
// Step 2: [scroll down]...
//
//***************************************************
/**
* Effects cause the upgrade and revision tools to behave
* in specific ways in response to compatibility issues.
*/
public enum Effect {
/**
* Before a reversion can take place there must be a complete
* data export to LDIF followed by a complete data import after
* the operation has completed. Assigning this effect to an
* issue will cause a detailed set of instructions to appear in
* the reversion tool explaining how to perform the task.
*/
REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED,
/**
* Before an upgrade can take place there must be a complete
* data export to LDIF followed by a complete data import after
* the operation has completed. Assigning this effect to an
* issue will cause a detailed set of instructions to appear in
* the upgrade tool explaining how to perform the task.
*/
UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED,
/**
* Indicates that the upgrader will show an informational message to the
* administrator. Use this effect when you want to have the
* upgrader show the user an informational message during upgrade
* but the message does not dictate that an action be performed.
* For instance you might want to let the user know that due to
* a data format incompatibility, it will be more difficult to
* revert this build to its previous version following this upgrade.
*
* If you want the message to be scarier, use
* <code>UPGRADE_SHOW_WARNING_MESSAGE</code> instead.
*/
UPGRADE_SHOW_INFO_MESSAGE,
/**
* Indicates that the reverter tool will show a message to the
* administrator. Use this effect when you want to have the
* reverter show the user an informational message during upgrade
* but the message does not dictate that an action be performed.
*
* If you want the message to be scarier, use
* <code>REVERSION_SHOW_WARNING_MESSAGE</code> instead.
*/
REVERSION_SHOW_INFO_MESSAGE,
/**
* Indicates that the upgrader will show a message to the
* administrator. Use this effect when you want to have the
* upgrader show the user an informational message during upgrade
* but the message does not dictate that an action be performed.
* For instance you might want to let the user know that due to
* a data format incompatibility, it will be more difficult to
* revert this build to its previous version following this upgrade.
*
* If you want the message to be less scary, use
* <code>UPGRADE_SHOW_INFO_MESSAGE</code> instead.
*/
UPGRADE_SHOW_WARNING_MESSAGE,
/**
* Indicates that the reverter tool will show a message to the
* administrator. Use this effect when you want to have the
* reverter show the user an informational message during upgrade
* but the message does not dictate that an action be performed.
*
* If you want the message to be less scary, use
* <code>REVERSION_SHOW_INFO_MESSAGE</code> instead.
*/
REVERSION_SHOW_WARNING_MESSAGE,
/**
* Indicates that the user needs to perform some manual action
* (for which there is not effect currently defined such as
* <code>UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED</code>) in order for
* the operation to be successful. The action itself should
* be described in detail in the upgrade message.
*/
UPGRADE_MANUAL_ACTION_REQUIRED,
/**
* Indicates that the user needs to perform some manual action
* (for which there is not effect currently defined such as
* <code>REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED</code>) in order for
* the operation to be successful. The action itself should
* be described in detail in the reversion message.
*/
REVERSION_MANUAL_ACTION_REQUIRED,
/**
* Indicates that it is not possible to upgrade between to builds
* between which lies a flag day. The upgrader will refuse to
* operate in this case.
*/
UPGRADE_NOT_POSSIBLE,
/**
* Indicates that it is not possible to revert between to builds
* between which lies a flag day. The reverter will refuse to run
* in this case.
*/
REVERSION_NOT_POSSIBLE,
/**
* Indicates that for some reason the server should not be restarted
* following a reversion. There might be situations where the admin
* needs to perform some actions before the server restarts (such as
* the database format being incompatible and the data needing an
* export followed by a re-import). This effect need not be included
* with <code>UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED</code> and
* <code>REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED</code> as this
* is assumed.
*/
NO_SERVER_RESTART_FOLLOWING_REVERSION,
}
//***************************************************
//
// TO DEFINE A NEW ISSUE:
//
// STEP 1: [scroll up]
//
// STEP 2: Define an cause below. A cause must be a specific
// event. For instance 'upgrade of the database libraries'
// on 12/17/2006. A cause associates the effect you selected
// in Step 1, detailed reversion and/or upgrade messages and
// a unique ID.
//
// A single issue may be apply to multiple branches of the
// code-base. For instance a single event might cause a flag
// day between upgrade/reversions from 1.0 to 2.0 as well as
// upgrading from 1.0 to 1.1. Therefore you must make sure
// that causes that appear in multiple branches have the same
// ID. Also, IDs should be unique among all causes in the
// code-base.
//
// STEP 3: [scroll down]
//
//***************************************************
/**
* Unique descriptor of an event that created a flag day for one
* or more versions of the OpenDJ codebase.
*/
public enum Cause {
/**
* Incompatible changes in ds-sync-hist normalization. This causes
* ds-sync-hist attribute indexes to be invalidated.
*/
DS_SYNC_HIST_NORMALIZATION_CHANGE_1(
10, // Unique ID. See javadoc for more information.
INFO_7635_UPGRADE.get(),
INFO_7635_REVERSION.get(),
Effect.REVERSION_MANUAL_ACTION_REQUIRED,
Effect.UPGRADE_MANUAL_ACTION_REQUIRED),
/**
* We not support the revert to the previous version.
*/
REVERT_NOT_SUPPORTED_1(
9, // Unique ID. See javadoc for more information.
INFO_5278_REVERSION.get(),
INFO_5278_REVERSION.get(),
Effect.REVERSION_NOT_POSSIBLE,
Effect.UPGRADE_SHOW_INFO_MESSAGE),
/**
* Incompatible changes in attribute value normalization. This causes
* indexes to be invalidated.
*/
STRINGPREP_NORMALIZATION_CHANGE_1(
8, // Unique ID. See javadoc for more information.
INFO_5134_UPGRADE.get(),
INFO_5134_REVERSION.get(),
Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED,
Effect.UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED),
/**
* Incompatible changes in DN normalization. This causes dn2id and
* RDN / DN syntax based attribute indexes to be invalidated.
*/
DN_NORMALIZATION_CHANGE_1(
7, // Unique ID. See javadoc for more information.
INFO_3873_UPGRADE.get(),
INFO_3873_REVERSION.get(),
Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED,
Effect.UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED),
/**
* Incompatible changes in the backend configuration (the db directory
* attribute has been modified).
*/
BACKEND_CONFIGURATION_CHANGE_1(
6, // Unique ID. See javadoc for more information.
INFO_3708_UPGRADE.get(),
INFO_3708_REVERSION.get(),
Effect.REVERSION_NOT_POSSIBLE,
Effect.UPGRADE_NOT_POSSIBLE),
/**
* Incompatible changes in the cryptomanager and specially in the way
* replication works. These changes were committed on several revisions
* and the flagday that has been chosen corresponds to revision 3294
* (opends 1.0.0 build 6 of 16/10/2007)
*/
REPLICATION_SECURITY_CHANGE_1(
5, // Unique ID. See javadoc for more information.
INFO_3294_UPGRADE.get(),
INFO_3294_REVERSION.get(),
Effect.REVERSION_NOT_POSSIBLE,
Effect.UPGRADE_NOT_POSSIBLE),
/**
* Incompatible property name change committed on 09/05/2007
* and described in the SVN log for rev 2974.
*/
PROPERTY_CHANGE_1(
4, // Unique ID. See javadoc for more information.
INFO_2974_UPGRADE.get(),
INFO_2974_REVERSION.get(),
Effect.REVERSION_NOT_POSSIBLE,
Effect.UPGRADE_NOT_POSSIBLE),
/**
* Database format change committed on 6/7/2007
* and described in the SVN log for rev 2049.
*/
DB_FORMAT_CHANGE_2(
3, // Unique ID. See javadoc for more information.
INFO_2049_UPGRADE.get(),
INFO_2049_REVERSION.get(),
Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED,
Effect.UPGRADE_SHOW_WARNING_MESSAGE),
/**
* Database format change committed on 4/6/2007
* and described in the SVN log for rev 1582.
*/
DB_FORMAT_CHANGE_1(
2, // Unique ID. See javadoc for more information.
INFO_1582_UPGRADE.get(),
INFO_1582_REVERSION.get(),
Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED,
Effect.UPGRADE_SHOW_WARNING_MESSAGE),
/**
* Upgrade of Berkley DB library to 3.2.13 on
* 12/17/2006.
*/
BERKLEY_UPGRADE_1(
1, // Unique ID. See javadoc for more information.
INFO_890_UPGRADE.get(),
INFO_890_REVERSION.get(),
Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED,
Effect.UPGRADE_SHOW_WARNING_MESSAGE);
/**
* Gets a <code>Cause</code> from its unique ID. If no cause
* is associated with <code>id</code> this method returns null.
* @param id of a cause
* @return Cause with <code>id</code>
*/
static Cause fromId(int id) {
Cause cause = null;
EnumSet<Cause> es = EnumSet.allOf(Cause.class);
for (Cause c : es) {
if (c.getId() == id) {
cause = c;
break;
}
}
return cause;
}
private int id;
private Set<Effect> effects = new HashSet<>();
private LocalizableMessage upgradeMsg;
private LocalizableMessage reversionMsg;
/**
* Creates a parameterized instance.
*
* @param id of this cause. It would get very complicated to try to
* deal with releases as a graph and attempting to compare
* versions to see what issues apply during an upgrade/reversion
* between two releases. Therefore IDs are used by the tools
* to identify issues would have already been seen during a previous
* upgrade and do not need to be rehashed.
* <p>
* So if an issue exists in the 1.0 branch, an upgrade from 2.0
* to 3.0 will suppress the issue since it would presumably already
* been dealt with when 2.0 was installed or upgraded to. Likewise
* if an issue is assocated with a particular minor version (1.1 for
* instance) major upgrades (1.0 to 2.0) will avoid presenting the
* issue.
*
* <ol>
* <li>IDs must be unique among different causes in all branches
* of the OpenDJ code.</li>
*
* <li>Causes in different branches representing the same issue
* must have identical IDs.</li>
*
* <li>The IDs are advertised by the server when start-ds -F
* is invoked. Therefore they should be kept to as few
* characters as possible.</li>
* </ol>
*
* @param upgradeMessage a message to be shown to the user during an
* upgrade between two different version between which this issue
* lies. This message might detail instructions for manual actions
* that must be performed (when used with the
* <code>UPGRADE_MANUAL_ACTION_REQUIRED</code>) or give the
* user a warning message (when used with
* <code>UPGRADE_SHOW_WARNING_MESSAGE</code>). If a message is
* present but no effects that would dictate how message is to
* be presented <code>UPGRADE_SHOW_INFO_MESSAGE</code> is
* assumed. This parameter may also be null in which case no
* action will be taken during upgrade.
*
* @param reversionMessage a message to be shown to the user during a
* reversion between two different version between which this issue
* lies. This message might detail instructions for manual actions
* that must be performed (when used with the
* <code>REVERSION_MANUAL_ACTION_REQUIRED</code>) or give the
* user a warning message (when used with
* <code>REVERSION_SHOW_WARNING_MESSAGE</code>). If a message is
* present but no effects that would dictate how message is to
* be presented <code>REVERSION_SHOW_INFO_MESSAGE</code> is
* assumed. This parameter may also be null in which case no
* action will be taken during reversion.
*
* @param effects of this cause which cause the upgrade/reversion tools
* to behave in particular ways
*/
private Cause(int id, LocalizableMessage upgradeMessage, LocalizableMessage reversionMessage,
Effect... effects) {
this.id = id;
this.upgradeMsg = upgradeMessage;
this.reversionMsg = reversionMessage;
if (effects != null) {
for (Effect c : effects) {
this.effects.add(c);
}
}
}
/**
* Gets the ID of this cause.
* @return id of this cause
*/
public int getId() {
return this.id;
}
/**
* Gets the set of effects that cause the upgrade/reversion
* tools to behave in particular ways.
*
* @return set of effects
*/
public Set<Effect> getEffects() {
return Collections.unmodifiableSet(effects);
}
/**
* Gets a localized message to be shown to the user during
* the upgrade process.
*
* @return a message to be shown to the user during an
* upgrade between two different version between which this issue
* lies. This message might detail instructions for manual actions
* that must be performed (when used with the
* <code>UPGRADE_MANUAL_ACTION_REQUIRED</code>) or just give the
* user useful information (when used with
* <code>UPGRADE_SHOW_INFO_MESSAGE</code>)
*/
public LocalizableMessage getLocalizedUpgradeMessage() {
return upgradeMsg;
}
/**
* Gets a localized message to be shown to the user during
* the reversion process.
*
* @return a message to be shown to the user during an
* upgrade between two different version between which this issue
* lies. This message might detail instructions for manual actions
* that must be performed (when used with the
* <code>REVERSION_MANUAL_ACTION_REQUIRED</code>) or just give the
* user useful information (when used with
* <code>REVERSION_SHOW_INFO_MESSAGE</code>)
*/
public LocalizableMessage getLocalizedReversionMessage() {
return reversionMsg;
}
}
/** Container for registered issues. */
private static final Set<VersionCompatibilityIssue> VERSION_COMPATIBILITY_ISSUES = new HashSet<>();
//***************************************************
//
// TO DEFINE A NEW ISSUE:
//
// STEP 2: [scroll up]
//
// STEP 3: Associate the cause with a particular build.
//
// DONE
//
//***************************************************
static
{
register(Cause.DS_SYNC_HIST_NORMALIZATION_CHANGE_1, new BuildVersion(2, 4,
5, 7635));
register (Cause.REVERT_NOT_SUPPORTED_1, new BuildVersion(2,0,0,5278));
register(Cause.STRINGPREP_NORMALIZATION_CHANGE_1,
new BuildVersion(1,2,0,5134));
register(Cause.DN_NORMALIZATION_CHANGE_1, new BuildVersion(1, 0, 0, 3873));
register(Cause.BACKEND_CONFIGURATION_CHANGE_1,
new BuildVersion(1, 0, 0, 3708));
register(Cause.REPLICATION_SECURITY_CHANGE_1,
new BuildVersion(1, 0, 0, 3294));
register(Cause.PROPERTY_CHANGE_1, new BuildVersion(1, 0, 0, 3053));
register(Cause.DB_FORMAT_CHANGE_2, new BuildVersion(0, 9, 0, 2049));
register(Cause.DB_FORMAT_CHANGE_1, new BuildVersion(0, 1, 0, 1582));
register(Cause.BERKLEY_UPGRADE_1, new BuildVersion(0, 1, 0, 890));
}
private static void register(Cause cause,
BuildVersion version) {
VERSION_COMPATIBILITY_ISSUES.add(new VersionCompatibilityIssue(cause,
version));
}
/**
* Gets the list of all registered issues.
*
* @return list of issues sorted by build version in which
* they appear
*/
public static List<VersionCompatibilityIssue> getAllEvents() {
List<VersionCompatibilityIssue> issueList = new ArrayList<>(VERSION_COMPATIBILITY_ISSUES);
Collections.sort(issueList, VERSION_COMPARATOR);
return Collections.unmodifiableList(issueList);
}
/**
* Gets the list of all registered issues excluding the
* issues specified by <code>excludeIds</code>.
*
* @param excludeIds collection of IDs representing issues
* that will not be returned in the list
* @param current build version
* @param neu build version
*
* @return list of issues sorted by build version in which
* they appear
*/
public static List<VersionCompatibilityIssue> getEvents(
Collection<Integer> excludeIds, BuildInformation current,
BuildInformation neu)
{
if (excludeIds == null)
{
excludeIds = Collections.emptySet();
}
List<VersionCompatibilityIssue> issueList = new ArrayList<>();
for (VersionCompatibilityIssue evt : VERSION_COMPATIBILITY_ISSUES) {
if (!excludeIds.contains(evt.getCause().getId())) {
BuildVersion currentVersion = new BuildVersion(
current.getMajorVersion(), current.getMinorVersion(),
current.getPointVersion(), current.getRevisionNumber());
// If the currentVersion is newer than the issue described, then there
// is no problem. This can occur for instance when we discovered a
// flag day too late (and we added the flag day description to the
// code way after the revision).
if (currentVersion.compareTo(evt.getVersion()) < 0)
{
issueList.add(evt);
}
}
}
Collections.sort(issueList, VERSION_COMPARATOR);
return Collections.unmodifiableList(issueList);
}
/**
* Returns events that have happened in between the SVN revision numbers
* of two different builds. Note that this method does not necessarily
* return all events that are pertinent. For instance a partilar event
* may have happend in a branch that we don't care about for the current
* upgrade. So this method should really just be used as a fall-back
* in the case where we are upgrading/reverting a build that was not
* instrumented to return the Upgrade Event IDs using start-ds -F.
*
* @param from build from which events will be returned
* @return List or IncompatibleVersionEvent objects
*/
public static List<VersionCompatibilityIssue> getEvents(BuildVersion from) {
List<VersionCompatibilityIssue> issueList = new ArrayList<>();
for (VersionCompatibilityIssue evt : VERSION_COMPATIBILITY_ISSUES) {
BuildVersion evtVer = evt.getVersion();
if (evtVer.compareTo(from) >= 0) {
issueList.add(evt);
}
}
Collections.sort(issueList, VERSION_COMPARATOR);
return issueList;
}
/**
* Comparator used to sort issues by the build version for
* which they apply.
*/
private static final Comparator<VersionCompatibilityIssue>
VERSION_COMPARATOR = new Comparator<VersionCompatibilityIssue>()
{
@Override
public int compare(VersionCompatibilityIssue o1,
VersionCompatibilityIssue o2) {
return o1.getVersion().compareTo(o2.getVersion());
}
};
private Cause cause;
private BuildVersion version;
private VersionCompatibilityIssue(Cause cause, BuildVersion version) {
this.cause = cause;
this.version = version;
}
/**
* Gets the cause of this issue.
* @return the cause
*/
public Cause getCause() {
return this.cause;
}
/**
* Gets the build version for which this issue applies.
* @return build version
*/
public BuildVersion getVersion() {
return this.version;
}
/**
* Retrieves a string representation of this version compatibility issue.
*
* @return A string representation of this version compatibility issue.
*/
@Override
public String toString() {
return Integer.toString(cause.getId());
}
}