public PushTransientStateNavigationTransition(Guid actionId, string name, string displayLabel, IEnumerable<Guid> sourceStateIds,
     WorkflowState transientTargetState, IResourceString displayTitle, IResourceString helpText) :
     base(actionId, name, sourceStateIds, displayTitle, helpText)
 {
   _displayLabel = displayLabel;
   _transientState = transientTargetState;
 }
 /// <summary>
 /// This constructor has to be called from the component managing the navigation context stack.
 /// </summary>
 public NavigationContext(WorkflowState workflowState, string displayLabel, NavigationContext predecessor,
     IWorkflowModel workflowModel)
 {
   _workflowState = workflowState;
   _displayLabel = displayLabel;
   _predecessor = predecessor;
   if (workflowModel != null)
   {
     _workflowModelId = workflowModel.ModelId;
     _models.Add(workflowModel.ModelId, workflowModel);
   }
 }
 /// <summary>
 /// Creates a <see cref="WorkflowAction"/> that pushes a dialog as transient state on the navigation stack.
 /// </summary>
 /// <param name="id"></param>
 /// <param name="name"></param>
 /// <param name="displayLabel"></param>
 /// <param name="dialogItems"></param>
 /// <param name="sourceState"></param>
 /// <param name="action"></param>
 /// <returns></returns>
 public static WorkflowAction CreateDialogMenuAction(Guid id, string name, string displayLabel, ItemsList dialogItems, WorkflowState sourceState, Action<ListItem> action)
 {
     return new PushTransientStateNavigationTransition(
         id,
         sourceState.Name + "->" + name,
         displayLabel,
         new Guid[] { sourceState.StateId },
         WorkflowState.CreateTransientState(name, displayLabel, true, "ovsDialogGenericItems", false, WorkflowType.Dialog),
         LocalizationHelper.CreateResourceString(displayLabel))
     {
         SortOrder = name,
         WorkflowNavigationContextVariables = new Dictionary<string, object>
         {
             { Constants.CONTEXT_VAR_ITEMS, dialogItems },
             { Constants.CONTEXT_VAR_COMMAND, new CommandContainer<ListItem>(action) }
         }
     };
 }
 protected static void PushNewNavigationWorkflowState(WorkflowState newState, string navbarDisplayLabel, NavigationData newNavigationData)
 {
   IWorkflowManager workflowManager = ServiceRegistration.Get<IWorkflowManager>();
   workflowManager.NavigatePushTransient(newState, new NavigationContextConfig
     {
       AdditionalContextVariables = new Dictionary<string, object>
         {
           {Consts.KEY_NAVIGATION_DATA, newNavigationData}
         },
       NavigationContextDisplayLabel = navbarDisplayLabel
     });
 }
 // Maybe called asynchronously.
 protected void NavigatePushTransientInternal(WorkflowState state, NavigationContextConfig config)
 {
   EnterWriteLock("NavigatePushTransient");
   try
   {
     try
     {
       if (DoPushNavigationContext(state, config))
         UpdateScreen_NeedsLock(true, true);
       WorkflowManagerMessaging.SendNavigationCompleteMessage();
     }
     catch (Exception e)
     {
       ServiceRegistration.Get<ILogger>().Error("WorkflowManager.NavigatePushTransientInternal: Error in workflow model or screen", e);
       NavigatePopInternal(1);
     }
   }
   finally
   {
     ExitWriteLock();
   }
 }
    /// <summary>
    /// Synchronous method which pushes the given workflow <paramref name="state"/> onto the navigation stack.
    /// </summary>
    /// <remarks>
    /// This method rethrows all exceptions which are thrown by workflow models. In case an exception is thrown,
    /// the internal state is still valid but the caller must pop the current navigation context from the workflow stack.
    /// </remarks>
    /// <param name="state">Workflow state to push.</param>
    /// <param name="config">Additional navigation context configuration.</param>
    /// <returns><c>true</c> if the push action was successful, else <c>false</c>.</returns>
    protected bool DoPushNavigationContext(WorkflowState state, NavigationContextConfig config)
    {
      if (config == null)
        config = EMPTY_NAVIGATION_CONTEXT_CONFIG;
      EnterWriteLock("DoPushNavigationContext");
      try
      {
        ILogger logger = ServiceRegistration.Get<ILogger>();
        NavigationContext current = CurrentNavigationContext;

        if (current != null && current.WorkflowState.IsTemporary && state.WorkflowType == WorkflowType.Workflow)
        {
          logger.Info("Current workflow state '{0}' is temporary, popping it from navigation stack", current.WorkflowState.Name);
          // The next statement can throw an exception - don't catch it - our caller should pop the current navigation context
          bool workflowStatePopped;
          DoPopNavigationContext(1, out workflowStatePopped);
        }

        NavigationContext predecessor = CurrentNavigationContext;
        logger.Info("WorkflowManager: Pushing workflow state '{0}' (id='{1}') onto the navigation stack...", state.Name, state.StateId);

        // Find non-transient state. If new state is transient, search for last non-transient state on stack.
        WorkflowState nonTransientState = state.IsTransient ? FindLastNonTransientState() : state;
        if (nonTransientState == null)
        {
          logger.Error("WorkflowManager: No non-transient state found on workflow context stack to be used as reference state. Workflow state to be pushed is '{0}' (id: '{1}')",
              state.Name, state.StateId);
          return false;
        }

        // Initialize workflow model
        Guid? workflowModelId = nonTransientState.WorkflowModelId;
        IWorkflowModel workflowModel = null;
        if (workflowModelId.HasValue)
        {
          object model = GetOrLoadModel(workflowModelId.Value);
          if (model is IWorkflowModel)
          {
            logger.Debug("WorkflowManager: Using workflow model with id '{0}' for new workflow state '{1}'",
                workflowModelId.Value, state.StateId);
            workflowModel = (IWorkflowModel) model;
          }
          else
            logger.Error("WorkflowManager: Model with id '{0}', which is used as workflow model in state '{1}', doesn't implement the interface '{2}'",
                workflowModelId.Value, state.StateId, typeof(IWorkflowModel).Name);
        }

        // Create new workflow context
        NavigationContext newContext = new NavigationContext(state, config.NavigationContextDisplayLabel, predecessor, workflowModel);
        if (config.AdditionalContextVariables != null)
          lock (newContext.SyncRoot)
            CollectionUtils.AddAll(newContext.ContextVariables, config.AdditionalContextVariables);

        // Check if state change is accepted
        bool canEnter = true;
        if (workflowModel != null)
          try
          {
            canEnter = workflowModel.CanEnterState(predecessor, newContext);
          }
          catch (Exception e)
          {
            logger.Error("WorkflowManager: Error checking if workflow model '{0}' can enter workflow state '{1}'", e,
              workflowModel.ModelId, newContext.WorkflowState.StateId);
            canEnter = false;
          }
        if (!canEnter)
        {
          logger.Debug("WorkflowManager: Workflow model with id '{0}' doesn't accept the state being pushed onto the workflow context stack. Reverting to old workflow state.", workflowModelId);
          return false;
        }

        // Store model exceptions
        IList<Exception> delayedExceptions = new List<Exception>();

        // Push new context
        logger.Debug("WorkflowManager: Entering workflow state '{0}'", state.Name);
        _navigationContextStack.Push(newContext);

        Guid? predecessorModelId = predecessor == null ? null : predecessor.WorkflowModelId;

        // Communicate context change to models
        bool modelChange = workflowModelId != predecessorModelId;

        // - Handle predecessor workflow model
        IWorkflowModel predecessorWorkflowModel = predecessorModelId.HasValue ?
            GetOrLoadModel(predecessorModelId.Value) as IWorkflowModel : null;
        if (predecessorWorkflowModel != null)
          if (modelChange)
          {
            logger.Debug("WorkflowManager: Deactivating predecessor workflow model '{0}'", predecessorModelId.Value);
            try
            {
              predecessorWorkflowModel.Deactivate(predecessor, newContext);
            }
            catch (Exception e)
            {
              logger.Error("WorkflowManager: Error deactivating workflow model '{0}'", e, predecessorWorkflowModel.ModelId);
              delayedExceptions.Add(e);
            }
          }
        // else: same model is currently active - model context change will be handled in the next block

        // - Handle new workflow model
        if (workflowModel != null)
          if (modelChange)
          {
            if (predecessor == null)
              logger.Debug("WorkflowManager: Starting first model context with workflow state '{0}' in workflow model '{1}'",
                  newContext.WorkflowState.StateId, workflowModelId.Value);
            else
              logger.Debug("WorkflowManager: Entering model context with workflow state '{0}' (old state was '{1}') in new workflow model '{2}'",
                  newContext.WorkflowState.StateId, predecessor.WorkflowState.StateId, workflowModelId.Value);
            try
            {
              workflowModel.EnterModelContext(predecessor, newContext);
            }
            catch (Exception e)
            {
              logger.Error("WorkflowManager: Error entering model context of workflow model '{0}' for workflow state '{1}'", e,
                  workflowModel.ModelId, newContext.WorkflowState.StateId);
              delayedExceptions.Add(e);
            }
          }
          else
          {
            logger.Debug("WorkflowManager: Changing model context to workflow state '{0}' (old state was '{1}') in workflow model '{2}'",
                newContext.WorkflowState.StateId, predecessor == null ? null : predecessor.WorkflowState.StateId.ToString(), workflowModelId.Value);
            try
            {
              workflowModel.ChangeModelContext(predecessor, newContext, true);
            }
            catch (Exception e)
            {
              logger.Error("WorkflowManager: Error changing model context of workflow model '{0}' from workflow state '{1}' to workflow state '{2}'",
                e, workflowModel.ModelId, predecessor.WorkflowState.StateId, newContext.WorkflowState.StateId);
              delayedExceptions.Add(e);
            }
          }
        if (state.WorkflowType == WorkflowType.Workflow)
        {
          // Compile menu actions
          logger.Debug("WorkflowManager: Compiling menu actions for workflow state '{0}'", state.Name);
          IDictionary<Guid, WorkflowAction> menuActions = new Dictionary<Guid, WorkflowAction>();
          foreach (WorkflowAction action in FilterActionsBySourceState(state.StateId, _menuActions.Values))
            menuActions.Add(action.ActionId, action);
          if (workflowModel != null)
            try
            {
              workflowModel.UpdateMenuActions(newContext, menuActions);
            }
            catch (Exception e)
            {
              logger.Error("WorkflowManager: Error updating menu actions in workflow model '{0}' for workflow state '{1}'", e,
                  workflowModel.ModelId, newContext.WorkflowState.StateId);
              delayedExceptions.Add(e);
            }
          newContext.SetMenuActions(menuActions.Values);
        }
        if (delayedExceptions.Count > 0)
          throw delayedExceptions.First();
        WorkflowManagerMessaging.SendStatePushedMessage(newContext);
        return true;
      }
      finally
      {
        ExitWriteLock();
        IterateCache_NoLock();
      }
    }
 public void NavigatePushTransientAsync(WorkflowState state, NavigationContextConfig config)
 {
   IThreadPool threadPool = ServiceRegistration.Get<IThreadPool>();
   threadPool.Add(() => NavigatePushTransientInternal(state, config));
 }
 public void NavigatePushTransient(WorkflowState state, NavigationContextConfig config)
 {
   NavigatePushTransientInternal(state, config);
 }
 public PushTransientStateNavigationTransition(Guid actionId, string name, string displayLabel, IEnumerable<Guid> sourceStateIds,
     WorkflowState transientTargetState, IResourceString displayTitle) :
   this(actionId, name, displayLabel, sourceStateIds, transientTargetState, displayTitle, null)
 {
 }
Exemple #10
0
 public PushTransientStateNavigationTransition(Guid actionId, string name, string displayLabel, IEnumerable <Guid> sourceStateIds,
                                               WorkflowState transientTargetState, IResourceString displayTitle) :
     this(actionId, name, displayLabel, sourceStateIds, transientTargetState, displayTitle, null)
 {
 }