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.
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
Logs an object with DEBUG level to the logger.
Parameters:
o - The object to dump.
Returns: The object o
Logs an object with INFO level to the logger.
Parameters:
o - The object to dump.
Returns: The object o
Logs an object with ERROR level to the logger.
Parameters:
o - The object to dump.
Returns: The object o
Prints an object to System.err.
Parameters:
o - The object that should be printed. null
is
allowed.
Returns: The object o
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
Prints an object to System.err.
Parameters:
o - The object that should be printed. null
is
allowed.
Returns: The object o
Throws an IllegalStateMessage.
Parameters:
o - The exception message.
Returns: Nothing, since an exception is thrown.
Reads the content of a file.
Parameters:
filePath - Path to the file
encoding - File encoding to use for reading
Returns: File content.
Reads the content of a file.
Parameters:
filePath - Path to the file
Returns: File content.
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
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
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
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.
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.
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.
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.
«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
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
Retrieves a configuration property.
Parameters:
o
- Property key
Returns: Property value, if defined, else null.
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 |
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();
This allows you to temporarily associate name-value pairs with any model element.
Extension:
org::eclipse::xtend::util::stdlib::elementprops
Sets the property named name
to the value.
Parameters:
element
- The model element
name
- Property name
element
- The property value
Returns: Nothing.
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
Reports a warning message to the workflow context.
Parameters:
message
- A message
Returns: The 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.
Reports a error message to the workflow context.
Parameters:
message
- A message
Returns: The 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.
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.
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
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
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.
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.
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.
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.
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
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.
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
Clones an object.
Parameters:
original
- The object that should be
cloned.
Returns: The cloned object.
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
Retrieves objects that reference a given object.
Parameters:
target
- The target object.
Returns: A list of objects referencing the target.
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
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
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
Creates a unique identifier for an object.
Parameters:
o
- A model element or other object.
Returns: A newly created UID for this object.
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:
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
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.
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
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.
Creates a trace between two elements.
Parameters:
from
- Source element.
to
- Target element.
kind
- Name for the trace from source to
target.
Returns: Nothing.
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.
[9] It is intended that the uml2ecore utility can add such a name attribute to every meta class automatically.