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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2007-2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.util; 029 import org.opends.messages.Message; 030 import org.opends.quicksetup.BuildInformation; 031 032 import static org.opends.messages.VersionMessages.*; 033 034 import java.util.Set; 035 import java.util.List; 036 import java.util.Collections; 037 import java.util.HashSet; 038 import java.util.ArrayList; 039 import java.util.EnumSet; 040 import java.util.Comparator; 041 import java.util.Collection; 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) 054 public 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 OpenDS codebase. 218 */ 219 public enum Cause { 220 /** 221 * Incompatible changes in DN normalization. This causes dn2id and 222 * RDN / DN syntax based attribute indexes to be invalidated. 223 */ 224 DN_NORMALIZATION_CHANGE_1( 225 7, // Unique ID. See javadoc for more information. 226 INFO_3873_UPGRADE.get(), 227 INFO_3873_REVERSION.get(), 228 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 229 Effect.UPGRADE_DATA_EXPORT_AND_REIMPORT_REQUIRED), 230 231 /** 232 * Incompatible changes in the backend configuration (the db directory 233 * attribute has been modified). 234 */ 235 BACKEND_CONFIGURATION_CHANGE_1( 236 6, // Unique ID. See javadoc for more information. 237 INFO_3708_UPGRADE.get(), 238 INFO_3708_REVERSION.get(), 239 Effect.REVERSION_NOT_POSSIBLE, 240 Effect.UPGRADE_NOT_POSSIBLE), 241 242 /** 243 * Incompatible changes in the cryptomanager and specially in the way 244 * replication works. These changes were committed on several revisions 245 * and the flagday that has been chosen corresponds to revision 3294 246 * (opends 1.0.0 build 6 of 16/10/2007) 247 */ 248 REPLICATION_SECURITY_CHANGE_1( 249 5, // Unique ID. See javadoc for more information. 250 INFO_3294_UPGRADE.get(), 251 INFO_3294_REVERSION.get(), 252 Effect.REVERSION_NOT_POSSIBLE, 253 Effect.UPGRADE_NOT_POSSIBLE), 254 255 /** 256 * Incompatible property name change committed on 09/05/2007 257 * and described in the SVN log for rev 2974. 258 */ 259 PROPERTY_CHANGE_1( 260 4, // Unique ID. See javadoc for more information. 261 INFO_2974_UPGRADE.get(), 262 INFO_2974_REVERSION.get(), 263 Effect.REVERSION_NOT_POSSIBLE, 264 Effect.UPGRADE_NOT_POSSIBLE), 265 266 /** 267 * Database format change committed on 6/7/2007 268 * and described in the SVN log for rev 2049. 269 */ 270 DB_FORMAT_CHANGE_2( 271 3, // Unique ID. See javadoc for more information. 272 INFO_2049_UPGRADE.get(), 273 INFO_2049_REVERSION.get(), 274 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 275 Effect.UPGRADE_SHOW_WARNING_MESSAGE), 276 277 /** 278 * Database format change committed on 4/6/2007 279 * and described in the SVN log for rev 1582. 280 */ 281 DB_FORMAT_CHANGE_1( 282 2, // Unique ID. See javadoc for more information. 283 INFO_1582_UPGRADE.get(), 284 INFO_1582_REVERSION.get(), 285 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 286 Effect.UPGRADE_SHOW_WARNING_MESSAGE), 287 288 /** 289 * Upgrade of Berkley DB library to 3.2.13 on 290 * 12/17/2006. 291 */ 292 BERKLEY_UPGRADE_1( 293 1, // Unique ID. See javadoc for more information. 294 INFO_890_UPGRADE.get(), 295 INFO_890_REVERSION.get(), 296 Effect.REVERSION_DATA_EXPORT_AND_REIMPORT_REQUIRED, 297 Effect.UPGRADE_SHOW_WARNING_MESSAGE); 298 299 /** 300 * Gets a <code>Cause</code> from its unique ID. If no cause 301 * is associated with <code>id</code> this method returns null. 302 * @param id of a cause 303 * @return Cause with <code>id</code> 304 */ 305 static Cause fromId(int id) { 306 Cause cause = null; 307 EnumSet<Cause> es = EnumSet.allOf(Cause.class); 308 for (Cause c : es) { 309 if (c.getId() == id) { 310 cause = c; 311 break; 312 } 313 } 314 return cause; 315 } 316 317 private int id; 318 private Set<Effect> effects = new HashSet<Effect>(); 319 private Message upgradeMsg; 320 private Message reversionMsg; 321 322 /** 323 * Creates a parameterized instance. 324 * 325 * @param id of this cause. It would get very complicated to try to 326 * deal with releases as a graph and attempting to compare 327 * versions to see what issues apply during an upgrade/reversion 328 * between two releases. Therefore IDs are used by the tools 329 * to identify issues would have already been seen during a previous 330 * upgrade and do not need to be rehashed. 331 * <p> 332 * So if an issue exists in the 1.0 branch, an upgrade from 2.0 333 * to 3.0 will suppress the issue since it would presumably already 334 * been dealt with when 2.0 was installed or upgraded to. Likewise 335 * if an issue is assocated with a particular minor version (1.1 for 336 * instance) major upgrades (1.0 to 2.0) will avoid presenting the 337 * issue. 338 * 339 * <ol> 340 * <li>IDs must be unique among different causes in all branches 341 * of the OpenDS code.</li> 342 * 343 * <li>Causes in different branches representing the same issue 344 * must have identical IDs.</li> 345 * 346 * <li>The IDs are advertised by the server when start-ds -F 347 * is invoked. Therefore they should be kept to as few 348 * characters as possible.</li> 349 * </ol> 350 * 351 * @param upgradeMessage a message to be shown to the user during an 352 * upgrade between two different version between which this issue 353 * lies. This message might detail instructions for manual actions 354 * that must be performed (when used with the 355 * <code>UPGRADE_MANUAL_ACTION_REQUIRED</code>) or give the 356 * user a warning message (when used with 357 * <code>UPGRADE_SHOW_WARNING_MESSAGE</code>). If a message is 358 * present but no effects that would dictate how message is to 359 * be presented <code>UPGRADE_SHOW_INFO_MESSAGE</code> is 360 * assumed. This parameter may also be null in which case no 361 * action will be taken during upgrade. 362 * 363 * @param reversionMessage a message to be shown to the user during a 364 * reversion between two different version between which this issue 365 * lies. This message might detail instructions for manual actions 366 * that must be performed (when used with the 367 * <code>REVERSION_MANUAL_ACTION_REQUIRED</code>) or give the 368 * user a warning message (when used with 369 * <code>REVERSION_SHOW_WARNING_MESSAGE</code>). If a message is 370 * present but no effects that would dictate how message is to 371 * be presented <code>REVERSION_SHOW_INFO_MESSAGE</code> is 372 * assumed. This parameter may also be null in which case no 373 * action will be taken during reversion. 374 * 375 * @param effects of this cause which cause the upgrade/reversion tools 376 * to behave in particular ways 377 */ 378 private Cause(int id, Message upgradeMessage, Message reversionMessage, 379 Effect... effects) { 380 this.id = id; 381 this.upgradeMsg = upgradeMessage; 382 this.reversionMsg = reversionMessage; 383 if (effects != null) { 384 for (Effect c : effects) { 385 this.effects.add(c); 386 } 387 } 388 } 389 390 /** 391 * Gets the ID of this cause. 392 * @return id of this cause 393 */ 394 public int getId() { 395 return this.id; 396 } 397 398 /** 399 * Gets the set of effects that cause the upgrade/reversion 400 * tools to behave in particular ways. 401 * 402 * @return set of effects 403 */ 404 public Set<Effect> getEffects() { 405 return Collections.unmodifiableSet(effects); 406 } 407 408 /** 409 * Gets a localized message to be shown to the user during 410 * the upgrade process. 411 * 412 * @return a message to be shown to the user during an 413 * upgrade between two different version between which this issue 414 * lies. This message might detail instructions for manual actions 415 * that must be performed (when used with the 416 * <code>UPGRADE_MANUAL_ACTION_REQUIRED</code>) or just give the 417 * user useful information (when used with 418 * <code>UPGRADE_SHOW_INFO_MESSAGE</code>) 419 */ 420 public Message getLocalizedUpgradeMessage() { 421 return upgradeMsg; 422 } 423 424 /** 425 * Gets a localized message to be shown to the user during 426 * the reversion process. 427 * 428 * @return a message to be shown to the user during an 429 * upgrade between two different version between which this issue 430 * lies. This message might detail instructions for manual actions 431 * that must be performed (when used with the 432 * <code>REVERSION_MANUAL_ACTION_REQUIRED</code>) or just give the 433 * user useful information (when used with 434 * <code>REVERSION_SHOW_INFO_MESSAGE</code>) 435 */ 436 public Message getLocalizedReversionMessage() { 437 return reversionMsg; 438 } 439 440 } 441 442 /** 443 * Container for registered issues. 444 */ 445 static private final Set<VersionCompatibilityIssue> 446 VERSION_COMPATIBILITY_ISSUES = 447 new HashSet<VersionCompatibilityIssue>(); 448 449 //*************************************************** 450 // 451 // TO DEFINE A NEW ISSUE: 452 // 453 // STEP 2: [scroll up] 454 // 455 // STEP 3: Associate the cause with a particular build. 456 // 457 // DONE 458 // 459 //*************************************************** 460 461 static { 462 register(Cause.DN_NORMALIZATION_CHANGE_1, new BuildVersion(1, 0, 0, 3873)); 463 register(Cause.BACKEND_CONFIGURATION_CHANGE_1, 464 new BuildVersion(1, 0, 0, 3708)); 465 register(Cause.REPLICATION_SECURITY_CHANGE_1, 466 new BuildVersion(1, 0, 0, 3294)); 467 register(Cause.PROPERTY_CHANGE_1, new BuildVersion(1, 0, 0, 3053)); 468 register(Cause.DB_FORMAT_CHANGE_2, new BuildVersion(0, 9, 0, 2049)); 469 register(Cause.DB_FORMAT_CHANGE_1, new BuildVersion(0, 1, 0, 1582)); 470 register(Cause.BERKLEY_UPGRADE_1, new BuildVersion(0, 1, 0, 890)); 471 } 472 473 static private void register(Cause cause, 474 BuildVersion version) { 475 VERSION_COMPATIBILITY_ISSUES.add(new VersionCompatibilityIssue(cause, 476 version)); 477 } 478 479 /** 480 * Gets the list of all registered issues. 481 * 482 * @return list of issues sorted by build version in which 483 * they appear 484 */ 485 static public List<VersionCompatibilityIssue> getAllEvents() { 486 List<VersionCompatibilityIssue> issueList = 487 new ArrayList<VersionCompatibilityIssue> 488 (VERSION_COMPATIBILITY_ISSUES); 489 Collections.sort(issueList, VERSION_COMPARATOR); 490 return Collections.unmodifiableList(issueList); 491 } 492 493 /** 494 * Gets the list of all registered issues excluding the 495 * issues specified by <code>excludeIds</code>. 496 * 497 * @param excludeIds collection of IDs representing issues 498 * that will not be returned in the list 499 * @param current build version 500 * @param neu build version 501 * 502 * @return list of issues sorted by build version in which 503 * they appear 504 */ 505 static public List<VersionCompatibilityIssue> getEvents( 506 Collection<Integer> excludeIds, BuildInformation current, 507 BuildInformation neu) 508 { 509 if (excludeIds == null) excludeIds = Collections.emptySet(); 510 List<VersionCompatibilityIssue> issueList = 511 new ArrayList<VersionCompatibilityIssue>(); 512 for (VersionCompatibilityIssue evt : VERSION_COMPATIBILITY_ISSUES) { 513 if (!excludeIds.contains(evt.getCause().getId())) { 514 boolean isUpgrade = neu.compareTo(current) >= 0; 515 BuildVersion currentVersion = new BuildVersion( 516 current.getMajorVersion(), current.getMinorVersion(), 517 current.getPointVersion(), current.getRevisionNumber()); 518 if (isUpgrade) 519 { 520 // If the currentVersion is newer than the issue described, then there 521 // is no problem. This can occur for instance when we discovered a 522 // flag day too late (and we added the flag day description to the 523 // code way after the revision). 524 if (currentVersion.compareTo(evt.getVersion()) < 0) 525 { 526 issueList.add(evt); 527 } 528 } 529 else 530 { 531 // If the newVersion in the reversion is newer than the issue 532 // described, then there is no problem. This can occur for instance 533 // when we discovered a flag day too late (and we added the flag day 534 // description to the code way after the revision). 535 if (currentVersion.compareTo(evt.getVersion()) < 0) 536 { 537 issueList.add(evt); 538 } 539 } 540 } 541 } 542 Collections.sort(issueList, VERSION_COMPARATOR); 543 return Collections.unmodifiableList(issueList); 544 } 545 546 /** 547 * Returns events that have happened in between the SVN revision numbers 548 * of two different builds. Note that this method does not necessarily 549 * return all events that are pertinent. For instance a partilar event 550 * may have happend in a branch that we don't care about for the current 551 * upgrade. So this method should really just be used as a fall-back 552 * in the case where we are upgrading/reverting a build that was not 553 * instrumented to return the Upgrade Event IDs using start-ds -F. 554 * 555 * @param from build from which events will be returned 556 * @return List or IncompatibleVersionEvent objects 557 */ 558 static public List<VersionCompatibilityIssue> getEvents(BuildVersion from) { 559 List<VersionCompatibilityIssue> issueList = 560 new ArrayList<VersionCompatibilityIssue>(); 561 for (VersionCompatibilityIssue evt : VERSION_COMPATIBILITY_ISSUES) { 562 BuildVersion evtVer = evt.getVersion(); 563 if (evtVer.compareTo(from) >= 0) { 564 issueList.add(evt); 565 } 566 } 567 Collections.sort(issueList, VERSION_COMPARATOR); 568 return issueList; 569 } 570 571 /** 572 * Comparator used to sort issues by the build version for 573 * which they apply. 574 */ 575 static private final Comparator<VersionCompatibilityIssue> 576 VERSION_COMPARATOR = new Comparator<VersionCompatibilityIssue>() 577 { 578 public int compare(VersionCompatibilityIssue o1, 579 VersionCompatibilityIssue o2) { 580 return o1.getVersion().compareTo(o2.getVersion()); 581 } 582 }; 583 584 private Cause cause; 585 private BuildVersion version; 586 587 private VersionCompatibilityIssue(Cause cause, BuildVersion version) { 588 this.cause = cause; 589 this.version = version; 590 } 591 592 /** 593 * Gets the cause of this issue. 594 * @return the cause 595 */ 596 public Cause getCause() { 597 return this.cause; 598 } 599 600 /** 601 * Gets the build version for which this issue applies. 602 * @return build version 603 */ 604 public BuildVersion getVersion() { 605 return this.version; 606 } 607 608 /** 609 * Retrieves a string representation of this version compatibility issue. 610 * 611 * @return A string representation of this version compatibility issue. 612 */ 613 public String toString() { 614 return Integer.toString(cause.getId()); 615 } 616 617 }