Tutorials
Attorney-Client Collaboration Site
"I was very impressed at the level of sophisticated user experience obtained in a browser-based application. But more importantly was the realization of the speed at which we can build applications. VE is one of the most intriguing products that I have seen in my 25 years in this field."
Greg Gilkerson,
President
PDI
ACCS Iteration #2

Iteration #2


Training Objectives:

In this lesson (iteration), the trainee will learn how to:

  • Create a new package that has a dependency on existing packages(s)
  • Create object extensions
  • Create bi-directional relationships
  • Create processes and object operations
  • Defining transactional boundaries in a process
  • Add rules to objects and their members including: initial value and domain rules, and defining a calculated attribute
  • Add simple formatting to control String length
  • Get better understanding of formulas and some of the core objects like String, and Dialog

Scope:

The scope of this iteration is to cover the following use cases:

  • Manage clients
    Provide CRUD functionality to manage the law firm clients by both actors: Administrator and Attorney. A client must have an id, name, email, phone number, fax number, and a full address.
  • Search for a client
    Provide a simple mechanism for Attorneys to search the client list by id, name, and/or email.
  • Create client case
    Provide an Attorney with a mechanism, to create a new case file for a specific client. The case file must only be visible to the attorney that created it. Each case must have id, title, description, creation date, client role, and involved parties.
  • Search for a client case
    Provide a simple mechanism for an Attorney to search their case list by id, title, description, client name, and/or involved parties.

Steps:

It is highly recommended that you consult with the VE/Designer online help at each of the steps below. To do so, make sure that the keyboard focus is in the area you need help on, then press F1. You can also use the help Find tab to search for a specific term or concept.
Create a New Package Named "cases"
  • Right-click on the project node, then select New->Package...
  • On the New Package Wizard, type in cases as the Package Name
  • A new package node will be added under "tutorials/accs" project.
  • The Package Editor will automatically be opened
  • Click on the General tab, then select lawfirm from the list of available packages, and press the right-arrow (>) button to make the cases package depend on lawfirm package.
Implement "Manage clients" Use Case
This use case calls for a Client object:
  • Return back to Object Model 1 tab in the Package Editor for cases
  • Create Client object with attributes: id, name, email, phone and fax
 
Now that we have a client object, we need a root object to hold on to it to make it part of the application persistent model. We already have such a root object (singleton), TheLawFirm that represents an instance of LawFirm. To extend this object without changing it in the lawfirm package,
  • Import #lawfirm/LawFirm by pressing the Import () icon, then selecting lawfirm/LawFirm
  • Right-click on the LawFirm object (in the top section of the rectangle), then select Create Extension
  • An extension object is added to the canvas with the default name LawFirm
  • Press Enter to leave the default name as is, then click on any empty space on the canvas to end the in-place edit mode
By extending the LawFirm object, we're able to add attributes, relationships, or operations to the extension without effecting the original object. All additions to the extension are automatically merged with the original object in runtime, which is a very powerful mechanism for creating small reusable packages with objects that get smarter as you combine with more packages.

Now that we've extended the LawFirm object, we're ready to complete the domain object model:

  • Add an Aggregate relationship clients from LawFirm extension to Client with cardinality of zero-or-more
  • Import Address object
  • Add a Composite relationship address from Client to the imported Address
Finally, let's modify the admin portal, and add a navigation to manage the law firm's clients as follow:
  • Title: Clients
  • Name: manageClients
  • Action: Manage
  • Resource: #lawfirm/TheLawFirm.clients
Implement "Search clients" Use Case
To implement this use case, we need to create a global (static) process that takes a search string as a parameter, and returns a bag of matching clients:
  • Right-click on the cases package node in the Project Explorer, then select New->Process
  • In the New Process Wizard, enter searchClients in the Process Name field
  • A new process named searchClients is created and added directly under cases package. The Process Editor is also automatically opened
  • Click on the Properties tab of the searchClients Process Editor
  • Change the Return Type to Client by clicking on the pull-down menu, selecting Object... then selecting cases/Client. Also check the Bag of box to specify that the return type is a bag of Client
  • To add a search parameter, click on the Click here to add cell in the Parameters tab, type search, then press Enter
  • The parameter can be used as is, but we would like to limit its length to 50 characters. To do so, click on the Format tab while the search parameter is selected, then type (50) in the Format field
Now that we defined the process envelope, we're ready to implement it:
  • Click on the Process Diagram tab
  • Let's add a local variable clients. To do so,
    • click on the Show/Hide Local Variables () icon on the Process Editor toolbar.
    • Click on the Click here to add cell, then type clients and press Enter
    • Check the Bag of box
    • Change the type to Client
  • Add a new activity to the process by pressing the Activity () icon on the Process Editor toolbar, move the mouse to the transition line connecting the start and end nodes, then click the mouse button.
  • Select the newly added activity, click on the formula field right above the toolbar, then type in:
    clients = TheLawFirm.clients.select( search.toKeywordFilter( { "id", "name", "email" } ) )
    This takes the search string parameter, generate a keyword filter block that searches the listed fields (i.e. id, name, and email). The filter block is then passed to the clients's select() operation, which will apply the filter block against each Client object in the TheLawFirm.clients and returns a bag with matching clients. The resulting bag is then assigned to the clients local variable. It is highly recommended that you press the F1 button while the keyboard focus is in the formula to learn about VE formulas
  • To return clients as the result of this process, select the end node (), then click on the formula field, type clients, then press Enter
To test the behavior of this new process, make sure that you have some clients populated. Use the admin portal new Clients navigation and add some clients. To launch the admin portal, you can open it then press the Play () icon while the window is active, or right-click on the admin node in the Project Explorer and select Execute.

Getting back to the searchClients process, make sure it is the active window then press the Play () icon on the VE/Designer toolbar. In the opened browser, type in some text in the Search field, then press Search Clients button to view the results.


Matching Clients
Implement "Create client case" Use Case
This is one of the more involved use cases in this iteration. It involves creating Case object, extending Attorney, and implementing a couple of object operations. Let's start with
  • Go back to the cases package editor
  • Add a new object named Case with attributes: id, title, date, description, clientRole, otherParties, clientName, and attorneyName.
  • Change the type of description, and otherParties to Text
  • Change date type to Date
  • Add an Aggregate relationship from Client to Case named cases with zero-or-more cardinality
  • Make the Client.cases relationship bi-directional by right-clicking on the cases label then selecting Add Inverse
Before we extend Attorney, let's add a new canvas to this package, then use it to flush out the Case model. To do so,
  • Right-click on the Object Model 1 tab, then select Add Model
  • You can rename the newly created canvas by right-clicking on its tab, selecting Rename Model, then typing a new name (e.g. Case Model)
  • You can also change the order of the new canvas (move left/right) also by right-clicking on its tab
  • Import lawfirm/Attorney
  • Extend Attorney as described in the previous step
  • Import cases/Case
  • Add an Association relationship from Attorney extension to Case with a zero-or-more cardinality named cases
  • Make Attorney.cases bi-directional as explained in the instructions above
  • Create a root object on lawfirm/Attorney with cardinality one. Rename it CurrentAttorney, and make it transient by right-clicking on the root object label and checking the Transient checkbox. This transient root object will be used to tell us which attorney is using the application (on this specific session)
  • Save the model
Since adding a new case is limited to attorneys, and is visible only to the specific attorney that added it, we need to know who is the attorney currently (in this web session) using the application. Accordingly, we'll add a global (static) operation to Attorney extension that checks CurrentAttorney and initializes it the very first time it's used in this session. To do so,
  • Add getCurrent() operation to Attorney extension by right-clicking on the top section of Attorney extension rectangle, selecting Edit Operations, typing getCurrent, then clicking outside of the rectangle to end the in-place editing mode.
  • Right-click on the getCurrent operation, and set the Visiblity to Trusted, so it will not be visible from outside of the application (to external entity like an end-user)
  • Double-click on the getCurrent operation to open the Object Editor for Attorney, and change its properties as follows
    • Return Type: Attorney (either the original or extension)
    • Scope: Global
  • Save and close the Object Editor and go back to cases package editor
To create the implementation of this operation, you can either
  • Right-click on the getCurrent operation in the cases package editor, then select Create Implementation, or
  • Right-click on the Attorney node under cases in the Project Explorer, select New->Process, and type in getCurrent
Either way, the Process Editor will automatically open to provide the implementation:
  • Add a Decision () step to the process
  • click on the true condition, then enter the formula
    CurrentAttorney.>name == null
    to check whether the CurrentAttorney is initialized or not. The reason we compare one of the root object's members (name) to null instead of the root object itself is that VE auto initializes the root object to a new instance.
  • Add activity right below the decision (make sure that the mouse is very close to the decision node so the activity is inserted under this condition not after it), and enter the formula
    CurrentAttorney = Dialog.select( TheLawFirm.attorneys )
    The Dialog object provides global (static) operations to interact with the actor (user). In this case, the select() operation will serve a page of available attorneys to the user to select one of them, then proceeds in the process with the user choice. Check out the documentation in the code completion for more information on Dialog and this operation, or press F1 then select Objects then Dialog.
    NOTE: This formula will change as soon as we incorporate security and user management in a later iteration in this tutorial.
  • For the process return, enter formula:
    TheLawFirm.attorneys[ name == CurrentAttorney.name ]
    to return an instance of Attorney with the same name as CurrentAttorney.name. Notice that we don't return CurrentAttorney itself as it might be a stale copy (more in a later iteration when discussing persistence).
  • You can test this process by pressing the Play () on the VE/Designer toolbar. But first, make sure that you have some attorneys populated by executing the admin portal and using the Attorneys navigation.
Now, it is time to add addCase() operation to Client:
  • In the cases package, add operation addCase to Client, then specify the following properties:
    • Parameters: one parameter named newCase of type Case
    • Return Type: String
  • Create implementation for addCase
  • Add activity to set the newCase's attorney to the current attorney. The formula is
    newCase.attorney = Attorney.getCurrent()
    Notice how setting on direction of a bi-directional relationship automatically sets the inverse direction.
  • Add activity to add newCase to the receiver's (Client) cases
    cases.add( newCase )
  • Set the return formula to
    "Case number {newCase.id} has been added successfully!".filled()
    The filled() operation on String evaluates the text in the curly-brackets and replaces them with the resulting value. See the code-completion documentation for more information and examples.
  • Since this operation changes the state of both Client and Attorney (which both could be persistent), we need to mark it transactional. To do so, right-click on the activity diagram start node (), then check the Transactional checkbox.
  • Save all
To test addCase(),
  • Execute the searchClients() process to locate a client
  • Double-click on the selector () in the result table to expand the desired client
  • Press the Add Case button on top of the page
  • Fill in the fields of the new case
  • Press the Add Case on the bottom of the page
  • You should get back the return string that the new case has been added successfully
To complete this use case, we need to add some rules to Case. Open the Object Editor for Case, select the Attributes tab, then apply the following rules:
  • Change id to Read Only For External (Advanced tab), with Initial Value set to
    counter( "CASE_ID" )
    (to auto generate the case id)
  • Change title length to 50 characters (set Format to (50))
  • Change date Initial Value to now() which initializes the date value to current date
  • Change clientRole so it's Initial Value is set to "N/A" and Domain set to { "N/A", "Defendant", "Plaintiff" }
  • Change clientName to Calculated with formula set to client.>name
  • Change attorneyName to Calculated with formula set to attorney.>name
After saving the changes, rerun the addCase() operation as described above and observe the differences.
Implement "Search cases" Use Case
The implementation of this use case is very similar to the Search Clients above. Accordingly, follow the same steps as above with the following exceptions:
  • Name the process searchCases instead of searchClients
  • Set the Return Type to Bag of Case
  • Name the local variable cases instead of clients
  • Set the activity formula to
    cases = Attorney.getCurrent().cases.select( search.toKeywordFilter( { "id", "title", "description", "clientName", "otherParties" } ) )
    which will limit the search in the case's id, title, description, clientName, and otherParties.
Once completed, run the searchCases() process to test it.

Implementation
Run

Run Results

Create Attorney Portal
Now that we completed the domain object model, we need to create attorney portal to represent the Attorney actor, and add the following navigations:
  • A place holder navigation for future use (will be used as a attorney portal page)
    • Title: Home
    • Name: home
  • Navigation for Search Clients
    • Title: Search Clients
    • Name: searchClients
    • Action: Execute
    • Resource: cases/searchClients
  • Navigation for Search Cases
    • Title: Search Cases
    • Name: searchCases
    • Action: Execute
    • Resource: cases/searchCases
  • Navigation for Manage Clients
    • Title: Manage Clients
    • Name: manageClients
    • Action: Manage
    • Resource: #lawfirm/TheLawFirm.clients
The Add Case use case is satisfied with addCase() operation on Client.
Run Attorney Portal
You're now ready to execute the attorney portal. While the Portal Editor is the active window, press the Play () icon on the VE/Designer toolbar. This will launch a attorney portal into a web browser.
Search Clients, Search Results, Expanded Client, Add Case
Search Cases, Search Results, Expanded Case
Manage Clients, List

Outstanding Functionality:

No outstanding functionality in this iteration.

Recap:

In this lesson (iteration), the trainee learned:

  • Creating a new package cases that has a dependency on lawfirm
  • Creating object extensions to LawFirm and Attorney in package cases
  • Creating two bi-directional relationships: Attorney.cases and Client.cases
  • Creating two global (static) processes: searchClients() and searchCases(); and two object operations: Client.addCase() and Attorney.getCurrent()
  • Defining transactional boundaries in Client.addCase()
  • Adding rules to Case attributes including: initial value and domain rules, and defining a calculated attribute
  • Adding simple formatting to control String length for both Case.title and search parameter in both searchClients() and searchCases
  • Using formulas and some of the core objects: String, and Dialog; and functions: now(), counter()
Copyright © 1999-2012  INTELLIUN CORPORATION. All rights reserved.