Iteration

We start our foray into usage of the While flowchart shape by building a basic example. We build the following schedule first, shown in Figure 13.20. This schedule is used to describe how iteration is accomplished. Later, we look at how transactions may be used with iterations, shown in Figure 13.22.

Figure 13.20. Business process for Iter.skv


Figure 13.22. Business process for Iter2.skv.


Design of Iter.skv Sample

The operation of the Iter.skv schedule is as follows. It first sets an initial starting count, and then it counts up from 1 to 3. In this schedule, nothing else useful is done for the repeated flow. At the end, the schedule simply stops. The COM component to the right implements three methods used by the schedule. We need to build this new component AdvOrchIter.CCounter before building the schedule.

The component AdvOrchIter.CCounter serves as a counter with memory (state). Although a schedule manages the state of its messages, we cannot use this built-in state management in our own schedule logic; we must add a COM component. Adding a COM component has additional benefits; it provides granular control over the use of other COM+ services of transaction, security, and state management. For this counter, we also implement persistence support and demonstrate the use of persistence in schedules by the XLANG Scheduler Engine.

The component AdvOrchIter.CCounter supports three methods: SetCount, IncrementCount, and GetCount. Notice in Figure 13.20 that the call to GetCount occurs both before entering the body of the While and inside the body of the While. This is a common pattern you might see in the usage of the While shape. The rule inside the While must test a condition that changes during the operation of the schedule, and often this change is directly the result of actions in the body of the While shape.

Building AdvOrchIter.CCounter COM Component

To implement the component AdvOrchIter.CCounter, we start by identifying some basic code. The code you have already seen in other examples is shown as it applies to this class in Listing 13.12. This code is for generating trace messages and for class initialization and termination. Nothing conceptually new here.

Listing 13.12. Basic tracing Code in AdvOrchIter.CCounter
Option Explicit

Private Declare Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal
 lpOutputString As String)

Const CCOUNTER_COUNT = "CCounter_Count"
Const DEF_CCOUNTER_COUNT = 0
Private m_nCount As Long

Private Sub Trace(sMsg As String)
    Dim sNow As String
    sNow = FormatDateTime(Now(), vbLongTime)
    OutputDebugString sNow & ":AdvOrchTxn.CCounter: " & sMsg & vbCrLf
End Sub

Private Sub Class_Initialize()
    Trace "Class_Initialize()"
    m_nCount = DEF_CCOUNTER_COUNT
End Sub

Private Sub Class_Terminate()
    Trace "Class_Terminate()"
End Sub

Listing 13.12 also contains some constants that we will use soon for implementing persistence. The m_nCounter variable embodies the entire (relevant) state of the class. In the Visual Basic project, change the class properties to UsesTransaction and Persistable. The operational part of the class is shown in Listing 13.13.

Listing 13.13. Count Management in AdvOrchIter.CCounter
Function GetCount() As Long
    GetCount = m_nCount
    Trace "GetCount() = " & CStr(m_nCount)
End Function

Sub SetCount(ByVal nCount As Long)
    m_nCount = nCount
    Trace "SetCount(" & CStr(m_nCount) & ")"
End Sub

Sub IncrementCount()
    m_nCount = m_nCount + 1
    Trace "IncrementCount() = " & CStr(m_nCount)
End Sub

Listing 13.13 shows the implementation for the functions and methods of the class. When you make the class Persistable, you add three new event handlers for the class. You can select these in the procedures drop-down list in the Visual Basic IDE. The three events are InitProperties, ReadProperties, and WriteProperties. Implement these event handlers as shown in Listing 13.14.

Listing 13.14. Persistence Support in AdvOrchIter.CCounter
Private Sub Class_InitProperties()
    Trace "Class_InitProperties()"
End Sub

' Implementation for IPersistStreamInit
Private Sub Class_ReadProperties(PropBag As PropertyBag)
    m_nCount = PropBag.ReadProperty(CCOUNTER_COUNT, DEF_CCOUNTER_COUNT)
    Trace "Class_ReadProperties(): m_nCount = " & CStr(m_nCount)
End Sub

' Implementation for IPersistStreamInit
Private Sub Class_WriteProperties(PropBag As PropertyBag)
    PropBag.WriteProperty CCOUNTER_COUNT, m_nCount, DEF_CCOUNTER_COUNT
    Trace "Class_WriteProperties(): m_nCount = " & CStr(m_nCount)
End Sub

As Listing 13.14 shows, appropriate tracing has been added. Notice also the use of the constants defined earlier. By defining the class as persistable and implementing the three required interfaces, Visual Basic 6.0 can provide an implementation for the IPersistStream interface for the class. This interface is used by the XLANG Scheduler Engine when it wants to persist the state of the COM component. See also Chapter 10 for more information on state management.

Now save and compile the Visual Basic project, making sure that you have turned on binary compatibility. Install the resulting DLL in a COM+ application. Now you can build the schedule shown previously in Figure 13.20.

Building the Iter.skv Schedule

Start by putting down the Action shapes and naming them as shown in Figure 13.20. In addition, put down the two End shapes. We will connect all shapes a bit later.

Drag a COM component implementation shape and drop it on the right. Create a static instance with the default port name of Port_1. On the third page of the wizard, select the registered component AdvOrchUtil.CCounter. The next wizard page shows the three methods exposed by this component; select all three. On the final page, make sure that the transactions are supported by the component and change the selection under the State Management Support drop-down to select Holds State, and Does Support Persistence.

Now, connect the actions on the left with the Port_1 on the right. Draw the connection as shown in Figure 13.20 and select the corresponding method in the wizard. Note that the actions Get starting count and Get new count not only call the same method, GetCount, but also share the same message. This is important; without this sharing, the schedule will not function correctly.

By connecting the actions to the methods through Port_1, you also create messages on the Data page. Now we can construct the rule in the While shape to check for the counter value. Right-click the While shape and add a rule. Name the rule Counter < 4 ?, an arbitrary but descriptive string. The scripting expression for the rule is as follows:

GetCount_out.GetCount < 4 

You may type in this expression or use the expression assistant to construct it. Now make the remaining connections as shown in the Figure 13.20. You may find the connector tool a handy mechanism for making connections quickly.

On the Data page there is only one connection of interest; this is to set the initial counter value from the constants in the schedule. This is shown in Figure 13.21. The constant is named StartingCount, of the type i1, and a value of one.

Figure 13.21. Data page for Iter.skv.


Running the Iter.skx Schedule

You can now run the schedule. Start up the XLANG Event Monitor, DbMon, and the Component Services administration console to see the running objects. Start the schedule using the event monitor. In the DbMon console, you should see something like Listing 13.15.

Listing 13.15. DbMon Trace of Running Iter.skx
2152: 9:46:00 AM:AdvOrchTxn.CCounter: Class_Initialize()
2152: 9:46:00 AM:AdvOrchTxn.CCounter: Class_InitProperties()
2152: 9:46:00 AM:AdvOrchTxn.CCounter: SetCount(1)
2152: 9:46:00 AM:AdvOrchTxn.CCounter: GetCount() = 1
2152: 9:46:00 AM:AdvOrchTxn.CCounter: IncrementCount() = 2
2152: 9:46:00 AM:AdvOrchTxn.CCounter: GetCount() = 2
2152: 9:46:00 AM:AdvOrchTxn.CCounter: IncrementCount() = 3
2152: 9:46:00 AM:AdvOrchTxn.CCounter: GetCount() = 3
2152: 9:46:00 AM:AdvOrchTxn.CCounter: IncrementCount() = 4
2152: 9:46:00 AM:AdvOrchTxn.CCounter: GetCount() = 4
2152: 9:46:00 AM:AdvOrchTxn.CCounter: Class_Terminate()

The schedule runs to completion quickly. The persistence support is not used in this run. This demonstrates a simple use of the While shape. For the next step, to keep the narrative cross-references from becoming confusing, save the Iter.skv schedule as Iter2.skv. In this new schedule, we will introduce a transaction and look at how the persistence of COM components is used by the schedule.

Building Iter2.skv Schedule with a Transaction

Modify Iter2.skv to include a transaction TxnWhile, as shown in Figure 13.22. This is a short-lived transaction. Set the Retry Count to zero and enable code for on failure handling. An extra action, called Abort ? has been added inside the transaction, which calls the AskToAbort method of the AdvOrchTxn.CAbortTxn class, described previously in Listing 13.7.

When the transaction fails, the process in Figure 13.23 is run. It merely shows the value of the counter as captured in the GetCount_in message. The page uses the method ShowMsgBox of the AdvOrchUtil.CMsg class described in Listing 13.1.

Figure 13.23. On Failure of TxnWhile for Iter2.skv.


Finally, the Data page associated with Iter2.skv is shown in Figure 13.24.

Figure 13.24. Data page for Iter2.skv.


The Data page shown in Figure 13.24 is fairly simple. The starting count is loaded into the counter, and the currently read value of the counter is fed to the ShowMsgBox message. Note that, although the While loop iterates through counter values 1 to 3, the Actions in this example follow the call to the IncrementCount call; hence, we see counter values 2 through 4 in the schedule. Also, note that if you had included the incrementing step inside the transaction, the loop would never exit if the transaction kept failing—so don't do that!

When you run this example, you are prompted whether to abort the transaction on each iteration of the While loop. The trace in DbMon shown in Listing 13.16 is generated by aborting the second iteration of the loop. The shaded lines are for Class_Initialize of the counter and for the GetCount function call so that it is easier to navigate the trace output.

Listing 13.16. DbMon Trace for Iter2.skx Without Preserving While State in Each Loop
2256: 3:29:17 PM:AdvOrchTxn.CCounter: Class_Initialize()
2256: 3:29:17 PM:AdvOrchTxn.CCounter: Class_InitProperties()
2256: 3:29:17 PM:AdvOrchTxn.CCounter: SetCount(1)
2256: 3:29:17 PM:AdvOrchTxn.CCounter: GetCount() = 1
2256: 3:29:17 PM:AdvOrchTxn.CCounter: IncrementCount() = 2
2256: 3:29:21 PM:AdvOrchTxn.CCounter: Class_WriteProperties(): m_nCount = 2
2256: 3:29:21 PM:AdvOrchTxn.CCounter: Class_WriteProperties(): m_nCount = 2
2256: 3:29:22 PM:AdvOrchTxn.CCounter: Class_Initialize()
2256: 3:29:22 PM:AdvOrchTxn.CCounter: Class_ReadProperties(): m_nCount = 2
2256: 3:29:23 PM:AdvOrchTxn.CCounter: GetCount() = 2
2256: 3:29:23 PM:AdvOrchTxn.CAbortTxn: Class_Initialize()
2256: 3:29:26 PM:AdvOrchTxn.CAbortTxn: AskToAbort(): SetComplete!
2256: 3:29:26 PM:AdvOrchTxn.CAbortTxn: Class_Terminate()
2256: 3:29:26 PM:AdvOrchTxn.CCounter: Class_WriteProperties(): m_nCount = 2
2256: 3:29:26 PM:AdvOrchTxn.CCounter: Class_Terminate()
2256: 3:29:26 PM:AdvOrchTxn.CCounter: Class_Initialize()
2256: 3:29:26 PM:AdvOrchTxn.CCounter: Class_ReadProperties(): m_nCount = 2
2256: 3:29:26 PM:AdvOrchTxn.CCounter: IncrementCount() = 3
2256: 3:29:27 PM:AdvOrchTxn.CCounter: Class_WriteProperties(): m_nCount = 3
2256: 3:29:27 PM:AdvOrchTxn.CCounter: Class_Initialize()
2256: 3:29:27 PM:AdvOrchTxn.CCounter: Class_ReadProperties(): m_nCount = 3
2256: 3:29:27 PM:AdvOrchTxn.CCounter: GetCount() = 3
2256: 3:29:27 PM:AdvOrchTxn.CAbortTxn: Class_Initialize()
2256: 3:29:28 PM:AdvOrchTxn.CAbortTxn: AskToAbort(): Aborted!
2256: 3:29:28 PM:AdvOrchTxn.CAbortTxn: Class_Terminate()
2256: 3:29:29 PM:AdvOrchTxn.CCounter: Class_Terminate()
2256: AdvOrchUtil.CMsg: Class_Initialize()
2256: AdvOrchUtil.CMsg: ShowMsgBox(): Msg=3 Title=
2256: 3:29:31 PM:AdvOrchTxn.CCounter: Class_Initialize()
2256: 3:29:31 PM:AdvOrchTxn.CCounter: Class_ReadProperties(): m_nCount = 3
2256: 3:29:31 PM:AdvOrchTxn.CCounter: IncrementCount() = 4
2256: 3:29:31 PM:AdvOrchTxn.CCounter: Class_WriteProperties(): m_nCount = 4
2256: 3:29:31 PM:AdvOrchTxn.CCounter: Class_Initialize()
2256: 3:29:31 PM:AdvOrchTxn.CCounter: Class_ReadProperties(): m_nCount = 4
2256: 3:29:31 PM:AdvOrchTxn.CCounter: GetCount() = 4
2256: 3:29:31 PM:AdvOrchTxn.CAbortTxn: Class_Initialize()
2256: 3:29:34 PM:AdvOrchTxn.CAbortTxn: AskToAbort(): SetComplete!
2256: 3:29:34 PM:AdvOrchTxn.CAbortTxn: Class_Terminate()
2256: 3:29:34 PM:AdvOrchTxn.CCounter: Class_Terminate()
2256: 3:29:34 PM:AdvOrchTxn.CCounter: Class_WriteProperties(): m_nCount = 4
2256: 3:29:34 PM:AdvOrchTxn.CCounter: Class_Terminate()
2256: 3:29:34 PM:AdvOrchTxn.CCounter: Class_Terminate()
2256: 3:29:34 PM:AdvOrchTxn.CCounter: Class_Terminate()
2256: AdvOrchUtil.CMsg: Class_Terminate()

The first call to IncrementCount denotes the start of the first iteration. The engine persists the state of the schedule and the counter prior to entering a transaction context. The process associated with the transaction starts from a known state; note the call to Class_ReadProperties just prior to every GetCount call. The outcome of a successful transaction is also committed to persistent store (Note the calls to WriteProperties). The counter is a COM+ configured component; the XLANG engine manages the lifetimes of the counter component instances. An appropriate counter instance is utilized based on the calling context, and the state for that instance is restored using the persistence support provided by the component. In the trace, it is not possible to discern the instance identities—for example, it is not possible to match which Class_Initialize pairs up with which Class_Terminate.

At the point when the counter is at 3, the transaction in that (second) loop iteration is aborted (The trace line is bolded). This causes the execution of the failure process page and the display of the message from the AdvOrchUtil.CMsg class. After the transaction is aborted, the old counter value is re-read from the persisted value—as if that iteration never occurred. This demonstrates that supporting persistence in COM components is important, particularly if your schedule uses transactions.

This concludes the discussion of iteration. The next section examines dynamic ports.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset