MagicDraw OpenAPI UserGuide
MagicDraw OpenAPI UserGuide
version 17.0.1
user guide
No Magic, Inc.
2011
All material contained herein is considered proprietary information owned by No Magic, Inc. and is not to be
shared, copied, or reproduced by any means. All information copyright 2003-2011 by No Magic, Inc. All Rights
Reserved.
CONTENTS 0
INTRODUCTION 8
PLUG-INS 10
How plug-ins work 10
Writing plug-in 11
Testing plug-in 13
Detail information 13
Plug-in descriptor 13
Plug-in classes 15
Plug-In class loading 16
Important notes for Unix systems 17
Resource dependent plug-in 17
Implementing ResourceDependentPlugin example 17
NEW! MagicDraw Plugin Integration with Eclipse 18
Extending Eclipse Main Menu with Plugin Command 18
DISTRIBUTING RESOURCES 34
How to distribute resources 34
Creating required files and folders structure 34
Resource Manager descriptor file 40
JYTHON SCRIPTING 43
Creating script 43
Step 1: Create directory 43
Step 2: Write script descriptor 43
Step 3: Write script code 44
Variables passed to script 44
Jython 45
UML MODEL 55
Project 55
Root Model 56
Accessing Model Element properties 56
Container properties 56
Collecting all children from all hierarchy levels 57
Visitors 58
InheritanceVisitor 58
Changing UML model 59
SessionManager 59
ModelElementsManager 59
Creating new model element 60
Editing model element 60
Adding new model element or moving it to another parent 60
Removing model element 61
NEW! Refactoring model elements 62
Creating Diagram 62
Creating new Relationship object 63
PRESENTATION ELEMENTS 67
Presentation Element 67
Using set and sSet 68
Diagram Presentation Element 68
Shapes 69
Paths 69
Presentation Elements Manager 69
Creating shape element 70
Creating path element 70
Reshaping shape element 70
Changing path break points 71
Deleting presentation element 71
Changing properties of presentation element 71
Notification of Presentation Element draw 72
NEW! Displaying Related Symbols 73
SYMBOLS RENDERING 74
Custom Renderer Provider 74
Registering Provider 74
Custom Symbol Renderer 74
Custom Renderers Sample 75
Creating Custom Renderers 75
Registering Custom Symbol Renderer Provider 77
DIAGRAM EVENTS 79
NEW! Diagram Listener Adapter 79
PATTERNS 80
Target concept 80
Using PatternHelper 80
Abstract Pattern 80
How to create my own pattern 82
Step 1: Create pattern properties class 82
Step 2: Create pattern panels class 83
Step 3: Create pattern class 83
Step 4: Create Description.html 84
Step 5: Create plug-in 84
PROPERTIES 86
PROJECT OPTIONS 99
Adding Own Project Options 99
Retrieving Project Option Value 100
ANNOTATIONS 118
VALIDATION 119
Basic concepts 119
Validation rule developer’s roadmap 120
Create OCL2.0 Validation Rule 120
Binary Validation Rule 121
Create Binary Validation Rule - Case A 122
Create Binary Validation Rule - Case B 122
Create Binary Validation Rule - Case C 123
Create Binary Validation Rule - Case D 124
Binary validation rule in plugin 125
How to provide a solution for a problem found during validation? 125
TEAMWORK 126
This document describes MagicDraw Open Java API and provides instructions how to write your own plug-ins,
create actions in the menus and toolbars, change UML model elements, and create new patterns.
In the generated JavaDoc you will find detailed descriptions of classes, their attributes, and operations. Java-
Doc is located in <MagicDraw installation directory>\openapi\docs.
Do not forget to add all jar files recursively (except md_commontw.jar and md_commontw_api.jar) from
<MagicDraw installation directory>/lib directory into your (IDE) classpath and make sure the patch.jar is the first in
the classpath.
Plug-ins are the only one way to change functionality of MagicDraw. The main purpose of plug-in architecture
is to add new functionality to MagicDraw although there is a limited ability to remove existing functionality using
plug-ins.
Typically plug-in creates some GUI components allowing user to use plug-in functionality. Generally this is not
necessary because plug-in can listen for some changes in project and activate itself on desired changes.
Check directory
[descriptor exists]
[no descriptor]
Read descriptor file
[requirements meets]
Writing plug-in
With this example we will create a plug-in that displays a message on MagicDraw startup.
Plug-in must contain at least one class derived from com.nomagic.magicdraw.plugins.Plugin class.
package myplugin;
public class MyPlugin extends com.nomagic.magicdraw.plugins.Plugin
{
public void init()
{
javax.swing.JOptionPane.showMessageDialog(null, "My Plugin init");
}
This plug-in shows message when it is initialized, and another message when it is closed.
To compile the written code, add all .jar files recursively from <MagicDraw installation directory>/lib to java
classpath.
IMPORTANT! Make sure that the first three .jar files are added in the following order:
1. patch.jar
2. brand.jar
3. brand_api.jar
Order is not important for the rest .jar files.
Plug-in descriptor is a file named plugin.xml. This file should be placed in myplugin directory.
<?xml version="1.0" encoding="UTF-8"?>
<plugin
id="my.first.plugin"
name="My First Plugin"
version="1.0"
provider-name="Coder"
class="myplugin.MyPlugin">
<requires>
<api version="1.0"/>
</requires>
<runtime>
<library name="myplugin.jar"/>
</runtime>
</plugin>
For detailed information about plug-in descriptor, see “Plug-in descriptor” on page 13.
Testing plug-in
1. Restart MagicDraw. On startup message should appear:
2. Then close MagicDraw (File menu -> Exit). Another message should appear:
• Another way to check plug-in is to look at md.log file. This file is located in the <User home
directory>\.magicdraw\<version> directory.
Also all plugins and their status are listed in the MagicDraw EnvironmentOptions Plugins tab.
LOAD PLUGINS:
com.nomagic.magicdraw.plugins.PluginDescriptor@edf730[ id = my.first.plugin, name =
My First Plugin, provider = Coder, version = 1.0, class = myplugin.MyPlugin,
requires api = 1.0, runtime = [Ljava.net.URL;@ff94b1]
INIT PLUGINS:
com.nomagic.magicdraw.plugins.PluginDescriptor@edf730[ id = my.first.plugin, name =
My First Plugin, provider = Coder, version = 1.0, class = myplugin.MyPlugin,
requires api = 1.0, runtime = [Ljava.net.URL;@ff94b1]
TIP! Looking at file is the best way to find problems when plug-in does not
work.
Detail information
Plug-in descriptor
Plug-in descriptor is a file written in XML and named plugin.xml. Each descriptor contains properties of one
plug-in. Descriptor file should contain one plugin element definition.
Element Description
Name Description
plugin Attributes
id Plug-in ID should be unique. Used to identify plug-in by
plug-ins manager internals and by requirements of other
plug-ins. Example: “my.first.plugin.0”
Element Description
required- Attributes
plugin
id ID of required plug-in.
Example: “my.first.plugin.0”
version Version of required plug-in.
Example: “1.1”
runtime Nested elements
library Runtime library for running plug-in.
library Attributes
name Name of the required library.
Example: "patterns.jar"
help Attributes
Plug-in classes
Plugin is the base abstract class for any MagicDraw plug-in. User written plug-in must be extended from this
class. Every plug-in has its own descriptor set by plug-ins manager. Plug-in has two special methods:
• public abstract void init() method is called on MagicDraw startup. Plug-in must override this
method and implement there its own functionality.
• public abstract boolean close() method is called on MagicDraw shutdown. Plug-in must
override this method and return to true if plug-in is ready to shutdown or false in other case. If
plug-in returns false, MagicDraw shutdown will be canceled.
• public abstract boolean isSupported() method is called before plug-in init. If this method returns
false, plugin will not be initialized. isSupported() may be used to check if plugin can be started
for example on this OS.
PluginDescriptor is the class that provides information loaded from plugin.xml file (plug-in descriptor) to plug-
in. Detail information about these classes can be found in javadoc.
Plugins Manager
MagicDraw Startup
3: create()
plugin : Plugin
4: setDescriptor( descriptor )
6: init()
MagicDraw Shutdown
7*[for all plugins]:
8: result := close()
Optional property “class-lookup” controls how classes are loaded if plugin has its own classloader. If value of
this property is LocalFirst, class is loaded from plugin classpath even if such class is already loaded in global
MagicDraw core class loader. This property is important if you want to use different version of the same classes
(libraries) used in MagicDraw core.
To become resource dependent plug-in, your plug-in class must implement com.nomagic.magicdraw.plu-
gins.ResourceDependentPlugin interface (Figure 1 on page 17).
This plug-in will be required for projects if project contains module “my_profile_filename”. Plug-in name and ver-
sion will be saved into project’s XMI file.
If an additional command should appear on the main menu or an additional button should be placed on the
main toolbar in MagicDraw after plugin installation, you need to create an Eclipse bundle that tells Eclipse
where the command or the button should be placed.
Example: Extending the Eclipse main menu with an additional command brought by a MagicDraw
plugin
Lets say you have already created a MagicDraw plugin that extends the main menu of MagicDraw with a com-
mand whose id, for example, is “CUSTOM_ACTION_ID”.
2. Create a descriptor (plugin.xml file) for the Eclipse bundle to place the command on the Eclipse
main menu.
TIP! This is an example of a descriptor that should place the command with id
“CUSTOM_ACTION_ID” under Diagrams > Diagram Wizards menu:
<!-- Define command and attach to category -->
<extension point="org.eclipse.ui.commands">
<command id="MyCustomActionWrapper.cmd"
name= "Command name"
categoryId="MagicDraw"/>
NOTE: This is a general way of adding a command to the Eclipse main menu.
3. Pack the command class with the Eclipse bundle descriptor to an Eclipse bundle (.jar file) and
save the file in <MagicDraw installation directory>/plugins/eclipse/plugins.
4. Integrate MagicDraw with Eclipse.
5. Start Eclipse.
MagicDraw plug-ins can be effectively developed using popular IDEs (Integrated Development Environment)
such as Eclipse, IntelliJ, and others. Developers may use theirs favorite IDE for agile MagicDraw plug-in
coding, building, testing, and debugging. This chapter describes the MagicDraw plug-in development in Eclipse
(www.eclipse.org) IDE.
In order to access MagicDraw Open API classes, the MagicDraw libraries (jars) must be added to the Eclipse
project build path. It is recommended to create a path variable for the MagicDraw installation directory. The
path variable should be used to specify MagicDraw libraries in the Eclipse project build path (see Figure 2 on
page 21). Variable relative paths simplify switching between different MagicDraw versions, and make the
MagicDraw plug-in project environment independent. If the developed MagicDraw plug-in uses other
MagicDraw plug-ins or external libraries, those libraries should be also added to the project build path.
Figure 2 -- Eclipse Java Project build path with specified MagicDraw libraries
NOTE Please note, that even plug-in descriptor file contains information about
runtime plug-in jar, it is not necessary to build and deploy this jar to
plug-in directory while plug-in is developed under Eclipse IDE.
If the created MagicDraw plug-in uses external libraries which conflict with the same MagicDraw libraries, the
ownClassload property value should be set as true in the plug-in descriptor as shown in the following example:
Figure 3 -- Eclipse Run Configuration settings for starting MagicDraw from Eclipse
Moreover, the heap size configuration and the MagicDraw installation directory should be provided as Java
Virtual Machine (JVM) arguments in the Arguments tab of the Run Configuration dialog (see Figure 4 on
page 23). MagicDraw output can be redirected to Eclipse Console by specifying the -verbose key as the
MagicDraw program argument.
Some more MagicDraw environment properties can be added. For instance, if MagicDraw needs to be loaded
with custom plug-ins only, the custom directory for MagicDraw plug-ins can be specified as the
md.plugins.dir property value:
-Dmd.plugins.dir=C:\development\plugins
MagicDraw can be also started in the debug mode as a regular Java program. To use the standard Eclipse
Debug feature, on the Eclipse menu, click Run > Debug. In this case, the MagicDraw plug-in code can be
debugged using break points, watchers, and other Eclipse debugging features. Moreover, the body of
MagicDraw plug-in methods can be changed and reloaded (hot-swapped) while running MagicDraw in the
debug mode. It is not need to restart MagicDraw each time the body of plug-in method is changed. It is
recommended to run MagicDraw in the debug mode while developing MagicDraw plug-ins.
Figure 4 -- MagicDraw heap size and installation directory configuration as JVM arguments
UML specification introduced changes in UML metamodel, so we are forced to make these changes in Open
API too. Also it was a good chance to make cleaner UML metamodel implementation API.
There are no big changes in Open API, so migration will not be a long and complicate task for you.
Most changes are made in UML Templates, Simple Time, Interactions.We suggest to look at UML 2.1.2 (2.2)
specification for such changes if you see some compile errors.
MagicDraw version 15.0 and later UML metamodel API provides just one final merged layer. All intermediate
layers were dropped from API. This change reduced UML metamodel API size few times.
We left the same package name for merged interfaces like in previous API version -
com.nomagic.uml2.ext.magicdraw.**. You do not need to make any changes in your code if you was using
interfaces from this layer. Otherwise you need simple change import statement in your java source files. For
example - import com.nomagic.uml2.omg.kernel.Element to import
com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Element.
UML metamodel interfaces uses Java 5 generics, so it is much easier to understand types of various collec-
tions in metamodel.
The core change is an introduction of IProject - IPrimaryProject and IAttachedProject. IPrimaryProject is a sin-
gle instance in the scope of a MagicDraw project. IPrimaryProject can have attached (used) any number of IAt-
tachedProject (modules), while IAttachedProject itself can attach other modules (IAttachedProject).
ProjectEventListener
The following methods have been added:
projectActivatedFromGUI (Project)
projectCreated (Project)
projectOpenedFromGUI (Project)
projectPreActivated (Project)
projectPreClosed (Project)
projectPreDeActivated (Project)
projectPreReplaced (Project,Project)
projectPreSaved (Project,boolean)
projectPreClosedFinal (Project)
An empty implementation of these methods must be added to the custom ProjectEventListener implementa-
tion. The code change is not required, if ProjectEventListenerAdapter is extended.
In earlier versions, a MagicDraw file was a plain xmi file with extensions used to save diagrams information and
project structure information (a mount table). A mdzip file was a compressed xmi file. The code engineering
information was saved in the different file with extension "mdr".
A project is collection of xmi, text, and binary resources. A native file format contains all resources saved as
separate files. All these files are collected to one zip file.
Version 17.0.1 saves the diagram element as a separate element extension named <modelExtension>. This
extension is stored in place where the diagram element is serialized (inside a diagram owner). If one owner has
more than one diagram, they may be written in the one extension. In this extension, a diagram element is saved
as a normal model element, and all its attributes and references are saved according xmi rules. A diagram
element contains DiagramRepresentationObject, which contains information about a diagram type, required
features, and so on. DiagramRepresentationObject contains DiagramContentsDescriptor, which describes
used elements in diagram and contains BinaryObject. BinaryObject has the attribute “streamContentID” which
identifies a zip entry for diagram symbols. All information is stored in <mdOwnedViews>. The following schema
presents finding diagram symbols entry id:
// close session
SessionManager.getInstance().closeSession();
In MagicDraw 17.0.1, an element created using the EMF factory will be placed in the repository that does not
belong to any project. The created object will be automatically added into the project’s repository after it will be
added into the container that is in the project’s repository.
All UML model elements are directly or indirectly contained by EMF resources. Resource of an element can be
retrieved in the standard way:
Element element;
org.eclipse.emf.ecore.resource.Resource resource = element.eResource();
Each MagicDraw project has the one EMF resource for private data (all not shared data) and can have the one
resource for shared data (if it has shared data). Project resources can be accessed in the following way:
// get primary project of the active project
IPrimaryProject project =
Application.getInstance().getProject().getPrimaryProject();
// get UML model project feature
UMLModelProjectFeature feature =
project.getFeature(UMLModelProjectFeature.class);
// get private resource
// NOTE: this method will return shared resource for attached project/module
Resource privateResource = feature.getUMLModelResource();
//do something with elements directly contained in the resource
EList<EObject> contents = privateResource.getContents();
for (EObject element : contents) {
// do something with the element
}
In this section, you will find information about how to share your created resources with other users. The easi-
est way to distribute data is to store resources to one zip archive and import the files to MagicDraw with the
MagicDraw Resource Manager. For more information about Resource Manager, see MagicDraw UserMan-
ual.pdf.
You can distribute one resource type or you may distribute the whole resources set.
For each resource files, there should be a created folders structure, which should match the folders structure of
the MagicDraw installation folder.
To distribute resources, you must create a resource manager descriptor file, which is described in the section
“Resource Manager descriptor file” on page 40.
Figure 6 -- Folders and files structure required for custom diagram distribution
For more information about creating new diagram types, see the section “New Diagram Types” on page 88 or
see the UML Profiling and DSL UserGuide.pdf custom diagrams creation.
Distributing Profiles
For more information about working with Profiles see MagicDraw UserManual.pdf and UML Profiling and DSL
UserGuide.pdf.
Distributing Templates
• description.html.
You can distribute your created samples and documentation and import into MagicDraw with the Resource
Manager.
Figure 9 -- Folders and files structure required for samples and documentation distribution
Distributing Plug-ins
The plug-in term may include all resources that could be distributed. Such as custom diagrams, profiles, tem-
plates, samples, and others.
See the general structure of the resources that could be distributed with the Resource Manager in the image
below.
Figure 11 -- Structure of directories and files that could be distributed through the Resource Manager
For more information about importing resources with Resource Manager, see MagicDraw UserManual.pdf.
The resource Manager descriptor file has specific naming. See the structure of the name:
For example:
MDR_Plugin_CustomPlugin_3001_descriptor.xml.l
NOTE All spaces are replaced with the underscore symbol “_“.
In this section you will see a basic sample of the Resource Manager descriptor file structure. This sample rep-
resents a plug-in distribution, which also includes custom diagram, profile, template, sample, and documentation.
You can also distribute custom diagrams, profiles, templates, or samples separately, you only need to change
the “type“ value.
<resourceDescriptor
critical="false"
date="2007-12-24+21:01"
description="My Plug-in"
homePage="http://www.magicdraw.com"
id="3001"
mdVersionMax="higher"
mdVersionMin="15.0"
name="CustomPlugin"
type="Plugin">
<edition>Enterprise</edition>
<edition>Architect</edition>
<edition>Standard</edition>
<edition>Professional Java</edition>
<edition>Professional C++</edition>
<edition>Professional C#</edition>
<edition>Professional ArcStyler</edition>
<edition>Reader</edition>
<edition>OptimalJ</edition>
<installation>
<file from="data/defaults/data/diagrams/CustomDiagram/descriptor.xml"
to="data/defaults/data/diagrams/CustomDiagram/descriptor.xml" />
<file from="profiles/CustomProfile.xml.zip"
to="profiles/CustomProfile.xml.zip" />
<file from="templates/CustomTemplate.xml.zip"
to="templates/CustomTemplate.xml.zip" />
<file from="samples/CustomPluginSample.mdzip"
to="samples/CustomPluginSample.mdzip" />
<file from="manual/CustomPluginManual.pdf"
to="manual/CustomPluginManual.pdf" />
<file from="plugins/customPlugin/*.*"
to="plugins/customPlugin/*.*" />
<file from="data/resourcemanager/MDR_Plugin_CustomPlugin_3001_descriptor.xml"
to="data/resourcemanager/MDR_Plugin_CustomPlugin_3001_descriptor.xml" />
</installation>
</resourceDescriptor>
See the terms used in the sample description in the table below:
Element Description
id Unique plug-in id. id is used to form a descriptor file name.
To prevent duplicates use a number starting from 3000.
name Plug-in name. Name is used to form a descriptor file name.
Plug-in name must be unique between all MagicDraw
resources.
type Type may be one of the following types: Custom Diagram,
Plugin, Profile, Sample, Template.
version internal version internal is an invisible resource number. This version
number is not visible to the user and may be used for an inter-
nal count. version internal may only be a number.
version human Human readable version number of the resource.
This version number is visible to users.
version human number may use numbers and/or words.
edition Supported MagicDraw editions.
installation installation includes files, which will be copied from the custom
plug-in archive to the MagicDraw folder.
IMPORTANT! Do not use "*.*" ! If file name includes “*.*“, when
uninstalling the plug-in all defined files will be removed. For
example if "samples/*.*" is defined, then uninstalling the
resource will remove all files from the “samples” folder.
MagicDraw allows you to access open API using Jython scripting language.
Creating script
In the following example we will create script which shows a message on MagicDraw startup.
In the table below, you will find the detailed script.xml file structure.
Element Description
script Attributes
Name Description
Scrip ID, should be unique. Used to identify script.
id
Example: “my.first.script.0”
Script name. No strict rules applied to this attribute.
name
Example: “Example script”
Script version. Allows numbers separated with one dot
version
value. Examples: “1.0”, “0.1”
After saving files, restart MagicDraw. On MagicDraw startup message dialog should appear.
PythonPluginDescriptor
+ getID() : String
+ getName() : String
+ getPluginDirectory() : File
+ getProvider() : String
+ getRequiresAPI() : String
+ getScriptFileName() : String
+ getVersion() : String
+ setID( id : String ) : void
+ setName( name : String ) : void
+ setPluginDirectory( directory : File ) : void
+ setProvider( provider : String ) : void
+ setRequiresAPI( version : String ) : void
+ setScriptFileName( aScriptFile : String ) : void
+ setVersion( version : String ) : void
+ toString() : String
Script can retrieve script directory and other necessary information from pluginDescriptor variable. There is no
need to change any other fields for this variable
Jython
Jython is an implementation of the high-level, dynamic, and object-oriented language Python which is seam-
lessly integrated with the Java platform.
Using Jython you may access all java API and MagicDraw open API. This allows to avoid compilation and to
get the same results without java code. Using scripting you may do everything that you can achieve using java
plug-in, and even more: you may change your code without recompiling and restarting an application.
MagicDraw actions mechanism enables to add new functionality to MagicDraw and the way to invoke it through
GUI.
Invoking Actions
Actions can be invoked from:
Main menu
Main toolbar
Diagram toolbar
The following MDAction subclasses that are used for basic purposes are already created in MagicDraw:
• DefaultBrowserAction – action class, used for browser action. Enables to access some
browser tree and nodes. Recommended to use for performing some actions with the selected
browser nodes.
• DefaultDiagramAction – action class for diagram action. Enables to access some diagram
elements. Recommended to use when for performing some actions with the selected diagram
elements.
• PropertyAction – action for changing some element or application property. Can be used for
changing properties defined by user.
You must override at least actionPerformed() method and implement in it what this actions is going to do.
/**
* Shows message.
*/
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(Application.getInstance().
getMainFrame().getDialogParent(), "This is:" + getName());
}
}
/**
* Creates action with name "ExampleAction"
*/
public BrowserAction()
{
super("", "ExampleAction", null, null);
}
JOptionPane.showMessageDialog(MDDialogParentProvider.getProvider().getDialogParent
(), text);
}
}
If action is not added to any group, updateState() method for all such actions will be invoked after executing
any command and after closing/opening project or window.
When some actions need to refresh their state, all actions without group can be updated manually:
ActionsStateUpdater.updateActionsState();
Table below explains how MagicDraw classes maps into GUI elements.
ActionsManagers for the main menu and all toolbars are created and configured once, so later actions can be
only disabled but not removed.
Context menus are created on every invoking, so ActionsManagers are created and configured every time and
actions can be added or removed every time.
// implement configuration.
// Add or remove some actions in ActionsManager.
// tree is passed as argument, provides ability to access nodes.
public void configure(ActionsManager mngr, Tree browser)
{
// actions must be added into some category.
// so create the new one, or add action into existing category.
MDActionsCategory category = new MDActionsCategory("", "");
category.addAction(browserAction);
Example 2: add some action into main menu, after creating a new project
// create some action.
final MDAction someAction = …
{
return AMConfigurator.MEDIUM_PRIORITY;
}
}
Actions hierarchy
AbstractAction
(javax.swing)
NMAction
(com.nomagic.actions)
ActionsCategory
(com.nomagic.actions)
MDAction
(com.nomagic.magicdraw.actions)
MDActionsCategory
(com.nomagic.magicdraw.actions)
DefaultBrowserAction DefaultDiagramAction
(com.nomagic.magicdraw.ui.browser.actions) (com.nomagic.magicdraw.ui.actions)
PropertyAction
(com.nomagic.magicdraw.actions)
MagicDraw UML model is an implementation of OMG UML 2.4.1 metamodel. We do not provide very detail
description of all UML metamodel elements and their properties in this documentation or javadoc. You can find
all this information in UML 2.4.1 superstructure specification on the Object Management Group official Web site
at http://www.omg.org/spec/UML/.
The base interface of all model classes is Element, implements BaseElement inteface.
BaseElement
(com.nomagic.magicdraw.uml)
ElementImpl Element
(com.nomagic.magicdraw.uml) (com.nomagic.uml2.ext.magicdraw.classes.mdkernel)
PresentationElement
(com.nomagic.magicdraw.uml.symbols)
All structure, derived from Element you can see in OMG-UML2.3 Superstructure Specification.
All attributes described in UML specification are implemented and accessible through setters and getters.
Project
Application
(com.nomagic.magicdraw.core)
-currentProject
Project
(com.nomagic.magicdraw.core)
-model
Model
(com.nomagic.uml2.ext.magicdraw.auxiliaryconstructs.mdmodels)
Project represents main storage of all project data like: main Package (Model) and all diagrams.
Project
<<getter>>+getActiveDiagram() : DiagramPresentationElement
<<getter>>+getDiagrams() : Collection
<<getter>>+getName() : String
<<getter>>+getFileName() : String
<<getter>>+getDataTypes() : Package
<<getter>>+isRemote() : boolean
<<getter>>+isDirty() : boolean
<<getter>>+getElementByID( id : String ) : BaseElement
<<getter>>+getUsedModulesDescriptors() : List
<<getter>>+getModel() : Model
...
Project keeps references to root Model, also has references to all diagrams.
Root Model
The whole model of one project is contained in a Model instance, accessible in the following way:
Model root = Application.getInstance().getProject().getModel();
Container properties
MagicDraw uses composite structure of the model.
Every model element is a container and contains its own children and knows about its own parent.
Model element parent can be accessed with Element.getOwner() method. Owned children can be received
with method Element.getOwnedElement()
You can access these container properties by names that are described in UML specification.
Method getOwnedElement() collects all children from all inner container properties.
Property change events are fired automatically when container properties are modified.
Containers implement subsets and unions constraints from UML metamodel specification. This explains how
modification of one container can affect other containers. Make sure you understand subsets and unions in
UML metamodel.
Some containers are read-only. This is true for all DERIVED UML metamodel properties. For example Ele-
ment.getOwnedElement() is read-only. If you want to add some inner Element you need to add it into subset of
ownedElement - for example for Package.getOwnedPackageMember().
It is enough to set one UML meta-association property value and opposite property will be set too. For example,
Class adding into Package can be done in two ways:
Class myclass = …;
Package myPackage …;
myClass.setOwner(myPackage);
or
myPackage.getOwnedPackageMember().add(myClass);
}
}
NOTE: get<property name>() method call for empty container property instantiates empty collection.
This leads to increased memory usage.
So before iterating check if container property is not empty with method has <property name>().
modelElement.get<SomeContainer>().remove(child);
Visitors
Every Element has accept() method for visiting it in Visitors (for more details about this mechanism, see Visitor
pattern.)
Visitor
Visitor has visit.. method for all types of model elements and presentation elements.
This is very useful when you are working with large collection of ModelElements and need to perform actions,
specific for every type of Element (for example save/load, copy/paste, or specific properties setting).
Just derive your class from InheritanceVisitor and override some visit.. methods.
InheritanceVisitor
InheritanceVisitor is an enhanced implementation of Visitor pattern and a subclass of Visitor, used for visiting
model elements and presentation elements.
For example you can put some code into visitClassifier() and it will be executed for all subclasses of a Classi-
fier.
Model elements visit… methods has additional context parameter of type VisitorContext. Visitor context is used
to track what super type visit… methods were already visited (to avoid, multiple visits because some model ele-
ments have multiple inheritance). Open API users should not work with visitor context. All tracking is done in
InheritanceVisitor and Visitor classes.
SessionManager
SessionManager
<<getter>>+getInstance() : SessionManager
+closeSession() : void
+createSession( sessionName : String ) : void
<<getter>>+isSessionCreated() : boolean
...
All modifications to model elements should be performed between createSession(sessionName) and closeSes-
sion() method calls.
After editing model element, a session must be closed. After that all changes will be applied to the model and
registered in command history (for undo/redo) as one command with a session name.
The following code can be used for accessing, checking and creating the session:
// access singleton instance by using getInstance()
// only one session can be active, so check this.
if (!SessionManager.getInstance().isSessionCreated())
{
// create new session.
SessionManager.getInstance().createSession();
}
If other session is already created and not closed, createSession method throws IllegalStateException runtime
exception.
ModelElementsManager
ModelElementsManager
<<getter>>+getInstance() : ModelElementsManager
+addElement( element : Element, parent : Element ) : void
+moveElement( element : Element, parent : Element ) : void
+removeElement( element : Element ) : void
+createDiagram( type : String, parent : Namespace ) : Diagram
...
ModelElementsManager is the singleton utility class for adding and removing model or moving them to other
parents.
This manager can be used only if some session was created with SessionManager.
ModelElementsManager performs additional checks before modification if element is not read only. Also check
if element can be added to parent is performed. If ModelElementsManager is not used programmer must per-
form these checks in code explicitly.
All changes in UML model be registered and on session closing will be added into command history.
// creating new session
SessionManager.getInstance().createSession("Edit package A");
ElementsFactory f = Application.getInstance().getProject().getElementsFactory();
All changes in UML model will be registered and on session closing will be added into command history.
// creating new session
SessionManager.getInstance().createSession("Edit class A");
if (classA.isEditable())
{
classA.setName(newName);
}
...
It is programmer responsibility to ensure that modified model element is not read only. To check if model ele-
ment is read only use Element.isEditable() method.
This manager can be used only if some session was created with SessionManager
ElementsFactory f = Application.getInstance().getProject().getElementsFactory();
If given model element cannot be added into a given parent, IllegalArgumentException is thrown.
For example Operation cannot be added into Package or Operation cannot be added into not locked for editing
Class (in the teamwork project).
SessionManager.getInstance().createSession("Remove class");
if (classA.isEditable()))
{
classA.dispose();
}
sessionManager.closeSession();
sessionManager.closeSession();
Creating Diagram
Example how to create and add to parent element:
Project project = Application.getInstance().getProject();
Namespace parent = project.getModel();
try
{
//class diagram is created and added to parent model element
Diagram diagram = ModelElementsManager.getInstance().
createDiagram(DiagramTypeConstants.UML_CLASS_DIAGRAM, parent);
//open diagram
project.getDiagram(diagram).open();
}
catch (ReadOnlyElementException e)
{
}
For getting supplier and client elements of relationship use ModelHelper.getSupplierElement(), Model-
Helper.getClientElement() methods.
sessionManager.closeSession();
sessionManager.closeSession();
We provide a helper class StereotypesHelper for hiding this mapping complexity . It has set of useful methods
for assigning, unassigning stereotypes and creating TaggedValues. Keep in mind that TaggedValues in this
helper class are called Slots.
// create profile
Profile profile = elementsFactory.createProfileInstance();
profile.setName("myProfile");
ModelElementsManager.getInstance().addElement(profile, project.getModel());
if (StereotypesHelper.canApplyStereotype(element, stereotype))
{
// apply stereotype
StereotypesHelper.addStereotype(element, stereotype);
// set tag value
StereotypesHelper.setStereotypePropertyValue(element, stereotype,
"myTag", "myTagValue");
}
// find profile
Hyperlinks
Hyperlinks are implemented using stereotypes and tag values. Stereotype "HyperlinkOwner" and the following
its properties (tags):
• hyperlinkText - all simple hyperlinks
• hyperlinkTextActive - active simple hyperlink
• hyperlinkModel - all hyperlinks to model element
• hyperlinkModelActive - active hyperlink to model element
// get stereotype
Stereotype stereotype = StereotypesHelper.getStereotype(
Project.getProject(element), "HyperlinkOwner");
// get hyperlinked elements
List modelValues = StereotypesHelper.getStereotypePropertyValue(element,
stereotype, "hyperlinkModel");
for (int i = modelValues.size() - 1; i >= 0; --i)
{
Element linkedElement = (Element) modelValues.get(i);
}
// active hyperlink
Object activeLinkedElement = StereotypesHelper.getStereotypePropertyFirst(
element, stereotype, "hyperlinkModelActive");
{
String link = (String) textValues.get(i);
}
// active hyperlink
Object activeLink = StereotypesHelper.getStereotypePropertyFirst(element,
stereotype, "hyperlinkTextActive");
// get stereotype
Stereotype stereotype = StereotypesHelper.getStereotype(project,
"HyperlinkOwner");
// apply stereotype
StereotypesHelper.addStereotype(element, stereotype);
// add hyperlinks
StereotypesHelper.setStereotypePropertyValue(element, stereotype,
"hyperlinkModel", linkedElement, true);
StereotypesHelper.setStereotypePropertyValue(element, stereotype,
"hyperlinkModel", activeLinkedElement, true);
String activeHttpLink = "http://www.magicdraw.com";
StereotypesHelper.setStereotypePropertyValue(element, stereotype,
"hyperlinkText", "http://www.nomagic.com", true);
StereotypesHelper.setStereotypePropertyValue(element, stereotype,
"hyperlinkText", activeHttpLink, true);
Presentation Element
UML semantic defines only UML metamodel. MagicDraw application has its own structure of classes for UML
elements representation in the diagram. Base class of this structure is PresentationElement.
In the metamodel, a PresentationElement is the BaseElement that presents a set of model elements to a user.
It is the base for all metaclasses used for presentation. All other metaclasses with this purpose are indirect
subclasses of PresentationElement.
Current version of MagicDraw Open API provides just a basic structure of presentation elements.
Every presentation element can have children. For example DiagramPresentationElement has a collection of
inner presentation elements. PresentationElement of some Package can have a collection of presentation
elements for inner Package elements.
A subclass of presentation elements PathConnector provides information about connected paths to the
presentation element. To get a collection of connected paths to the presentation element, use method
PathConnector.getConnectedPathElements().
The same rules are for add, sAddPresentationElement and remove, sRemovePresentationElement
accessories. The same naming rules are used in all MagicDraw.
Shapes
Shapes are presentation elements created for such model elements as classes, packages, models,
subsystems and others.
Paths
Paths are presentation elements created for such model elements as Relationships.
PresentationElementsManager can be used only inside the created session with SessionsManager. If session
is not created, IllegalStateExceptions is thrown.
PresentationElementsManager can be used only in already loaded and active project. In other cases, results
can be unpredictable.
The diagram is not passed into createPathElement method. A new path element is created in the same
diagram as client or supplier presentation elements.
PresentationsElementsManager.getInstance().reshapeShapeElement(element,
newBounds);
SessionsManager.getInstance().closeSession();
Every shape element has a preferred size. Shape size cannot be smaller than the preferred size. If you will try
to set smaller bounds, these bounds will be increased to the preferred size.
If shape has Autosize property set to TRUE, bounds will be reduced to the preferred size.
The order of points in the list must be from the supplier to client connection point. The list may or may not
include the client and supplier connection points.
At first the given points list will be adopted for the current path style (Rectilinear, Bezier. or Oblique) and only
then applied for the path.
All related presentation elements - all children and connected paths - will be removed too.
ShapeElement element = …;
PropertyManager properties = new PropertyManager();
properties.addProperty(new BooleanProperty(PropertyID.AUTOSIZE, true));
SessionsManager.getInstance().createSession(“Test”);
PresentationsElementsManager.getInstance().setPresentationElementProperties(elemen
t, properties);
SessionsManager.getInstance().closeSession();
The properties must be new instances. You cannot do something like this:
ShapeElement element = …;
PropertyManager properties = element.getPropertyManager().
properties.getProperty(PropertyID.AUTOSIZE).setValue(new Boolean(true);
SessionsManager.getInstance().createSession(“Test”);
PresentationsElementsManager.getInstance().setPresentationElementProperties(elemen
t, properties);
SessionsManager.getInstance().closeSession();
PresentationElement view = ...; // A symbol for which you need to invoke the
displaying related symbols action.
DisplayRelatedSymbols.displayRelatedSymbols(view, info);
sessionManager.closeSession();
The custom symbol rendering API allows modifying the default symbol view. This API includes:
1. Renderer provider API, which allows to provide a custom renderer for the specific symbol.
2. Renderers, which can modify the default symbol appearance.
In this chapter, we will review, how to register the specific symbol views provider and give the example covering
the custom renderers for the package, slots, and dependency link symbols.
TIP! You can find the code examples in <MagicDraw installation direc-
tory>\openapi\examples\symbolrendering folder.
Registering Provider
To make your provider start working, you must register it into the PresentationElementRendererManager. To
add your provider into the custom providers list, use the following method:
PresentationElementRendererManager.getInstance().addProvider(new
RendererProvider());
Figure 13 -- Abstract class of the Presentation Element Renderer Class, by default extended with specific renderers for
path symbols (PathRenderer) and for shape symbols (ShapeRenderer)
The custom package renderer - the empty package (i.e., without inner elements) is filled with green
color:
The custom slot renderer (used in instance specification symbol) - the slot values are rounded:
The custom dependency link renderer - the dependency link is a blue thicker line with custom line
ends:
DependencyRenderer()
{
// custom client end renderer - use filled circle at the end
mClientEndRenderer = new PathEndRenderer(PathEndAdornment.CIRCLE,
PathEndAdornmentModifier.FILLED);
}
/**
* Custom renderers provider.
*/
class RendererProvider implements PresentationElementRendererProvider
{
private SlotRenderer mSlotRenderer;
private DependencyRenderer mDependencyRenderer;
private PackageRenderer mPackageRenderer;
RendererProvider()
{
mSlotRenderer = new SlotRenderer();
mDependencyRenderer = new DependencyRenderer();
mPackageRenderer = new PackageRenderer();
}
return null;
}
};
PresentationElementRendererManager.getInstance().addProvider(new
RendererProvider());
To listen to diagram change events, you need to create the DiagramListenerAdapter object, i.e., pass the prop-
erty change listener as a delegator, which will receive all events.
new DiagramListenerAdapter(propertyChangeListener)
To start using the adapter, install it. Uninstall it when it is no longer necessary, i.e., you do not need to receive
any events about diagram changes anymore.
adapter.install(project);
MagicDraw provides API for applying some design pattern for the selected classifier (pattern’s target). Pattern
can modify a target classifier or even the whole model. It also can create presentation elements in the target
diagram.
Target concept
Pattern’s target encapsulates information about classifier you want to apply pattern for.
Target owns:
• classifier
• classifier’s presentation element
• diagram of presentation element
Target is passed to pattern’s method AbstractPattern.applyPattern. It is also accessible from pattern’s proper-
ties AbstractPatternProperties.
Using PatternHelper
Open API provides a helper class PatternHelper with useful methods for patterns.
Abstract Pattern
Every implementation of specific pattern must provide:
• Pattern properties
• Pattern panels
• Pattern implementation
PatternInfo is used only for pattern registration in the PatternsManager. Other usages are internal and do not
impact specific patterns.
Every pattern must provide main properties and optionally can have extended properties. Main properties are
used for user input from the first pattern wizard page. Extended properties may be used for storing user input
from other wizard pages.
Specific pattern must provide implementation of this abstract class and override AbstractPatternProperties.con-
figurePropertyManager method. If specific pattern has some extended properties, it must override AbstractPat-
ternProperties .configureExtendedPropertyManager method. Both these methods must configure some
property manager – add or remove properties from it.
Every pattern must provide one or more panels for the patterns wizard. First wizard page is always used for dis-
playing main pattern properties. Other pages are optional and may be pattern specific. AbstractPanelContainer
class is used for providing the following information:
Specific pattern must provide pattern implementation class. This class must extend AbstractPattern and imple-
ment AbstractPattern.applyPattern and AbstractPattern.getCategorizedName methods.
import com.nomagic.magicdraw.plugins.impl.patterns.AbstractPatternProperties;
import com.nomagic.magicdraw.properties.StringProperty;
import com.nomagic.magicdraw.properties.PropertyManager;
/**
* Add two properties into main properties manager.
*/
protected void configurePropertyManager()
{
StringProperty p = new StringProperty(TARGET_CLASS,
getTarget().getTargetClassifier().getName());
p.setResourceProvider(MyResourceProvider.getInstance());
p.setEditable(false);
PropertyManager properties = getPropertyManager();
properties.addProperty(p);
Names of MagicDraw properties can be translated into other languages, so they are not hard coded inside the
properties. To get property name from property ID, PropertyResourceProvider is used.
/**
* Returns shared instance of this provider.
* @return shared instance.
*/
public static MyResourceProvider getInstance()
{
if(mInstance == null)
{
/**
* Returns resource for given key.
* @param key a resource key.
* @return the resource for given key.
*/
public String getString(String key)
{
if(key.equals(MyPatternProperties.METHOD_NAME))
{
return "Method Name";
}
else
if(key.equals(MyPatternProperties.TARGET_CLASS))
{
return "Target Class";
}
return null;
}
}
import com.nomagic.magicdraw.core.Application;
import com.nomagic.magicdraw.openapi.uml.ReadOnlyElementException;
import com.nomagic.magicdraw.plugins.impl.patterns.AbstractPattern;
import com.nomagic.magicdraw.plugins.impl.patterns.AbstractPatternProperties;
import com.nomagic.magicdraw.plugins.impl.patterns.PatternHelper;
import com.nomagic.magicdraw.plugins.impl.patterns.Target;
import com.nomagic.magicdraw.properties.PropertyManager;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Operation;
import com.nomagic.uml2.impl.ElementsFactory;
/**
* Applies design pattern to the target, using properties, passed as an
argument.
* @param target Target, the pattern is applied for.
* @param prop the pattern properties.
*/
public void applyPattern(Target target, AbstractPatternProperties prop) throws
ReadOnlyElementException
{
PropertyManager propManager = prop.getPropertyManager();
String methodName =
propManager.getProperty(MyPatternProperties.METHOD_NAME).getValue().toString();
ElementsFactory ef =
Application.getInstance().getProject().getElementsFactory();
Operation op = ef.createOperationInstance();
op.setName(methodName);
PatternHelper.addDistinctOperation(target.getTargetClassifier(), op);
}
}
import com.nomagic.magicdraw.plugins.Plugin;
import
com.nomagic.magicdraw.plugins.impl.patterns.impl.common.PatternPropertiesPanel;
import com.nomagic.magicdraw.plugins.impl.patterns.PatternInfo;
import com.nomagic.magicdraw.plugins.impl.patterns.PatternsManager;
"Description.html"));
}
/**
* Close this plugin always.
* @return false always
*/
public boolean close()
{
return true;
}
/**
* @see com.nomagic.magicdraw.plugins.Plugin#isSupported()
*/
public boolean isSupported()
{
return true;
}
}
class="com.nomagic.magicdraw.plugins.impl.examples.mypatterns.MyPatternPlugin">
<requires>
<api version="1.0"/>
<required-plugin id="com.nomagic.magicdraw.plugins.impl.patterns"/>
</requires>
<runtime>
<library name="mypatterns.jar"/>
</runtime>
</plugin>
Compile all classes and bundle them into mypatterns.jar file. Also add Description.html into this jar file.
Create subfolder mypatterns in the <MagicDraw install>/plugins directory and copy mypatterns.jar and
plugin.xml into it.
MagicDraw Open API provides a set of classes used as properties for diagrams’ symbols and design patterns.
Every property has two major attributes – ID and value. Property has value of type java.lang.Object. Every spe-
cific property has value of specific type. For example value of BooleanProperty is java.lang.Boolean, value of
String property is java.lang.String.
Every property has specific editor for editing value of the property. For example BooleanProperty is edited with
javax.swing.JCheckBox component, ChoiceProperty with javax.swing.JComboBox, StringProperty with
javax.swing.JTextField.
You may provide your own PropertyEditor for some specific property editing. In order to do this you need to
override Property.createEditor method.
You must set some PropertyResourceProvider to your property instance in order to display normal name, not
id of the property in the MagicDraw UI. PropertyResourceProvider has just one method PropertyResourcePro-
vider.getString(key), where key is id of your property.
The collections of properties are grouped by PropertyManagers. Every PropertyManager has name and list of
properties. It can return property by id, properties with the same value, properties whose values are different.
For more details about every specific kind of property see javadoc.
There are two groups of the diagrams in MagicDraw – creatable and not creatable. Only the diagrams of creat-
able type can be created (instantiated). Not creatable diagram serves as the base for other types of diagrams.
Communication and Sequence diagrams are subdiagrams of the Interaction diagram. Activity, Interaction,
State Machine and Protocol State Machine diagram are subdiagram of the Behavior diagram.
<<diagram>>
Behavior
{creatable=false}
<<diagram>> <<diagram>>
Sequence Communication
{creatable} {creatable}
The only way to add a new diagram type in MagicDraw is to extend one of the already existing diagram types
and register it. This mechanism is described below.
DiagramDescriptor
+getDiagramActions() : MDActionsManager
+getDiagramContextConfigurator() : DiagramContextAMConfigurator
+getDiagramShortcutsConfigurator() : AMConfigurator
+getDiagramToolbarConfigurator() : AMConfigurator
+getDiagramTypeId() : String
+getLargeIcon() : ImageIcon
+getPluralDiagramTypeHumanName() : String
+getSingularDiagramTypeHumanName() : String
+getSmallIconURL() : URL
+getSuperType() : String
+isCreatable() : boolean
Example 1: example diagram descriptor (see OpenAPI examples for the full source code)
/**
* Descriptor of specific diagram.
*/
public class SpecificDiagramDescriptor extends DiagramDescriptor
{
public static final String SPECIFIC_DIAGRAM = "Specific Diagram";
/**
* Let this diagram type be a sub type of class diagram type.
*/
public String getSuperType()
{
return DiagramType.UML_CLASS_DIAGRAM;
}
/**
* This is creatable diagram.
*/
public boolean isCreatable()
{
return true;
}
/**
* Actions used in this diagram.
*/
public MDActionsManager getDiagramActions()
{
return SpecificDiagramActions.ACTIONS;
}
/**
* Configurator for diagram toolbar.
*/
public AMConfigurator getDiagramToolbarConfigurator()
{
return new SpecificDiagramToolbarConfigurator();
}
/**
* Configurator for diagram shortcuts.
*/
public AMConfigurator getDiagramShortcutsConfigurator()
{
return new ClassDiagramShortcutsConfigurator();
}
/**
* Configurator for diagram context menu.
*/
public DiagramContextAMConfigurator getDiagramContextConfigurator()
{
return new BaseDiagramContextAMConfigurator();
}
/**
* Id of the diagram type.
*/
public String getDiagramTypeId()
{
return SPECIFIC_DIAGRAM;
}
/**
* Diagram type human name.
*/
public String getSingularDiagramTypeHumanName()
{
return "Specific Diagram";
}
/**
* Diagram type human name in plural form.
*/
public String getPluralDiagramTypeHumanName()
{
return "Specific Diagrams";
}
/**
* Large icon for diagram.
*/
public ImageIcon getLargeIcon()
{
return new ImageIconProxy(new VectorImageIconControler(getClass(),
"icons/specificdiagram.svg", VectorImageIconControler.SVG));
}
/**
* URL to small icon for diagram.
*/
public URL getSmallIconURL()
{
return getClass().getResource("icons/specificdiagram.svg");
}
}
Example 1: example diagram descriptor registration (see OpenAPI examples for the full source code)
class SpecificDiagramPlugin extends Plugin
{
/**
* Initializing the plugin.
*/
public void init()
{
// registering new diagram type
Application.getInstance().addNewDiagramType(new
SpecificDiagramDescriptor());
}
/**
* Return true always,
* because this plugin does not have any close specific actions.
*/
public boolean close()
{
return true;
}
/**
* Return true always,
* because this plugin does not
* have any specific suportability conditions.
*/
public boolean isSupported()
{
return true;
}
}
ProjectsManager
A project is the fundamental MagicDraw data structure. Project includes all UML model and diagrams.
Application
(com.nomagic.magicdraw.core)
ProjectsManager
(com.nomagic.magicdraw.core)
*
Project
(com.nomagic.magicdraw.core)
ProjectsManager
(com.nomagic.magicdraw.core)
...
+closeProject() : void
+createProject() : Project
+getActiveProject() : Project
+getProjects() : List
+isProjectActive( project : Project ) : boolean
+loadProject( descriptor : ProjectDescriptor, silent : boolean ) : void
+saveProject( descriptor : ProjectDescriptor, silent : boolean ) : void
+setActiveProject( project : Project ) : void
...
ProjectsManager provides API for Project creating, closing, saving, loading, and activating.
MagicDraw can have multiple opened projects, but only one project can be active.
//gets all projects
List projects = projectsManager.getProjects();
ProjectDescriptor
ProjectDescriptor represents a project (and module) as a resource for storing and loading.
Project management
Projects are saved and loaded by using two methods in ProjectsManager class.
• saveProject(ProjectDescriptor descriptor, boolean silent)
• loadProject(ProjectDescriptor descriptor, boolean silent)
NOTES “Save” and “Load” means “Commit” and “Update” for the Teamwork Project.
A project cannot be saved using descriptor, if project isn’t specified and a project cannot be
loaded, if file isn’t specified. In such cases IllegalStateException is thrown.
Silent mode means that during save or load process no GUI interruptions for user input will be used, e.g. no
Commit Project dialog box while committing a teamwork project or no Save dialog box while saving a new
project (project will be saved into the last used directory).
ProjectDescriptor projectDescriptor =
ProjectDescriptorsFactory.getDescriptorForProject(project);
// save project
projectsManager.saveProject(projectDescriptor, true);
.getRemoteProjectDescriptorByQualifiedName(remoteProjectQualifiedName);
if (projectDescriptor != null)
{
projectsManager.loadProject(projectDescriptor, true);
}
Module management
ProjectsManager also provides module management (module usage, export, import, reload, and package shar-
ing) methods.
Local and teamwork module usage does not differs. Just appropriate project descriptor must be used:
ProjectsManager projectsManager = Application.getInstance().getProjectsManager();
File file = new File(moduleFilePath);
ProjectDescriptor projectDescriptor =
ProjectDescriptorsFactory.createProjectDescriptor(file.toURI());
// use module
projectsManager.useModule(project, projectDescriptor);
Local and teamwork module import does not differs. Just appropriate project descriptor must be used:
ProjectsManager projectsManager = Application.getInstance().getProjectsManager();
File file = new File(moduleFilePath);
ProjectDescriptor projectDescriptor =
ProjectDescriptorsFactory.createProjectDescriptor(file.toURI());
projectsManager.importModule(project, projectDescriptor);
Local and teamwork module reload does not differs. Just appropriate project descriptor must be used:
ProjectsManager projectsManager =
Application.getInstance().getProjectsManager();
File file = new File(moduleFilePath);
ProjectDescriptor projectDescriptor =
ProjectDescriptorsFactory.createProjectDescriptor(file.toURI());
projectsManager.reloadModule(project, projectDescriptor);
ProjectsManager projectsManager =
Application.getInstance().getProjectsManager();
SessionManager.getInstance().createSession("Create shared package");
// share package
projectsManager.sharePackage(project, Arrays.asList(aPackage), "my
module");
// save project
ProjectDescriptor projectDescriptor =
ProjectDescriptorsFactory.getDescriptorForProject(project);
projectsManager.saveProject(projectDescriptor, true);
There are API for standard and advanced project merging. Standard API encapsulates all three steps into a sin-
gle call, while advanced merge API allows for accessing the project differences and controlling what changes
are accepted or rejected.
See the sample API usage code in the <MagicDraw install>\openapi\examples\merge folder.
MagicDraw UML provides the API for adding the custom project options. These options are project related and
saved together with project data. In this chapter, we will describe how to add a new property and how to
retrieve its value.
The following example shows, how to add the above mentioned project option’s configurator at the plug-in’s
init() method in order to have the additional project option ”Test Property” for every project.
ProjectOptions.addConfigurator(new ProjectOptionsConfigurator()
{
public void configure(ProjectOptions projectOptions)
{
com.nomagic.magicdraw.properties.Property property =
projectOptions.getProperty(ProjectOptions.PROJECT_GENERAL_PROPERTIES,
"TEST_PROPERTY_ID");
if (property == null)
{
// create property, if does not exist
property = new StringProperty("TEST_PROPERTY_ID", "description");
// group
property.setGroup("MY_GROUP");
// custom resource provider
property.setResourceProvider(new PropertyResourceProvider()
{
public String getString(String string, Property property)
{
if ("TEST_PROPERTY_ID".equals(string))
{
// translate ID
return "Test Property";
}
if ("TEST_PROPERTY_ID_DESCRIPTION".equals(string))
{
// translate description
return "Test Property in My Group";
}
if ("MY_GROUP".equals(string))
{
// translate group
return "My Group";
}
return string;
}
});
// add property
projectOptions.addProperty(ProjectOptions.PROJECT_GENERAL_PROPERTIES, property);
}
}
});
MagicDraw UML provides the API for listening to the events, while changing a model. There is a possibility
either to get an event immediately after the property has been changed, or get the event about all the changes
in the transaction, after this transaction has been executed.
The transaction listener is notified, when all the changes within the transaction are done and the transaction is
closed.
TIP! You can find the code examples in <MagicDraw installation direc-
tory>\\openapi\examples\events.
In order to understand, which property has been changed and how it was done, let’s review a short explanation
of the PropertyChangeEvent.
The events’ names related with model creation/ deletion are listed in the
com.nomagic.uml2.ext.jmi.UML2MetamodelConstants class.
project.getRepositoryListenerRegistry().addPropertyChangeListener(listener,
(RefObject)null);
This listener will get all the property change events from any element.
To listen for any delete operation in the repository and get notified before the delete action is performed, use:
project.getRepositoryListenerRegistry().addPropertyChangeListener(listener,
UML2MetamodelConstants.BEFORE_DELETE);
This listener will be notified, when any model element is set to be deleted.
element.addPropertyChangeListener(listener);
To listen for any property changes of the specific element type, use:
This listener will be notified, when any property of any element in the project with this type is changed. If “con-
figs” is NULL, the listener will get all property change events.
The SmartListenerConfig class provides static methods for default configuration of property chains. This is
useful, when listening for common property change events.
The listener contains transactionCommited() method, which provides a collection of all Property-
ChangeEvents that were executed in a transaction.
element.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
// evt.getPropertyName() is Changed
}
});
Listener for listening to the specific property (NAME) of the specific element:
element.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
if (PropertyNames.NAME.equals(evt.getPropertyName()))
{
// name is Changed
}
}
});
Listener for listening the specific property (NAME) of the specific element type (Classifier):
// create smartListenerConfig for Name property
SmartListenerConfig cfg = new SmartListenerConfig(PropertyNames.NAME);
List<SmartListenerConfig> configs = Collections.singletonList(cfg);
TransactionCommitListener
This example shows, how to create a transaction commit listener:
Classifier propertyOwner =
(Classifier) owner;
propertyOwner
.setName("Contains ("
+ propertyOwner.getAttribute().size() + ") attributes");
}
}
}
}
}
};
}
}
This “transaction commit listener” checks, if new property is created in classifier and updates classifier’s (prop-
erty owner) name. All changes are done in the same session.
transactionManager.addTransactionCommitListener(transactionListener);
Selection in diagrams
Every PresentationElement can access selected elements or change their own selection status.
PresentationElement
+getSelected() : List
+isSelected() : boolean
+setAllSelected( select : boolean ) : void
+setSelected( select : boolean ) : void
+setSelected( elements : List ) : void
...
Selection events
//now selected
List news = (List)evt.getNewValue();
//do something
}
}
});
Browser
+getActiveTree() : BrowserTabTree
+getContainmentTree() : ContainmentTree
+getDiagramsTree() : DiagramsTree
+getExtensionsTree() : ExtensionsTree
+getInheritanceTree() : InheritanceTree
+getSearchResultsTree() : SearchResultsTree
...
Every tree is based on Swing JTree and all manipulations can be done by using API provided by Swing:
JTree tree = activeTree.getTree();
To create image from the whole diagram, use method export(DiagramPresentationElement, int, File).
To create image from selected symbols in the diagram, use method export(DiagramPresentationElement, int,
File, boolean).
return result;
}
In calculateMetricValue you should put the code that will calculate the local value for your metric. In the exam-
ple it is calculating the number of stereotypes of the elements. This value can be used while calculating other
modes than Local mode.
While implementing acceptModelElement(BaseElement element) method, you have to check the type of ele-
ments you want your metrics to be calculated for. However you should restrict it to types of elements that can
be shown in metrics results windows. Elements that can be displayed are Class, Interfaces, Diagrams, Pack-
ages, or Model packages.
You may check if the element is eligible to be show, using the method acceptElement(BaseElement ele-
ment) from MetricsManager class.
MetricsManager class also has a acceptDiagramElement (BaseElement element) that verifies if the given
element is a diagram element.
Metric class:
Constructor
The next example will create a metric with the given data about the metrics and put it into the Other group.
public MyMetric()
{
super("My Metric", "MM", MetricType.OTHER, "MY_METRIC",
MetricValue.INTEGER_VALUE);
setDescription("This is my metric.");
}
You have also to provide a constructor for your metrics that must call the following super constructor:
public Metric(String name, String abbreviation, MetricType type, String id, int
metricValueType)
You will have to provide unique name, abbreviation, and ID for your metric.
The value return type can be integer or real, the constants are on MetricValue class.
There are already some predefined types in MetricType class that can be used.
MetricType class:
MetricType
+BASIC_TYPE : MetricType
+MODEL_SIZE : MetricType
+RELATIONSHIPS : MetricType
+DIAGRAMS : MetricType
+CLASS_EMPLOYMENT : MetricType
+INHERITANCE : MetricType
+COHESION : MetricType
+COMPLEXITY : MetricType
+MOOD : MetricType
+OTHER : MetricType
+REQUIREMENTS : MetricType
...
+MetricType( type : String, description : String )
+getDescription() : String
+setDescription( description : String ) : void
+getType() : String
+setType( type : String ) : void
...
In your plugin class you must use then the MetricsManager addMetric(Metric metric) method to add the new
metric to MagicDraw. Now your metric will be available for using as any predefined metric.
MetricsManager
<<getter>>+getInstance() : MetricsManager
+acceptElement( element : BaseElement ) : boolean
+acceptDiagramElement( element : BaseElement ) : boolean
+removeMetricsSuite( metricsSuite : MetricsSuite ) : void
+removeMetric( metric : Metric ) : void
+removeMetric( id : String ) : void
+addMetricsSuite( metricsSuite : MetricsSuite ) : void
+addMetric( metric : Metric ) : void
+addMetrics( metrics : Collection ) : void
<<getter>>+getMetricsSuite( name : String ) : MetricsSuite
<<getter>>+getMetricsSuiteByID( id : String ) : MetricsSuite
+contains( metricsSuiteID : String ) : boolean
...
<requires>
<api version="1.0"/>
<required-plugin id="com.nomagic.magicdraw.metrics"/>
</requires>
<runtime>
<library name="mymetrics.jar"/>
</runtime>
</plugin>
MyMetricsPlugin class
public class MyMetricsPlugin extends Plugin
{
public void init()
{
MyMetric myMetric = new MyMetric();
MetricsManager.getInstance().addMetric(myMetric);
}
MyMetric class
public class MyMetric extends Metric
{
public MyMetric()
{
super("My Metric", "MM", MetricType.OTHER, "MY_METRIC",
MetricValue.INTEGER_VALUE);
setDescription("This is my metric. This metric will calculate the number of
stereotypes for classes.");
}
return result;
Metric
<<constructor>>+Metric( name : String, abbreviation : String, type : MetricType, id : String, metricValueType : int )
+calculate( target : BaseElement, calculator : MetricsCalculator ) : MetricResult
#calculateLocalMetricValue( target : BaseElement ) : MetricResult MetricType
+acceptModelElement( element : BaseElement ) : boolean +BASIC_TYPE : MetricType
+round( number : float ) : int +MODEL_SIZE : MetricType
+addProperty( property ) : void +RELATIONSHIPS : MetricType
+addProperties( properties : Collection ) : void +DIAGRAMS : MetricType
+removeProperties( properties : Collection ) : void +CLASS_EMPLOYMENT : MetricType
+removeProperty( property ) : void +INHERITANCE : MetricType
<<getter>>+getMetricsProperties() : MetricsProperties +COHESION : MetricType
<<setter>>+setMetricsProperties( metricProperties : MetricsProperties ) : void +COMPLEXITY : MetricType
<<getter>>+getAbbreviation() : String
-mType +MOOD : MetricType
<<setter>>+setAbbreviation( abbreviation : String ) : void +OTHER : MetricType
<<getter>>+getDescription() : String +REQUIREMENTS : MetricType
<<setter>>+setDescription( description : String ) : void ...
<<getter>>+getName() : String
<<setter>>+setName( name : String ) : void <<constructor>>+MetricType( type : String, description : String )
<<getter>>+getType() : MetricType <<getter>>+getDescription() : String
<<getter>>-getPropertyIntegerValue( property : String ) : int <<setter>>+setDescription( description : String ) : void
<<getter>>-getPropertyFloatValue( property : String ) : float <<getter>>+getType() : String
<<getter>>+isPackage( element : BaseElement ) : boolean <<setter>>+setType( type : String ) : void
...
<<getter>>+getID() : String
<<setter>>+setID( id : String ) : void
<<getter>>-getPackageForElement( element : BaseElement ) : BaseElement
<<getter>>+getMetricValueType() : int
<<setter>>+setMetricValueType( metricValueType : int ) : void
...
MetricResult
<<constructor>>+MetricResult( value : MetricValue )
+addValue( value : MetricValue ) : void
<<getter>>+getValue() : MetricValue
<<setter>>+setValue( value : MetricValue ) : void
<<setter>>+setValue( value : int ) : void MetricValue
<<setter>>+setValue( value : float ) : void -mValue
+@INTEGER_VALUE : int{frozen}
<<setter>>+setMinValue( value : MetricValue, value2 : MetricValue ) : void +@REAL_VALUE : int{frozen}
<<setter>>+setMaxValue( value : MetricValue, value2 : MetricValue ) : void
<<getter>>+isDifferentFromZero() : boolean
<<getter>>+getValueAsFloat() : float
<<getter>>+getValueAsInteger() : int
+hasValidResult() : boolean
+create( value : float ) : MetricValue
+create( value : int ) : MetricValue
<<setter>>+setCalculatedElements( calculatedElements : int ) : void
<<getter>>+getCalculatedElements() : int
...
Adding Configuration
Open API provides a way to configure Elements' specification windows. With your own configurator you can
create new Nodes or remove already existing Nodes. Nodes are items of Tree visible on the left side in every
Specification window.
MagicDraw API provides a way to add your own custom diagram painters for painting some additional stuff on
the diagram canvas. A good sample would be some highlighting in the diagram.
NOTE! Painter can be added only into opened diagram's DiagramSurface. BTW, only opened diagram
has DiagramSurface. Closed diagram will return null.
Code sniplet:
Application.getInstance().addProjectEventListener(new
ProjectEventListenerAdapter()
{
public void projectOpened(Project project)
{
project.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
if(evt.getPropertyName().equals(Project.DIAGRAM_OPENED))
{
DiagramPresentationElement diagram =
Application.getInstance().getProject().getActiveDiagram();
diagram.getDiagramSurface().addPainter(new
DiagramSurfacePainter()
{
public void paint(Graphics g,
DiagramPresentationElement diagram)
{
g.setColor(Color.BLUE);
List symbols = diagram.getPresentationElements();
for (int i = 0; i < symbols.size(); i++)
{
PresentationElement o = (PresentationElement)
symbols.get(i);
if( o instanceof ShapeElement)
{
Rectangle bounds = o.getBounds();
bounds.grow(5,5);
((Graphics2D)g).draw(bounds);
}
}
}
});
}
}
});
}
});
Full running sample is provided in Open API examples with name CustomDiagramPainter.
Using MagicDraw API you can add an annotation to any base element (model element or symbol in a dia-
gram).
TIP! Find the sample plugin named “annotations” in MagicDraw Open API
examples directory.
Basic concepts
Validation rules and validation suites specify what will be validating and how. They also specify how problem
found by validation rule can be solved.
Annotation defines validation result. It contains information about what is incorrect, severity of the problem,
and possible actions that can be used to solve the problem.
OCL2.0 validation rule can be used in an active validation suite. In this case validation rule will be executed on
any change of constrained elements that are from the validation scope. Executing of the validation rule might
be triggered even if no properties important to the validation rule actually changed and this can slow down
active validating speed. In order to avoid degradation of performance you can create a binary validation rule
that uses OCL2.0 expression to validate model elements but also provides additional information for the
MagicDraw that allows to optimize triggering of executing after model elements change. E.g. we want to check
whether all classes have names. This can be done by creating OCL2.0 validation rule and specifying OLC2.0
expression:
name <> ‘’
The problem is that such a validation rule actually is interested in a class property name value change but it will
be executed on every property value of a class change. How we can fix this problem and inform MagicDraw to
execute the validation rule only on class property name change:
1. Create a constraint.
2. Set stereotype «UML Standard Profile::Validation Profile::validationRule» for the validation rule.
3. Set severity level, error message, and abbreviation.
4. Specify constrained element(s).
5. Specify specification language OCL2.0
6. Enter OCL2.0 expression as a body of specification
7. Create a Java class that extends com.nomagic.magicdraw.validation.DefaultValidation-
RuleImpl class
8. Override method public Map<Class<? extends Element>, Collection<SmartListenerConfig>>
getListenerConfigurations()
public Map<Class<? extends Element>, Collection<SmartListenerConfig>>
getListenerConfigurations()
{
Map<Class<? extends Element>, Collection<SmartListenerConfig>> configs =
new HashMap<Class<? extends Element>,
Collection<SmartListenerConfig>>();
Collection<SmartListenerConfig> configsForClass = new
ArrayList<SmartListenerConfig>();
configsForClass.add(SmartListenerConfig.NAME_CONFIG);
configs.put(com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Class.class,
configsForClass);
return configs;
}
9. Specify the validation rule’s implementation property value - qualified name of the class
10. Add/import the created validation rule to a validation suite
1. Create a constraint
2. Set stereotype «UML Standard Profile::Validation Profile::validationRule» for the validation rule
3. Set severity level, error message, and abbreviation.
4. Specify constrained element(s)
5. Specify specification language binary
6. Create Java implementation class (see all possible cases below)
7. Compile Java code, resulting in one or several classes.
8. Ensure that MagicDraw can find & load these classes. You can place them in the MagicDraw
classpath or use the MagicDraw plugins mechanism. The same rules as writing the code for
open API are used here.
These steps are common to all possible binary validation cases and will not be repeated in each case
description.
This case is not recommended for validating model elements because validation rule provider must implement
not only validating of model elements but also other details that are provided by MagicDraw validation engine.
In this case, validation rule provider must correctly implement validating of model elements that are from
validation scope defined in project options, should take care that implementation would respect project property
Exclude element from read-only modules and is responsible for implementing when validation has to be
executed.
Validation rule that is interested in model class and interface names changes example
configMap.put(com.nomagic.uml2.ext.magicdraw.classes.mdinterfaces.Interface.class,
configs);
return configMap;-
}
NOTE In the Constraint Specification dialog box, the Constrained Element property should be Class
and Interface from the UML Standard Profile.
Validation rule that is interested in Activity parameters and Activity parameter node changes example:
parameterConfig.listenToNested(PropertyNames.OWNED_PARAMETER).listenTo(parameterPr
opertiesList);
SmartListenerConfig cfg = new SmartListenerConfig();
Collection<String> argumentCftList = new ArrayList<String>();
argumentCftList.add(PropertyNames.PARAMETER);
argumentCftList.add(PropertyNames.TYPE);
argumentCftList.add(PropertyNames.OWNED_TYPE);
cfg.listenTo(argumentCftList);
SmartListenerConfig argumentConfig = new SmartListenerConfig();
argumentConfig.listenTo(PropertyNames.NODE, cfg);
configs.add(parameterConfig);
configs.add(argumentConfig);
configMap.put(Activity.class, configs);
return configMap;
}
The referred java method must be a static method and it must take exactly one parameter. Several validating
methods can be placed into one Java class or use one class per validating method – this is irrelevant.
The type of the parameter MUST match the type of the constrained element of the validation rule. For validation
rules on metaclasses, use the appropriate class from the com.nomagic.uml2.ext.magicdraw.* package.
For the validation rules on stereotypes, use the same class as you would use when specifying the validation
rule for metaclass of that stereotype. For validation rules on the classifiers of the model, use the
com.nomagic.uml2.ext.magicdraw.classes.mdkernel.InstanceSpecification as the type of
the parameter.
The following is an example of a trivial validation rule, which always returns true (i.e. all elements are valid):
Java code:
package com.nomagic.magicdraw.validation;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.DataType;
{
public static Boolean testMeta(DataType exp)
{
return Boolean.TRUE;
}
}
Compile such code into Java bytecode and locate it where MagicDraw can load it (classpath, plugin), and then
you can use it for validation:
1. Create the validation rule in our model.
2. Select DataType metaclass as the constrained element of the rule.
3. Select Binary language for the expression of the rule.
4. Specify com.nomagic.magicdraw.validation.TestRule.testMeta as the body of the
expression of the rule.
Run the validation suite with included validation rule. The method will be invoked for each datatype model
element, found in the scope of the validation run. For each element, where this method returns false, an entry
will be placed in the validation results table.
For more information about writing Java code, which navigates through the model and accesses various data
from the model, see other sections of current user guide.
EvaluationConfigurator.getInstance().registerBinaryImplementers(<PluginClassName>.
class.getClassLoader());
Code sniplet:
// check logged user
if (!user.equals(TeamworkUtils.getLoggedUserName()))
{
// login to teamwork
if (!TeamworkUtils.login(server, -1, user, password))
{
// login failed
return;
}
}
projectsManager.loadProject(projectDescriptor, true);
Project project = Application.getInstance().getProject();
Since MagicDraw 16.0 you can perform Code Engineering using OpenAPI.
Code engineering allows generation of source code from specific model, and source code reversing into model
elements. MagicDraw provides API for:
• Code engineering sets creation for particular programming languages.
• Automatic component creation for every class involved in forward engineering and every file
involved into reverse engineering.
• Specification of working or output, or temporary directories for processing source code files.
Destination of the code reverse operation output can be any model package.
In this chapter we will review how to manage code engineering and how to do reverse and forward engineer-
ing.
Forward Engineering
To perform code generation, elements should be added to the CodeEngineeringSet object. Use the following
method to add a list of model elements to the code engineering set:
• addElementsToCodeEngineeringSet(List<BaseElement> modelElements)
Reverse Engineering
Source code files are required to perform the Reverse Engineering. There are 2 methods available for adding
files into code engineering set:
1. addFilesToCodeEngineeringSet(List<File> file);
This method adds given list of files to code engineering set.
2. addAllFilesRecursivelyToCES(String path);
This method adds all specific source code files to code engineering set, starting from given
directory.
NOTE Source code files should be in working directory, in order to have suc-
cessful reverse.
When creating the code engineering set, the following fields are required:
• Language and dialect IDs. All languages and dialects IDs are stored in the
CodeEngineeringConstants class.
• Name of the code engineering set.
• Project, where code engineering set will be added.
• Working package.
• Working directory.
CodeEngineeringManager.getJavaClasspath( project )
CodeEngineeringManager.setResolveCollectionGenerics(project,true)
Here null dialect is used for java language, because java doesn't have any dialect.
This sets given instance of code engineering set working directory and adds all files from that directory.
MagicDraw Oracle DDL script generation is based on the Velocity engine. It provides ability to change gener-
ated DDL script by changing velocity template. In this chapter we will introduce how Oracle DDL generation
works in MagicDraw, how to change template for some specific things.
Knowledge of the Velocity Template Language is necessary for understanding, editing, or creating templates.
This example shows velocity macro for Oracle VIEW object generation:
#macro ( generateView $data )
#set ( $QUERY_RESTICTION = "query restriction")
#set ( $force = false)
#set ( $force = $oracleHelper.getBooleanValueFromDefaultProfile(
$data,$VIEW_STEREOTYPE, $FORCE_TAG ) )
Model element with stereotype “view” is passed to macro function, and then all element information is retrieved
by $oracleHelper utility class. Oracle View stereotype has 3 properties. These tagged values store information
about force, query restriction and query statements.
Customizing template
To change generation of the particular Oracle Object, add new functionality to its macro in velocity template.
Helper utility class will assist in retrieving model information. Read the next chapter to get familiar with available
methods.
We suggest to make a back up of default template. Default template is stored in <MagicDraw install folder>\
data\DB_engineering\Oracle_template folder. The template file can be changed in the CG Properties Editor dialog
box (in the Oracle DDL set shortcut menu, choose the Properties command).
When generating DDL, objects are passed from code engineering set to velocity engine.
Utility class
This utility class helps to retrieve information from MagicDraw model elements.
• $oracleHelper.getBooleanValueFromDefaultProfile($element,
$stereotypeName, $propertyName)
Given an Element, Stereotype name and Tag name, returns tag value as Boolean from Oracle
profile.
• $oracleHelper.getPropertiesListFromDefaultProfile($element,
$stereotypeName, $propertyName)
Returns list of given property values, that exists on given element with applied stereotype from
Oracle profile.
• $oracleHelper.getFirstPropertyValueFromProfile($element,
$stereotypeName, $propertyName)
Returns First given Tag property value from given element, which has applied given stereotype.
• $oracleHelper.getDefaultValueAsBoolean($property)
Given an property, returns default value as boolean.
• $oracleHelper.getFirtPropertyValueFromGivenProfile($element,
$profileName, $stereotypeName, $propertyName)
Returns first given tag property value from given element, which has applied given stereotype
from profile.
• $oracleHelper.getPropertiesListFromProfile($element, $profileName,
$stereotypeName, $propertyName)
Returns list of given property values, that exists on given element with applied stereotype from
given profile.
• $oracleHelper.getStringValue($object)
Given an value from Tag, returns String representation.
• $oracleHelper.isDataType($element)
Returns true if element is data type.
• $oracleHelper.getType($type, $modifier)
Given a type and modifier, returns it's description.
• $oracleHelper.getTypeModifier($element)
Returns Type modifier for given element.
• $oracleHelper.getParameters($operation)
• $oracleHelper.getColumnConstraint($column)
Return given property Constraint.
• $oracleHelper.getCreate($element)
Returns CREATE statement for given element.
• $oracleHelper.getReturnParameter($operation, $createIfNeeded)
Returns Return type parameter of given Operation.
• $oracleHelper.getIndexNameDefinition($index)
Returns Name of given Index.
• $oracleHelper.getTableConstraintDefinition($dependency)
Given a dependency, returns table constraint definition.
• $oracleHelper.isObjectPackage($element)
Checks if given element is a Package.
• $oracleHelper.isPackageDatabase($package)
Returns true if given package is Database.
• $oracleHelper.isPublic($element)
Returns true if given element has public visibility.
• $oracleHelper.reverseList($list)
Reverses give list.
• $oracleHelper.getRefName($element)
Returns reference name description for element with "Ref:Element" tag.
Example
In this sample we will extend current Oracle View DROP statement. In the Default template we have Oracle
view drop function. In this sample the simple macro is presented and it generates the following text:
DROP VIEW view_name;
We will add a new tag to identify the "CASCADE CONSTRAINTS" clause in the DROP VIEW statement. The
following script will be generated:
DROP VIEW view_name CASCADE CONSTRAINTS;
We need to create a new stereotype with the Boolean property, or extend the default “View” Stereotype with a
new property. Name a new property "cascade_clause". Apply the stereotype to the View object and set value to
“true”.
This line retrieves boolean value from the given tag in given stereotype "$view_stereotype" and sets it to a
newly created $cascadeOption value.
Then add a new checking clause into the drop statement. See the final method bellow:
#macro (dropView $data )
## sets value to new variable
#set($cascadeOption =
$oracleHelper.getBooleanValueFromDefaultProfile($data,$VIEW_STEREOTYPE,
"cascade_clause") )
#writeLine( "DROP VIEW $utils.getQualifiedName( $data )#if ($cascadeOption) CASCADE
CONSTRAINTS#end${semicolon}" $nospace)
#end
MagicDraw plug-ins allows adding some custom action into MagicDraw actions sets. This approach works fine
providing custom actions for user in UI, but does not solve custom task executing in the batch mode. For exam-
ple, if you want to run MagicDraw, open some project, execute code generation and close MagicDraw, plug-ins
will not work.
NOTE! MagicDraw application can not be run on headless device even in batch mode. Graphical
environment is required.
MagicDraw provides API for running it in the batch mode. For this you need to extend the following class:
com.nomagic.magicdraw.commandline.CommandLine
Code sniplet:
public class ExportDiagramImages extends CommandLine
{
public static void main(String[] args)
{
// launch MagicDraw
new ExportDiagramImages().launch(args);
}
protected void run()
{
File projectFile = ...;
//open some project
ProjectDescriptor projectDescriptor =
ProjectDescriptorsFactory.createProjectDescriptor(projectFile.toURI());
Application.getInstance().getProjectsManager().loadProject(projectDescriptor
, true);
// project is opened and now you can work with your project
}
}
Full working sample is provided in Open API examples with name ImageGenerator. It takes a project file, desti-
nation directory as arguments and generates images for all diagrams.
NOTE! Do not forget to add all *.jar files recursively (except md_commontw.jar and
md_commontw_api.jar) from <MagicDraw installation directory>/lib directory into the classpath.
Make sure the patch.jar is the first in the classpath.
MagicDraw provides a JUnit (www.junit.org) based test framework which can be used for the MagicDraw JUnit
tests development. The main purpose of the MagicDraw test framework is to simplify the automatic unit and
integration tests development for the MagicDraw program and its plug-ins. The MagicDraw test framework can
be used by developers for testing their own MagicDraw plug-ins or for testing standard essential MagicDraw
features.
The MagicDraw test framework consists of an abstract JUnit test case implementation and a number of tools
which might be used for the following purposes:
• Starting the MagicDraw program.
• Managing MagicDraw projects
• Checking MagicDraw program for memory leaks.
MagicDrawTestCase provides default and specific constructors for creating a test case instance with a specific
custom name for the specific test case method. Test cases with specific names might be helpful when several
instances of the same test case are created and analyzed.
The MagicDraw test case initialization and tear down should be implemented in overridden
MagicDrawTestCase setUpTest() and tearDownTest() methods. The standard JUnit method suite() might be
used for preparing the tests suite with several instances of test cases which may use different test data.
import com.nomagic.magicdraw.tests.MagicDrawTestCase;
public class MyTest extends MagicDrawTestCase
{
public MyTest(String testMethodToRun, String testName)
{
super(testMethodToRun, testName);
}
@Override
protected void setUpTest() throws Exception
{
super.setUpTest();
//do setup here
}
@Override
protected void tearDownTest() throws Exception
{
super.tearDownTest();
//do tear down here
}
MagicDrawTestCase also provides methods for opening, saving, and closing MagicDraw projects. It also
performs the memory leak test after the test case has been completed and after the MagicDraw project has
been closed. The memory leak test for the whole test case can be disabled using the setMemoryTestReady()
method, while the setSkipMemoryTest() method can be used to disable the memory leaks test on closing the
MagicDraw project.
The list of required MagicDraw plug-ins for the test case can be configured by overriding the
getRequiredPlugins() method of MagicDrawTestCase. The overridden method implementation should return
the list of required plug-ins IDs. Textual information about required MagicDraw plug-ins and their loading status
can be obtained using getRequiredPluginsDescription() and isRequiredPluginsLoaded() methods.
Textual information about the test process can be logged using the Log4j logger. The test case logger for the
TEST category can be accessed using the getLog() method of MagicDrawTestCase. More information about
the Log4j logger configuration and usage can be found at http://logging.apache.org/log4j/1.2/manual.html.
MagicDrawTestCase class. MagicDraw projects can be compared by checking their model elements and
element symbols in diagrams for equality.
The model elements comparison can be configured using the ModelComparator interface. Developers may
exclude some model elements from the comparison by providing the custom ModelComparatorFilter interface
implementation. Please note that the default implementation of ProjectComparator does not compare the
diagram information table, root model comment, and elements from modules.
The default implementation of DiagramComparator compares diagrams for changes by analyzing a location
and size of the symbols presented in diagrams. The graphical differences of compared diagrams can be saved
in the graphical PNG file using the saveDiffToImageFiles() method of the DiagramComparator interface.
Developers may create their own comparators for the custom diagrams and model elements comparison by
implementing ModelComparator and DiagramComparator interfaces. The custom Model and Diagram
comparators implementation can be set to ProjectComparator using appropriate setter methods.
MagicDraw test cases may produce some resources as a test output. The output directory for a specific test
case can be created using TestEnvironment.getOutputDir(class). The class here specifies a class of the test
case which output directory should be accessed. There are also methods for working with output files. An
output file for a specific MagicDraw project can be simply created by changing the project file extension
(TestEnvironment.getFileWithExtension) or adding a special prefix to its name
(TestEnvironment.createFileNameWithPrefix()).
In order to start MagicDraw correctly, all MagicDraw libraries from <MagicDraw installation directory>\lib should
be added recursively to the test case running class path. The MagicDraw test case starts the MagicDraw
program which requires the higher heap size configuration. The Max heap size should be no less than 400MB
and the maximum size for the permanent generation heap should be no less than 128MB. These properties
can be configured by providing arguments to Java Virtual Machine (JVM) as follows:
-Xmx800M -XX:MaxPermSize=135m
The MagicDraw installation directory should be also specified using the install.root system property which can
be passed to JVM as a runtime argument as following:
-Dinstall.root=path_to_MagicDraw_installation_directory
If MagicDraw installation is set up to use the floating license, the following server properties should be passed
to JVM as runtime arguments:
-DFL_SERVER_ADDRESS=flexnet_license_server_address
-DFL_SERVER_PORT=license_server_port
-DFL_EDITION=magicdraw_edition
Test cases may use external resources such as configuration files and MagicDraw projects during tests. It is
recommended to keep external test resources apart from test case implementation class files. The MagicDraw
test framework provides methods for retrieving test resources from the one specific resource directory. The
resource directory for test cases can be configured by specifying the tests.resources system property of JVM.
The tests resource property can be passed to JVM as a runtime argument as follows:
-Dtests.resources=path_to_resources_directory
The Log4j logger using in MagicDraw test cases can be configured by specifying the test.properties file which
should be placed in <MagicDraw Installation directory>\data. The following sample presents the content of the
test.properties file. It configures the logger to print INFO category messages to a console with a specific
pattern.
log4j.appender.SO=org.apache.log4j.ConsoleAppender
log4j.appender.SO.layout=org.apache.log4j.PatternLayout
log4j.appender.SO.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
log4j.rootCategory=INFO,SO
log4j.category.PLUGINS=INFO
log4j.category.GENERAL=INFO
log4j.category.MULTIUSER=INFO