/// <inheritdoc/> /// <exception cref="InvalidOperationException">One of paths returned by /// <see cref="Hint.GetTargets"/> method isn't found.</exception> public void Add(Hint hint) { ArgumentValidator.EnsureArgumentNotNull(hint, "hint"); if (set.Contains(hint)) { throw new InvalidOperationException(Strings.ExItemAlreadyExists); } try { var targets = hint.GetTargets().ToList(); var nodes = new List <Node>(); foreach (var target in targets) { Node node; if (target.Model == ModelType.Source) { node = (Node)SourceModel.Resolve(target.Path, true); } else { node = (Node)TargetModel.Resolve(target.Path, true); } nodes.Add(node); if (!hintMap.ContainsKey(node)) { hintMap.Add(node, new Dictionary <Type, object>()); } var nodeHintMap = hintMap[node]; var hintType = hint.GetType(); if (!nodeHintMap.ContainsKey(hintType)) { nodeHintMap.Add(hintType, null); } var hintOrList = nodeHintMap[hintType]; if (hintOrList == null) { nodeHintMap[hintType] = hint; } else { var list = hintOrList as List <Hint>; if (list == null) { var oldHint = (Hint)hintOrList; nodeHintMap[hintType] = new List <Hint>(new[] { oldHint, hint }); } else { list.Add(hint); } } } } catch (Exception) { var oldHints = list.ToList(); // Cloning the list Clear(); foreach (var oldHint in oldHints) { Add(oldHint); } throw; } set.Add(hint); list.Add(hint); }
/// <inheritdoc/> /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c> /// is out of range.</exception> /// <exception cref="InvalidOperationException">Upgrade sequence validation has failed.</exception> public ReadOnlyList <NodeAction> GetUpgradeSequence(Difference difference, HintSet hints, IComparer comparer) { ArgumentValidator.EnsureArgumentNotNull(hints, nameof(hints)); ArgumentValidator.EnsureArgumentNotNull(comparer, nameof(comparer)); if (difference == null) { return(new ReadOnlyList <NodeAction>(Enumerable.Empty <NodeAction>().ToList())); } TemporaryRenames = new Dictionary <string, Node>(StringComparer.OrdinalIgnoreCase); SourceModel = (IModel)difference.Source; TargetModel = (IModel)difference.Target; Hints = hints ?? new HintSet(SourceModel, TargetModel); Comparer = comparer; if (Hints.SourceModel != SourceModel) { throw new ArgumentOutOfRangeException("hints.SourceModel"); } if (Hints.TargetModel != TargetModel) { throw new ArgumentOutOfRangeException("hints.TargetModel"); } CurrentModel = (IModel)SourceModel.Clone(null, SourceModel.Name); Difference = difference; var previous = currentAsync.Value; currentAsync.Value = this; using (NullActionHandler.Instance.Activate()) { try { var actions = new GroupingNodeAction(); ProcessStage(UpgradeStage.CleanupData, actions); ProcessStage(UpgradeStage.Prepare, actions); ProcessStage(UpgradeStage.TemporaryRename, actions); ProcessStage(UpgradeStage.Upgrade, actions); ProcessStage(UpgradeStage.CopyData, actions); ProcessStage(UpgradeStage.PostCopyData, actions); ProcessStage(UpgradeStage.Cleanup, actions); var validationHints = new HintSet(CurrentModel, TargetModel); Hints.OfType <IgnoreHint>() .Where(h => CurrentModel.Resolve(h.Path, false) != null && SourceModel.Resolve(h.Path, false) != null) .ForEach(validationHints.Add); var diff = comparer.Compare(CurrentModel, TargetModel, validationHints); if (diff != null) { CoreLog.InfoRegion(Strings.LogAutomaticUpgradeSequenceValidation); CoreLog.Info(Strings.LogValidationFailed); CoreLog.Info(Strings.LogItemFormat, Strings.Difference); CoreLog.Info("{0}", diff); CoreLog.Info(Strings.LogItemFormat + "\r\n{1}", Strings.UpgradeSequence, new ActionSequence() { actions }); CoreLog.Info(Strings.LogItemFormat, Strings.ExpectedTargetModel); TargetModel.Dump(); CoreLog.Info(Strings.LogItemFormat, Strings.ActualTargetModel); CurrentModel.Dump(); throw new InvalidOperationException(Strings.ExUpgradeSequenceValidationFailure); } return(new ReadOnlyList <NodeAction>(actions.Actions, true)); } finally { currentAsync.Value = previous; } } }