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 }