🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Bootcamp:Chapter 15
This page was created by Hans.karlsen on 2023-01-23. Last edited by Wikiadmin on 2026-07-29.

This chapter is for Bootcamp learners who want to generate car registration numbers safely when multiple users create cars at the same time.

This chapter is for Bootcamp learners who want to generate car registration numbers safely when multiple users create cars at the same time.

Template loop detected: Training:Bootcamp:Chapter 15

Before you begin

Complete Training:Bootcamp:Chapter 14 and make sure that your model can upload to a running MDrivenServer. This chapter changes the model and relies on MDrivenServer evolving the database schema when you upload it.

The registration-number format used in this chapter is ABC123. The first part consists of three letters and the second part is a number. The exercise first implements generation locally, then shows why local generation is not safe across concurrent server contexts, and finally uses the SysAsyncTicket pattern to serialize the assignment.

What you will build

You will:

  • create a Car.GetNewRegistrationNumber():String method;
  • store the current sequence state on SysSingleton;
  • use the debugger and the OCL stepper to diagnose an expression;
  • assign a registration number when a Car enters the BrandNew state;
  • import the SysAsyncTicket model pattern and schedule the assignment through DoAsync;
  • make RegistrationNumber read-only in the relevant ViewModels; and
  • mark the attribute as Realtime=true so the assigned value returns to the client sooner.

Part 1: Generate the next registration number

Create the method and sequence state

  1. On class Car, create the method GetNewRegistrationNumber():String.
  2. On SysSingleton, add the following nullable integer attributes. They retain the state needed to calculate the next value.
Attribute Initial value Purpose
RegNumberLetter1Current:Integer? 65 Current value for the first letter
RegNumberLetter2Current:Integer? 65 Current value for the second letter
RegNumberLetter3Current:Integer? 65 Current value for the third letter
RegNumberNumberPartCurrent:Integer? 1 Current numeric part
  1. For each of the three letter attributes, set both the default value and InitialValue to 65.
  2. Set InitialValue for RegNumberNumberPartCurrent to 1.
  3. Implement the method logic shown in Video 15. It must return a string in the ABC123 form, advance the stored sequence state, and carry to the next letter when a letter reaches Z.

The value 65 is the starting value used by this exercise for the letter sequence. Test the rollover behavior later by repeatedly executing the method until a letter reaches Z.

Use semicolons in an OCL action expression

An OCL expression returns one result. When an action expression must perform several operations, separate the expressions with a semicolon (;). The result of the complete expression is the result of its last expression.

Expression Result
expr1;expr2 The result of expr2
expr1;expr2;expr3 The result of expr3
expr1;expr2; Invalid: an expression cannot end with a semicolon

For example, use earlier expressions to update the sequence state and make the final expression produce the registration-number string. Do not leave a trailing semicolon after that final result.

Upload and test the method in the debugger

  1. Save the model and upload it to MDrivenServer. Confirm that the server status reports the database evolution for the new SysSingleton attributes.
  2. Select Play, open the debugger, and select MDrivenServer persistence.
  3. Open a debugger search window for Car, search for cars, and drag a car to the green expression dot. This assigns that car to self for the debugger expression.
  4. Change the expression mode to Action and execute self.GetNewRegistrationNumber.
  5. If the result or stored values are not what you expect, start the expression with Step, select Start, and use Step into to enter the method. Follow each expression and identify where the returned result or sequence update differs from the intended behavior.
  6. Correct the method, save, and upload the model again.
  7. If the debugger is still open, select Re-Read Model. Uploading alone does not update the model already loaded by the debugger.
  8. Repeat self.GetNewRegistrationNumber with F5. Hold F5 to execute repeatedly and observe the rollover from Z to the next letter position.
  9. Cancel the test changes when you finish.

Part 2: Assign a number when a car is created

Add the state entry action

  1. Open the state diagram for Car.
  2. On state BrandNew, add an entry action:
self.RegistrationNumber:=self.GetNewRegistrationNumber
  1. Save and upload the model to MDrivenServer.
  2. In the browser application, create a new Car. Verify that the new car receives a registration number.

At this stage, the assignment can work for one user but is not safe for concurrent users.

Reproduce the concurrency issue

  1. Open the application in two independent browser contexts. For example, use a normal window and an incognito window, and sign in separately.
  2. Use an account that has permission to create a new car. The b@b.se user does not have this permission in the Bootcamp model; use a@a.se where needed.
  3. Place both windows on the Car Seeker page.
  4. Select New Car in both windows as close together as possible.
  5. Observe that both new cars can receive the same registration number.

This conflict occurs because both server contexts can read the same current sequence state before either update is committed. A system should keep unrelated work asynchronous so users are not blocked by lengthy operations. For a shared number sequence, however, generation and assignment must be serialized: only one matching assignment job may run at a time.

Part 3: Serialize assignment with SysAsyncTicket

Import the pattern

  1. Download the SysAsyncTicket merge model from the MDriven wiki and merge it into your model.
  2. Verify that your active packages use SysSuperClass as their default superclass. Classes without an explicit superclass then inherit from SysSuperClass.
  3. Confirm that the imported pattern makes the DoAsync method available through that inheritance.

SysAsyncTicket is the pattern recognized by MDrivenServer for asynchronous work. Calling DoAsync moves the operation to the server. MDrivenServer serializes jobs with the same signature, which prevents two cars from receiving the same registration number through this assignment operation.

Move the assignment into an asynchronous method

  1. Create a method on Car named ActuallyAssignNewNumber.
  2. Move the former entry-action assignment into that method:
self.RegistrationNumber:=self.GetNewRegistrationNumber
  1. Replace the BrandNew entry action with:
self.DoAsync('ActuallyAssignNewNumber')
  1. Save and upload the model.
  2. Create a new car in the application and save it. Wait for the registration number to return from MDrivenServer.
  3. Repeat the two-browser test. Create new cars in both contexts repeatedly. Verify that no two new cars receive the same number.

Inspect asynchronous work on MDrivenServer

  1. Open the MDrivenServer administration UI at http://localhost:5000, or use the port configured in the Cloud Connect dialog.
  2. Sign in with the Bootcamp administrator account: user a, password 123456.
  3. Open Running then PeriodicActions. Review the actions that inspect SysAsyncTicket records and remove old tickets.
  4. Open Running then Data in A0. Select SysAsyncTicket, then select Search. Locate ticket data for Car.ActuallyAssignNewNumber and check that no issue is reported.
  5. Open Running then WorkInfo to inspect the server events recorded for the work.

Prevent manual edits to registration numbers

The registration number is system-assigned. Make it read-only wherever the UI exposes it, so users do not mistake it for editable data.

  1. Select the RegistrationNumber attribute on Car and use Changed by - Cross Reference.
  2. Open ViewModelColumn ProperCarView.RegistrationNumber R/W.
  3. Select RegistrationNumber and set its Readonly Expression to true.
  4. Run Changed by - Cross Reference again. It also identifies TheTemplateForCarTransferOwnershipDocumentReport.
  5. Open that ViewModel and set the RegistrationNumber column's Readonly Expression to true.

You can use IsStatic instead when it fits the intended UI, but this exercise uses a read-only expression to make the restriction explicit in each ViewModel.

Mark the result as realtime

  1. Select Car.RegistrationNumber.
  2. Open the Tagged Values dialog.
  3. Select Refresh From Wiki.
  4. Select <Create Empty TV>, choose Realtime, and set its value to true.
  5. Close the dialog, save the model, and upload it to MDrivenServer.
  6. Create another new car and verify that its registration number returns faster than before.

Check your result

Before continuing, verify all of the following:

  • A new car receives a registration number in the expected format.
  • Repeated method calls advance the sequence and handle letter rollover.
  • Two independent browser contexts cannot obtain the same number for new cars.
  • MDrivenServer records the asynchronous assignment as Car.ActuallyAssignNewNumber work.
  • Registration numbers are read-only in both identified ViewModels.
  • Car.RegistrationNumber has the Realtime=true tagged value.

The chapter download is available as AfterChapter15.zip.

See also

Before you begin

Complete Training:Bootcamp:Chapter 14 and make sure that your model can upload to a running MDrivenServer. This chapter changes the model and relies on MDrivenServer evolving the database schema when you upload it.

The registration-number format used in this chapter is ABC123. The first part consists of three letters and the second part is a number. The exercise first implements generation locally, then shows why local generation is not safe across concurrent server contexts, and finally uses the SysAsyncTicket pattern to serialize the assignment.

What you will build

You will:

  • create a Car.GetNewRegistrationNumber():String method;
  • store the current sequence state on SysSingleton;
  • use the debugger and the OCL stepper to diagnose an expression;
  • assign a registration number when a Car enters the BrandNew state;
  • import the SysAsyncTicket model pattern and schedule the assignment through DoAsync;
  • make RegistrationNumber read-only in the relevant ViewModels; and
  • mark the attribute as Realtime=true so the assigned value returns to the client sooner.

Part 1: Generate the next registration number

Create the method and sequence state

  1. On class Car, create the method GetNewRegistrationNumber():String.
  2. On SysSingleton, add the following nullable integer attributes. They retain the state needed to calculate the next value.
Attribute Initial value Purpose
RegNumberLetter1Current:Integer? 65 Current value for the first letter
RegNumberLetter2Current:Integer? 65 Current value for the second letter
RegNumberLetter3Current:Integer? 65 Current value for the third letter
RegNumberNumberPartCurrent:Integer? 1 Current numeric part
  1. For each of the three letter attributes, set both the default value and InitialValue to 65.
  2. Set InitialValue for RegNumberNumberPartCurrent to 1.
  3. Implement the method logic shown in Video 15. It must return a string in the ABC123 form, advance the stored sequence state, and carry to the next letter when a letter reaches Z.

The value 65 is the starting value used by this exercise for the letter sequence. Test the rollover behavior later by repeatedly executing the method until a letter reaches Z.

Use semicolons in an OCL action expression

An OCL expression returns one result. When an action expression must perform several operations, separate the expressions with a semicolon (;). The result of the complete expression is the result of its last expression.

Expression Result
expr1;expr2 The result of expr2
expr1;expr2;expr3 The result of expr3
expr1;expr2; Invalid: an expression cannot end with a semicolon

For example, use earlier expressions to update the sequence state and make the final expression produce the registration-number string. Do not leave a trailing semicolon after that final result.

Upload and test the method in the debugger

  1. Save the model and upload it to MDrivenServer. Confirm that the server status reports the database evolution for the new SysSingleton attributes.
  2. Select Play, open the debugger, and select MDrivenServer persistence.
  3. Open a debugger search window for Car, search for cars, and drag a car to the green expression dot. This assigns that car to self for the debugger expression.
  4. Change the expression mode to Action and execute self.GetNewRegistrationNumber.
  5. If the result or stored values are not what you expect, start the expression with Step, select Start, and use Step into to enter the method. Follow each expression and identify where the returned result or sequence update differs from the intended behavior.
  6. Correct the method, save, and upload the model again.
  7. If the debugger is still open, select Re-Read Model. Uploading alone does not update the model already loaded by the debugger.
  8. Repeat self.GetNewRegistrationNumber with F5. Hold F5 to execute repeatedly and observe the rollover from Z to the next letter position.
  9. Cancel the test changes when you finish.

Part 2: Assign a number when a car is created

Add the state entry action

  1. Open the state diagram for Car.
  2. On state BrandNew, add an entry action:
self.RegistrationNumber:=self.GetNewRegistrationNumber
  1. Save and upload the model to MDrivenServer.
  2. In the browser application, create a new Car. Verify that the new car receives a registration number.

At this stage, the assignment can work for one user but is not safe for concurrent users.

Reproduce the concurrency issue

  1. Open the application in two independent browser contexts. For example, use a normal window and an incognito window, and sign in separately.
  2. Use an account that has permission to create a new car. The b@b.se user does not have this permission in the Bootcamp model; use a@a.se where needed.
  3. Place both windows on the Car Seeker page.
  4. Select New Car in both windows as close together as possible.
  5. Observe that both new cars can receive the same registration number.

This conflict occurs because both server contexts can read the same current sequence state before either update is committed. A system should keep unrelated work asynchronous so users are not blocked by lengthy operations. For a shared number sequence, however, generation and assignment must be serialized: only one matching assignment job may run at a time.

Part 3: Serialize assignment with SysAsyncTicket

Import the pattern

  1. Download the SysAsyncTicket merge model from the MDriven wiki and merge it into your model.
  2. Verify that your active packages use SysSuperClass as their default superclass. Classes without an explicit superclass then inherit from SysSuperClass.
  3. Confirm that the imported pattern makes the DoAsync method available through that inheritance.

SysAsyncTicket is the pattern recognized by MDrivenServer for asynchronous work. Calling DoAsync moves the operation to the server. MDrivenServer serializes jobs with the same signature, which prevents two cars from receiving the same registration number through this assignment operation.

Move the assignment into an asynchronous method

  1. Create a method on Car named ActuallyAssignNewNumber.
  2. Move the former entry-action assignment into that method:
self.RegistrationNumber:=self.GetNewRegistrationNumber
  1. Replace the BrandNew entry action with:
self.DoAsync('ActuallyAssignNewNumber')
  1. Save and upload the model.
  2. Create a new car in the application and save it. Wait for the registration number to return from MDrivenServer.
  3. Repeat the two-browser test. Create new cars in both contexts repeatedly. Verify that no two new cars receive the same number.

Inspect asynchronous work on MDrivenServer

  1. Open the MDrivenServer administration UI at http://localhost:5000, or use the port configured in the Cloud Connect dialog.
  2. Sign in with the Bootcamp administrator account: user a, password 123456.
  3. Open Running then PeriodicActions. Review the actions that inspect SysAsyncTicket records and remove old tickets.
  4. Open Running then Data in A0. Select SysAsyncTicket, then select Search. Locate ticket data for Car.ActuallyAssignNewNumber and check that no issue is reported.
  5. Open Running then WorkInfo to inspect the server events recorded for the work.

Prevent manual edits to registration numbers

The registration number is system-assigned. Make it read-only wherever the UI exposes it, so users do not mistake it for editable data.

  1. Select the RegistrationNumber attribute on Car and use Changed by - Cross Reference.
  2. Open ViewModelColumn ProperCarView.RegistrationNumber R/W.
  3. Select RegistrationNumber and set its Readonly Expression to true.
  4. Run Changed by - Cross Reference again. It also identifies TheTemplateForCarTransferOwnershipDocumentReport.
  5. Open that ViewModel and set the RegistrationNumber column's Readonly Expression to true.

You can use IsStatic instead when it fits the intended UI, but this exercise uses a read-only expression to make the restriction explicit in each ViewModel.

Mark the result as realtime

  1. Select Car.RegistrationNumber.
  2. Open the Tagged Values dialog.
  3. Select Refresh From Wiki.
  4. Select <Create Empty TV>, choose Realtime, and set its value to true.
  5. Close the dialog, save the model, and upload it to MDrivenServer.
  6. Create another new car and verify that its registration number returns faster than before.

Check your result

Before continuing, verify all of the following:

  • A new car receives a registration number in the expected format.
  • Repeated method calls advance the sequence and handle letter rollover.
  • Two independent browser contexts cannot obtain the same number for new cars.
  • MDrivenServer records the asynchronous assignment as Car.ActuallyAssignNewNumber work.
  • Registration numbers are read-only in both identified ViewModels.
  • Car.RegistrationNumber has the Realtime=true tagged value.

The chapter download is available as AfterChapter15.zip.

See also