Step 1: Schematize
a. Create model schema for Use Case domain
Use “Oslo” Intellipad tool to create M Schema file. Save the file as SimpleUseCase.m.
module SimpleUseCaseSpecification
{
export UseCase, UseCases;
UseCases : UseCase*;
type UseCase
{
Id : Integer64 = AutoNumber();
Name : Text;
SuccessScenario : Text;
Goal : Text?;
PrimaryActor : Text?;
} where identity Id;
}
This model is very simple with one type (UseCase) and one extent (UseCases). It doesn’t use any complex nested types, either.
The T-SQL for above schema is as follows. In Intellipad, use M Mode -> Generic T-SQL Preview to view the SQL generated for an M Schema.
set xact_abort on;
go
begin transaction;
go
set ansi_nulls on;
go
create schema [SimpleUseCaseSpecification];
go
create table [SimpleUseCaseSpecification].[UseCases]
(
[Id] bigint not null identity,
[Goal] nvarchar(max) null,
[Name] nvarchar(max) not null,
[PrimaryActor] nvarchar(max) not null,
[SuccessScenario] nvarchar(max) not null,
constraint [PK_UseCases] primary key clustered ([Id])
);
go
commit transaction;
go
b. Compile the model schema into an “M” Image
Use M Compiler to compile the M Schema into a binary format. The following command will output a file called SimpleUseCase.mx.
m.exe –t:Repository –p:Image SimpleUseCase.m
c. Install Use Case MImage in “Oslo” Repository
Use M Image loader to install the M image into the “Oslo” Repository.
mx.exe /i:SimpleUseCase.mx /db:Repository
At this point, you can use Microsoft SQL Server Management Studio (or any other data access tool) to validate that tables/views have been created in the Repository catalog.
Step 2: Instance Creation (M Instance)
a. Create sample model instance(s) for Use Case domain
Use “Oslo” Intellipad tool to create M Instance file. Save the file as SimpleUseCaseSampleInput.m. The following snippet will result in two Use Case instances – “Smoke detection” and “Disarm alarm system”. The example use case instances are taken from this PDF link available on Alistair Cockburn’s website. You can choose to include the sample instances in the same M file where the schema is defined, but it is cleaner to keep the schemas and instances separate.
module SimpleUseCaseSpecification
{
// Sample Instances
UseCases
{
{
Name = "Smoke detection",
Goal = "To inform stakeholders of the fire in the house",
SuccessScenario = "1> One of the smoke detector signals smoke presence. 2> System identifies smoke detector location by its comm. port. 3> System informs stakeholders via phone line and the a/v speaker.",
PrimaryActor = "Smoke detector"
},
{
Name = "Disarm alarm system",
Goal = "Quick, safe and straight forward disarming of the alarm system.",
SuccessScenario = "1> User enters 4 digit password. 2> System recognizes password and disarms. 3> User disables alarm system.",
PrimaryActor = "House Owner"
}
}
}
The M instances correspond to the following T-SQL statements.
insert into [SimpleUseCaseSpecification].[UseCases] ([Name], [Goal], [SuccessScenario], [PrimaryActor])
values (N'Smoke detection', N'To inform stakeholders of the fire in the house', N'1> One of the smoke detector signals smoke presence. 2> System identifies smoke detector location by its comm. port. 3> System informs stakeholders via phone line and the a/v speaker.', N'Smoke detector')
;
insert into [SimpleUseCaseSpecification].[UseCases] ([Name], [Goal], [SuccessScenario], [PrimaryActor])
values (N'Disarm alarm system', N'Quick, safe and straight forward disarming of the alarm system.', N'1> User enters 4 digit password. 2> System recognizes password and disarms. 3> User disables alarm system.', N'House Owner')
;
b. Compile the model instance into an “M” Image
To compile the model instances into an “M” binary image -
m -t:Repository -p:Image -r:SimpleUseCase.mx SimpleUseCaseSampleInput.m
c. Install Use Case data “M” Image in “Oslo” Repository
To insert the use case model instances into the repository, run the following utility. On success, you should be able to use your favorite database access technology to explore data in the repository. Of course, if you had access to Quadrant, I would have recommended you to use Quadrant to browse this data.
mx /i:SimpleUseCaseSampleInput.mx /db:Repository /r:SimpleUseCase.mx
Step 3: Instance Creation (Textual DSL)
a. Determine the input format/template and create sample input
For the simple Use Case schema, as a starter, let’s use the following simple language. We will later evolve this to match most of Use Case Template by Alistair Cockburn. The file will contain 1 or more use cases, delimited by “*”. Each use case has a field name label followed by a text literal. Save the file as SimpleUseCaseInput.uc.
Use Case: "Activate perimeter monitoring"
Goal in Context: "To have one part of the house monitored for alarm conditions, and other part available for use."
Primary Actor: "Home Owner"
Main Success Scenario: "Actor selects to set perimeter area monitoring. System activates."
*
b. Create grammar
The grammar is written such so that the output productions result in a M Instance graph very similar to one created by hand in Step 2a.
module SimpleUseCaseSpecification
{
import CommonLanguages { Common as C };
language SimpleUseCaseLanguage
{
interleave WhiteSpacing = C.Space | C.LF | C.CR;
// Entry point
syntax Main =
uclist:C.List(UseCaseDecl)
=> UseCases { valuesof(uclist) };
// One Use Case
syntax UseCaseDecl =
u:UseCaseNameDecl
g:GoalDecl
a:ActorDecl
s:MainScenarioDecl
EndUseCaseDecl
=> { u, g, a, s };
syntax UseCaseNameDecl =
kwUseCase n:C.Text
=> Name {n};
syntax GoalDecl =
kwGoal goal:C.Text
=> Goal {goal};
syntax ActorDecl =
kwActor n:C.Text
=> PrimaryActor {n};
syntax MainScenarioDecl =
kwMainScenario sc:C.Text
=> SuccessScenario { sc };
syntax EndUseCaseDecl = "*";
// Tokens
@{Classification["Keyword"]} token kwUseCase = "Use Case: ";
@{Classification["Keyword"]} token kwGoal = "Goal in Context: ";
@{Classification["Keyword"]} token kwActor = "Primary Actor: ";
@{Classification["Keyword"]} token kwMainScenario = "Main Success Scenario: ";
}
}
module CommonLanguages
{
export Common;
language Common
{
// Parameterized List rule
syntax List(element)
= item:element => [item]
| item:element list:List(element) => [item, valuesof(list)];
syntax List(element, separator)
= item:element => [item]
| item:element separator list:List(element, separator) => [item, valuesof(list)];
// Whitespace
syntax LF = "\u000A";
syntax CR = "\u000D";
syntax Space = "\u0020";
syntax Whitespace = LF | CR | Space;
syntax NewLine = LF | CR;
token Text = ( 'A'..'Z' | 'a'..'z' | TSpecialChar | TNumber )+;
token TSpecialChar = ('.' | ',' | '$' | '%' | '#' | '>' | '<' | '/' | '\\' | '\t' | TSpace )+;
token TSpace = ' ';
token TNumber = ( '0'..'9' )+;
}
}
The above listed grammar generates the following M graph for the given input. You can use Intellipad’s MGrammar Mode -> Tree Preview to see the input, grammar and output in three panes side by side.

Here is the M Graph output.
UseCases{
{
Name{
"Activate perimeter monitoring"
},
Goal{
"To have one part of the house monitored for alarm conditions, and other part available for use."
},
PrimaryActor{
"Home Owner"
},
SuccessScenario{
"Actor selects to set perimeter area monitoring. System activates."
}
}
}
a. Compile grammar language definition into an MImage
Compile the M Grammar file. The following command should output SimpleUseCase.mgx.
mg SimpleUseCase.mg
b. Generate M instance output for the sample input
Use the binary M Grammar image file as a reference to work with the sample textual DSL input and generate M instance graph. The following command should output SimpleUseCaseInput.m.
mgx –r:SimpleUseCase.mgx –MmoduleName:SimpleUseCaseSpecification SimpleUseCaseInput.uc
c. Repeat step 2b & 2c to load instances in “Oslo” Repository
Compile the M Instance definition into a binary M Image.
m -t:Repository -p:Image -r:SimpleUseCase.mx SimpleUseCaseInput.m
Load the M Instance binary image into the Repository.
mx /i:SimpleUseCaseInput.mx /db:Repository /r:SimpleUseCase.mx
Step 4: Instance Creation (“Quadrant” Visual Modeling Tool)
If we start Quadrant after performing each individual step, we should expect to see the following:
· After Step 1, Quadrant should be able to recognize that a new domain ‘Use Case’ is available in the repository
o Click on EXPLORER -> Browse All and scroll down to find SimpleUseCaseSpecification module shown in the second pane
o Selecting the module should show available extents in the third pane, in our case, UseCases
· After Step 2, Wendy should be able to browse/edit the sample instances of the Use Cases available in the repository
o Click on EXPLORER -> Browse All
o Select SimpleUseCaseSpecifications in second pane
o Select UseCases in third pane; the use case instances are shown in the 4th pane.
· After Step 3, Wendy should be able to browse/edit the sample instance created using Custom Textual DSL
Let's see what the Step 4 entails in order for Wendy to create/edit/delete instances using different data visualizations.
Start Quadrant and navigate to Use Case model in the Repository Explorer.

If you drag UseCases from Repository Explorer onto the Quadrant workspace, by default, it will open it in a Workpad using a “List” editor. You can use ribbon tab UseCases -> Switch View to switch to one of other out-of-box editors such as “Table”. See the picture below with 4 open workpads:
· Workpad showing a collection of available Use Case instances in the repository using out-of-box List editor
· Workpad showing a collection of available Use Case instances in the repository using out-of-box Table editor
· Workpad showing single instance of Use Case (“Disarm alarm system”) using out-of-box Property Sheet editor
· Workpad showing single instance of Use Case (“Activate perimeter monitoring”) using out-of-box Diagram Mster/Detail editor

a. Extend Quadrant
The Quadrant editor configurations are themselves modeled and stored in the repository. So how can ISVs and SIs create instances of these “Quadrant” models:
· Use database access technology of choice – EDM, ADO.NET, etc.
· Use Quadrant (this even gives Wendy some degree of freedom to customize the end-user experience for her own needs). My guess is most ISVs would prefer to do these customizations using a “batch file” like approach. This is where M Grammar again comes in handy. In the limit (not V1), Microsoft will provide some variation of textual editor DSL to make it easier for ISVs to share, version and create custom editor configurations for their domains.
For the simple use case domain, I have done the following customizations using Quadrant itself.
· Change the icon associated with UseCases schema
o Model: Quadrant.SchemaExtension.ViewerHints
o Property: StaticEntityIcon (Quadrant.SchemaExtension.EntityIcon)
· Change the display name for single Use Case instance – by default the database identifier is used
o Model: Quadrant.SchemaExtension.ViewerHints
o Property: DescriptionProperty
· Set “Table” as the preferred editor for working with collection of Use Cases
o Model: Quadrant.Defaults.PreferredViewersForEntityTypes
o Property: Collection

After the customizations, the four use case workpads use the “Name” of the use case as the display name and make use of the custom icon.

b. Use “Quadrant” to create instances
Wendy can now use base functionality provided by Quadrant to create new and edit/delete existing Use Case instances. See screencast [here].
Complete Example
Let’s evolve the Use Case domain model to be a little more complex that what we have defined so far. You can use instructions provided in Steps 1 – 3 as appropriate with the revised example to load the model schema and/or model instances into the repository.
Revised M Schema and M Instances -- UseCase.m
module UseCaseSpecification
{
export Actor, Actors;
export UseCase, UseCases;
export SystemBoundary, SystemBoundaries;
export Association, Associations;
// **** Extents
Actors : Actor* where
item.RelatesToSystemBoundary in SystemBoundaries;
UseCases : UseCase* where
item.PrimaryActor in Actors &&
item.SuccessScenario in UseCaseScenarios &&
item.DefinedInSystemBoundary in SystemBoundaries &&
item.RelatedInformation in RelatedInformation;
SystemBoundaries : SystemBoundary*;
UseCaseScenarios : UseCaseScenario*;
RelatedInformation : RelatedInfoType*;
Associations : Association* where
item.From in UseCases &&
item.To in UseCases;
// **** Types
type UMLItem
{
Id : Integer64 = AutoNumber();
Name : Text;
Description : Text?;
} where identity Id;
// A human user or external system with which the
// system interacts.
type Actor : UMLItem
{
RelatesToSystemBoundary : SystemBoundary?;
}
// Functional requirement described from the
// perspective of the users of a system
type UseCase : UMLItem
{
DefinedInSystemBoundary : SystemBoundary?;
Goal : Text?;
Scope : Text?;
Preconditions : Text?;
SuccessEndCondition : Text?;
FailedEndCondition : Text?;
PrimaryActor : Actor?;
Trigger : Text?;
SuccessScenario : UseCaseScenario?;
RelatedInformation : RelatedInfoType?;
}
type RelatedInfoType
{
Id : Integer64 = AutoNumber();
Priority : Text? where value in { "High", "Medium", "Low" };
PerformanceTarget : Text?;
Frequency : Text?;
} where identity Id;
// Success Scenario for a UseCase
type UseCaseScenario : UMLItem
{
Steps : Text*;
}
type SystemBoundary : UMLItem;
// Specifies relationship between two use cases
type Association : UMLItem
{
From : UseCase?;
To : UseCase?;
Kind : AssociationKind = "Include";
}
type AssociationKind { "Include", "Extend", "Generalization" }
// *** Sample Instances
UseCases
{
{
Name = "Smoke detection",
Goal = "To inform stakeholders of the fire in the house",
Scope = "Alarm System",
Preconditions = "Alarm system is armed and active. Detector is working. Communication means are functioning.",
SuccessEndCondition = "Stakeholder is informed",
FailedEndCondition = "Stakeholder are not informed of smoke. Fire destroys monitored property.",
PrimaryActor =
{
Name = "Smoke Detector"
},
Trigger = "Detection of smoke",
DefinedInSystemBoundary =
{
Name = "Alarm System"
},
SuccessScenario =
{
Name = "Steps for smoke detection",
Steps =
{
{ "One of the smoke detector signals smoke presence." },
{ "System identifies smoke detector location by its comm. port." },
{ "System informs stakeholders via phone line and the a/v speaker." }
}
},
RelatedInformation =
{
Priority = "High",
PerformanceTarget = "Stakeholders should be notified within 5 seconds",
Frequency = "Rarely. Only in extreme cases of fire, or strong smoke concentration."
}
},
{
Name = "Disarm alarm system",
Goal = "Quick, safe and straight forward disarming of the alarm system.",
Scope = "Authentication and system enabling",
Preconditions = "Alarm system is armed and active. User knows disarming procedure and remembers password.",
SuccessEndCondition = "System is disarmed",
FailedEndCondition = "System goes off",
PrimaryActor =
{
Name = "House Owner"
},
Trigger = "Entry of numerical password sequence",
SuccessScenario =
{
Name = "Steps for disarming alarm system",
Steps =
{
{ "User enters 4 digit password" },
{ "System recognizes password and disarms" },
{ "User disables alarm system" }
}
},
RelatedInformation =
{
Priority = "High",
PerformanceTarget = "Disarming process has to occur within 15 seconds.",
Frequency = "At least 3 times a day. Every time user leaves the house."
}
}
}
}
Revised textual use case template -- UseCaseInput.uc
Use Case: Smoke detection
CHARACTERISTIC INFORMATION
Goal in Context: To inform stakeholders of the fire in the house
Scope: Alarm System
Preconditions: Alarm system is armed and active. Detector is working. Communication means are functioning.
Success End Condition: Stakeholder is informed
Error End Condition: Stakeholder are not informed of smoke. Fire destroys monitored property.
Primary Actor: Smoke Detector
Trigger: Detection of smoke
MAIN SUCCESS SCENARIO
Step#1 One of the smoke detector signals smoke presence.
Step#2 System identifies smoke detector location by its commport.
Step#3 System informs stakeholders via phone line and the a/v speaker.
RELATED INFORMATION
Priority: High
Performance Target: Stakeholders should be notified within 5 seconds.
Frequency: Rarely. Only in extreme cases of fire, or strong smoke concentration.
SCHEDULE
Due Date: Jan/12/1000
*
Use Case: Disarm alarm system
CHARACTERISTIC INFORMATION
Goal in Context: Quick, safe and straight forward disarming of the alarm system.
Scope: Authentication and system enabling
Preconditions: Alarm system is armed and active. User knows disarming procedure and remembers password.
Success End Condition: System is disarmed
Error End Condition: System goes off
Primary Actor: House Owner
Trigger: Entry of numerical password sequence
MAIN SUCCESS SCENARIO
Step#1 User enters 4 digit password
Step#2 System recognizes password and disarms
Step#3 User disables alarm system
RELATED INFORMATION
Priority: High
Performance Target: Disarming process has to occur within 15 seconds.
Frequency: At least 3 times a day. Every time user leaves the house.
*
Revised M Grammar -- UseCase.mg
module UseCaseSpecification
{
import CommonLanguages { Common as C };
language UseCaseLanguage
{
// Ignore whitespace
interleave Skippable = C.LF | C.CR | C.Space;
// Entry point
syntax Main =
t:UseCaseDocument+
=> UseCases { valuesof(t) };
// One Use Case
syntax UseCaseDocument =
kwUseCase ucn:C.Text
kwCharInfo?
cinfo:CharInfoSubSectionDecl?
sl:C.List(SectionDecl)
EndUseCaseDecl
=> { Name {ucn}, valuesof(cinfo), valuesof(sl) };
syntax EndUseCaseDecl = "*";
// Each section in the use case
syntax SectionDecl =
section:MainScenarioSectionDecl => section
| section:SubVariationsSectionDecl => section
| section:RelatedInfoSectionDecl => section
| section:OpenIssuesSectionDecl => section
| section:ScheduleSectionDecl => section;
// CHARACTERISTIC INFORMATION SECTION
syntax CharInfoSectionDecl =
sl:C.List(CharInfoSubSectionDecl)
=> { valuesof(sl) };
syntax CharInfoSubSectionDecl =
(g:GoalDecl => g)
(s:ScopeDecl => s)
(p:PreconditionsDecl => p)
(su:SuccessEndCondDecl => su)
(e:ErrorEndCondDecl => e)
(a:ActorDecl => a)
(t:TriggerDecl => t);
syntax GoalDecl =
kwGoal n:C.Text
=> Goal {n};
syntax ScopeDecl =
kwScope n:C.Text
=> Scope {n};
syntax PreconditionsDecl =
kwPreconditions n:C.Text
=> Preconditions {n};
syntax SuccessEndCondDecl =
kwSuccessEndCond n:C.Text
=> SuccessEndCondition {n};
syntax ErrorEndCondDecl =
kwErrorEndCond n:C.Text
=> FailedEndCondition {n};
syntax ActorDecl =
kwActor n:C.Text
=> PrimaryActor { Name {n} };
syntax TriggerDecl =
kwTrigger n:C.Text
=> Trigger {n};
// MAIN SUCCESS SCENARIO SECTION
syntax MainScenarioSectionDecl =
kwMainScenario
sl:C.List(ScenarioStepDecl)?
=> SuccessScenario { Steps { valuesof(sl) } };
syntax ScenarioStepDecl =
"Step#" i:C.TNumber n:C.Text
=> {n};
// SUB-VARIATIONS SECTION
syntax SubVariationsSectionDecl =
kwSubVariations
des:C.Text?
vl:C.List(SubVariationDecl)?
=> Variations { valuesof(vl) };
syntax SubVariationDecl =
"Variation#" i:C.TNumber n:C.Text
=> Variation {n};
// RELATED INFORMATION SECTION
syntax RelatedInfoSectionDecl =
kwRelatedInfo
pri:PriorityDecl?
perf:PerfTargetDecl?
freq:FreqDecl?
=> RelatedInformation { pri, perf, freq };
syntax PriorityDecl =
kwPriority n:PriorityEnum
=> Priority {n};
syntax PriorityEnum =
n:"High" => n
| n:"Medium" => n
| n:"Low" => n;
syntax PerfTargetDecl =
kwPerfTarget n:C.Text
=> PerformanceTarget {n};
syntax FreqDecl =
kwFreq n:C.Text
=> Frequency {n};
// OPEN ISSUES SECTION
syntax OpenIssuesSectionDecl =
kwOpenIssues
il:C.List(IssueDecl)
=> Issues {valuesof(il)};
syntax IssueDecl =
"Issue#" i:C.TNumber n:C.Text
=> Issue {n};
// SCHEDULE
syntax ScheduleSectionDecl =
kwSchedule
kwDueDate date:C.TDate
=> DueDate {date};
// Common
// Tokens
token kwCharInfo = "CHARACTERISTIC INFORMATION";
token kwMainScenario = "MAIN SUCCESS SCENARIO";
token kwSubVariations = "SUB-VARIATIONS";
token kwRelatedInfo = "RELATED INFORMATION";
token kwOpenIssues = "OPEN ISSUES";
token kwSchedule = "SCHEDULE";
@{Classification["Keyword"]} token kwUseCase = "Use Case: ";
// Characteristic Information
token kwGoal = "Goal in Context: ";
token kwScope = "Scope: ";
token kwPreconditions = "Preconditions: ";
token kwActor = "Primary Actor: ";
token kwTrigger = "Trigger: ";
token kwSuccessEndCond = "Success End Condition: ";
token kwErrorEndCond = "Error End Condition: ";
// Main Success Scenario
// Sub Variations
// Related Information
token kwPriority = "Priority: ";
token kwPerfTarget = "Performance Target: ";
token kwFreq = "Frequency: ";
token kwDueDate = "Due Date: ";
}
}
module CommonLanguages
{
export Common;
language Common
{
// Parameterized List rule
syntax List(element)
= item:element => [item]
| item:element list:List(element) => [item, valuesof(list)];
syntax List(element, separator)
= item:element => [item]
| item:element separator list:List(element, separator) => [item, valuesof(list)];
// Whitespace
syntax LF = "\u000A";
syntax CR = "\u000D";
syntax Space = "\u0020";
syntax Whitespace = LF | CR | Space;
syntax NewLine = LF | CR;
token TDate = TMonth "/" TNumber "/" TYear;
token TMonth = ("Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec" );
token TYear = ('1'..'3') ('0'..'9') ('0'..'9') ('0'..'9');
token Text = ('A'..'Z' | 'a'..'z' | ' ') ( 'A'..'Z' | 'a'..'z' | TSpecialChar | TNumber )+;
token TSpecialChar = ('.' | ',' | '$' | '%' | '>' | '<' | '/' | '\\' | '\t' | TSpace )+;
token TSpace = ' '+;
token TNumber = '0'..'9'+;
// token Text = ('a'..'z' | 'A'..'Z') ('a'..'z' | TSpecialChar | TNumber | 'A'..'Z' | ' ' | '\t')* ('a'..'z' | 'A'..'Z' | '.');
token TComma = ",";
token TSemiColon = ";";
}
}
Revised Use Case Model in “Quadrant”
Coming soon!
Summary
To summarize, we created a new model using “M” Schema and installed it in the “Oslo” Repository using “M” tool chain. We also created a textual DSL using “M” Grammar and customized “Quadrant” Visual Modeling Tool to enable end-users to populate Repository with the model instances.
Download the source M and MG files used in the attached MUseCaseSample.zip.