Definition: a domain is a separate real, hypothetical, or abstract world inhabited by a distinct set of classes that behave according to rules and policies characteristic of that domain.
The main reason for using domains is that it simplifies the analyst's job. It's hard enough to think about one subject matter at a time, without mixing them up.
A prime example is input/output; if you're considering the rules of engagement for a weapon system, you really don't want to be worrying about how the data gets into and out of the system.
Most CASE tools are pretty bad at allowing more than one person to access the model at once. If you can arrange that a group of classes and relationships can be treated as a group, by minimising the interactions with other groups of classes as far as possible, you stand a better chance of getting the tool to do what you need.
Another reason is to provide sensible work packages!
Given the above, the obvious way to model domains is as packages in the logical model, stereotyped «domain».
Domain packages can have child packages. This might be to make the model structure clearer (for example, by separating off all the type definitions). Alternatively, they might contain model statements that aren't intended to be translated; such child packages can be stereotyped «ignore» (to be honest, any package in the model which is stereotyped «ignore» will be ignored, as will all its children, recursively).
init = package.operation specifies an operation to be called before any other domain initialization.
name = package name specifies the actual package name.
revision = revision-id-string specifies the domain's version control ID.
For testing purposes, it may be convenient to gather the «public» classes and public types of a domain into a child package stereotyped «domain-interface». The package name should be Domain Interface, which controls where the generated code is placed, and the tagged value name=Domain set so that the Ada package names match those of the actual software.
A domain is translated as a top-level Ada package, with the name derived from the package name using the usual name conversion rules (it can be overridden using the {name=new-name} tag).
Child UML packages are included (recursively). The child UML package structure is not reflected in the generated code (for example, all classes end up as direct Ada child packages of the domain package).
Domain types are implemented in the domain package. For string types, a string hash function is generated as a child subprogram of the domain package.
Domain classes are implemented as children of the domain package.
Six further children are generated as standard:
The calls are in alphabetical order by class and then by operation.
See also further discussion.
Each domain must be initialized by calling the procedure Domain.Initialize, probably from your main program. Because it's a child unit, it must be withed explicitly.
If you're building your application, rather than unit tests, you'll probably want to pass Domain.Initialize the Event Queue that Domain is to use.
Because all the packages in a domain are implemented as children, you hardly ever need to mention the domain package when referencing other packages (you do need to mention the domain in the context clauses, though):
with Domain.Other_Class; separate (Domain.Class) procedure Foo is begin Other_Class.Bar; ...