Monday, July 09, 2007

K2 Underground

Dear Blog-surfer,

Most of my blog has always been dedicated to articles and write-ups on K2.net. As I recently joined the K2 Insider community, my K2.net efforts will be directed to the new K2.net community portal, www.k2underground.com.

I'll keep this blog up to date with other articles and stories.

The Naked Programmer

Monday, May 07, 2007

Using a K2.net 2003 process as a 'function call'

Although this kind of thing will be much easier in K2.net [BlackPearl] using SmartFunctions, sometime we would like to run a K2.net 2003 process to determine the outcome of a set of rules only. Normally this process will not have any client interaction as it mearly takes some input, apply a set of rules using the K2.net line rules, and output some result. Doing this we get the K2.net visual representation of our business rules and the outcome of it.

The calling code treat the K2.net process instance as a method call, creating a new process instance, passing the initial data into the process via datafields and then wait for the process instance to reach an 'answer point', then read the answer from the process instance.

The assumption is that there is alway only one outcome from the business rules.

Firstly, our process. This is a very simple process that will set some datafield called Result to true.

The code inside the True server event looks like this:

Sub Main(ByVal K2 As ServerEventContext)
 ' make this server event wait
 K2.Synchronous = False
 ' store the server event's serial in a process level datafield
 K2.ProcessInstance.DataFields("WaitingServerEventSerial").Value = K2.SerialNumber
 ' set the result of this process, i.e. the business rule
 K2.ProcessInstance.DataFields("Result").Value = True
End Sub

Note that we set the Synchronous property to False. This will make this server event wait until we instruct it to complete. We need to do this so that we can grab the outcome of the business rules (True in this example, stored in the datafield called Result). For the calling code to get to this server event to complete it, the server event store its serial number in a process level datafield called WaitingServerEventSerial.

The calling code looks this this:

Sub Main()
 Dim myConn As SourceCode.K2ROM.Connection = Nothing
 Try
 ' this opens a connection to the K2 server
 myConn = New SourceCode.K2ROM.Connection
myConn.Open("localhost")

 ' this is the rules based process
 Dim myProc As SourceCode.K2ROM.ProcessInstance
 Dim piString As String = "Async\Rules"

 ' this creates the process instance
 myProc = myConn.CreateProcessInstance(piString)

 ' this starts the process instance but does not return control to this code
 ' until the process hits a waiting point. in this case the server event thats
 ' been marked to be K2.Synchronous = False

 myConn.StartProcessInstance(myProc, True)

 ' save the process instance ID and use it to open the process again
 Dim myProcID = myProc.ID
 myProc = myConn.OpenProcessInstance(myProcID)

 ' get the result
 Dim result As Boolean = CType(myProc.DataFields("Result").Value, Boolean)

 ' and very important, tell the server event to complete (by getting the waiting server
 ' event's serial number from the process instance datafield. if we don't do this then the
 ' process instance will stay active

 Dim waitingServerEventSerial As String = myProc.DataFields("WaitingServerEventSerial").Value.ToString()
 Dim waitingServerEvent As SourceCode.K2ROM.ServerItem = myConn.OpenServerItem(waitingServerEventSerial)
waitingServerEvent.Finish()

 Console.WriteLine("Result is " & result.ToString())

Catch ex As Exception
 Console.WriteLine(ex.ToString)
Finally
 If Not myConn Is Nothing Then
 myConn.Close()
 End If
End Try
Console.ReadLine()
End Sub

The client code creates and starts a process instance. Note the Sync property is set to True when starting the process instance. This will make sure that the StartProcessInstance method will not return control to the calling code until the process hits a client event for Async server event. In our example this Async server event is the outcome of the business logic that we are waiting for.

Once this point is reached and control is passed back to our client code we reload the process instance, get the outcome of the business rules via the Result datafield and then instruct the waiting server event to finish by picking its serial number up from the datafield WaitingServerEventSerial.

PS. Thanks Richard Neal and Mark Jones who's questions prompted me to do this article.

PSS. Often clients ask me to code in the language they use, so I've decided to at last also post a sample in VB.NET. Also note that I always use a simple pattern where I always make sure that the connection to the K2.net server is closed.

Wednesday, April 11, 2007

Microsoft Virtual PC 2007 and me Dell Inspiron 6000

What a battle... took me days to find a solution to this; installed VPC 2007 on my Dell Inspiron (its got the Centrino chipset). The virtual machine would keep on being jittery, slow, and unresponsive. Poor performance all over.

This solved it:
http://codebetter.com/blogs/jeff.lynch/archive/2006/11/28/VPC-2007-Beta_3A00_-Centrino-915-Chipset-Issues.aspx

Like noted, not the perfect fix and eats away nicely at the battery, but it works.

Monday, January 15, 2007

This version or that version?

It might be required to create an instance of a specific version of a process. Some reasons:

0. When exporting a new version of a process, the K2 server makes it the default version automatically. This is a bit of a pain as new instances of the new exported process will be automatically created by clients that don't spesify a spesific version.

1. Export process that's passed QA in development to production and run final pre-production testing before making the process live. In this scenario your user interface will always specify the version of the process when creating an instance.

2. Sometimes changes to a process require changes to the user and/or system interfaces. In this scenario the user interface can create a process on a specific version but should also render itself correctly for a specific version of the process (more about that in the next blog).
Using the K2ROM.dll library one can specify what version of the process to create using the overloaded .CreateProcessinstance method.

SourceCode.K2ROM.Connection con = new SourceCode.K2ROM.Connection();
con.Open("127.0.0.1");

SourceCode.K2ROM.ProcessInstance pi;
pi = con.CreateProcessInstance(@"Project\Process", 2);

This will create an instance of the Process process using version 2.

Thursday, November 16, 2006

Repair Error, this instance or a whole lot more?

K2.net 2003 have the great feature of fixing errors on the fly. When any code component in K2 (line rule, start or preceding rule, event, etc.) generates an unhandled exception, the process instance goes into an Error state. These process instances in Error state can be viewed form the K2.net Service Manager by creating a Error Profile and then viewing the errors in that profile.




From here the Service Manager allows you to open the details of the error and various details of the error can be viewed including:

  • Process Name
  • Error Type
  • Error Location
  • Error Details


The really nice feature is being able to see the code that generated the error. From this view you can edit the code and repair the error on the fly.




But... what is the effect of doing this? The K2 server stores only ONE copy of this code. Its stored in the _Code table in the transaction DB (normally called K2). By modifying the code in this error details window and hitting the Repair button, the Service Manager updates the code in the _Code table and re-executes the object (in my example an error was created in an Server Event, so the event is re-executed with the new code).

Because there is only one copy of the code, the change made is reflected for ALL process instances and all new process instances. So be careful what you do in your code change as its going to affect way more than just the current process instance! As a matter of fact, even previous version of the process having the same code is updated.

Something else to note is that the original process definition will still contain the un-edited bad code and will also need to be looked at before you re-export the process.

I must apologise to my ex students as I've probably not been explaining the behaviour correctly in the past. We burn and learn. Comments (including possible moans at me) welcome!