Stdlib

Introduction
Stdlib extensions
Stdlib workflow components

Introduction

openArchitectureWare delivers a set of small useful utility extensions and components in the org.openarchitectureware.util.stdlib package. A dependency to this plugin is already added and reexported by the org.openarchitectureware.dependencies plugin, so you don't need to add an explicit dependency to stdlib.

Stdlib extensions

This section describes the components and extensions provided by Stdlib. We use the shortcut "oaw.util.stdlib..." for component classes in package "org.openarchitectureware.util.stdlib" in workflow configurations for convenience.

Note that many functions of the Stdlib make use of static variables in their Java implementation, thus the values are kept through a complete oAW workflow. Also, because of the static implementation, the features are not threadsafe.

IO extensions

This is an extremely useful library to print information to the logging facility. It is really valuable through transformation processes or for complex expressions to know what exactly expressions are evaluated to.

Extension functions

Extension: org::openarchitectureware::util::stdlib::io

debug (Object o)

Logs an object with DEBUG level to the logger.

Parameters:

  • o - The object to dump.

Returns: The object o

info (Object o)

Logs an object with INFO level to the logger.

Parameters:

  • o - The object to dump.

Returns: The object o

error (Object o)

Logs an object with ERROR level to the logger.

Parameters:

  • o - The object to dump.

Returns: The object o

syserr (Object o)

Prints an object to System.err.

Parameters:

  • o - The object that should be printed. null is allowed.

Returns: The object o

syserr (Object o, String prefix)

Prints an Object to stderr with a prefix string.

Parameters:

  • o - The object that should be printed. null is allowed.

Returns: The object o

throwError (Object o)

Throws an IllegalStateMessage.

Parameters:

  • o - The exception message.

Returns: Nothing, since an exception is thrown.

Examples

import data;
extension org::openarchitectureware::util::stdlib::io;

create DataModel this duplicate(DataModel s):
  entity.addAll( s.entity.duplicate() ) ->
  setName(s.name);
  
create Entity this duplicate(Entity old):
  (old.name+" has "+old.reference.size+" references").info() ->
  old.reference.name.info() ->

This leads to the following output on the console:

922  INFO  - Person has 1 references
923  INFO  - [autos]
926  INFO  - Vehicle has 0 references
926  INFO  - []

Of course IO extension functions can also be used within Xpand, but if used for logging purposes you have to deal with one side effect: Since the functions return the passed object (the result of an expression, in the simplest case just a string) and Xpand prints out expression results to the opened file, the message will be shown on the console, but also be in the result file. This you might want to avoid, so you can use a small trick for this: after calling a log function use the chaining operator and let the result of the expression be an empty string:

«EXTENSION org::openarchitectureware::util::stdlib::io»
...
«DEFINE javaClass FOR Entity»
  «REM»The following expression will dump the feature names without producing output as side effect«ENDREM»
  «features.name.info() -> ""»

This will produce this output on the console:

1122 INFO  IOExtensions       - [name, age, address]
1740 INFO  IOExtensions       - [street, zip, city]

Each function returns the object on which they have been called, so you can build chain expressions. Or, in other words, if you have some expression like

element.x.y.z.select(t|t.someProp).a

you can always embed one of these io functions anywhere such as in

element.x.syserr().y.z.select(t|t.someProp.info()).a

Controlling the log level

You may want to control the logging level for the messages which are printed via the logging facility. How this is configured in detail depends on the underlying logging framework. openArchitectureWare uses the Apache Commons Logging library, which may dispatches to another logging framework, mostly Log4J.

To control the logging level exactly for the IO extensions you have to know the category to which the messages are logged to. It is common to use the class names of the classes that use the logger. In the case of the IO extensions this class is org.openarchitectureware.util.stdlib.IOExtensions.

The following example shows a Log4J configuration file which would disable log levels below warning. This example would only work if the properties file is found at the beginning of the classpath. Make sure that the file would be found before any other Log4J configurations on your classpath. The file must be named log4j.properties.

log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %p %C{1} %m %n

log4j.rootLogger = INFO, CONSOLE
# suppress info messages from IOExtensions
log4j.logger.org.openarchitectureware.util.stdlib.IOExtensions=WARN, CONSOLE
log4j.additivity.org.openarchitectureware.util.stdlib.IOExtensions=false

Counter extensions

Sometimes it is necessary to have counters within transformation code. The counter extensions enable to initialize, manipulate and retrieve counters.

Extension functions

Extension: org::openarchitectureware::util::stdlib::counter

int counterInc (Object o)

Increments a counter.

Parameters:

  • o - A key for this counter. If this function is called with a Null argument an anonymous counter is used. If no counter was registered for the key a new counter instance will be created and initialized with 0.

Returns: The incremented counter.

int counterDec (Object o)

Decrements a counter.

Parameters:

  • o - A key for this counter. If this function is called with a Null argument an anonymous counter is used. If no counter was registered for the key a new counter instance will be created and initialized with 0.

Returns: The decremented counter.

int counterReset (Object o)

Resets a counter.

Parameters:

  • o - A key for this counter. If this function is called with a Null argument an anonymous counter is used. If no counter was registered for the key a new counter instance will be created and initialized with 0.

Returns: Always 0.

int counterGet (Object o)

Retrieves the current state of a counter.

Parameters:

  • o - A key for this counter. If this function is called with a Null argument the anonymous counter is used.

Returns: Current counter value.

Example

«DEFINE CounterExtensionsDemo FOR Object»
«FILE "CounterExtensions.txt"»
  First counter:
  get         : «counterGet()»
  inc         : «counterInc()»
  inc         : «counterInc()»
  inc         : «counterInc()»
  dec         : «counterDec()»

  Second (named) counter:
  inc         : «counterInc("idx")» 
  inc         : «counterInc("idx")» 
  inc         : «counterInc("idx")»
  reset       : «counterReset("idx")»
  inc         : «counterInc("idx")»

  First counter:
  inc         : «counterInc()»
  
«ENDFILE»
«ENDDEFINE»

This example will create the following output:

  First counter:
  get         : 0
  inc         : 1
  inc         : 2
  inc         : 3
  dec         : 2

  Second (named) counter:
  inc         : 1 
  inc         : 2 
  inc         : 3
  reset       : 0
  inc         : 1

  First counter:
  inc         : 3

Properties extensions

You might want to specify configuration values from properties files from your transformation code. The Properties extensions can help you there. Before being able to access the properties through an extension function the properties files must be read and its values stored. This is done through the workflow component PropertiesReader, which is described below.

Extension functions

Extension: org::openarchitectureware::util::stdlib::properties

String getProperty(String key)

Retrieves a configuration property.

Parameters:

  • o - Property key.

Returns: Property value, if defined, else null.

Workflow component

The workflow component PropertiesReader is used to load properties files. It is possible to configure multiple properties files by adding the propertiesFile tag multiple times.

Table 26. Workflow component org.openarchitectureware.util.stdlib.PropertiesReader

PropertyTypeMandatoryDescription
propertiesFileStringyesThe properties file to read.

Example

Workflow configuration:

<component class="oaw.util.stdlib.PropertiesReader">
  <propertiesFile value="src/config1.properties"/>
  <propertiesFile value="src/config2.properties"/>
</component>

config1.properties:

shapes = box,polygon,ellipse,point

Usage in an extension:

extension org::openarchitectureware::util::stdlib::properties;

cached List[String] SHAPES () : getProperty("shapes").split(",").trim();

Element properties extensions

This allows you to temporarily associate name-value pairs with any model element.

Extension functions

Extension: org::openarchitectureware::util::stdlib::elementprops

Void setProperty( Object element, String name, Object value )

Sets the property named name to the value.

Parameters:

  • element - The model element.

  • name - Property name.

  • value - The property value.

Returns: nothing.

Object getProperty( Object element, String name )

Retrieves a dynamic property from an element.

Parameters:

  • element - The model element.

  • name - Property name.

Returns: The property value.

Issues extensions

In template code there is no direct access to the Issues instance of the workflow's context possible. The Issues extensions help to report warnings and errors to the Issues instance during transformation.

This should not encourage you to use constraint checking and generally raise errors directly from within the transformations. However, sometimes it is sensible and useful to be able to do that.

Extension functions

Extension: org::openarchitectureware::util::stdlib::issues

String reportWarning( String message )

Reports a warning message to the workflow context.

Parameters:

  • message - A message.

Returns: The message.

String reportWarning( Object object, String message )

Reports a warning message and the qualified name of a context object to the workflow context.

Parameters:

  • object - A context object.

  • message - A message.

Returns: The message.

String reportError( String message )

Reports a error message to the workflow context.

Parameters:

  • message - A message.

Returns: The message.

String reportError( Object object, String message )

Reports a error message and the qualified name of a context object to the workflow context.

Parameters:

  • object - A context object.

  • message - A message.

Returns: The message.

Workflow component

The Issues extensions require that the workflow component org.openarchitectureware.util.stdlib.ExtIssueReporter is configured in the workflow before calling the extensions. The purpose of this component is make the workflow's Issues instance available for the extensions.

The ExtIssueReporter component does not have any properties.

Example

Workflow configuration:

<?xml version="1.0"?>
<workflow>
  ...
  <component class="oaw.util.stdlib.ExtIssueReporter"/>

Using from Xtend:

import metamodel;
extension org::openarchitectureware::util::stdlib::issues;

demo (Model this) :
  issuesExtensionsDemo()
  ;

issuesExtensionsDemo () :
  reportWarning("Reporting a warn message from Xtend to the workflow");

Console output:

INFO WorkflowRunner running workflow: workflow/generator.oaw 
...
...
INFO CompositeComponent ExtIssueReporter: setting up issue logging from within .ext and .xpt files 
INFO WorkflowRunner workflow completed in 1101ms! 
WARN WorkflowRunner Reporting a warn message from Xtend to the workflow 

Naming extensions

The Naming extensions are only usable with EMF models.

This one helps with names, qualified names and namespaces. A qualified name is defined as the seuqence of primitive names of the containment hierarchy of an element, seperated by a dot (e.g. java.lang.String). In order for this to work, model elements are expected to have a name attribute of type EString.[9]

Extension functions

Extension: org::openarchitectureware::util::stdlib::naming

String namespace(Object this)

Returns the namespace, i.e. the qualified name minus the name of the element itself.

Parameters:

  • this - A model element.

Returns: The qualified namespace name of the element.

String qualifiedName(Object this)

Returns the qualified name (dot separated) of an element by evaluating its containment hierarchy.

Parameters:

  • this - A model element.

Returns: The qualified name of the element.

String loc(Object this)

Tries to build a useful description of an element in the model; very useful for error reporting.

Parameters:

  • this - A model element.

Returns: Location information about the element.

Object findByName( Collection candidates, String name )

Searches the candidates for an element with a specific name.

Parameters:

  • candidates - A collection of model elements.

  • name - The searched element name.

Returns: The searched element or null if no element with that name is contained in the candidates collection.

Globalvar extensions

Sometimes you might want to share information within a transformation process. One alternative is the use of GLOBALVAR expressions, but this needs that the variables are configured in the workflow.

The Globalvar extensions help to store and retrieve objects within a transformation process.

Extension functions

Extension: org::openarchitectureware::util::stdlib::globalvar

Object storeGlobalVar(String s, Object o)

Stores an object.

Parameters:

  • s - A key.

  • o - The object to store. Pass null to remove the global var.

Returns: The object.

Object getGlobalVar(String s)

Retrieves a stored object.

Parameters:

  • s - The key under which the object is stored.

Returns: The stored object or null if no object was stored for the key.

Object removeGlobalVar(String s)

Removes a stored object from the global var store.

Parameters:

  • s - The key under which the object is stored.

Returns: The stored object or null if no object was stored for the key.

Example

Usage in Xtend:

import metamodel;
extension org::openarchitectureware::util::stdlib::io;
extension org::openarchitectureware::util::stdlib::globalvar;

demo (Model this) :
  globalvarExtensionsDemo1() ->
  globalvarExtensionsDemo2()
;

globalvarExtensionsDemo1 () :
    "Storing global var...".info() ->
    storeGlobalVar("msg", "oAW is cool stuff!");
    
globalvarExtensionsDemo2 () :
    ("Getting message from global var: "+getGlobalVar("msg")).info();    

Console output:

INFO IOExtensions Storing global var... 
INFO IOExtensions Getting message from global var: oAW is cool stuff! 

This a simple example storing a string, but of course you can store the result of any expression this way.

Cloning extensions

The cloning utilities help you to clone a model element and all its children. The clone(Object) function clones a single object and its children, whereas the clone(List) clones a list of elements. The semantics of cloning is as follows:

  • the object passed in as a parameter is duplicated

  • all objects referenced via containment references are also duplicated, recursively

  • the values of the attributes are duplicated

  • non-containing references to other objects are copied while the target is not cloned (a reference to the original is created in the new object)

Extension functions

Extension org::openarchitectureware::util::stdlib::cloning

Object clone( Object original )

Clones an object.

Parameters:

  • original - The object that should be cloned.

Returns: The cloned object.

List clone( List l )

Clones a list of objects.

Parameters:

  • l - Source list

Returns: A list of cloned objects.

Cross references extensions

Sometimes there is the need to find objects that reference a specific object. This extension helps to solve this recurring task. This extension can only be used for EMF based models.

Extension functions

Extension: org::openarchitectureware::util::stdlib::crossref

List[EObject] getReferencingObjects(EObject target)

Retrieves objects that reference a given object.

Parameters:

  • target - The target object.

Returns: A list of objects referencing the target.

Example

Usage in Xtend:

extension org::openarchitectureware::util::stdlib::crossref;

crossRefDemo (Model this) :
    eAllContents.typeSelect(Datatype).dumpCrossReferences();
    
dumpCrossReferences (Datatype this) :
    ("Number of cross references to datatype "+name+":"
    + getReferencingObjects().size)
    .info()
    ;

Console output:

INFO IOExtensions Number of cross references to datatype Integer:1 
INFO IOExtensions Number of cross references to datatype String:4 

UID extensions

Often it is required to create and retrieve unique identifiers for objects through the transformation process. The UID extensions provide a simple mechanism for this task. Unique identifiers are calculated from the current system time plus an internal counter. The extensions therefore only guarantee that the identifier stays the same within one workflow execution, but will change through different runs. If you need to have unique identifiers that stay the same over every generation run (e.g. for Protected Regions Ids) then you need another mechanism.

If you are loading the model that assigns IDs to EObject (only for EMF based models) the xmlId() function will be useful. Especially when using UML2 models this function will return a unique and non-changing identifier for objects.

Extension functions

Extension: org::openarchitectureware::util::stdlib::uid

cached String uid( Object o )

Retrieves objects that reference a given object.

Parameters:

  • target - The target object.

Returns: A list of objects referencing the target.

cached String uid( Object o )

Creates a unique identifier for an object.

Parameters:

  • target - The target object.

Returns: A list of objects referencing the target.

String xmlId (ecore::EObject o)

Retrieves an object's identifier. The object must be read from a XMLResource.

Parameters:

  • o - An object.

Returns: The object's id. Returns null if the object was not load from a XMLResource.

Mixin extensions

These utilities help with mixin models. Mixin models are typically simple models that provide additional information about model elements in a source model of a transformation. They can be seen as annotations.

These utilities expect that the mixin models have a very specific structure: A root element, and then any subtree, where the elements have a name attribute. Here's an example:

Figure 26. Mixin model example

Mixin model example

The mixin elements are ControllingServiceRefSpec and BundleSpec. They are owned by the root element, Cbd2OsgiMixin. The name is expected to contain the qualified name of the element the annotation refers to. Once the model is set up like this, and made available to a transformation using the workflow's GLOBALVAR facilities, you can then use the extension functions.

Extension functions

Extension: org::openarchitectureware::util::stdlib::mixin

Object getMandatoryMixin( Object mixinModel, Object ctx, oaw::Type t )

Returns the corresponding mixin element for the context object; the mixin must be of type t and its name attribute must correspond to the qualified name of the context. If none is found, a workflow ERROR is raised and a null object is returned (so you can call additional operations on it without getting a null evaluation error).

Parameters:

  • mixinModel - The root element of the mixin model.

  • ctx - The context object.

  • t - The type of the mixin model element.

Returns: The mixin model element corresponding to ctx.

Object getOptionalMixin( Object mixinModel, Object ctx, oaw::Type t )

Same as getMandatoryMixin(), but does not raise an error in case nothing is found.

Tracing extensions

The tracing extensions allow to create trace paths during your model transformations. This is done by creating a trace model which holds references from source to target elements. Traces must be added explicitly to the transformation code.

Extension functions

Extension org::openarchitectureware::util::stdlib::tracing

Void createTrace( Object from, Object to, String kind, String backKind )

Creates a trace between two elements.

Parameters:

  • from - Source element.

  • to - Target element.

  • kind - Name for the trace from source to target.

  • backkind - Name for the trace from target back to source.

Returns: Nothing.

Void createTrace( Object from, Object to, String kind )

Creates a trace between two elements.

Parameters:

  • from - Source element.

  • to - Target element.

  • kind - Name for the trace.

Returns: Nothing.

Void clearTrace()

Clears all traces.

Parameters: none

Returns: Nothing.

Object getSingleTraceTarget( Object from, String kind )

Finds the target of a trace. This function will report an error if no trace for the source element to the target of the specified kind can be found.

Parameters:

  • from - Source element.

  • kind - Trace kind name.

Returns: The target element of that trace.

boolean hasTrace( Object from, String kind )

Proves if a trace of a specific kind exists for some element.

Parameters:

  • from - Source element.

  • kind - Trace kind name.

Returns: true, if a trace of that kind exists for the element.

Stdlib workflow components

Besides the extensions described in the previous section oAW's Stdlib provides some workflow components.

SystemCommand

This component executes a system command.

Table 27. Workflow component org.openarchitectureware.util.stdlib.SystemCommand

PropertyTypeMandatoryDescription
commandStringyesThe command to execute.
directoryStringnoExecution directory.
argStringno(multiple) command arguments
envStringno(multiple) additional environment entries. Format: [key],[value]

Example:

<component class="oaw.util.stdlib.SystemCommand">
  <directory value="src-gen"/>
  <command value="sh"/>
  <arg value="processdot.sh"/>
</component>

Console output:

1639 INFO  - Running command '[sh, processdot.sh]' in directory [absolutepath] ...
1667 INFO  - processing shape_box.dot ...
2597 INFO  - processing shape_polygon.dot ...
...
3564 INFO  - Execution of command was successful.

Windows tip:

When executing a command on windows this is typically done with the cmd as command value. It is important that the command terminates, therefore the argument /c must be appended as arg value.[10]

SlotCopier

This component copies an element from one slot to another. The slot content is not cloned.

Table 28. Workflow component org.openarchitectureware.util.stdlib.SlotCopier

PropertyTypeMandatoryDescription
fromSlotStringyesSource slot name.
toSlotStringyesDestination slot name.
removeTopLevelListbooleannoIf true the source slot must contain a list and the top level list is removed (i.e. the first element from the list is copied to the destination slot), otherwise it is not removed.


Example:

<component class="oaw.util.stdlib.SlotCopier">
    <fromSlot value="model"/>
    <toSlot value="target"/>
</component>

Console output:

INFO SlotCopier copying org.eclipse.emf.ecore.impl.DynamicEObjectImpl@1fdbef 
  (eClass: org.eclipse.emf.ecore.impl.EClassImpl@fc5b01 (name: Model) (instanceClassName: null) 
  (abstract: false, interface: false)) 
  [org.eclipse.emf.ecore.impl.DynamicEObjectImpl] 

SlotListAdder

This component copies an element from one slot to a list contained in another slot.

Table 29. Workflow component org.openarchitectureware.util.stdlib.SlotListAdder

PropertyTypeMandatoryDescription
modelSlotStringyesSource slot name.
listSlotStringyesTarget slot name. This slot contains a list of elements.
uniqueNamesbooleannoIf true, names have to be unique, otherwise not. Requires that modelSlot contains an EObject.

Example:

This example adds the content of slot 'model' to the slot 'targetList'. The slot 'targetList' does not contain anything at the time of execution.

<component class="oaw.util.stdlib.SlotListAdder">
    <modelSlot value="model"/>
    <listSlot value="targetList"/>
</component>

Console output:

INFO CompositeComponent SlotListAdder: adding contents of slot 'model' to the list of stuff in 'targetList' 
...
...
INFO WorkflowRunner workflow completed in 1503ms! 
WARN WorkflowRunner 'targetList' is empty, creating a new list. [org.openarchitectureware.util.stdlib.SlotListAdder@7536e7]  

Note that the warn messages will appear after the workflow finished, since they are reported as a workflow warn issue.

SlotPrinter

This component prints a workflow context slot content to the log. This can be useful for debugging purposes.

Table 30. Workflow component org.openarchitectureware.util.stdlib.SlotPrinter

PropertyTypeMandatoryDescription
slotNameStringyesThe name of a slot whose content should be dumped.
messageStringnoAn optional message that will be prefixed to the log output.
levelStringnoThe log level for the message. Valid values are TRACE, DEBUG, INFO, WARN.

Example:

<component class="oaw.util.stdlib.SlotPrinter">
    <slotName value="model"/>
    <message value="DUMP"/>
    <level value="INFO"/>
</component>

Console output:

INFO SlotPrinter DUMP: (slot: model)org.eclipse.emf.ecore.impl.DynamicEObjectImpl@d22ddb 
  (eClass: org.eclipse.emf.ecore.impl.EClassImpl@fe0ce9 (name: Model) (instanceClassName: null) 
  (abstract: false, interface: false)) 


[9] It is intended that the uml2ecore utility can add such a name attribute to every meta class automatically.