You can use this OCL code in the Car.GetNewRegistrationNumber():String method to generate the next registration number in the ABC123 format for the Chapter 15 bootcamp exercise.
Purpose
This method reads the current registration-number counter from SysSingleton.oclSingleton, advances the counter, and returns the new value as three letters followed by a three-digit number.
For example, when the stored values represent AAA001, the method advances them and returns AAA002. The numeric part is formatted with leading zeroes, so a value of 2 is returned as 002.
Prerequisites
Complete the setup in Training:Bootcamp:Chapter 15 before adding the expression.
The method uses these Integer? attributes on SysSingleton:
| Attribute | Initial value in the bootcamp exercise | Purpose |
|---|---|---|
RegNumberLetter1Current
|
65
|
Stores the UTF-32 value for the first letter. |
RegNumberLetter2Current
|
65
|
Stores the UTF-32 value for the second letter. |
RegNumberLetter3Current
|
65
|
Stores the UTF-32 value for the third letter. |
RegNumberNumberPartCurrent
|
1
|
Stores the numeric part of the registration number. |
Set both the default value and the InitialValue to 65 for each letter attribute. Set the InitialValue of RegNumberNumberPartCurrent to 1. The value 65 is converted to A by Char.ConvertFromUtf32.
Add the method expression
- Create the
GetNewRegistrationNumber():Stringmethod onCar, as described in Training:Bootcamp:Chapter 15. - Open the method expression editor.
- Replace the expression with the following code.
- Save the model. When using MDrivenServer, upload the model so the new
SysSingletonattributes are added to the database schema.
let sing=SysSingleton.oclSingleton in (
let letter1=sing.RegNumberLetter1Current+1 in
(
sing.RegNumberLetter1Current:=(letter1>Char.ConvertToUtf32('Z',0))->casetruefalse(sing.RegNumberLetter2Current:=sing.RegNumberLetter2Current+1; Char.ConvertToUtf32('A',0),letter1)
);
let letter2=sing.RegNumberLetter2Current in
(
sing.RegNumberLetter2Current:=(letter2>Char.ConvertToUtf32('Z',0))->casetruefalse(sing.RegNumberLetter3Current:=sing.RegNumberLetter3Current+1; Char.ConvertToUtf32('A',0),letter2)
);
let letter3=sing.RegNumberLetter3Current in
(
sing.RegNumberLetter3Current:=(letter3>Char.ConvertToUtf32('Z',0))->casetruefalse(Char.ConvertToUtf32('A',0),letter3)
);
let numberpart=sing.RegNumberNumberPartCurrent+1 in
(
sing.RegNumberNumberPartCurrent:=(numberpart>999)->casetruefalse(0,numberpart)
);
Char.ConvertFromUtf32(sing.RegNumberLetter1Current)+Char.ConvertFromUtf32(sing.RegNumberLetter2Current)+Char.ConvertFromUtf32(sing.RegNumberLetter3Current)+sing.RegNumberNumberPartCurrent.ToString('000')
)
How the expression works
let sing=SysSingleton.oclSingleton gets the singleton object that holds the four current counter values. Every call updates this shared state rather than storing a counter on an individual Car object.
Advance letters and roll over at Z
The expression stores letters as UTF-32 integer values. It increments the first letter first.
- If the first letter is not past
Z, it retains the incremented value. - If it is past
Z, it resets that letter toAand increments the next letter. - The same rollover logic is applied from the second letter to the third letter.
- When the third letter is past
Z, it resets toA.
For example, when the letter counters reach AZZ, advancing the first letter produces BAA after the rollovers are applied.
Advance and format the numeric part
The numeric counter is incremented and reset to 0 when it becomes greater than 999.
ToString('000') formats the stored number as three digits:
| Stored numeric value | Formatted value |
|---|---|
2
|
002
|
25
|
025
|
999
|
999
|
Return one result
The final expression concatenates the converted letters and formatted number, returning one String result.
The semicolon (;) separates expressions that must be evaluated in sequence. In this method, earlier expressions update the singleton counters and the final concatenation is the returned result. Do not end the expression with a semicolon: an OCL expression must return one result, and the result of a semicolon sequence is its last expression.
Important: concurrent assignment
This code maintains the shared counter, but the Chapter 15 exercise also introduces the SysAsyncTicket model pattern. Use that pattern when assignment must be serialized. Without serialization, two users assigning a number at roughly the same time can be given the same registration number. Continue with Training:Bootcamp:Chapter 15 to import and use the pattern recognized by MDrivenServer.
Test the method
- Run the model with persistence set to MDrivenServer, as instructed in Training:Bootcamp:Chapter 15.
- Evaluate the method for a
Carin the debugger. - Call it again and verify that the numeric portion advances, for example from
AAA002toAAA003when using the specified initial values. - Test a rollover boundary by setting a current letter value to the UTF-32 value for
Z, then evaluating the method and checking that the letter resets toAand the next letter advances.
