# Stdlib extensions

This section describes the components and extensions provided by Stdlib. We use the shortcut xpand.util.stdlib... for component classes in package org.eclipse.xtend.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 MWE 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: `org::eclipse::xtend::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 System.err.

Parameters:

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

- prefix - A prefix string for the message.

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

#### throwError (Object o)

Throws an IllegalStateMessage.

Parameters:

- o - The exception message.

Returns: Nothing, since an exception is thrown.

#### String includeFile (String filePath, String encoding)

Reads the content of a file.

Parameters:

- filePath - Path to the file

  encoding - File encoding to use for reading

Returns: File content.

#### String includeFile (String filePath)

Reads the content of a file.

Parameters:

- filePath - Path to the file

Returns: File content.

#### Examples

    import data;
    extension org.eclipse.xtend.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::eclipse::xtend::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. Xpand 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.eclipse.xtend.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.eclipse.xtend.util.stdlib.IOExtensions=WARN, CONSOLE
    log4j.additivity.org.eclipse.xtend.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: `org::eclipse:xtend:::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: Allways 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 an 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: `org::eclipse::xtend::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 1. Workflow component org.eclipse.xtend.util.stdlib.PropertiesReader

Property | Type | Mandatory | Description
propertiesFile | String | yes | The properties file to read

#### Example

Workflow configuration:

    <component class="org.eclipse.xtend.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::eclipse::xtend::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: `org::eclipse::xtend::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

- `element` - 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: `org::eclipse::xtend::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 objectt

- `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.eclipse.xtend.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="xpand.util.stdlib.ExtIssueReporter"/>

Using from Xtend:

    import metamodel;
    extension org::eclipse::xtend::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.mwe
    ...
    ...
    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: `org::eclipse::xtend::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: `org::eclipse::xtend::util::stdlib::globalvar`

#### Example

Usage in Xtend:

    import metamodel;
    extension org::eclipse::xtend::util::stdlib::io;
    extension org::eclipse::xtend::util::stdlib::globalvar;

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

    globalvarExtensionsDemo1 () :
        "Storing global var...".info() ->
        storeGlobalVar("msg", "Xpand 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: Xpand 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: `org::eclipse::xtend::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: The 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: `org::eclipse::xtend::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::eclipse::xtend::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: `org::eclipse::xtend::util::stdlib::uid`

#### cached String uid( Object o )

Retrieves an unique identifier for an object. Creates a new one on first access.

Parameters:

- `o` - A model element or other object.

Returns: The UID for this object

#### String createUID( Object o )

Creates a unique identifier for an object.

Parameters:

- `o` - A model element or other object.

Returns: A newly created UID for this object.

#### 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 1. 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: org::eclipse::xtend::util::stdlib::mixin

#### Object getMandatoryMixin( Object mixinModel, Object ctx, xpand2::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, xpand2::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: `org::eclipse::xtend::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 from source to target.

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.

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