This article continues to analyze the design and code of the document workflow system based on Notes/domino to enable users to apply and create their own workflows. (csdn download Resources once uploaded can not be modified, very inconvenient, now will be changed to GitHub, if you find the download has problems, please contact me. )
When we modeled the workflow in the previous article, we abstracted the following types of objects:
Workflow: Each workflow instance holds information such as the name of the workflow, the current node, and is responsible for handling the operations of each node of the process.
Business object with workflow: Here is the purchase order.
The configuration object for a workflow: The actual difference between the different workflow instances and the operations of each node is read from the configuration data.
The last type of object is represented as workflow, node, and operation three configuration documents, as described above. The first two classes of objects are stored in our notes workflow in the same document, the process document master document. Now let's look at the form design and code classes that correspond to this document.
Process Sub-form
The fields of the process document are contained within the Flowcontrols subform, and the main document corresponds to the main form, so that the main document has the data to run the workflow as long as the child form is embedded in the main form.
Here are a few things to keep in mind when you apply it to create your workflow:
1. There are three types of users who can perform workflow operations, one is the process in the current node, and is stored in the Personincharge field of the Flowcontrols sub-form. The second is to be able to perform operations such as canceling cancel the special user, saved in the Flowhandlers field. Third, privileged user roles, such as the [IT] role used in this presentation process, can perform both of these operations. This [IT] is not intended to be configured, so it is used directly in the hidden formulas and code of the Actions button. So you need to replace it with the role of a privileged user in your system.
2. The process name is saved in the Flowname field. Because a specific process name cannot be written directly within a generic child form, the process name of the app is written to the field when the main document is created. For example:
dim doc as notesdocument ' Createdoc is a function in LS library lsnotes set doc=createdoc ( "fmpurchasing" ) Doc. Flowname= "Purchasing" dim ws as new notesuiworkspace Call ws. Editdocument (true , doc)
3. The current status is saved in the Status field. Where you want to display the current state on the form, you can create a calculated text or a value that displays when the calculated field refers to the Status field.
4.ActionOptions and action are used to accommodate the action options and user selection when the user clicks on the process action. Personincharge and Flowhandlers Each save the current handler for the process and the user who can perform special operations. Flowends a flag that guarantees that the process is closed, with an initial value of 0 and 1 at the end. CreatedBy the creator of the record document. Flowreaders saves the document to the reader, Flowwriters saves other possible editors other than the process handler. Flowcomments is used to temporarily accommodate comments written by the user during the process operation.
5. When the user clicks on the process action on the child form ... , the system needs to read the data from the process operation configuration document and calculate the action options that are visible to the user. The code class that completes this function is flowactions saved in the Lssimpleflow script library.
Workflow Classes
The language used by this process system to operate in client and xpages environments is LotusScript and Java respectively. The following first discusses the implementation under LotusScript. The generic code that handles each node operation of the process consists of three classes, all in the Lssimpleflow script library. The three classes are used to meet the needs of testing outside of a common application. The back-end code as the core is in the Abstractflow class. The general process operation uses its subclass Simpleflow, which is the task of getting the main document from Notesuidocument, handling the field validation and other tasks involving interface interaction. The Batchflow class passes into the main document within the constructor and does not use any front-end classes that can be used for testing or bulk approval. These classes may be referred to as process engines for convenience.
As mentioned earlier, these classes can accomplish the general functionality of the following processes:
- Verify the required fields.
- Modify the permissions of the process document, including the relevant reader domain, author domain, access control section.
- Add an action record.
- Modify the configured business fields.
- Send an email notifying the relevant handler.
The actual workflow often has special needs, which requires the ability to expand the process class in some way, basically can be summed up in the process before and after the implementation of a certain logic, may be referred to as Querysubmit and postsubmit business logic. There are a number of ways in which Lotus Notes can theoretically be considered.
1. Write the code for the specific process in the configuration document.
Because LotusScript is an interpreted scripting language, the process engine can read the code as text as it reads other configuration data, and then interpret the execution.
The disadvantage is that the code is not written in the designer, there is no syntax check, color coding, formatting and other help, the runtime if the error is difficult to debug, and no preprocessing speed will be slightly slower.
2. Add the functions that run the specific process logic in the code of the Process class.
For example, the Querysubmit and Postsubmit functions are called in the Submit method of the Process class, either in a script library lssimpleflow with the process engine or in another script library referenced by Lssimpleflow.
The disadvantage is that a generic process class relies on a particular process logic. The Lssimpleflow script Library cannot be deployed separately into an application. If a function such as Querysubmit is stored in the Lssimpleflow script library, the script library cannot be simply refreshed once the process engine code needs to be corrected or upgraded. If these specific logic is stored in another script library referenced by the Lssimpleflow script Library, then the name of the library must be written dead, and the design of the generic code to refer to the particular code is strangely difficult to understand.
3. Use the event mechanism to invoke code for a specific process in the process engine.
To achieve separation between the process engine and the specific process code, the so-called event mechanism is used in many programming languages. LotusScript also supports events, but is limited to pre-defined events for objects such as Notesuidocument. In order for the custom class to support the event mechanism, we need to write our own code. In the 33. Object-oriented LotusScript (vi) for custom object simulation events and custom event programming in Java, LotusScript, and JavaScript in several articles I discussed two ways to implement event mechanisms in LotusScript. To emulate the Querysubmit event before the Submit method of the process engine, as an example of the better implementation of custom events in Java, you need to write a Floweventhandler class that contains the Querysubmit method. The addEventHandler method of the process engine is then invoked to pass in an instance of the class, and the Querysubmit method of the instance is called in the Submit method.
4. Writing code for a specific process in a subclass of a generic process class
The empty querysubmit and Postsubmit functions are called in the Submit method of the Abstractflow class. In Simpleflow subclasses, such as the purchaseflow of the procurement workflow that we demonstrate, the actual code is written in this two functions. This is similar to the implementation interface in Java.
This approach also requires writing a class for a particular process, as opposed to taking an event mechanism. Another benefit is the ability to override other methods of a generic process class in a subclass when needed, such as when a process operation configuration document is difficult to meet the complex requirements of the next node for an operation, you can overwrite the Getnextnode method, where the required logic is written.
5. Write code for a specific process in a script library that references the process engine as a function rather than as a class
The class code in both of these methods is written in a script library that references the Lssimpleflow library, so is it important to write the code of a particular process in an object-oriented manner, directly in a set of functions, and invoke the generic process class and other functions sequentially in the main function?
Compared with method 4, this approach has only a few minor disadvantages:
Because the logic of Postsubmit is called from within the Simpleflow class's Submit method to run after calling the Submit method from the main function, the front-end document that was originally completed within the Submit method notesuidocument a series of reload, Refresh and AutoRefresh operations should also be moved to the Postsubmit function. Plus the Querysubmit and Postsubmit functions are bound to use other objects such as the main document, which must be written in code and not directly referenced as in subclasses.
Usually the logic of Querysubmit is to run after the validation of the form within the Submit method, and it is not possible to invoke the Querysubmit and Simpleflow objects in a function's method order.
In the above discussion, we choose the method 4--to write code for a particular process in a subclass of a generic process class. The code for a particular process class is accommodated in the Lslocalflow script library, which has to be fixed because the Flowcontrols child form that calls it needs to be sure to reference its name. The actions of the child form ultimately call the Submitflow function in this script library:
FunctionSubmitflow (Flow as String, Curnode as String, action as String)If notIsdebuggingls () Then on Error GotoErrorHandlerEnd If ' Dim Objflow as New simpleflow (flow,curnode,action) DimObjflow as NewPurchaseflow (Flow, curnode, action)PagerObjflow.submitExit FunctionErrorHandler:PagerObjflow.rollback () MessageBoxError&"occured when flow submitted on line"&CStr(ERL), -,"Error"&CStr(ERR)Exit Function End Function
From the code above, if there is no special business logic for the current process, you can use the generic process class Simpleflow, or you would use a Simpleflow subclass, the purchaseflow here. Finally, let's talk about the error handling that is contained in the IF statement.
Error handling and impersonation transactions
The above code if you apply normal error handling, ordinary users will see the error message is slightly more friendly. But because the backbone code is contained in the Submit method, the line that catches the error is almost destined to be the line, which is not helpful for determining the code that really goes wrong. And because the error is captured, it is useless to open the debug LotusScript tool for the Notes client. So it seems that error handling code should not be added. But here's a delicate question. If an error occurs during the execution of the submit method of the Process class, it is likely that the current main document has been modified, even the status of the document and the value of the access control field have been modified, and in such a "broken" state, when the user closes the document, it will result in an exception document that cannot interpret its data and perform subsequent operations. , for example, the process is already in the next node, but the document permissions have not changed. The generic process engine class can still be carefully written and tested to minimize the likelihood of errors. But the code that is specific to a process can also cause these problems, and their quality depends on their respective authors.
When working with other programming languages and relational databases, the solution to ensure that the data is not in such an inconsistent state is transaction (transaction). A series of state changes within a transaction, either successful or rolled back to the original position in case of failure. This feature is not supported in the LotusScript and Notes databases. All we can do is simulate as much as possible, so there is a rollback method in the Abstractflow class that restores all the domain values of the main document to the initial state saved in a temporary backup document. The purpose of adding error-handling code in the Submitflow function is to use the rollback method to prevent the data in the main document from being in an indeterminate state when an error occurs. The remaining problem is how to debug when an error occurs, preferably with a convenient way to invalidate the error handling code without modifying the code. This is the origin of Isdebuggingls and a tool agent Tools\toggle LS Error handler. They control whether the error-handling code is in effect by setting and checking a special Notes environment variable "Debug_ls". The latter toggles the value of the environment variable "Debug_ls" between 0 and 1, which checks whether the value is 1. This way, in the Submitflow function, if you check to be in the "Debug" state, do not do error handling, you can use the debugger to track errors.
95. Notes/domino-based Document Workflow System (VII)