001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2007-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.util; 028 029import static org.opends.messages.VersionMessages.*; 030 031import org.forgerock.i18n.LocalizableMessage; 032import org.opends.quicksetup.BuildInformation; 033 034import java.util.ArrayList; 035import java.util.Collection; 036import java.util.Collections; 037import java.util.Comparator; 038import java.util.EnumSet; 039import java.util.HashSet; 040import java.util.List; 041import java.util.Set; 042 043/** 044 * Record for version compatibility issues (also known as 'flag days') which 045 * are events associated with particular builds or builds between which upgrade 046 * or reversion may required additional steps, notification of issues, or 047 * be prohibited altogether. 048 */ 049@org.opends.server.types.PublicAPI( 050 stability=org.opends.server.types.StabilityLevel.VOLATILE, 051 mayInstantiate=false, 052 mayExtend=false, 053 mayInvoke=true) 054public final class VersionCompatibilityIssue { 055 056 //*************************************************** 057 // 058 // TO DEFINE A NEW ISSUE: 059 // 060 // Step 1: Select (or add to) effects from the list 061 // below that will cause the upgrade or 062 // reversion tools to behave in particular 063 // ways. If you add to this list you will 064 // likely need to update the UpgradeOracle 065 // and ReversionOracle code. 066 // 067 // Step 2: [scroll down]... 068 // 069 //*************************************************** 070 071 /** 072 * Effects cause the upgrade and revision tools to behave 073 * in specific ways in response to compatibility issues. 074 */ 075 public enum Effect { 076 077 /** 078 * Before a reversion can take place there must be a complete 079 * data export to LDIF followed by a complete data import after 080 * the operation has completed. Assigning this effect to an 081 * issue will cause a detailed set of instructions to appear in 082 * the reversion tool explaining how to perform the task. 083 */ 084 REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 085 086 /** 087 * Before an upgrade can take place there must be a complete 088 * data export to LDIF followed by a complete data import after 089 * the operation has completed. Assigning this effect to an 090 * issue will cause a detailed set of instructions to appear in 091 * the upgrade tool explaining how to perform the task. 092 */ 093 UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED, 094 095 /** 096 * Indicates that the upgrader will show an informational message to the 097 * administrator. Use this effect when you want to have the 098 * upgrader show the user an informational message during upgrade 099 * but the message does not dictate that an action be performed. 100 * For instance you might want to let the user know that due to 101 * a data format incompatibility, it will be more difficult to 102 * revert this build to its previous version following this upgrade. 103 * 104 * If you want the message to be scarier, use 105 * <code>UPGRADE_SHOW_WARNING_MESSAGE</code> instead. 106 */ 107 UPGRADE_SHOW_INFO_MESSAGE, 108 109 /** 110 * Indicates that the reverter tool will show a message to the 111 * administrator. Use this effect when you want to have the 112 * reverter show the user an informational message during upgrade 113 * but the message does not dictate that an action be performed. 114 * 115 * If you want the message to be scarier, use 116 * <code>REVERSION_SHOW_WARNING_MESSAGE</code> instead. 117 */ 118 REVERSION_SHOW_INFO_MESSAGE, 119 120 /** 121 * Indicates that the upgrader will show a message to the 122 * administrator. Use this effect when you want to have the 123 * upgrader show the user an informational message during upgrade 124 * but the message does not dictate that an action be performed. 125 * For instance you might want to let the user know that due to 126 * a data format incompatibility, it will be more difficult to 127 * revert this build to its previous version following this upgrade. 128 * 129 * If you want the message to be less scary, use 130 * <code>UPGRADE_SHOW_INFO_MESSAGE</code> instead. 131 */ 132 UPGRADE_SHOW_WARNING_MESSAGE, 133 134 /** 135 * Indicates that the reverter tool will show a message to the 136 * administrator. Use this effect when you want to have the 137 * reverter show the user an informational message during upgrade 138 * but the message does not dictate that an action be performed. 139 * 140 * If you want the message to be less scary, use 141 * <code>REVERSION_SHOW_INFO_MESSAGE</code> instead. 142 */ 143 REVERSION_SHOW_WARNING_MESSAGE, 144 145 /** 146 * Indicates that the user needs to perform some manual action 147 * (for which there is not effect currently defined such as 148 * <code>UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED</code>) in order for 149 * the operation to be successful. The action itself should 150 * be described in detail in the upgrade message. 151 */ 152 UPGRADE_MANUAL_ACTION_REQUIRED, 153 154 /** 155 * Indicates that the user needs to perform some manual action 156 * (for which there is not effect currently defined such as 157 * <code>REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED</code>) in order for 158 * the operation to be successful. The action itself should 159 * be described in detail in the reversion message. 160 */ 161 REVERSION_MANUAL_ACTION_REQUIRED, 162 163 /** 164 * Indicates that it is not possible to upgrade between to builds 165 * between which lies a flag day. The upgrader will refuse to 166 * operate in this case. 167 */ 168 UPGRADE_NOT_POSSIBLE, 169 170 /** 171 * Indicates that it is not possible to revert between to builds 172 * between which lies a flag day. The reverter will refuse to run 173 * in this case. 174 */ 175 REVERSION_NOT_POSSIBLE, 176 177 /** 178 * Indicates that for some reason the server should not be restarted 179 * following a reversion. There might be situations where the admin 180 * needs to perform some actions before the server restarts (such as 181 * the database format being incompatible and the data needing an 182 * export followed by a re-import). This effect need not be included 183 * with <code>UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED</code> and 184 * <code>REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED</code> as this 185 * is assumed. 186 */ 187 NO_SERVER_RESTART_FOLLOWING_REVERSION, 188 189 } 190 191 //*************************************************** 192 // 193 // TO DEFINE A NEW ISSUE: 194 // 195 // STEP 1: [scroll up] 196 // 197 // STEP 2: Define an cause below. A cause must be a specific 198 // event. For instance 'upgrade of the database libraries' 199 // on 12/17/2006. A cause associates the effect you selected 200 // in Step 1, detailed reversion and/or upgrade messages and 201 // a unique ID. 202 // 203 // A single issue may be apply to multiple branches of the 204 // code-base. For instance a single event might cause a flag 205 // day between upgrade/reversions from 1.0 to 2.0 as well as 206 // upgrading from 1.0 to 1.1. Therefore you must make sure 207 // that causes that appear in multiple branches have the same 208 // ID. Also, IDs should be unique among all causes in the 209 // code-base. 210 // 211 // STEP 3: [scroll down] 212 // 213 //*************************************************** 214 215 /** 216 * Unique descriptor of an event that created a flag day for one 217 * or more versions of the OpenDJ codebase. 218 */ 219 public enum Cause { 220 221 /** 222 * Incompatible changes in ds-sync-hist normalization. This causes 223 * ds-sync-hist attribute indexes to be invalidated. 224 */ 225 DS_SYNC_HIST_NORMALIZATION_CHANGE_1( 226 10, // Unique ID. See javadoc for more information. 227 INFO_7635_UPGRADE.get(), 228 INFO_7635_REVERSION.get(), 229 Effect.REVERSION_MANUAL_ACTION_REQUIRED, 230 Effect.UPGRADE_MANUAL_ACTION_REQUIRED), 231 232 233 /** 234 * We not support the revert to the previous version. 235 */ 236 REVERT_NOT_SUPPORTED_1( 237 9, // Unique ID. See javadoc for more information. 238 INFO_5278_REVERSION.get(), 239 INFO_5278_REVERSION.get(), 240 Effect.REVERSION_NOT_POSSIBLE, 241 Effect.UPGRADE_SHOW_INFO_MESSAGE), 242 243 244 /** 245 * Incompatible changes in attribute value normalization. This causes 246 * indexes to be invalidated. 247 */ 248 STRINGPREP_NORMALIZATION_CHANGE_1( 249 8, // Unique ID. See javadoc for more information. 250 INFO_5134_UPGRADE.get(), 251 INFO_5134_REVERSION.get(), 252 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 253 Effect.UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED), 254 255 /** 256 * Incompatible changes in DN normalization. This causes dn2id and 257 * RDN / DN syntax based attribute indexes to be invalidated. 258 */ 259 DN_NORMALIZATION_CHANGE_1( 260 7, // Unique ID. See javadoc for more information. 261 INFO_3873_UPGRADE.get(), 262 INFO_3873_REVERSION.get(), 263 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 264 Effect.UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED), 265 266 /** 267 * Incompatible changes in the backend configuration (the db directory 268 * attribute has been modified). 269 */ 270 BACKEND_CONFIGURATION_CHANGE_1( 271 6, // Unique ID. See javadoc for more information. 272 INFO_3708_UPGRADE.get(), 273 INFO_3708_REVERSION.get(), 274 Effect.REVERSION_NOT_POSSIBLE, 275 Effect.UPGRADE_NOT_POSSIBLE), 276 277 /** 278 * Incompatible changes in the cryptomanager and specially in the way 279 * replication works. These changes were committed on several revisions 280 * and the flagday that has been chosen corresponds to revision 3294 281 * (opends 1.0.0 build 6 of 16/10/2007) 282 */ 283 REPLICATION_SECURITY_CHANGE_1( 284 5, // Unique ID. See javadoc for more information. 285 INFO_3294_UPGRADE.get(), 286 INFO_3294_REVERSION.get(), 287 Effect.REVERSION_NOT_POSSIBLE, 288 Effect.UPGRADE_NOT_POSSIBLE), 289 290 /** 291 * Incompatible property name change committed on 09/05/2007 292 * and described in the SVN log for rev 2974. 293 */ 294 PROPERTY_CHANGE_1( 295 4, // Unique ID. See javadoc for more information. 296 INFO_2974_UPGRADE.get(), 297 INFO_2974_REVERSION.get(), 298 Effect.REVERSION_NOT_POSSIBLE, 299 Effect.UPGRADE_NOT_POSSIBLE), 300 301 /** 302 * Database format change committed on 6/7/2007 303 * and described in the SVN log for rev 2049. 304 */ 305 DB_FORMAT_CHANGE_2( 306 3, // Unique ID. See javadoc for more information. 307 INFO_2049_UPGRADE.get(), 308 INFO_2049_REVERSION.get(), 309 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 310 Effect.UPGRADE_SHOW_WARNING_MESSAGE), 311 312 /** 313 * Database format change committed on 4/6/2007 314 * and described in the SVN log for rev 1582. 315 */ 316 DB_FORMAT_CHANGE_1( 317 2, // Unique ID. See javadoc for more information. 318 INFO_1582_UPGRADE.get(), 319 INFO_1582_REVERSION.get(), 320 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 321 Effect.UPGRADE_SHOW_WARNING_MESSAGE), 322 323 /** 324 * Upgrade of Berkley DB library to 3.2.13 on 325 * 12/17/2006. 326 */ 327 BERKLEY_UPGRADE_1( 328 1, // Unique ID. See javadoc for more information. 329 INFO_890_UPGRADE.get(), 330 INFO_890_REVERSION.get(), 331 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 332 Effect.UPGRADE_SHOW_WARNING_MESSAGE); 333 334 /** 335 * Gets a <code>Cause</code> from its unique ID. If no cause 336 * is associated with <code>id</code> this method returns null. 337 * @param id of a cause 338 * @return Cause with <code>id</code> 339 */ 340 static Cause fromId(int id) { 341 Cause cause = null; 342 EnumSet<Cause> es = EnumSet.allOf(Cause.class); 343 for (Cause c : es) { 344 if (c.getId() == id) { 345 cause = c; 346 break; 347 } 348 } 349 return cause; 350 } 351 352 private int id; 353 private Set<Effect> effects = new HashSet<>(); 354 private LocalizableMessage upgradeMsg; 355 private LocalizableMessage reversionMsg; 356 357 /** 358 * Creates a parameterized instance. 359 * 360 * @param id of this cause. It would get very complicated to try to 361 * deal with releases as a graph and attempting to compare 362 * versions to see what issues apply during an upgrade/reversion 363 * between two releases. Therefore IDs are used by the tools 364 * to identify issues would have already been seen during a previous 365 * upgrade and do not need to be rehashed. 366 * <p> 367 * So if an issue exists in the 1.0 branch, an upgrade from 2.0 368 * to 3.0 will suppress the issue since it would presumably already 369 * been dealt with when 2.0 was installed or upgraded to. Likewise 370 * if an issue is assocated with a particular minor version (1.1 for 371 * instance) major upgrades (1.0 to 2.0) will avoid presenting the 372 * issue. 373 * 374 * <ol> 375 * <li>IDs must be unique among different causes in all branches 376 * of the OpenDJ code.</li> 377 * 378 * <li>Causes in different branches representing the same issue 379 * must have identical IDs.</li> 380 * 381 * <li>The IDs are advertised by the server when start-ds -F 382 * is invoked. Therefore they should be kept to as few 383 * characters as possible.</li> 384 * </ol> 385 * 386 * @param upgradeMessage a message to be shown to the user during an 387 * upgrade between two different version between which this issue 388 * lies. This message might detail instructions for manual actions 389 * that must be performed (when used with the 390 * <code>UPGRADE_MANUAL_ACTION_REQUIRED</code>) or give the 391 * user a warning message (when used with 392 * <code>UPGRADE_SHOW_WARNING_MESSAGE</code>). If a message is 393 * present but no effects that would dictate how message is to 394 * be presented <code>UPGRADE_SHOW_INFO_MESSAGE</code> is 395 * assumed. This parameter may also be null in which case no 396 * action will be taken during upgrade. 397 * 398 * @param reversionMessage a message to be shown to the user during a 399 * reversion between two different version between which this issue 400 * lies. This message might detail instructions for manual actions 401 * that must be performed (when used with the 402 * <code>REVERSION_MANUAL_ACTION_REQUIRED</code>) or give the 403 * user a warning message (when used with 404 * <code>REVERSION_SHOW_WARNING_MESSAGE</code>). If a message is 405 * present but no effects that would dictate how message is to 406 * be presented <code>REVERSION_SHOW_INFO_MESSAGE</code> is 407 * assumed. This parameter may also be null in which case no 408 * action will be taken during reversion. 409 * 410 * @param effects of this cause which cause the upgrade/reversion tools 411 * to behave in particular ways 412 */ 413 private Cause(int id, LocalizableMessage upgradeMessage, LocalizableMessage reversionMessage, 414 Effect... effects) { 415 this.id = id; 416 this.upgradeMsg = upgradeMessage; 417 this.reversionMsg = reversionMessage; 418 if (effects != null) { 419 Collections.addAll(this.effects, effects); 420 } 421 } 422 423 /** 424 * Gets the ID of this cause. 425 * @return id of this cause 426 */ 427 public int getId() { 428 return this.id; 429 } 430 431 /** 432 * Gets the set of effects that cause the upgrade/reversion 433 * tools to behave in particular ways. 434 * 435 * @return set of effects 436 */ 437 public Set<Effect> getEffects() { 438 return Collections.unmodifiableSet(effects); 439 } 440 441 /** 442 * Gets a localized message to be shown to the user during 443 * the upgrade process. 444 * 445 * @return a message to be shown to the user during an 446 * upgrade between two different version between which this issue 447 * lies. This message might detail instructions for manual actions 448 * that must be performed (when used with the 449 * <code>UPGRADE_MANUAL_ACTION_REQUIRED</code>) or just give the 450 * user useful information (when used with 451 * <code>UPGRADE_SHOW_INFO_MESSAGE</code>) 452 */ 453 public LocalizableMessage getLocalizedUpgradeMessage() { 454 return upgradeMsg; 455 } 456 457 /** 458 * Gets a localized message to be shown to the user during 459 * the reversion process. 460 * 461 * @return a message to be shown to the user during an 462 * upgrade between two different version between which this issue 463 * lies. This message might detail instructions for manual actions 464 * that must be performed (when used with the 465 * <code>REVERSION_MANUAL_ACTION_REQUIRED</code>) or just give the 466 * user useful information (when used with 467 * <code>REVERSION_SHOW_INFO_MESSAGE</code>) 468 */ 469 public LocalizableMessage getLocalizedReversionMessage() { 470 return reversionMsg; 471 } 472 473 } 474 475 /** Container for registered issues. */ 476 private static final Set<VersionCompatibilityIssue> VERSION_COMPATIBILITY_ISSUES = new HashSet<>(); 477 478 //*************************************************** 479 // 480 // TO DEFINE A NEW ISSUE: 481 // 482 // STEP 2: [scroll up] 483 // 484 // STEP 3: Associate the cause with a particular build. 485 // 486 // DONE 487 // 488 //*************************************************** 489 490 static 491 { 492 register(Cause.DS_SYNC_HIST_NORMALIZATION_CHANGE_1, new BuildVersion(2, 4, 493 5, 7635)); 494 register (Cause.REVERT_NOT_SUPPORTED_1, new BuildVersion(2,0,0,5278)); 495 register(Cause.STRINGPREP_NORMALIZATION_CHANGE_1, 496 new BuildVersion(1,2,0,5134)); 497 register(Cause.DN_NORMALIZATION_CHANGE_1, new BuildVersion(1, 0, 0, 3873)); 498 register(Cause.BACKEND_CONFIGURATION_CHANGE_1, 499 new BuildVersion(1, 0, 0, 3708)); 500 register(Cause.REPLICATION_SECURITY_CHANGE_1, 501 new BuildVersion(1, 0, 0, 3294)); 502 register(Cause.PROPERTY_CHANGE_1, new BuildVersion(1, 0, 0, 3053)); 503 register(Cause.DB_FORMAT_CHANGE_2, new BuildVersion(0, 9, 0, 2049)); 504 register(Cause.DB_FORMAT_CHANGE_1, new BuildVersion(0, 1, 0, 1582)); 505 register(Cause.BERKLEY_UPGRADE_1, new BuildVersion(0, 1, 0, 890)); 506 } 507 508 private static void register(Cause cause, 509 BuildVersion version) { 510 VERSION_COMPATIBILITY_ISSUES.add(new VersionCompatibilityIssue(cause, 511 version)); 512 } 513 514 /** 515 * Gets the list of all registered issues. 516 * 517 * @return list of issues sorted by build version in which 518 * they appear 519 */ 520 public static List<VersionCompatibilityIssue> getAllEvents() { 521 List<VersionCompatibilityIssue> issueList = new ArrayList<>(VERSION_COMPATIBILITY_ISSUES); 522 Collections.sort(issueList, VERSION_COMPARATOR); 523 return Collections.unmodifiableList(issueList); 524 } 525 526 /** 527 * Gets the list of all registered issues excluding the 528 * issues specified by <code>excludeIds</code>. 529 * 530 * @param excludeIds collection of IDs representing issues 531 * that will not be returned in the list 532 * @param current build version 533 * @param neu build version 534 * 535 * @return list of issues sorted by build version in which 536 * they appear 537 */ 538 public static List<VersionCompatibilityIssue> getEvents( 539 Collection<Integer> excludeIds, BuildInformation current, 540 BuildInformation neu) 541 { 542 if (excludeIds == null) 543 { 544 excludeIds = Collections.emptySet(); 545 } 546 List<VersionCompatibilityIssue> issueList = new ArrayList<>(); 547 for (VersionCompatibilityIssue evt : VERSION_COMPATIBILITY_ISSUES) { 548 if (!excludeIds.contains(evt.getCause().getId())) { 549 BuildVersion currentVersion = new BuildVersion( 550 current.getMajorVersion(), current.getMinorVersion(), 551 current.getPointVersion(), current.getRevisionNumber()); 552 // If the currentVersion is newer than the issue described, then there 553 // is no problem. This can occur for instance when we discovered a 554 // flag day too late (and we added the flag day description to the 555 // code way after the revision). 556 if (currentVersion.compareTo(evt.getVersion()) < 0) 557 { 558 issueList.add(evt); 559 } 560 } 561 } 562 Collections.sort(issueList, VERSION_COMPARATOR); 563 return Collections.unmodifiableList(issueList); 564 } 565 566 /** 567 * Returns events that have happened in between the SVN revision numbers 568 * of two different builds. Note that this method does not necessarily 569 * return all events that are pertinent. For instance a partilar event 570 * may have happend in a branch that we don't care about for the current 571 * upgrade. So this method should really just be used as a fall-back 572 * in the case where we are upgrading/reverting a build that was not 573 * instrumented to return the Upgrade Event IDs using start-ds -F. 574 * 575 * @param from build from which events will be returned 576 * @return List or IncompatibleVersionEvent objects 577 */ 578 public static List<VersionCompatibilityIssue> getEvents(BuildVersion from) { 579 List<VersionCompatibilityIssue> issueList = new ArrayList<>(); 580 for (VersionCompatibilityIssue evt : VERSION_COMPATIBILITY_ISSUES) { 581 BuildVersion evtVer = evt.getVersion(); 582 if (evtVer.compareTo(from) >= 0) { 583 issueList.add(evt); 584 } 585 } 586 Collections.sort(issueList, VERSION_COMPARATOR); 587 return issueList; 588 } 589 590 /** 591 * Comparator used to sort issues by the build version for 592 * which they apply. 593 */ 594 private static final Comparator<VersionCompatibilityIssue> 595 VERSION_COMPARATOR = new Comparator<VersionCompatibilityIssue>() 596 { 597 @Override 598 public int compare(VersionCompatibilityIssue o1, 599 VersionCompatibilityIssue o2) { 600 return o1.getVersion().compareTo(o2.getVersion()); 601 } 602 }; 603 604 private Cause cause; 605 private BuildVersion version; 606 607 private VersionCompatibilityIssue(Cause cause, BuildVersion version) { 608 this.cause = cause; 609 this.version = version; 610 } 611 612 /** 613 * Gets the cause of this issue. 614 * @return the cause 615 */ 616 public Cause getCause() { 617 return this.cause; 618 } 619 620 /** 621 * Gets the build version for which this issue applies. 622 * @return build version 623 */ 624 public BuildVersion getVersion() { 625 return this.version; 626 } 627 628 /** 629 * Retrieves a string representation of this version compatibility issue. 630 * 631 * @return A string representation of this version compatibility issue. 632 */ 633 @Override 634 public String toString() { 635 return Integer.toString(cause.getId()); 636 } 637 638}