Пример #1
0
        internal void Invoke()
        {
            // just to be safe, the c'tor should have caught this
            Debug.Assert(_cpc != null, "cpc cannot be null");
            if (_cpc == null)
            {
                throw new ArgumentNullException("_cpc");
            }

            // if there is nothing to do, just return
            if (_commands.Count == 0 &&
                _cpc.IntegrityChecks.Count == 0)
            {
                return;
            }

            // Note down whether or not the artifact was originally dirty, since we don't want hydration commands marking the file
            // as clean if there are uncommited diagram layout edits for instance.
            var artifactInitiallyDirty = _cpc.Artifact.IsDirty;

            // First add the commands to the command processor context so that the top-level processor can determine
            // how to post-process based on them.
            _cpc.EnqueuedCommands.AddRange(_commands);

            // We need to set the command processor since the behavior methods query this.
            foreach (var command in _commands)
            {
                command.CommandProcessor = this;
            }

            // since the Invoke() method is the gateway towards editing the model, we should first
            // ask ourselves if we can perform edits. This query is propagated down to the XML model level
            // where we base our answer on what the SCC provider tells us if we are in VS.
            // But we should only do this for the top-level transaction (otherwise we end up calling
            // VsXmlModel.CanEditXmlModel() for _every_ nested Command which causes perf problems
            // for transactions which use a large number of nested commands e.g. Update Model on a
            // large database)
            // Note: this means we do not support multi-artifact transactions. If we started doing wanting
            // to support multi-artifact transactions then the approach below would need to be expanded to
            // call CanEditArtifact() for each artifact in the transaction
            if (!_cpc.HasOpenTransaction)
            {
                if (!_cpc.Artifact.CanEditArtifact())
                {
                    var documentPath = String.Empty;
                    var uri          = _cpc.Artifact.Uri;
                    try
                    {
                        documentPath = uri.LocalPath;
                    }
                    catch (InvalidOperationException)
                    {
                        Debug.Fail("Could not parse the LocalPath from the URI for this particular Artifact");
                    }
                    throw new FileNotEditableException(
                              String.Format(CultureInfo.CurrentCulture, Resources.FileNotEditableErrorMessage, documentPath));
                }
            }

            var tx = _cpc.EfiTransaction;
            var isOuterMostTransaction = false;

            try
            {
                // open a local transaction if the cpc doesn't have one
                if (_cpc.HasOpenTransaction == false)
                {
                    tx = _cpc.CreateTransaction();
                    isOuterMostTransaction = true;
                }
                Debug.Assert(isOuterMostTransaction ? tx != null : true, "Why is the transaction null & isOuterMostTransaction true?");

                // invoke all of the commands in our queue
                while (_commands.Count > 0)
                {
                    var command = _commands.Dequeue();
                    command.Invoke(this);
                }

                // if we are managing the outer most transaction, do our post-processing
                if (isOuterMostTransaction)
                {
                    PostProcessUpdate(_cpc, tx, artifactInitiallyDirty);
                }
            }
            catch (Exception e)
            {
                if (isOuterMostTransaction
                    &&
                    tx != null
                    &&
                    tx.Status == EfiTransaction.EfiTxStatus.Open)
                {
                    tx.Rollback();
                }

                // BUGBUG: 557416

                if (isOuterMostTransaction)
                {
                    _cpc.ClearBindingsForRebind();
                    _cpc.ClearIntegrityChecks();
                }

                if (!(e is CommandValidationFailedException))
                {
                    Debug.Fail("Exception thrown inside CommandProcessor. " + e.Message);
                }

                throw;
            }
            finally
            {
                if (isOuterMostTransaction)
                {
                    _cpc.DisposeTransaction();
                }
            }
        }
Пример #2
0
        private void PostProcessUpdate(CommandProcessorContext cpc, EfiTransaction tx, bool artifactInitiallyDirty)
        {
            var setUndoScope = false;

            try
            {
                // process those checks that need to run in the originating xact
                while (cpc.IntegrityChecks.Count > 0)
                {
                    // peek for the next check and invoke it, don't dequeue it so we
                    // won't add dupes and recurse forever
                    var check = cpc.IntegrityChecks.Peek();
                    check.Invoke();

                    // now pop it off the queue
                    cpc.IntegrityChecks.Dequeue();
                }

                if (cpc.EditingContext.ParentUndoUnitStarted == false)
                {
                    cpc.EditingContext.ParentUndoUnitStarted = true;
                    cpc.Artifact.XmlModelProvider.BeginUndoScope(cpc.EfiTransaction.Name);
                    setUndoScope = true;
                }

                if (_shouldNotifyObservers)
                {
                    cpc.Artifact.ModelManager.BeforeCommitChangeGroups(cpc);
                }

                // Do not mark the artifact as clean if the artifact was initially dirty before commands
                // were executed... otherwise we may lose information like diagram layout and configurations.
                // Also, translation rules can perform immediate changes to configurations which will dirty the artifact
                // but are not recorded through the enqueued commands. So we should not set the artifact to clean in this case.
                tx.Commit(!artifactInitiallyDirty);
                cpc.DisposeTransaction();

#if DEBUG
                var visitor = cpc.Artifact.GetVerifyModelIntegrityVisitor(true, true, true, true, true);
                visitor.Traverse(cpc.Artifact);

                if (visitor.ErrorCount > 0)
                {
                    Debug.WriteLine("Model Integrity Verifier found " + visitor.ErrorCount + " error(s):");
                    Debug.WriteLine(visitor.AllSerializedErrors);
                    Debug.Assert(
                        false, "Model Integrity Verifier found " + visitor.ErrorCount + " error(s). See the Debug console for details.");
                }
#endif

                if (_shouldNotifyObservers)
                {
                    cpc.Artifact.ModelManager.RouteChangeGroups();
                }
                else
                {
                    // Changegroups have been recorded in the model manager;
                    // if we don't clear them they will be routed on the next observable transaction.
                    cpc.Artifact.ModelManager.ClearChangeGroups();
                }
            }
            finally
            {
                if (setUndoScope)
                {
                    cpc.Artifact.XmlModelProvider.EndUndoScope();
                    cpc.EditingContext.ParentUndoUnitStarted = false;
                }
            }
        }
Пример #3
0
        private void PostProcessUpdate(CommandProcessorContext cpc, EfiTransaction tx, bool artifactInitiallyDirty)
        {
            var setUndoScope = false;
            try
            {
                // process those checks that need to run in the originating xact
                while (cpc.IntegrityChecks.Count > 0)
                {
                    // peek for the next check and invoke it, don't dequeue it so we
                    // won't add dupes and recurse forever
                    var check = cpc.IntegrityChecks.Peek();
                    check.Invoke();

                    // now pop it off the queue
                    cpc.IntegrityChecks.Dequeue();
                }

                if (cpc.EditingContext.ParentUndoUnitStarted == false)
                {
                    cpc.EditingContext.ParentUndoUnitStarted = true;
                    cpc.Artifact.XmlModelProvider.BeginUndoScope(cpc.EfiTransaction.Name);
                    setUndoScope = true;
                }

                if (_shouldNotifyObservers)
                {
                    cpc.Artifact.ModelManager.BeforeCommitChangeGroups(cpc);
                }

                // Do not mark the artifact as clean if the artifact was initially dirty before commands
                // were executed... otherwise we may lose information like diagram layout and configurations.
                // Also, translation rules can perform immediate changes to configurations which will dirty the artifact
                // but are not recorded through the enqueued commands. So we should not set the artifact to clean in this case.
                tx.Commit(!artifactInitiallyDirty);
                cpc.DisposeTransaction();

#if DEBUG
                var visitor = cpc.Artifact.GetVerifyModelIntegrityVisitor(true, true, true, true, true);
                visitor.Traverse(cpc.Artifact);

                if (visitor.ErrorCount > 0)
                {
                    Debug.WriteLine("Model Integrity Verifier found " + visitor.ErrorCount + " error(s):");
                    Debug.WriteLine(visitor.AllSerializedErrors);
                    Debug.Assert(
                        false, "Model Integrity Verifier found " + visitor.ErrorCount + " error(s). See the Debug console for details.");
                }
#endif

                if (_shouldNotifyObservers)
                {
                    cpc.Artifact.ModelManager.RouteChangeGroups();
                }
                else
                {
                    // Changegroups have been recorded in the model manager;
                    // if we don't clear them they will be routed on the next observable transaction.
                    cpc.Artifact.ModelManager.ClearChangeGroups();
                }
            }
            finally
            {
                if (setUndoScope)
                {
                    cpc.Artifact.XmlModelProvider.EndUndoScope();
                    cpc.EditingContext.ParentUndoUnitStarted = false;
                }
            }
        }