| || |
This Tutorial is a key element in the Training Ramp for Automated Business Logic.
If you are new to Automated Business Logic, you might want to jump to the examples to review code, and see how Business Logic deals with complex problems
Using a Case Study approach of a familiar but complex database, this Tutorial explains the approach for using Automated Business Logic. It progresses from simple (and typical) examples, to very complex examples.
The sub-sections below provide a summary of the steps to use Business Logic. For further background, see the Overview and the Architecture.
Install and Configure
After installing (jars, etc), configure your project by registering Business Logic as a Hibernate event listener.
Get Familiar with Business Logic
The basis of Business Logic Development is the Core Rules. Specify transactional business logic as annotated methods in Business Logic Component "logic" Java or Groovy classes that parallel your domain objects.
You can find a list of the rules here, summarized as follows in our check credit example:
Far beyond simple single-attribute validations, the requirement is multi-attribute constraints, such as this Customer Constraint:
In particular multi-table derivation rules such as
Customer.balance = sum(order.total where paid = false)
- Derivations are multi-table, as in the example above
- Derivations can chain, both to constraints, and other derivations:
Order.total = sum(Lineitem.amount)
Lineitem.amount = quantity * partPrice
Lineitem.partPrice = copy(Part.price)
- Chaining and dependencies are automatically handled (logic is declarative, somewhat similar to a spreadsheet)
- Derivations can include if/else logic, state transition logic, and reference related data
Create Java Project(s) for your application according to your organizations' standards; click to see the BusLogIntro Structure.
Standard Hibernate Data Model
The "nouns" of Business Logic are the Data Model Classes you define to Hibernate: the beans, and the config file. The sample data model is illustrated below: a familiar set of Customers, Purchase Orders, Line Items and Products. While small, we have incorporated a number of complex structures as further explained in the Database Structure.
Declare Business Logic
You declare your logic with Business Logic Components, as summarized below:
Declaring Business Logic
|To declare Business Logic (click the diagram to enlarge):
1. Create a Java/Groovy Business Logic Component
- This is a class that corresponds to a Hibernate-managed Bean (Domain Object)
- The Logic Engine provides access to current/old values, and Logic Context
2. Declare your logic using Logic Annotations on methods
3. For more information, take the tour
- Your component can contain other methods
- Your Business Logic can reference these and other Java/Groovy services
The tour describes a substantial set of Logic Debugging tools, include extensive console logging, integration with your IDE's debugger, and a Logic Console.
To respond to changes in the business, simply add/change rules. In any order.
Unlike procedural programming where you need to understand dependencies / ordering, re-use, and performance, these services are all automated.
Logicdoc: Capture / Trace Requirements
Logicdoc, an extension of Java/Groovydoc, provides the usual mechanisms to capture technical documentation. The extensions enable you to capture requirements (to assure a common understanding with Business Users), and trace these to the Logic that implements them. Logicdoc is completely optional, but experience has shown it is worth considering.
The following examples are "typically" complex, and are a great place to start learning about Business Logic. The next section examines some more complex examples.
How you review these examples might depend on your objectives:
- I am evaluating - I want to see some code, and understand solutions to a range of Use Cases
You can simply review the problems / solutions (Note: these examples are provided in the download, although we have removed some comments here so things fit in a screen shot).
- I am about to do a project - I need to see how to solve problems, and document my work
We suggest you have a window / sheet of paper for the data model and for the rules;
then try to solve each problem, and compare your solution to the sample
Quick note: the Home Page video was built upon the BusLogicDemo database. The following examples are built upon BusLogicIntro (similar but larger).
BusLogicIntro is included in the Download; you can explore it (including all of the examples below have jUnit tests you can run) in Explore BusLogicIntro.
Place Order has a number of different requirements that illustrate the most common business logic patterns. In actual practice, consider retaining your requirements and their logic solutions in Logicdoc, as shown in the Logicdoc Summary (documented as Use Case Name:
Requirement: Check Credit
When the client inserts a
Purchaseorder and some
Lineitems, the business logic must check that the
balance < creditLimit. This requires that we derive the Customer's
balance from the Purchaseorder
amountUnPaid, a rollup of the Lineitem
The logic for Check Credit is declared as follows:
The logic triggered by each LineItem insertion is summarized as follows:
- the lineitem logic derives the amount
- this adjusts Purchaseorder amountTotal per its derivation rule; this automatically Forward Chains to other Purchaseorder logic, which derives amountUnPaid
- this adjusts Customer balance per its derivation rule, and verifies the check credit constraint
That looks pretty simple, right? But it is important to understand how rules fit into the overall process:
- How are they managed - communicated to others (e.g., maintenance), and revised?
Please see the Logicdoc Summary - the critical element is shown below:
Requirement: no Empty Orders
Since it makes no business sense to place an order with no line items, we implement the noEmptyOrder requirement using the following logic:
Optionally, we can document and trace our requirement with Logicdoc.
This example illustrates a number of concepts:
- Counts as existence checks - the
itemCount indicates whether the order has any items
- Commit time constraints - the constraint is executed after item logic has adjusted the itemCount
- Constrain derived result
The last item bears some note. As explained in Commit constraints, using a "regular" constraint would have the effect that all orders are rejected. Not popular with the VP Sales. Since Commit Constraints run after all the rows are processed, the
itemCount will reflect the
Lineitems (if any), so the logic will operate as intended.
Please click the title link.
Make Order Ready
Placed Orders are typically placed in a "Shopping Cart" state (
order.isReady == false), where they do not affect Customer balance and Product quantities until a subsequent Make Order Ready transaction is executed (also see the Logicdoc). So, we need to devise logic that, when an Order is "made ready" (updae a purchase order, setting
order.isReady == false)...
- increases the customer balances and
- adjusts Product quantities, and if reorderQuantity is exceeded, set reorderRequired
The solution is illustrated here:
Since the Customer has a Sum:
Customer.Balance = Sum(orders.amountUnPaid where isReady)
The Balance is increased due to the Qualification Condition Change (see table).
Similarly, we don't want to reduce
Product inventory, and set reorder flags, until Purchaseorders are marked as ready. So, we need to define logic to make this happen.
This is a bit more challenging, since the
Product Domain Object is not directly related to
Purchaseorder, so that the qualification condition cannot reference
Purchaseorder.isReady. So, we introduce
Lineitem.isReady, enabling us to define the following logic:
Derive Lineitem.isReady as Purchaseorder.isReady
Derive Product.totalQtyOrdered as sum("lineitems.qtyOrdered where isReady = true")
Derive Product.isReorderRequired as amountAvailable > qtyReorder
- The first Formula is a Parent Reference, so changes are Forward Chain altered Parent References to Children to each Lineitem
- That activates Lineitem logic, where the change to the Qualification Condition adjusts the
- That activates Product Logic, which computes
This is a classic example of the providing an allocation re-usable service via Business Logic Extensibility. Here we add a Payment to a Customer, and its amount is allocated to that Customers' outstanding unpaid orders.
Please see the database structure:
allocateFromTo rule creates
PaymentPurchaseorderAllocation rows that represent the amount of the payment disbursed to each recipient Purchaseorder.
PaymentPurchaseorderAllocation logic determines the exact amount allocated,
- Which then increments the
- Which in turn affects the Purchaseorder.amountUnPaid, which adjusts the
The exact logic is shown below - 4 rules (several of which were already defined for Place Order):
Consider when a Product price is changed, and that product is a component of a kit. The Requirement must be that each of the kits reflect the price change (e.g., if a bolt increases in price, so do all the kits that use bolts: wings, fuselages, etc).
Please see the database structure. The screen shot below illustrates the solution: 4 rules. They operate as follows when an End User changes a Product.price:
- The Product.price is referenced by
ProductBillofmaterials.value. So, when Product.price is changed, a Parent Reference Cascade Forward Chains to the
ProductBillofmaterials rows to refire the referencing logic (
value) for all the Kits using this component Product
- The ProductBillofmaterials.value value is referenced by
Product.sumComponentsValue, so the system performs a Child Aggregate Adjustment for each kit using the component
- The Product.price references the sumComponentsValue, so this recurses on steps 1 and 2 for each kit using the component
This example illustrates key rule behaviors:
While described here as a separate topic, this is a requirement within Place Order. When ordering a Product that is a kit (i.e., composed of other Parts, such as a plane with Wings etc), we want to reduce inventory for each of the components of the kit.
The key requirement is to populate the SubItems for a kit-based Lineitem. See the database structure - subItems are a child of LineItem objects, representing the bill of materials explosion. The solution is to utilize the Insert Into From rule extension: see first action rule below.
InsertIntoFrom operation is described here. The qtyOrdered rule computes computes the item quantity for kits (for non-kits, it simply returns / defaults the entered value).
The entire solution requires 3 rules (key rules shown below, click title to see all):
Bill of Materials Exclusion Structure
The kit / component lists of the Bill of Materials can be used to illustrate the common inclusion / exclusion pattern
, namely searching lists (child rows) to ensure that objects do / not exist. In this example, we invoke FindWhere
to ensure that a component is not a containing kit.
This constraint searches sub-components to verify that the component (such as a plane) is not a kit that contains the component (such as a Wing). Transitive closure is not addressed in this example.
Click the title to see how to roll a budget up an org chart (database structure here). 2 rules:
Click the title to see how to audit by creating child rows on designated parent changes, with control over which attributes are copied into the audit trial. 1 rule:
Auditing is the simplest example of a family of Insert Into From rule extension.
Copy services are provided for cloning business objects, including provisions for copying related child data such as the Lineitems for a Purchaseorder. These are typically called via a single action rule, so cloning a Purchaseorder is 1 rule. Click the title for more information.
The Logic Method is shown below, based on the Insert logic extension: