Back to top
 
 
 

Customizing Workflows

In CloudPortal™ Business Manager, user can perform certain actions to achieve a desired business purpose. These actions can be considered as business transactions that help in achieving this business purpose. A workflow is a multi-stage process that consists of multiple phases. Every phase consists of a set of activities, (smallest unit of work in a workflow) that should be completed successfully in order to complete the phase. All phases should be completed to complete a business transaction.

You can customize any existing workflow by performing any of the following:
  • Move the activities into another phase.
  • Change the order of the phases.
  • Remove the activities from any phase.
    Note: The above mentioned tasks can be edited in workflows.xml
  • Add any new activity to any phase.
  • Add a new phase with new activities or existing activities.

To perform the above mentioned tasks, follow the steps explained below:

How to create a new activity
  1. Create an activity in citrix.cpbm.custom bundle by creating a new class which implements the interface "com.citrix.cpbm.workflow.activity.Activity".
  2. Create a task within the activity, so that the task will be opened when the activity is started.
    Consider the following example where AddSecondaryEmailActivity is the activity being created, and ADD_SEC_EMAIL is the task within that activity and its status is being checked for completion.
    package com.citrix.cpbm.workflow.custom.activity;    import com.citrix.cpbm.core.workflow.model.BusinessTransaction;  import com.citrix.cpbm.core.workflow.model.Task;  import com.citrix.cpbm.core.workflow.model.Task.State;  import com.citrix.cpbm.workflow.activity.Activity;  import com.citrix.cpbm.workflow.activity.WorkflowActivityExecutionException;  import com.vmops.service.AuthorityService;  import com.vmops.service.UserAlertPreferencesService;    public class AddSecondaryEmailActivity implements Activity{                  private AuthorityService authorityService;                  private UserAlertPreferencesService userAlertPreferencesService;                    public void setUserAlertPreferencesService(                       UserAlertPreferencesService userAlertPreferencesService) {                this.userAlertPreferencesService = userAlertPreferencesService;         }           public AuthorityService getAuthorityService() {             return authorityService;         }           public void setAuthorityService(AuthorityService authorityService) {             this.authorityService = authorityService;         }           @Override         public void start(BusinessTransaction businessTransaction,                       Record activityRecord) throws WorkflowActivityExecutionException {                         }           @Override         public Status run(BusinessTransaction businessTransaction,                       Record activityRecord) throws WorkflowActivityExecutionException {                Status activityStatus;             if (isActivityComplete(businessTransaction, activityRecord)) {               activityStatus = Status.SUCCESS;             } else {               activityStatus = doActivity(businessTransaction, activityRecord);             }                          if (activityRecord.getTask() == null && Status.WAITING == activityStatus) {                 Task action = createAction(businessTransaction);                 activityRecord.setTask(action);             }                          return activityStatus;         }                  protected Boolean isActivityComplete(BusinessTransaction businessTransaction,                       Record record) throws WorkflowActivityExecutionException {                if(userAlertPreferencesService.getCount(businessTransaction.getTenant().getOwner())>0){                       return true;                }else                       return false;         }                  public Task createAction(BusinessTransaction businessTransaction)                       throws WorkflowActivityExecutionException {                Task action = new Task("ADD_SEC_EMAIL", businessTransaction.getTenant(), businessTransaction.getTenant().getOwner(),                        businessTransaction, State.PENDING, authorityService.findByAuthority("ROLE_ACCOUNT_USER_CRUD"),                        Task.DisplayMode.POPUP);                    return action;         }                  protected Status doActivity(BusinessTransaction businessTransaction,                       Record activityPayload) throws WorkflowActivityExecutionException {                  Task action = activityPayload.getTask();                if (action != null) {                      if (action.getState() == Task.State.SUCCESS) {                        return Status.SUCCESS;                      } else if (action.getState() == Task.State.FAILURE) {                        return Status.FAILURE;                   }                }                    return Status.WAITING;         }    }    
  3. Add the newly created custom activity bean in applicationContext-workflow-customizations.xml file which is in src/main/resources/META-INF/spring/ of citrix.cpbm.custom.common bundle.
    For the above example, following bean is added:
    <bean id="addSecondaryEmailActivity" class="com.citrix.cpbm.workflow.custom.activity.AddSecondaryEmailActivity">    <property name="authorityService" ref="authorityService"/>    <property name="userService" ref="userService"/>    <property name="userAlertPreferencesService" ref="userAlertPreferencesService"/>  </bean>   
  4. Add the activity reference in osgi-context.xml file which is in src/main/resources/META-INF/spring/ of citrix.cpbm.custom bundle.
    For the above example, following reference is added:
    <osgi:service interface="com.citrix.cpbm.workflow.activity.Activity" ref="addSecondaryEmailActivity" />
    Note: Also publish new service dependencies (if any).
  5. Specify a user friendly name for the task label in CustomApplicationResources.properties file in src/main/resources/OSGI-INF/l10n/resources of citrix.cpbm.custom bundle for it to be displayed in the UI task list.

    For the above example, following labels are specified to display when secondary email task is created

    ui.widget.task.type.ADD_SEC_EMAIL.name= Add Secondary Email for {0}

    ui.task.type.ADD_SEC_EMAIL.name= Add Secondary Email for {0}

You can add new workflow definitions also which can either replace existing definition or can be started for a new rule by customizing the file transactionWorkflowMap.xml. To add a new workflow for a transaction, perform the following steps:
  1. Add a new rule in transactionWorkflowMap.xml.

    To write rules in transaction workflow map (transactionWorkflowMap.xml):

    Whenever a business transaction is triggered, the system will apply the applicable rules available in transactionWorkflowMap.xml on the business transaction and if the rule matches, then it will return the corresponding workflow. If multiple rules gets matched, then the system will return the workflow associated with a match that comes first.

    For example -
      <Match type="tenantStateChange" workflow="credit-card-account-activation">      <Rule>{#transaction.tenantInitialState.name == 'NEW' and #transaction.tenantTargetState.name == 'ACTIVE'   and  #transaction.tenant.accountType.paymentModes == 2}</Rule>  </Match>

    In above snippet, when a business transaction of type tenantStateChange is triggered for initial state "NEW" and target state "ACTIVE" for a tenant having payment mode as 2 (which internally means credit card), then system returns the credit-card-account-activation workflow.

Writing a rule

For writing a rule, any direct or transitive property available in business transaction object can be used.

Following are the properties available directly or transitively in different business transactions:

TenantStateChangeTransaction
Name Type
tenant com.vmops.model. Tenant
tenantInitialState com.vmops.model.Tenant.State
tenantTargetState com.vmops.model.Tenant.State

TenantAccountTypeConversionTransaction

Name Type
tenant com.vmops.model. Tenant
accountTypeInitial com.vmops.model.AccountType
accountType com.vmops.model.AccountType.State
paymentInfo String

PaymentInfoChangeTransaction

Name Type
tenant com.vmops.model. Tenant
accountTypeInitial com.vmops.model.AccountType
accountType com.vmops.model.AccountType.State
paymentInfo java.lang.String

SubscriptionActivationTransaction

Name Type
tenant com.vmops.model. Tenant
subscription com.vmops.model.Subscription
subscriptionInitialState com.vmops.model.Subscription.State
subscriptionTargetState com.vmops.model.Subscription.State
isProvisioned java.lang.String

CloudServiceActivationTransaction

Name Type
serviceInstance com.vmops.model.ServiceInstance
initialState com.vmops.model.TenantHandle.State
targetState com.vmops.model.TenantHandle.State
instanceProperty java.lang.String

com.vmops.model.Tenant

Name Type
sourceChannel com.vmops.model. Channel
accountType com.vmops.model.AccountType
spendLimit java.math.BigDecimal
initialDeposit java.math.BigDecimal
address com.vmops.model.Address
currency com.vmops.model.CurrencyValue
state com.vmops.model. Tenant.State
createdAt java.util.Date

Subscription

Name Type
state com.vmops.model. Subscription.State
tenant com.vmops.model.Tenant
productBundle com.vmops.model.ProductBundle
createdAt java.util.Date
derivedFrom com.vmops.model.Subscription

AccountType

Name Type
name java.lang.String
paymentModes java.lang.Long
trial boolean
paymentInfoRequired boolean
autoPayRequired boolean
instantpayRequired boolean
vextendCredit boolean
selfRegistrationAllowed boolean
manualRegistrationAllowed boolean
notionalBilling boolean
manualActivation boolean

Channel

Name Type
name java.lang. String
code java.lang. String

ProductBundle

Name Type
name java.lang. String
code java.lang. String

com.vmops.model.CurrencyValue

Name Type
currencyCode java.lang. String
currencyName java.lang. String

com.vmops.model.Address

Name Type
city java.lang. String
state java.lang. String
postalCode java.lang. String
country java.lang. String

Service

Name Type
Category java.lang.String
type java.lang.String
serviceName java.lang.String
vendor java.lang.String
adapterRef java.lang.String

ServiceInstance

Name Type
service com.vmops.model.Service
name java.lang.String
description java.lang.String
code java.lang.String

Creating Custom Action URL Resolver

If the Task created Type is NAVIGATE, then you have to specify the action Resolver URL. Following are the steps to create custom action URL resolver:
  1. Create a CustomActionUrlResolver.java and populate the parameters list.
    For Example : Below is the sample code of creating the customActionUrlResolver for above created adding secondary email activity.
      /* Copyright (C) 2012 Citrix, Inc. All rights reserved. */  package com.citrix.cpbm.workflow.custom.resolver;    import java.util.ArrayList;  import java.util.HashMap;  import java.util.List;  import java.util.Map;  import java.util.Set;    import com.citrix.cpbm.core.workflow.model.Task;  import com.citrix.cpbm.workflow.pendingaction.resolver.impl.AbstractActionUrlResolver;    public class CustomActionUrlResolver extends AbstractActionUrlResolver {      private Map<String, String> actionUrls = new HashMap<String, String>();      @Override    public Set<String> getSupportedTypes() {      return actionUrls.keySet();    }      public void setActionUrls(Map<String, String> actionUrls) {      this.actionUrls = actionUrls;    }      @Override    public List<String> getParams(Task action) {      List<String> params = new ArrayList<String>();      if ("ADD_SEC_EMAIL".equalsIgnoreCase(action.getType())) {        params.add(action.getTenant().getOwner().getUuid());      }      return params;    }      @Override    public String getActionUrl(Task action) {      return actionUrls.get(action.getType());    }    }  
  2. Add the bean for the newly created CustomActionUrlResolver in applicationContext-workflow-customizations.xml file which is under src/main/resources/META-INF/spring/ of citrix.cpbm.custom bundle. Provide the target URL in the value field of <entry>
    For the above example, following bean is added for newly created sample CustomActionUrlResolver.
    <bean id="customActionUrlResolver" class="com.citrix.cpbm.workflow.custom.resolver.CustomActionUrlResolver">       <property name="actionUrls">      <map>        <entry key="ADD_SEC_EMAIL" value="users/%1$s/myprofile"></entry>      </map>    </property>   </bean>  
  3. Add the reference of the newly created CustomActionUrlResolver in osgi-context.xml file which is under src/main/resources/META-INF/spring/ of citrix.cpbm.custom bundle.

    For the above example, following reference is added:
    <osgi:service interface="com.citrix.cpbm.workflow.pendingaction.resolver.ActionUrlResolver" ref="customActionUrlResolver"/>
 

Comments