Hawk includes specific support for MDT2 UML models and UML profiles developed using Papyrus UML. This can be used by enabling the UMLMetaModelResourceFactory
and UMLModelResourceFactory
plugins when creating a Hawk instance.
The implementation mostly reuses MDT UML2 and Papyrus UML as-is, in order to maximize compatibility. There are some minor caveats, which are documented in this page.
Hawk indexes plain UML2 models with the .uml
extension, and Papyrus profiles with the .profile.uml
extension. It does not index .di
nor .notation
files at the moment, as these do not provide semantic information.
.xmi
files are not indexed by the Hawk UML components, to avoid conflicts with the plain EMF support (matching the file to the proper model resource is done strictly by file extension). You are recommended to rename your UML2 XMI files to .uml
for now.
UML2 provides an implementation of the UML standard libraries, with packages containing some common datatypes (e.g. String or Integer). If your models use any of these libraries, we heavily recommend that you add a PredefinedUMLLibraries
component in your “Indexed Locations” section. Otherwise, any references from your models to the libraries will be left unresolved, and you will not be able to use those predefined entities in your queries.
This is because Hawk operates normally on files, and the predefined UML libraries are generally bundled within the UML2 plugins. The PredefinedUMLLibraries
exposes those bundled resources to Hawk in a way that is transparent to the querying language.
Beyond registering all the metamodels required to index plain UML models, the UML metamodel resource factory in Hawk can register .profile.uml
files as metamodels. This allows us to index UML models with custom profiles in Hawk.
Since UML profiles can be versioned, Hawk will register version X.Y.Z
of profile with URI http://your/profile
with http://your/profile/X.Y.Z
as the URI. When querying with Hawk, you will have to specify http://your/profile/X.Y.Z
in your default namespaces, in order to resolve the ambiguity that may exist between multiple versions of the same metamodel.
If a new version of the UML profile is created, you will need to register the .profile.uml
file again with Hawk before it can index models that use that version of the profile. Hawk treats entities of different versions of the same profile as entirely different types.
In terms of implementation details, Hawk takes advantage of the fact that .profile.uml
files contain a collection of Ecore EPackages
. Hawk simply adds the /X.Y.Z
version suffix to their namespace URI, and otherwise leaves them untouched.
We will show how Hawk can be used to index all the UML models in an Eclipse workspace, including those that have custom profiles applied to them. To illustrate our approach, we will use these toy models created with Papyrus. We assume that you have installed Hawk into your Eclipse instance, following the steps in [[this wiki page|Installation]].
The model is a very simple UML class diagram:
It only has two classes, one of which has the <<Special>>
stereotype with a priority
property equal to 23. This value is not shown in the diagram, but it can be checked from the “Profile” page of the “Properties” view when the class is selected.
The profile including the <<Special>>
stereotype is also very simple:
The diagram imports the Class
UML metaclass, and then extends it with the <<Special>>
stereotype.
Before we can run any queries, we need to create a Hawk index. If we have installed Hawk correctly, we will be able to open the “Hawk” view and see something like this:
Right now, we have no indexes in Hawk. We need to press the “Add” button, which is highlighted in red above. We should see a dialog similar to this:
Important points:
Instance type
should be a LocalHawkFactory
if we intend to index our workspace.Local storage folder
will contain some of the configuration of that Hawk instance, and the database.Remote location
is irrelevant when using the LocalHawkFactory
.Disable all
the plugins and then check only the UML metamodel and model resource factories.Min/Max Delay
indicate how often will Hawk poll all the indexed locations. If you are only indexing the current workspace, you can leave both at 0 to disable polling: regardless of this setting, Hawk will react automatically whenever something in the workspace changes.Once the index has been created, you should see an entry for it in the “Hawk” view:
From the screenshot above, we know that the index is RUNNING
(available for queries) and not UPDATING
nor STOPPED
, so we can start configuring it as we need. First, we should double click on it to open the configuration dialog:
We should go to the “Metamodels” tab and click on “Add...”, then select the specialThings.profile/model.profile.uml
file. Hawk will register our custom profile as a metamodel, and we will be ready to index models using all the versions of this profile so far. Should we define any newer versions, we will have to add the file again to Hawk.
The dialog will now list the new metamodel:
Now we are ready to add the locations where the models to be indexed are stored. We go to the “Indexed Locations” tab and click on “Add”. First, we will add the predefined UML libraries with some commonly used instances (e.g. UML data types):
We need to pick the right “Type”, and then enter /
in the “Location” field. The location is ignored for this repository, but due to current limitations in the UI we have to enter something in the field.
Next, we have to tell Hawk to index all the models in the workspace. We will “Add” another location, and this time fill the dialog like this:
Again, the /
“Location” is irrelevant but required by the UI.
Hawk will spend some time UPDATING
, and once it is RUNNING
again we will be ready to run some queries on it.
We can finally query Hawk now. To do so, we need to select our index on the “Hawk” view and click on the “Query” button, which looks like a magnifying glass:
We will see a dialog like this one, with all fields empty:
Enter the query return Class.all.name;
and click on the “Run Query” button. This query lists the names of all the classes indexed so far by Hawk. You will notice that we obtain these results:
[E, T, MyClass, Special, V, NotSoSpecial, Stereotype1, K, E]
The E/T/V/K/E classes came from the predefined UML libraries. If you want only the results from your workspace, you must tell Hawk through the “Context Repositories” field, by entering platform:/resource
. This is the base URI used by Hawk to identify all the files in your workspace. Click on “Run Query” again, and you should obtain the results shown in the screenshot:
[MyClass, Stereotype1, Special, NotSoSpecial]
Note how the query also returns the classes in the profile. Should you want to avoid this, you can either use the “Context Files” field (*model.uml
will do this) to further restrict the scope of the query.
If you would like to find all applications of stereotype X
, you can simply use X.all
and then use base_Metaclass
to find the object that was annotated with that stereotype. For instance, this query will find the name of all the classes that had the <<Special>>
stereotype applied to them:
return Special.all.base_Class.name;
You will get:
[MyClass]
You can also access stereotype properties:
return Special.all.collect(s| Sequence { s.priority, s.base_Class.name } ).asSequence;
This will produce:
[[23, MyClass]]
If you want to go the other way around, you can use reverse reference navigation on those base_X
references to find the stereotypes that have been applied to a UML object:
return Class.all .selectOne(s|s.name = 'MyClass') .revRefNav_base_Class .collect(st|Model.getTypeOf(st)) .name;
This would produce:
[Special]