Thursday, July 23, 2009

K2 Roles

Introduction to K2 Roles

K2 Roles are a way to create re-usable groups of users that can be used across processes. For instance you could create a K2 Role called Accounting Managers and that K2 Role can be used in a K2 Destination Rule. They are similar to an AD Group or a SharePoint Group but a little different. One added advantage of using K2 Roles will be kept in sync with tasks created for users to action. So what does that mean? Basically when you do not use a K2 Role and assign a specific user account to a destination rule that account will tied to the slot that is created at run time. Once the slot is created for that destination user it cannot be changed unless the user or administrator delegates the task. However if the you use a K2 Role, users that are in of the Accounting Managers K2 Role, will have immediate access to the worklist item slot (based on the refresh interval). So this is good thing to use if you anticipate that users who can potentially be assigned a task may change often.

I highly recommend reading this whitepaper - http://k2underground.com/files/folders/technical_product_documents/entry20948.aspx. It explains what is a K2 Role in detail.

Here are some of my notes on K2 Roles:

  • Destination Rules are required to compile a client side event. They can be set to Static user: user dynamically, AD Group, XML list, K2 Role, SmartObject, etc.
  • K2 Roles are a role is a common group that is defined within K2 that can be re-used across K2 processes. K2 Roles can be made of from accounts in AD or a custom repository like in SmartObject.
  • Slots determine how many Worklist items can be Open for an Activity. As soon as a user clicks on a Worklist item, the status immediately changes from Available to Open and 1 Activity Slot is occupied. The number of Slots can be limited to a specific number or a slot can be created for each destination. Slots control how users will work with data. Configuration of the destination rules directly determine how many slots are created.
  • Succeeding rules by default will evaluate the outcomes of actions along with the Slots that are created to determine if the Activity is allowed to go to the next Activity in the process.
  • By default all destination rules are set to "plan just once". A slot will be created for each user and a Worklist items is created however only one activity instance is created. Any time a user is added to a K2 Role it should appear on their worklist based on interval.
  • Plan per Destination supports parallel processing as multiple activity instances will be created for each user. "All at once" allows all users to access the worklist item. One at a time" only allows one user at a time to access the item.
  • Plan per Slot use for an IPC event or call out to an external system.
  • Cached K2 Roles - By default, a single slot will be created for each Role. By default, on a 10 minute interval, the Role and its users will be refreshed with that slot. This can be configured in each K2 process that is deployed by using the K2 Workspace. If you select, "Resolve all roles and groups to users", changes to the K2 role will not be reflected but using the "Keep roles synchronized" checkbox will keep in sync on interval.
  • Dynamic Roles can only be used with "Plan just once" or "Plan per destination" where Roles do not resolve to users. Dynamic roles are on-demand. This means the K2 Role is refreshed when dynamic roles are defined and every time worklists are opened which contain items that use the role. This ensures that new users in a K2 Role will see the worklist item immediately and users removed from K2 Role will have permission blocked.

Getting User who Actioned

When using K2 Roles I have run into situations that have tripped me up a couple times. Let's say I have a client side event (InfoPath) and I want to perform custom code after the InfoPath event. Specifically, I need to know who was the user who actioned the event. To do this you need to execute the following code:

public static string GetActionUser(ActivityInstance activityInstance) {
//Loop over the activity slots to see who was the user who
//actioned the worklist item.
foreach (Slot slot in K2.ActivityInstanceDestionation.ActivityInstance.WorklistSlots) {
if (slot.Status == ActInstSlotStatus.Completed) {
return slot.User.Name;
}
}
return "";
}

What this does is loop over the slots, checks which slot was completed and by whom. You cannot go directly to the ActivityInstanceDestionation because the K2 Role was assigned as the destination user. However slots will be created dynamically for each user in the K2 Role based on the refresh interval.

Email All users in K2 Role

In many situations, I have needed to email all of the users in a K2 Role. One solution to do this without having to write any custom code would be to go to the advanced destination rules of an activity where an Email Event has been added. Select Plan per Destination All at Once. Then select Resolve All Roles to users. Then in the Email Event select send the email to the Destination User checkbox. I would only recommend doing this in an Email Event that is in its own Activity. Do not do this in the same activity where you have a client side event, like an InfoPath event. What this will do is not allow the K2 Role to be dynamic refreshed defeating the purpose of all the stuff we just talked about.

Another approach would be to use the following code to build a string of email addresses that are in the K2 Role. Then set the email string into an activity level field. Then use activity level field in the Email Event wizard. You can see in the code I have an AD SmartObject with a method called GetDetails that I use to get the user's email address.


using SourceCode.Security.UserRoleManager.Management;
using SourceCode.SmartObjects.Client;
public static string GetEmailsInRole(string conn, string roleName){
string emailAddress = "";
conn = conn.Replace(" ", "");
UserRoleManager roleManager = null;
SmartObjectClientServer server = null;

try {
//Create Manager
roleManager = new UserRoleManager();
roleManager.CreateConnection();
roleManager.Connection.Open(conn);

//Get Role
Role role = roleManager.GetRole(roleName);

//SmartObject server reference
server = new SmartObjectClientServer();
server.CreateConnection();
server.Connection.Open(conn);

//Get Person Definition
SmartObject person = server.GetSmartObject("Person");
person.MethodToExecute = "GetDetails";

foreach (RoleItem item in role.Include) {
//Now get the email from the smartobject
person.Properties["ADID"].Value = item.Name.Replace("K2:", "");
server.ExecuteScalar(person);

emailAddress += person.Properties["Email"].Value +";";
}

//remove last semi-colon
emailAddress = emailAddress.Substring(0, emailAddress.Length - 1);
}
catch (Exception ex) {
}
Finally {
if (roleManager.Connection != null) {
roleManager.Connection.Close();
}

if (server.Connection != null) {
server.Connection.Close();
}
}

return emailAddress;
}
}

6 comments:

amar said...

Do we need to create the Person Smartobject or is it already in the K2 Workspace?

Jason Apergis said...

I created a SmartObject called Person that uses the Active Directory server. So yes, you will need to create a SmartObject.

amar said...

Thanks for the reply. I am new to K2. I have a small question. The smartobject gets created in a different server than the smartobject server. So do we need to provide two different connectionstrings. One for the smartobjectserver(which has the activedirectory) and another for the smartobject("Person"). Also could you throw some light on how to create the person smartobject.
thanks in advance

Jason Apergis said...

All of your questions would be answered in the K2 blackpearl Wrox book we wrote. Focus on reading the SmartObject and Deployment Chapaters (specificaly read about the Environment Server).

There should only be one connection string. That connection string will change between your development, qa and production environments. The K2 environment server will handle that for you.

The book discusses step by step how to create an Person smartobject. Sorry for not wanting to rewrite on the blog something a took a bunch of time to write in the book. Check it out - it will be very helpful.

Jason

amar said...

Thank You. I have resolved that. One more question. How is the getdetails method should be set? Should I select the map service property to "smart object method parameter" ?

Regards
Amarnath

Jason Apergis said...

The Configure Method Parameters could be used but I skip it and go to the Add Service Object Method screen and map the method input and output data to the SmartObject properties directly.

Jason