| <?xml version="1.0" encoding="UTF-8"?> |
| <chapter id="core_reference" xreflabel="Core reference"> |
| <title><emphasis>Xpand</emphasis> / <emphasis>Xtend</emphasis> / |
| <emphasis>Check</emphasis> Reference</title> |
| |
| <section id="r10_introduction"> |
| <title>Introduction</title> |
| |
| <para>The <emphasis>Xpand</emphasis> generator framework provides textual |
| languages, that are useful in different contexts in the MDSD process (e.g. |
| validation, metamodel extensions, code generation, model transformation). |
| Each language (<emphasis>Check</emphasis>, <emphasis>Xtend</emphasis>, and |
| <emphasis>Xpand</emphasis>) is built upon a common expression language and |
| type system. Therefore, they can operate on the same models, metamodels |
| and meta-metamodels and you do not need to learn the syntax again and |
| again, because it is always the same.</para> |
| |
| <para>The expressions framework provides a uniform abstraction layer over |
| different meta-meta-models (e.g. EMF Ecore, Eclipse UML2, JavaBeans, XML |
| Schema etc.). Additionally, it offers a powerful, statically typed |
| expressions language, which is used in the various textual |
| languages.</para> |
| </section> |
| |
| <section id="r10_typesystem"> |
| <title>Type System <indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Data type</secondary> |
| </indexterm> <indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Parameterized type</secondary> |
| </indexterm></title> |
| |
| <para>The abstraction layer on API basis is called a type system. It |
| provides access to built-in types and different registered metamodel |
| implementations. These registered metamodel implementations offer access |
| to the types they provide. The first part of this documentation describes |
| the type system. The expression sub-language is described afterwards in |
| the second part of this documentation. This differentiation is necessary |
| because the type system and the expression language are two different |
| things. The type system is a kind of reflection layer, that can be |
| extended with metamodel implementations. The expression language defines a |
| concrete syntax for executable expressions, using the type system.</para> |
| |
| <para>The Java API described here is located in the |
| <package>org.eclipse.xpand.type</package> package and is a part of the |
| subproject <package>core.expressions</package>.</para> |
| |
| <section id="r10_typesystem_types"> |
| <title>Types</title> |
| |
| <para>Every object (e.g. model elements, values, etc.) has a type. A |
| type contains properties and operations. In addition it might inherit |
| from other types (multiple inheritance is also possible, depending on |
| the underlying meta-meta-model).</para> |
| |
| <section id="r10_typesystem_typenames"> |
| <title>Type Names</title> |
| |
| <para>Types have a simple name (e.g. <classname>String</classname>) |
| and an optional namespace used to distingish between two types with |
| the same name (e.g. <classname>my::metamodel</classname>). The |
| delimiter for name space fragments is a double colon |
| "<classname>::</classname>". A fully qualified name looks like this: |
| <programlisting language="xtend">my::fully::qualified::MetaType</programlisting></para> |
| |
| <para>The namespace and name used by a specific type is defined by the |
| corresponding <classname>MetaModel</classname><indexterm> |
| <primary>MetaModel</primary> |
| </indexterm> implementation. The <classname>EmfMetaModel<indexterm> |
| <primary>EmfMetaModel</primary> |
| </indexterm></classname>, for instance, maps |
| <classname>EPackages</classname> to namespace and |
| <classname>EClassifiers</classname> to names.<indexterm> |
| <primary>EPackages</primary> |
| </indexterm> <indexterm> |
| <primary>EClassifiers</primary> |
| </indexterm> Therefore, the name of the Ecore element |
| <classname>EClassifier</classname> is called:</para> |
| |
| <programlisting>ecore::EClassifier</programlisting> |
| |
| <para>If you do not want to use namespaces (for whatever reason), you |
| can always implement your own metamodel and map the names |
| accordingly.</para> |
| </section> |
| |
| <section id="r10_typesystem_collection_typenames"> |
| <title>Collection Type Names</title> |
| |
| <para>The built-in type system also contains the following collection |
| types<indexterm> |
| <primary>Collection type</primary> |
| </indexterm>: <classname>Collection</classname>, |
| <classname>List</classname> and <classname>Set</classname>. Because |
| the expressions language is statically type checked and we do not like |
| casts and <classname>ClassCastExceptions</classname>, we introduced |
| the concept of <emphasis>parameterized types</emphasis>. The type |
| system does not support full featured generics, because we do not need |
| them.</para> |
| |
| <para>The syntax is:</para> |
| |
| <programlisting>Collection[my::Type] |
| List[my::Type] |
| Set[my::Type] |
| </programlisting> |
| </section> |
| |
| <section id="r10_typesystem_features"> |
| <title>Features</title> |
| |
| <para>Each type offers features. The type (resp. the metamodel) is |
| responsible for mapping the features. There are three different kinds |
| of features: <itemizedlist> |
| <listitem> |
| <para>Properties</para> |
| </listitem> |
| |
| <listitem> |
| <para>Operations</para> |
| </listitem> |
| |
| <listitem> |
| <para>Static properties</para> |
| </listitem> |
| </itemizedlist></para> |
| |
| <para><emphasis>Properties</emphasis><indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Property</secondary> |
| </indexterm> are straight forward: They have a name and a type. They |
| can be invoked on instances of the corresponding type. The same is |
| true for <emphasis>Operations</emphasis><indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Operation</secondary> |
| </indexterm>. But in contrast to properties, they can have |
| parameters. <emphasis>Static properties</emphasis> <indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Static property</secondary> |
| </indexterm>are the equivalent to enums or constants. They must be |
| invoked statically and they do not have parameters.</para> |
| </section> |
| </section> |
| |
| <section id="r10_builtintypes"> |
| <title>Built-In Types<indexterm> |
| <primary>Built-in type</primary> |
| </indexterm></title> |
| |
| <para>As mentioned before, the expressions framework has several |
| built-in types that define operations and properties. In the following, |
| we will give a rough overview of the types and their features. We will |
| not document all of the operations here, because the built-in types will |
| evolve over time and we want to derive the documentation from the |
| implementation (model-driven, of course). For a complete reference, |
| consult the generated <link linkend="???">API |
| documentation</link>.</para> |
| |
| <section id="r10_builtintypes_object"> |
| <title><classname>Object<indexterm> |
| <primary>Built-in type</primary> |
| |
| <secondary>Object</secondary> |
| </indexterm></classname></title> |
| |
| <para><classname>Object</classname> defines a couple of basic |
| operations, like <methodname>equals()</methodname>. The property |
| metaType provides access to Xpand's type for that Object. Every type |
| has to extend <classname>Object</classname>.</para> |
| </section> |
| |
| <section id="r10_builtintypes_void"> |
| <title><classname>Void</classname><indexterm> |
| <primary>Built-in type</primary> |
| |
| <secondary>Void</secondary> |
| </indexterm></title> |
| |
| <para>The <classname>Void</classname> type can be specified as the |
| return type for operations, although it is not recommended, because |
| whenever possible expressions should be free of side effects whenever |
| possible. The only possible value is <varname>null</varname>. |
| Sometimes it might be useful to use <classname>Void</classname> as an |
| parameter type, if you want to be able to call a function for |
| different argument types and also supply a valid implementation when |
| the function is invoked with <varname>null</varname>.</para> |
| </section> |
| |
| <section id="r10_builtintypes_simple"> |
| <title>Simple types (Data types)</title> |
| |
| <indexterm> |
| <primary>Built-in type</primary> |
| |
| <secondary>Simple type</secondary> |
| </indexterm> |
| |
| <para>The type system doesn't have a concept data type. Data types are |
| just types. As in OCL, we support the following types: |
| <classname>String</classname>, <classname>Boolean</classname>, |
| <classname>Integer</classname>, <classname>Real</classname>. |
| <itemizedlist> |
| <listitem> |
| <para><classname>String</classname><indexterm> |
| <primary>String type</primary> |
| </indexterm>: A rich and convenient |
| <classname>String</classname> library is especially important |
| for code generation. The type system supports the '+' operator |
| for concatenation, the usual |
| <classname>java.lang.String</classname> operations |
| (<methodname>length()</methodname>, etc.) and some special |
| operations (like <methodname>toFirstUpper()</methodname>, |
| <methodname>toFirstLower()</methodname>, regular expressions, |
| etc. often needed in code generation templates).</para> |
| </listitem> |
| |
| <listitem> |
| <para><classname>Boolean</classname><indexterm> |
| <primary>Boolean type</primary> |
| </indexterm>: <classname>Boolean</classname> offers the usual |
| operators (Java syntax): &&, ||, !, etc.</para> |
| </listitem> |
| |
| <listitem> |
| <para><classname>Integer</classname><indexterm> |
| <primary>Integer type</primary> |
| </indexterm> and <classname>Real</classname><indexterm> |
| <primary>Real type</primary> |
| </indexterm>: <classname>Integer</classname> and |
| <classname>Real</classname> offer the usual compare operators |
| (<,>,<=,>=) and simple arithmetics (+,-,*,/). Note |
| that <emphasis><classname>Integer</classname> extends |
| <classname>Real</classname>!</emphasis></para> |
| </listitem> |
| </itemizedlist></para> |
| </section> |
| |
| <section id="r10_builtintypes_collections"> |
| <title>Collection types</title> |
| |
| <indexterm> |
| <primary>Built-in type</primary> |
| |
| <secondary>Collection types</secondary> |
| </indexterm> |
| |
| <para>The type system has three different Collection types. |
| <classname>Collection</classname><indexterm> |
| <primary>Collection</primary> |
| </indexterm> is the base type, it provides several operations known |
| from <classname>java.util.Collection</classname>. The other two types |
| (<classname>List</classname><indexterm> |
| <primary>List</primary> |
| </indexterm>, <classname>Set<indexterm> |
| <primary>Set type</primary> |
| </indexterm></classname>) correspond to their |
| <package>java.util</package> equivalents, too.</para> |
| </section> |
| |
| <section id="r10_builtintypes_typesystem_types"> |
| <title>Type system types</title> |
| |
| <para>The type system describes itself, hence, there are types for the |
| different concepts. These types are needed for reflective programming. |
| To avoid confusion with metatypes with the same name (it is not |
| unusual to have a metatype called <classname>Operation</classname>, |
| for instance) we have prefixed all of the types with the namespace |
| <classname>xpand2</classname>. We have:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><classname>xpand2::Type</classname></para> |
| </listitem> |
| |
| <listitem> |
| <para><classname>xpand2::Feature</classname></para> |
| </listitem> |
| |
| <listitem> |
| <para><classname>xpand2::Property</classname></para> |
| </listitem> |
| |
| <listitem> |
| <para><classname>xpand2::StaticProperty</classname></para> |
| </listitem> |
| |
| <listitem> |
| <para><classname>xpand2::Operation</classname></para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>You should be aware that if you name a type by name in an |
| expression the object you get is in fact an |
| <classname>xpand2::Type</classname>. A common use case is to prove |
| that an object is of some type or its subtype, using the |
| <methodname>instanceOf()</methodname> operation or exactly of one |
| type.</para> |
| |
| <para><programlisting language="java">// results to true, if the result of someExpression is of type MyType or its subtypes |
| MyType.isInstance(someExpression) |
| |
| // results to true, if the result of someExpression is exactly of type MyType |
| someExpression.metaType == MyType</programlisting>Note that this should be |
| only used when really required. The recommended way to handle |
| alternative implementations for a type hierarchy is using <link |
| linkend="???">Multiple Dispatch</link>.</para> |
| </section> |
| </section> |
| |
| <section id="r10_metamodel_implementations"> |
| <title>Metamodel Implementations (also known as |
| Meta-Metamodels)<indexterm> |
| <primary>Metamodel implementation</primary> |
| </indexterm></title> |
| |
| <para>By default, the type system only knows the <link |
| linkend="???">built-in types</link>. In order to register your own |
| metatypes (e.g. <classname>Entity</classname> or |
| <classname>State</classname>), you need to register a respective |
| metamodel implementation with the type system. Within a metamodel |
| implementation the <emphasis>Xpand</emphasis> type system elements |
| (<classname>Type</classname>, <classname>Property</classname>, |
| <indexterm> |
| <primary>property</primary> |
| </indexterm><classname> Operation) </classname><indexterm> |
| <primary>Operation</primary> |
| </indexterm> are mapped to an arbitrary other type system (e.g. Java |
| reflections, Ecore or XML Schema).</para> |
| |
| <section id="r10_metamodel_example_java"> |
| <title>Example JavaMetaModel</title> |
| |
| <para>For instance, if you want to have the following JavaBean act as |
| a metatype (i.e. your model contains instances of the type):</para> |
| |
| <programlisting language="java">public class Attribute { |
| private String name; |
| private String type; |
| public String getName() { |
| return name; |
| } |
| public void setName(String name) { |
| this.name = name; |
| } |
| public String getType() { |
| return type; |
| } |
| public void setType(String type) { |
| this.type = type; |
| } |
| } |
| </programlisting> |
| |
| <para>You need to use the <classname>JavaMetaModel</classname> |
| <indexterm> |
| <primary>JavaMetaModel</primary> |
| </indexterm> implementation which uses the ordinary Java reflection |
| layer in order to map access to the model.</para> |
| |
| <para>So, if you have the following expression in e.g. |
| <emphasis>Xpand</emphasis>:</para> |
| |
| <programlisting>myattr.name.toFirstUpper()</programlisting> |
| |
| <para>and <varname>myattr</varname> is the name of a local variable |
| pointing to an instance of <classname>Attribute</classname>. The |
| <emphasis>Xpand</emphasis> type system asks the metamodel |
| implementations, if they 'know' a type for the instance of Attribute. |
| If you have the <classname>JavaMetaModel</classname> registered it |
| will return an <classname>xpand2::Type</classname> which maps to the |
| underlying Java class. When the type is asked if it knows a property |
| '<varname>name</varname>', it will inspect the Java class using the |
| Java reflection API.</para> |
| |
| <para>The JavaMetaModel implementation shipped with |
| <emphasis>Xpand</emphasis> can be configured with a strategy |
| [GOF95-Pattern] in order to control or change the mapping. For |
| instance, the <classname>JavaBeansStrategy</classname> maps getter and |
| setter methods to simple properties, so we would use this strategy for |
| the example above.</para> |
| </section> |
| |
| <section id="r10_metamodel_contributors"> |
| <title>Eclipse IDE MetaModelContributors</title> |
| |
| <para>You should know that for each <classname>Metamodel</classname> |
| <indexterm> |
| <primary>Metamodel</primary> |
| </indexterm>implementation you use at runtime, you need to have a so |
| called <classname>MetamodelContributor</classname> extension for the |
| plugins to work with. If you just use one of the standard metamodel |
| implementations (EMF, UML2 or Java) you don't have to worry about it, |
| since <emphasis>Xpand</emphasis> is shipped with respective |
| MetamodelContributors (see the corresponding docs for details). If you |
| need to implement your own |
| <classname>MetamodelContributor</classname><indexterm> |
| <primary>MetamodelContributor</primary> |
| </indexterm> you should have a look at the Eclipse plug-in reference |
| doc.</para> |
| </section> |
| |
| <section id="r10_metamodel_workflow"> |
| <title>Configuring Metamodel implementations with the workflow</title> |
| |
| <para>You need to configure your <emphasis>Xpand</emphasis> language |
| components with the respective metamodel implementations.</para> |
| |
| <para>A possible configuration of the <classname>Xpand2</classname> |
| generator component looks like this:</para> |
| |
| <programlisting language="xml"><component class="org.eclipse.xpand2.Generator"> |
| <metaModel class="org.eclipse.type.emf.EmfMetaModel"> |
| <metaModelPackage value="my.generated.MetaModel1Package"/> |
| </metaModel> |
| <metaModel class="org.eclipse.type.emf.EmfMetaModel"> |
| <metaModelFile value="my/java/package/metamodel2.ecore"/> |
| </metaModel> |
| ... |
| </component> |
| </programlisting> |
| |
| <para>In this example the <classname>EmfMetaModel</classname> |
| implementation is configured two times. This means that we want to use |
| two metamodels at the same time, both based on EMF. The |
| <property>metaModelPackage</property> property is a property that is |
| specific to the <classname>EmfMetaModel</classname> (located in the |
| <filename>org.eclipse.xtend.typesystem.emf</filename> plugin). It |
| points to the generated <classname>EPackages</classname> interface. |
| The second meta model is configured using the Ecore file. You do no |
| need to have a generated Ecore model for <emphasis>Xpand</emphasis> in |
| order to work. The <classname>EmfMetaModel</classname> works with |
| dynamic EMF models just as it works with generated EMF models.</para> |
| |
| <para>Note that is recommended to prefer the |
| <classname>EmfRegistryMetaModel</classname> instead of the |
| <classname>EmfMetaModel</classname>, although |
| <classname>EmfMetaModel</classname> is derived from the |
| <classname>EmfRegistryMetaModel</classname>. Further it is recommended |
| to use platform URIs (see <ulink |
| url="http://help.eclipse.org/galileo/topic/org.eclipse.emf.doc/references/javadoc/org/eclipse/emf/common/util/URI.html">API |
| Doc URI</ulink>) to refer to EMF resources.</para> |
| |
| <para>The use of platform URIs in the workflow requires setting up EMF |
| for standalone execution with the |
| <classname>StandaloneSetup</classname> class from the |
| <classname>org.eclipse.emf.mwe.utils</classname> plugin. Further, |
| StandaloneSetup is used to register known EMF packages. An equivalent |
| workflow configuration for the sample above would look like |
| this:</para> |
| |
| <para><programlisting language="xml"><bean class="org.eclipse.emf.mwe.utils.StandaloneSetup"> |
| <platformUri value=".."/> |
| <registerGeneratedEPackage value="my.generated.MetaModel1Package"/> |
| <registerEcoreFile value="platform:/resource/my/java/package/metamodel2.ecore"/> |
| </bean> |
| ... |
| <component class="org.eclipse.xpand2.Generator"> |
| <metaModel class="org.eclipse.type.emf.EmfRegistryMetaModel"/> |
| ... |
| </component> |
| </programlisting>The <classname>StandaloneSetup</classname> is given the path |
| to the platform. This is the path to which platform resource URIs are |
| resolved relative to. It usually points to the workspace or check out |
| location of the plugin project, which is usually one directory above |
| the working directory in which a workflow is executed.</para> |
| |
| <para>Metamodel instances are often shared between different |
| components that make use of expressions (most notably the Xpand |
| <classname>Generator</classname>, |
| <classname>XtendComponent</classname> and |
| <classname>CheckComponent</classname>). Normally you don't want that a |
| Metamodel instance configured and instantiated for each workflow |
| component. MWE lets you instantiate a class using the |
| <methodname><bean></methodname> tag and by giving the bean an id |
| value, this same instance can be referred to using the idRef |
| attribute. This would lead to this workflow:</para> |
| |
| <para><programlisting language="xml"><bean class="org.eclipse.emf.mwe.utils.StandaloneSetup"> |
| <platformUri value=".."/> |
| <registerGeneratedEPackage value="my.generated.MetaModel1Package"/> |
| <registerEcoreFile value="platform:/resource/my/java/package/metamodel2.ecore"/> |
| </bean> |
| <bean id="mm_emf" class="org.eclipse.type.emf.EmfRegistryMetaModel"/> |
| ... |
| <component class="org.eclipse.xpand2.Generator"> |
| <metaModel idRef="mm_emf"/> |
| ... |
| </component> |
| </programlisting></para> |
| </section> |
| </section> |
| |
| <section id="r10_using_different_metamodels"> |
| <title>Using different Metamodel implementations (also known as |
| Meta-Metamodels)</title> |
| |
| <para>With Xpand you can work on different kinds of Model |
| representations at the same time in a transparent manner. One can work |
| with EMF models, XML DOM models, and simple JavaBeans in the same |
| <emphasis>Xpand</emphasis> template. You just need to configure the |
| respective MetaModel implementations.</para> |
| |
| <para>If you want to do so you need to know how the type lookup works. |
| Let us assume that we have an EMF metamodel <indexterm> |
| <primary>EMF metamodel</primary> |
| </indexterm> and a model based on some Java classes. Then the |
| following would be a possible configuration:</para> |
| |
| <programlisting language="xml"><component class="org.eclipse.xpand2.Generator"> |
| <metaModel class="org.eclipse.internal.xtend.type.impl.java.JavaMetaModel"/> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel"> |
| <metaModelFile value="my/java/package/metamodel.ecore"/> |
| </metaModel> |
| |
| ... |
| </component> |
| </programlisting> |
| |
| <para>When the runtime needs to access a property of a given object, it |
| asks the metamodels in the configured order. Let us assume that our |
| model element is an instance of the Java type |
| <classname>org.eclipse.emf.ecore.EObject</classname> and it is a dynamic |
| instance of an EMF EClass <classname>MyType</classname>.</para> |
| |
| <para>We have <emphasis>three</emphasis> Metamodels: <orderedlist> |
| <indexterm> |
| <primary>Metamodel</primary> |
| </indexterm> |
| |
| <listitem> |
| <para>Built-Ins (always the first one)</para> |
| </listitem> |
| |
| <listitem> |
| <para>JavaMetaModel</para> |
| </listitem> |
| |
| <listitem> |
| <para>EMFMetaModel - metamodel.ecore</para> |
| </listitem> |
| </orderedlist></para> |
| |
| <para>The first one will return the type <classname>Object</classname> |
| (not <classname>java.lang.Object</classname> but |
| <classname>Object</classname> of <emphasis>Xpand</emphasis>!). At this |
| point the type <classname>Object</classname> best fits the request, so |
| it will act as the desired type.</para> |
| |
| <para>The second metamodel returns a type called |
| <classname>org::eclipse::emf::ecore::EObject</classname> The type system |
| will check if the returned type is a specialization of the current |
| 'best-fit' type (<classname>Object</classname>). It is, because it |
| extends <classname>Object</classname> (Every metatype has to extend |
| <classname>Object</classname>). At this time the type system assumes |
| <classname>org::eclipse::emf::ecore::EObject</classname> to be the |
| desired type.</para> |
| |
| <para>The third metamodel will return |
| <classname>metamodel::MyType</classname> which is the desired type. But |
| unfortunately it doesn't extend |
| <classname>org::eclipse::emf::ecore::EObject</classname> as it has |
| nothing to do with those Java types. Instead it extends |
| <classname>emf::EObject</classname> which extends |
| <classname>Object</classname>.</para> |
| |
| <para>We need to swap the configuration of the two metamodels to get the |
| desired type.</para> |
| |
| <programlisting language="xml"><component class="org.eclipse.xpand2.Generator"> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel"> |
| <metaModelFile value="my/java/package/metamodel.ecore"/> |
| </metaModel> |
| <metaModel class="org.eclipse.internal.xtend.type.impl.java.JavaMetaModel"/> |
| |
| ... |
| </component></programlisting> |
| |
| <para>The order of the metamodels is important for the work within the |
| Xpand-editors. The metamodels to work with can be configured inside the |
| <emphasis>Xtend/Xpand</emphasis> -properties dialog. The |
| <emphasis>Activated metamodel contributors</emphasis> table is a ordered |
| list. The more specific metamodels have to be placed at the top of the |
| list. <mediaobject> |
| <imageobject role="fo"> |
| <imagedata fileref="images/eclipse_integration/projectProperties.png" |
| scale="80" /> |
| </imageobject> |
| |
| <imageobject role="html"> |
| <imagedata fileref="images/eclipse_integration/projectProperties.png" /> |
| </imageobject> |
| </mediaobject></para> |
| </section> |
| |
| <section id="metamodel_reference" xreflabel="Metamodel reference"> |
| <title>Metamodel Reference</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| </indexterm> |
| |
| <para>In the following, each of the built-in metamodels that come with |
| <emphasis>Xpand</emphasis> will be documented. Furthermore, there will |
| be some guidelines on how to implement your own metamodel.</para> |
| |
| <section id="emf_metamodels" xreflabel="EMF metamodels"> |
| <title>EMF Metamodels</title> |
| |
| <para>This section will describe the metamodels that can be used for |
| EMF models. <emphasis role="strong">Please note that you have to |
| execute one of the setup utility classes, <classname>Setup</classname> |
| or <classname>StandaloneSetup</classname>, in your workflow before you |
| can use one of the EMF metamodels.</emphasis></para> |
| |
| <section id="emfregistry_metamodel" xreflabel="EMF registry metamodel"> |
| <title>The EMF Registry Metamodel |
| (org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel)</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>EMF Registry</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>EmfRegistryMetaModel</primary> |
| </indexterm> |
| |
| <para>This metamodel looks for the referenced metamodels in the |
| global EMF model registry. This means, when using this metamodel, |
| only models that are registered in this global EMF model registry |
| will be accessible from within the metamodel.</para> |
| |
| <para>This metamodel provides the following configuration |
| property:</para> |
| |
| <table frame="all" id="properties_emfregistrymetamodel"> |
| <title>Properties of |
| <classname>EmfRegistryMetaModel</classname></title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="emfregistrymetamodel_property_name" /> |
| |
| <colspec colname="emfregistrymetamodel_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry><varname>useSingleGlobalResourceSet</varname></entry> |
| |
| <entry>This boolean property determines the way resource |
| sets are used. If set to <emphasis>true</emphasis>, all |
| model resources will be stored in a single global resource |
| set. Otherwise, a separate resource set will be used for |
| each model resource.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| |
| <section id="emf_metamodel" xreflabel="EMF metamodel"> |
| <title>The EMF Metamodel |
| (org.eclipse.xtend.typesystem.emf.EmfMetaModel)</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>EMF</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>EmfMetaModel</primary> |
| </indexterm> |
| |
| <para>This metamodel is a specialized version of the <xref |
| linkend="emfregistry_metamodel" />. In addition to the features of |
| the former, it allows to specify an unregistered model in different |
| ways that will be added to the metamodel.</para> |
| |
| <para>This metamodel provides the following configuration |
| properties:</para> |
| |
| <table frame="all" id="properties_emfmetamodel"> |
| <title>Properties of <classname>EmfMetaModel</classname></title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="emfmetamodel_property_name" /> |
| |
| <colspec colname="emfmetamodel_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry><varname>useSingleGlobalResourceSet</varname></entry> |
| |
| <entry>This boolean property determines the way resource |
| sets are used. If set to <emphasis>true</emphasis>, all |
| model resources will be stored in a single global resource |
| set. Otherwise, a separate resource set will be used for |
| each model resource.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>metaModelFile</varname></entry> |
| |
| <entry>Sets the path to the Ecore file that will be added to |
| the metamodel.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>metaModelDescriptor</varname></entry> |
| |
| <entry>Adds a model to the metamodel by specifying the name |
| of an EPackage descriptor class.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>metaModelPackage</varname></entry> |
| |
| <entry>Adds a model to the metamodel by specifying the name |
| of an EPackage.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| </section> |
| |
| <section id="uml_metamodels" xreflabel="UML metamodels"> |
| <title>UML Metamodels</title> |
| |
| <para><emphasis>Xpand</emphasis> also provides several metamodels that |
| allow to use UML models in conjunction with this model-to-text |
| generation framework. <emphasis role="strong">Please note that you |
| have to execute the setup utility class <classname>Setup</classname> |
| in your workflow before you can use one of the UML |
| metamodels</emphasis></para> |
| |
| <section id="uml2_metamodel" xreflabel="UML2 metamodel"> |
| <title>The UML2 Metamodel |
| (org.eclipse.xtend.typesystem.uml2.UML2MetaModel)</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>UML2</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>UML2MetaModel</primary> |
| </indexterm> |
| |
| <para>This metamodel is a specialized version of the <emphasis><xref |
| linkend="emf_metamodel" /></emphasis>. It provides access to UML2 |
| models, and it has the following configuration properties:</para> |
| |
| <table frame="all" id="properties_uml2metamodel"> |
| <title>Properties of <classname>UML2MetaModel</classname></title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="uml2metamodel_property_name" /> |
| |
| <colspec colname="uml2metamodel_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry><varname>useSingleGlobalResourceSet</varname></entry> |
| |
| <entry>This boolean property determines the way resource |
| sets are used. If set to <emphasis>true</emphasis>, all |
| model resources will be stored in a single global resource |
| set. Otherwise, a separate resource set will be used for |
| each model resource.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>modelFile</varname></entry> |
| |
| <entry>Sets the path to the UML2 model file that will be |
| added to the metamodel.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <para>This implementation will be rarely used, since usually |
| profiled UML models will be used and therefore the Profile Metamodel |
| is.</para> |
| </section> |
| |
| <section id="uml2profile_metamodel" xreflabel="UML2 profile metamodel"> |
| <title>The UML2 Profile Metamodel |
| (org.eclipse.xtend.typesystem.uml2.profile.ProfileMetaModel)</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>UML2</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>ProfileMetaModel</primary> |
| </indexterm> |
| |
| <para>This metamodel allows to apply UML profiles to UML2 models, |
| and extends the UML2 Metamodel. It has the following configuration |
| properties:</para> |
| |
| <table frame="all" id="properties_profilemetamodel"> |
| <title>Properties of |
| <classname>ProfileMetaModel</classname></title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="profilemetamodel_property_name" /> |
| |
| <colspec colname="profilemetamodel_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry><varname>useSingleGlobalResourceSet</varname></entry> |
| |
| <entry>This boolean property determines the way resource |
| sets are used. If set to <emphasis>true</emphasis>, all |
| model resources will be stored in a single global resource |
| set. Otherwise, a separate resource set will be used for |
| each model resource.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>modelFile</varname></entry> |
| |
| <entry>Sets the path to the UML2 model file that will be |
| added to the metamodel. Use resource URIs for the |
| values.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>profile</varname></entry> |
| |
| <entry>Sets the path to the UML profile that will be applied |
| to the UML2 model. This property can be used multiple times |
| if more than one profile is used. Use resource URIs for the |
| values.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| |
| <section id="xmi_reader" xreflabel="XMI reader"> |
| <title>The XMI reader |
| (org.eclipse.xtend.typesystem.uml2.profile.ProfilingExtensions.XmiReader)</title> |
| |
| <indexterm> |
| <primary>XMI reader</primary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XMIReader</primary> |
| </indexterm> |
| |
| <para>The XMI reader component is important when working with UML |
| models. It allows to read out a model stored in an XMI file and put |
| its contents into a model slot.</para> |
| |
| <para>The <classname>XMIReader</classname> component provides the |
| following configurable properties:</para> |
| |
| <table frame="all" id="properties_xmireader"> |
| <title>Properties of <classname>XMIReader</classname></title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="xmireader_property_name" /> |
| |
| <colspec colname="xmireader_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry>metaModelFile</entry> |
| |
| <entry>Sets the path to the Ecore file that will be added to |
| the metamodel.</entry> |
| </row> |
| |
| <row> |
| <entry>metaModelDescriptor</entry> |
| |
| <entry>Adds a model to the metamodel by specifying the name |
| of an EPackage descriptor class.</entry> |
| </row> |
| |
| <row> |
| <entry>metaModelPackage</entry> |
| |
| <entry>Adds a model to the metamodel by specifying the name |
| of an EPackage.</entry> |
| </row> |
| |
| <row> |
| <entry>outputSlot</entry> |
| |
| <entry>Sets the name of the model slot where the read model |
| will be stored in.</entry> |
| </row> |
| |
| <row> |
| <entry>firstElementOnly</entry> |
| |
| <entry>This boolean property determines if only the first |
| model element of the XMI file will be used. If set to |
| <emphasis>true</emphasis>, only the first model element will |
| be used, all other elements will be ignored. Otherwise, all |
| model elements in the XMI file will be used.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| </section> |
| |
| <section id="java_metamodel" xreflabel="Java metamodel"> |
| <title>The Java Metamodel |
| (org.eclipse.internal.xtend.type.impl.java.JavaMetaModel)</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>Java</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>JavaMetaModel</primary> |
| </indexterm> |
| |
| <para>The Java metamodel allows normal Java classes as metatypes for |
| your metamodel. The <classname>JavaMetaClass</classname> uses the |
| strategy pattern to define how the elements are exactly mapped to the |
| metamodel elements. There is a class called |
| <classname>org.eclipse.internal.xtend.type.impl.java.JavaBeansMetaModel</classname> |
| that is preconfigured with a strategy that maps simple Java beans onto |
| the metamodel elements.</para> |
| |
| <para>The Java metamodel has no configurable properties.</para> |
| </section> |
| |
| <section id="xsd_metamodel" xreflabel="XSD metamodel"> |
| <title>The XSD Metamodel |
| (org.eclipse.xtend.typesystem.xsd.XSDMetaModel)</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>XSD</secondary> |
| </indexterm> |
| |
| <indexterm> |
| <primary>XSDMetaModel</primary> |
| </indexterm> |
| |
| <para>The XSD metamodel provides access to models implemented in the |
| XML Schema Definition language. It has the following configuration |
| properties:</para> |
| |
| <table frame="all" id="properties_xsdmetamodel"> |
| <title>Properties of <classname>XSDMetaModel</classname></title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="xsdmetamodel_property_name" /> |
| |
| <colspec colname="xsdmetamodel_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry><varname>id</varname></entry> |
| |
| <entry>Sets the ID of the current model.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>registerPackagesGlobally</varname></entry> |
| |
| <entry>This boolean property determines if the model packages |
| will be registered globally. If set to |
| <emphasis>true</emphasis>, the model packages will be |
| registered in the global registry. Otherwise, packages will |
| not be registered.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>savePackagesPath</varname></entry> |
| |
| <entry>Sets the path where model packages will be saved (in |
| XMI format).</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| |
| <section id="implementing_metamodels" |
| xreflabel="Implementing your own metamodel"> |
| <title>Implementing Your Own Metamodel</title> |
| |
| <indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>Implementing metamodels</secondary> |
| </indexterm> |
| |
| <para>The <emphasis>Xpand</emphasis> framework also allows you to |
| integrate new metamodel implementations. This section quickly outlines |
| the steps that have to be taken in order to implement a |
| metamodel:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>Create a class that implements the |
| <classname>MetaModel</classname> interface.</para> |
| </listitem> |
| |
| <listitem> |
| <para>In order to be able to integrate your metamodel into the |
| Eclipse UI, you also have to provide a metamodel contributor class |
| for your metamodel implementation that implements either the |
| <classname>MetaModelContributor</classname> or the |
| <classname>MetaModelContributor2</classname> interface.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Finally, you have to extend the |
| <classname>org.eclipse.xtend.shared.ui.metaModelContributors</classname> |
| extension point in order to register your metamodel contributor |
| with the Eclipse UI.</para> |
| </listitem> |
| </orderedlist> |
| </section> |
| </section> |
| </section> |
| |
| <section id="r10_expressions_language" xreflabel="Expressions"> |
| <title>Expressions<indexterm> |
| <primary>Expression</primary> |
| </indexterm></title> |
| |
| <para>The expression sub-language<indexterm> |
| <primary>Expression language</primary> |
| </indexterm> is a syntactical mixture of Java and OCL<indexterm> |
| <primary>OCL</primary> |
| </indexterm>. This documentation provides a detailed description of each |
| available expression. Let us start with some simple examples.</para> |
| |
| <para>Accessing a property:</para> |
| |
| <programlisting>myModelElement.name</programlisting> |
| |
| <para>Accessing an operation:</para> |
| |
| <programlisting>myModelElement.doStuff()</programlisting> |
| |
| <para>simple arithmetic:</para> |
| |
| <programlisting>1 + 1 * 2</programlisting> |
| |
| <para>boolean expressions (just an example:-)):</para> |
| |
| <programlisting>!('text'.startsWith('t') && ! false)</programlisting> |
| |
| <section id="r10_expressions_builtin"> |
| <title>Literals and special operators for built-in types</title> |
| |
| <para>There are several literals<indexterm> |
| <primary>Literals</primary> |
| </indexterm> for built-in types:</para> |
| |
| <section id="r10_expressions_builtin_object"> |
| <title><classname>Object</classname> <indexterm> |
| <primary>Built-in type</primary> |
| |
| <secondary><classname>Object</classname></secondary> |
| </indexterm> <indexterm> |
| <primary>Built-in type</primary> |
| |
| <secondary><classname>Void</classname></secondary> |
| </indexterm></title> |
| |
| <para>There are naturally no literals for object, but we have two |
| operators:</para> |
| |
| <para>equals:</para> |
| |
| <programlisting>obj1 == obj2</programlisting> |
| |
| <para>not equals:</para> |
| |
| <programlisting>obj1 != obj2</programlisting> |
| </section> |
| |
| <section id="r10_expressions_builtin_void"> |
| <title><classname>Void</classname></title> |
| |
| <para>The only possible instance of <classname>Void</classname> is the |
| <varname>null</varname> reference. Therefore, we have one |
| literal:</para> |
| |
| <programlisting>null</programlisting> |
| </section> |
| |
| <section id="r10_expressions_builtin_typeliterals"> |
| <title>Type literals</title> |
| |
| <para>The literal for types is just the name of the type (no |
| '<filename>.class</filename>' suffix, etc.). Example:</para> |
| |
| <programlisting>String // the type string |
| my::special::Type // evaluates to the type 'my::special::Type'</programlisting> |
| </section> |
| |
| <section id="r10_expressions_builtin_staticproperties"> |
| <title>StaticProperty literals</title> |
| |
| <para>The literal for static properties<indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Static property</secondary> |
| </indexterm> (aka enum literals<indexterm> |
| <primary>Enumeration</primary> |
| |
| <secondary>Literal</secondary> |
| </indexterm>) is correlative to type literals:</para> |
| |
| <programlisting>my::Color::RED</programlisting> |
| </section> |
| |
| <section id="r10_expressions_builtin_string"> |
| <title><classname>String</classname></title> |
| |
| <para>There are two different literal syntaxes (with the same |
| semantics):</para> |
| |
| <programlisting>'a String literal' |
| "a String literal" // both are okay</programlisting> |
| |
| <para>For Strings the expression sub-language supports the plus |
| operator that is overloaded with concatenation:</para> |
| |
| <programlisting>'my element '+ ele.name +' is really cool!'</programlisting> |
| |
| <para>Note, that multi-line Strings are supported.</para> |
| </section> |
| |
| <section id="r10_expressions_builtin_boolean"> |
| <title><classname>Boolean</classname></title> |
| |
| <para>The boolean literals are:</para> |
| |
| <programlisting>true |
| false</programlisting> |
| |
| <para>Operators are:</para> |
| |
| <programlisting>true && false // AND |
| true || false // OR |
| ! true // NOT</programlisting> |
| </section> |
| |
| <section id="r10_expressions_builtin_numeric"> |
| <title><classname>Integer</classname> and |
| <classname>Real</classname></title> |
| |
| <para>The syntax for integer literals is as expected:</para> |
| |
| <programlisting>// integer literals |
| 3 |
| 57278 |
| // real literals |
| 3.0 |
| 0.75</programlisting> |
| |
| <para>Additionally, we have the common arithmetic operators:</para> |
| |
| <programlisting>3 + 4 // addition |
| 4 - 5 // subtraction |
| 2 * 6 // multiplication |
| 3 / 64 // divide |
| // Unary minus operator |
| - 42 |
| - 47.11 |
| </programlisting> |
| |
| <para>Furthermore, the well known compare operators are |
| defined:</para> |
| |
| <programlisting>4 > 5 // greater than |
| 4 < 5 // smaller than |
| 4 >= 23 // greater equals than |
| 4 <= 12 // smaller equals than</programlisting> |
| </section> |
| |
| <section id="r10_expressions_builtin_collections"> |
| <title>Collections</title> |
| |
| <para>There is a literal for lists:</para> |
| |
| <programlisting>{1,2,3,4} // a list with four integers</programlisting> |
| |
| <para>There is no other special concrete syntax for collections. If |
| you need a set, you have to call the <methodname>toSet()</methodname> |
| operation on the list literal:</para> |
| |
| <programlisting>{1,2,4,4}.toSet() // a set with 3(!) integers</programlisting> |
| </section> |
| </section> |
| |
| <section id="r10_expressions_collection_operations"> |
| <title>Special Collection operations</title> |
| |
| <para>Like OCL, the <emphasis>Xpand</emphasis> expression sub-language |
| defines several special operations on collections. However, those |
| operations are not members of the type system, therefore you cannot use |
| them in a reflective manner.</para> |
| |
| <section id="r10_expressions_collection_select"> |
| <title><methodname>select<indexterm> |
| <primary>select</primary> |
| </indexterm></methodname></title> |
| |
| <para>Sometimes, an expression yields a large collection, but one is |
| only interested in a special subset of the collection. The expression |
| sub-language has special constructs to specify a selection out of a |
| specific collection. These are the <methodname>select</methodname> and |
| <methodname>reject</methodname> operations. The select specifies a |
| subset of a collection. A <methodname>select</methodname> is an |
| operation on a collection and is specified as follows:</para> |
| |
| <programlisting>collection.select(v | boolean-expression-with-v)</programlisting> |
| |
| <para><methodname>select</methodname> returns a sublist of the |
| specified collection. The list contains all elements for which the |
| evaluation of <varname>boolean-expression-with-v</varname> results is |
| <varname>true</varname>. Example:</para> |
| |
| <programlisting>{1,2,3,4}.select(i | i >= 3) // returns {3,4}</programlisting> |
| </section> |
| |
| <section id="r10_expressions_collection_typeselect"> |
| <title><methodname>typeSelect</methodname> <indexterm> |
| <primary>typeSelect</primary> |
| </indexterm></title> |
| |
| <para>A special version of a select expression is |
| <methodname>typeSelect</methodname>. Rather than providing a boolean |
| expression a class name is here provided.</para> |
| |
| <programlisting>collection.typeSelect(SomeType) </programlisting> |
| |
| <para><methodname>typeSelect</methodname> returns that sublist of the |
| specified collection, that contains only objects which are an instance |
| of the specified class (also inherited). It is equivalent to the |
| expression</para> |
| |
| <para><programlisting>collection.select(e | SomeType.isInstance(e)) </programlisting></para> |
| </section> |
| |
| <section id="r10_expressions_collection_reject"> |
| <title><methodname>reject<indexterm> |
| <primary>reject</primary> |
| </indexterm></methodname></title> |
| |
| <para>The <methodname>reject</methodname> operation is similar to the |
| <methodname>select</methodname> operation, but with |
| <methodname>reject</methodname> we get the subset of all the elements |
| of the collection for which the expression evaluates to |
| <varname>false</varname>. The <methodname>reject</methodname> syntax |
| is identical to the <methodname>select</methodname> syntax:</para> |
| |
| <programlisting>collection.reject(v | boolean-expression-with-v)</programlisting> |
| |
| <para>Example:</para> |
| |
| <programlisting>{1,2,3,4}.reject(i | i >= 3) // returns {1,2}</programlisting> |
| </section> |
| |
| <section id="r10_expressions_collection_collect"> |
| <title><methodname>collect<indexterm> |
| <primary>collect</primary> |
| </indexterm></methodname></title> |
| |
| <para>As shown in the previous section, the |
| <methodname>select</methodname> and <methodname>reject</methodname> |
| operations always result in a sub-collection of the original |
| collection. Sometimes one wants to apply an operation on all elements |
| of the collection and collect the results of the evaluation in a list. |
| In such cases, we can use a <methodname>collect</methodname> |
| operation. The <methodname>collect</methodname> operation uses the |
| same syntax as the <methodname>select</methodname> and |
| <methodname>reject</methodname> and is written like this:</para> |
| |
| <programlisting>collection.collect(v | expression-with-v)</programlisting> |
| |
| <para><methodname>collect</methodname> again iterates over the target |
| collection and evaluates the given expression on each element. In |
| contrast to <methodname>select</methodname>, the evaluation result is |
| collected in a list. When an iteration is finished the list with all |
| results is returned. Example:</para> |
| |
| <programlisting>namedElements.collect(ne | ne.name) // returns a list of strings |
| namedElements.collect(ne | ne.name.length > 3) // returns a list of boolean |
| </programlisting> |
| </section> |
| |
| <section id="r10_expressions_collection_collect_shorthand"> |
| <title>Shorthand for <methodname>collect</methodname> (and more than |
| that)</title> |
| |
| <para>As navigation through many objects is very common, there is a |
| shorthand notation for collect <indexterm> |
| <primary>collect</primary> |
| </indexterm>that makes the expressions more readable. Instead |
| of</para> |
| |
| <programlisting>self.employee.collect(e | e.birthdate) </programlisting> |
| |
| <para>one can also write:</para> |
| |
| <programlisting>self.employee.birthdate</programlisting> |
| |
| <para>In general, when a property is applied to a collection of |
| Objects, it will automatically be interpreted as a |
| <methodname>collect</methodname> over the members of the collection |
| with the specified property.</para> |
| |
| <para>The syntax is a shorthand for <methodname>collect</methodname>, |
| if the feature does not return a collection itself. But sometimes we |
| have the following:</para> |
| |
| <programlisting>self.buildings.rooms.windows // returns a list of windows</programlisting> |
| |
| <para>This syntax works, but one cannot express it using the |
| <methodname>collect</methodname> operation in an easy way.</para> |
| </section> |
| |
| <section id="r10_expressions_collection_forall"> |
| <title><methodname>forAll</methodname></title> |
| |
| <para>Often a boolean expression has to be evaluated for all elements |
| in a collection. The <methodname>forAll</methodname><indexterm> |
| <primary>forAll</primary> |
| </indexterm> operation allows specifying a Boolean expression, which |
| must be <varname>true</varname> for all objects in a collection in |
| order for the <methodname>forAll</methodname> operation to return |
| <varname>true</varname>:</para> |
| |
| <programlisting>collection.forAll(v | boolean-expression-with-v)</programlisting> |
| |
| <para>The result of <methodname>forAll</methodname> is |
| <varname>true</varname> if |
| <varname>boolean-expression-with-v</varname> is <varname>true |
| </varname>for all the elements contained in a collection. If |
| <varname>boolean-expression-with-v</varname> is |
| <varname>false</varname> for one or more of the elements in the |
| collection, then the <methodname>forAll</methodname> expression |
| evaluates to <varname>false</varname>.</para> |
| |
| <bridgehead>Example:</bridgehead> |
| |
| <programlisting>{3,4,500}.forAll(i | i < 10) // evaluates to false (500 < 10 is false)</programlisting> |
| </section> |
| |
| <section id="r10_expressions_collection_exists"> |
| <title><methodname>exists<indexterm> |
| <primary>exists</primary> |
| </indexterm></methodname></title> |
| |
| <para>Often you will need to know whether there is at least one |
| element in a collection for which a boolean is |
| <varname>true</varname>. The exists operation allows you to specify a |
| Boolean expression which must be <varname>true</varname> for at least |
| one object in a collection:</para> |
| |
| <programlisting>collection.exists(v | boolean-expression-with-v)</programlisting> |
| |
| <para>The result of the exists operation is <varname>true</varname> if |
| <varname>boolean-expression-with-v</varname> is |
| <varname>true</varname> for at least one element of collection. If the |
| <varname>boolean-expression-with-v</varname> is |
| <varname>false</varname> for all elements in collection, then the |
| complete expression evaluates to <varname>false</varname>.</para> |
| |
| <bridgehead>Example:</bridgehead> |
| |
| <programlisting>{3,4,500}.exists(i | i < 10) // evaluates to true (e.g. 3 < 10 is true)</programlisting> |
| </section> |
| |
| <section id="r10_expressions_collection_sortby"> |
| <title><methodname>sortBy</methodname></title> |
| |
| <para>If you want to sort a list of elements, you can use the higher |
| order function <methodname>sortBy</methodname> <indexterm> |
| <primary>sortBy</primary> |
| </indexterm>. The list you invoke the |
| <methodname>sortBy</methodname> operation on, is sorted by the results |
| of the given expression.</para> |
| |
| <bridgehead>Example:</bridgehead> |
| |
| <programlisting>myListOfEntity.sortBy(entity | entity.name)</programlisting> |
| |
| <para>In the example the list of entities is sorted by the name of the |
| entities. Note that there is no such <classname>Comparable</classname> |
| type in <emphasis>Xpand</emphasis>. If the values returned from the |
| expression are instances of |
| <classname>java.util.Comparable</classname> the |
| <methodname>compareTo</methodname> method is used, otherwise |
| <methodname>toString()</methodname> is invoked and the the result is |
| used.</para> |
| |
| <para>All the following expressions return |
| <varname>true</varname>:</para> |
| |
| <programlisting>{'C','B','A'}.sortBy(e | e) == {'A','B','C'} |
| {'AAA','BB','C'}.sortBy(e | e.length) == {'C','BB','AAA'} |
| {5,3,1,2}.sortBy(e | e) == {1,2,3,5} |
| {5,3,1,2}.sortBy(e | e - 2 * e) == {5,3,2,1} |
| ...</programlisting> |
| </section> |
| </section> |
| |
| <section id="r10_expressions_if"> |
| <title><methodname>if</methodname> expression</title> |
| |
| <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>if</secondary> |
| </indexterm> |
| |
| <para>There are two different forms of conditional expressions. The |
| first one is the so-called <emphasis>if expression</emphasis>. |
| Syntax:</para> |
| |
| <programlisting>condition ? thenExpression : elseExpression</programlisting> |
| |
| <para><emphasis role="bold">Example:</emphasis></para> |
| |
| <programlisting>name != null ? name : 'unknown'</programlisting> |
| |
| <para>Alternatively, you also could write:</para> |
| |
| <programlisting>if name != null then |
| name |
| else |
| 'unknown' |
| </programlisting> |
| </section> |
| |
| <section id="r10_expressions_switch"> |
| <title><methodname>switch</methodname> expression</title> |
| |
| <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>switch</secondary> |
| </indexterm> |
| |
| <para>The other one is called <emphasis>switch expression</emphasis>. |
| Syntax:</para> |
| |
| <programlisting>switch (expression) { |
| (case expression : thenExpression)* |
| default : catchAllExpression |
| }</programlisting> |
| |
| <para>The default part is mandatory, because |
| <methodname>switch</methodname> is an expression, therefore it needs to |
| evaluate to something in any case.</para> |
| |
| <para><emphasis role="bold">Example:</emphasis></para> |
| |
| <programlisting>switch (person.name) { |
| case 'Hansen' : 'Du kanns platt schnacken' |
| default : 'Du kanns mi nech verstohn!' |
| }</programlisting> |
| |
| <para>There is an abbreviation for <emphasis>Boolean</emphasis> |
| expressions:</para> |
| |
| <programlisting>switch { |
| case booleanExpression : thenExpression |
| default : catchAllExpression |
| } </programlisting> |
| </section> |
| |
| <section id="r10_expressions_chain"> |
| <title>Chain expression</title> |
| |
| <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>chain</secondary> |
| </indexterm> |
| |
| <para>Expressions and functional languages should be free of side |
| effects as far as possible. But sometimes there you need invocations |
| that do have side effects. In some cases expressions even do not have a |
| return type (i.e. the return type is <classname>Void</classname>). If |
| you need to call such operations, you can use the chain |
| expression.</para> |
| |
| <para><emphasis role="bold">Syntax:</emphasis></para> |
| |
| <programlisting>anExpr -> |
| anotherExpr -> |
| lastExpr </programlisting> |
| |
| <para>Each expression is evaluated in sequence, but only the result of |
| the last expression is returned.</para> |
| |
| <para><emphasis role="bold">Example</emphasis>:</para> |
| |
| <programlisting>person.setName('test') -> |
| person</programlisting> |
| |
| <para>This chain expression will set the <varname>name</varname> of the |
| person first, before it returns the person object itself.</para> |
| </section> |
| |
| <section id="r10_expressions_create"> |
| <title><methodname>new</methodname> expression</title> |
| |
| <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>new</secondary> |
| </indexterm> |
| |
| <para>The <methodname>new</methodname> expression is used to instantiate |
| new objects of a given type:</para> |
| |
| <programlisting>new TypeName</programlisting> |
| |
| <para>Note that often <link linkend="???">create extensions</link> are |
| the better way to instantiate objects when used for model |
| transformations.</para> |
| </section> |
| |
| <section id="r10_expressions_globalvar"> |
| <title>'GLOBALVAR' expression</title> |
| |
| <para>Sometimes you don't want to pass everything down the call stack by |
| parameter. Therefore, we have the <methodname>GLOBALVAR</methodname> |
| <indexterm> |
| <primary>GLOBALVAR</primary> |
| </indexterm> expression. There are two things you need to do, to use |
| global variables.</para> |
| |
| <section id="r10_expressions_globalvar_workflow"> |
| <title>Using GLOBALVARS to configure workflows</title> |
| |
| <para>Each workflow component using the expression framework |
| (<emphasis>Xpand</emphasis>, <emphasis>Check</emphasis> and |
| <emphasis>Xtend</emphasis>) can be configured with global variables. |
| <indexterm> |
| <primary>Global variables</primary> |
| </indexterm> Here is an example:</para> |
| |
| <programlisting language="xml"><workflow> |
| .... stuff |
| <component class="org.eclipse.xpand2.Generator"> |
| ... usual stuff (see ref doc) |
| <globalVarDef name="MyPSM" value="slotNameOfPSM"/> |
| <globalVarDef name="ImplClassSuffix" value="'Impl'"/> |
| </component> |
| </workflow></programlisting> |
| |
| <para>Note that <varname>value</varname> contains an expression or |
| slot name. If you want to pass a string value you will have to quote |
| the value, like the value for <classname>ImplClassSuffix</classname> |
| in the example.</para> |
| |
| <para>If you have injected global variables into the respective |
| component, you can call them using the following syntax:</para> |
| |
| <programlisting>GLOBALVAR ImplClassSuffix</programlisting> |
| |
| <para>Note, we don't have any static type information. Therefore |
| <classname>Object</classname> is assumed. So, you have to down cast |
| the global variable to the intended type:</para> |
| |
| <programlisting>((String) GLOBALVAR ImplClassSuffix)</programlisting> |
| |
| <para>It is good practice to type it once, using an Extension and then |
| always refer to that extension:</para> |
| |
| <programlisting language="xtend">String implClassSuffix() : GLOBALVAR ImplClassSuffix; |
| // usage of the typed global var extension |
| ImplName(Class c) : |
| name+implClassSuffix();</programlisting> |
| </section> |
| </section> |
| |
| <section id="r10_expressions_multidispatch"> |
| <title>Multi methods (multiple dispatch)</title> |
| |
| <para>The expressions language supports multiple dispatching <indexterm> |
| <primary>Multiple dispatching</primary> |
| </indexterm>. This means that when there is a bunch of overloaded |
| operations, the decision which operation has to be resolved is based on |
| the dynamic type of all parameters (the implicit |
| '<varname>this</varname>' included).</para> |
| |
| <para>In Java only the dynamic type of the '<varname>this</varname>' |
| element is considered, for parameters the static type is used (this is |
| called single dispatch).</para> |
| |
| <para>Here is a Java example:</para> |
| |
| <programlisting language="xtend">class MyType { |
| boolean equals(Object o) { |
| if (o instanceof MyClass) { |
| return equals((MyClass)o); |
| } |
| return super.equals(o); |
| } |
| boolean equals(MyType mt) { |
| //implementation... |
| } |
| } </programlisting> |
| |
| <para>The method <methodname>equals(Object o)</methodname> would not |
| have to be overwritten, if Java would support multiple dispatch.</para> |
| </section> |
| |
| <section id="r10_expressions_casting"> |
| <title>Casting<indexterm> |
| <primary>Casting</primary> |
| </indexterm></title> |
| |
| <para>The expression language is statically type checked. Although there |
| are many concepts that help the programmer to have really good static |
| type information, sometimes. One knows more about the real type than the |
| system. To explicitly give the system such an information casts are |
| available. <emphasis>Casts are 100% static, so you do not need them, if |
| you never statically typecheck your expressions! </emphasis></para> |
| |
| <para>The syntax for casts is very Java-like:</para> |
| |
| <programlisting>((String)unTypedList.get(0)).toUpperCase()</programlisting> |
| </section> |
| |
| <section> |
| <title>Xpand keywords and metamodel properties<indexterm> |
| <primary>Keyword</primary> |
| |
| <secondary>Property</secondary> |
| </indexterm></title> |
| |
| <para>When the name of a metamodel property conflicts with an |
| <emphasis>Xpand</emphasis> or <emphasis>Xtend</emphasis> keyword, the |
| conflict is resolved in favour of the keyword. To refer to the metamodel |
| property in these cases, its name must be preceded by a |
| '<varname>^</varname>' character.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting>private String foo(Import ^import) : ^import.name; |
| </programlisting> |
| </section> |
| </section> |
| |
| <section id="Check_language" xreflabel="Check language"> |
| <title><emphasis>Check</emphasis></title> |
| |
| <section id="Check_language_description" |
| xreflabel="Description of the Check language"> |
| <title>Description of the <emphasis>Check</emphasis> language</title> |
| |
| <para><emphasis>Xpand</emphasis> also provides a language to specify |
| constraints <indexterm> |
| <primary>Constraint</primary> |
| </indexterm> that the model has to fulfill in order to be correct. |
| This language is very easy to understand and use. Basically, it is built |
| around the expression syntax that has been discussed in detail in the |
| previous section. Constraints specified in the |
| <emphasis>Check</emphasis> <indexterm> |
| <primary>Check</primary> |
| |
| <secondary>Language</secondary> |
| </indexterm> language have to be stored in files with the file |
| extension <filename>.chk</filename> <indexterm> |
| <primary>.chk</primary> |
| </indexterm><indexterm> |
| <primary>Check</primary> |
| |
| <secondary>File extension</secondary> |
| </indexterm>. Furthermore, these files have to be on the Java |
| classpath, of course, in order to be found. Let us look at an example, |
| in order to understand what these constraints look like and what they |
| do:<programlisting language="check">import data; |
| context Attribute ERROR |
| "Names have to be more than one character long." : |
| name.length > 1;</programlisting>Now, let us look at the example line by |
| line:<orderedlist> |
| <listitem> |
| <para>First, the metamodel has to be imported.</para> |
| </listitem> |
| |
| <listitem> |
| <para>Then, the context is specified for which the constraint |
| applies. In other words, after the <code>context</code> keyword, |
| we put the name of the metaclass that is going to be checked by |
| the constraint. Then, there follows either <code>ERROR</code> or |
| <code>WARNING</code>, These keywords specify what kind of action |
| will be taken in case the constraint fails:<table frame="all"> |
| <title>Types of action for <emphasis>Check</emphasis> |
| constraints</title> |
| |
| <tgroup cols="2" colsep="1" rowsep="1"> |
| <colspec colnum="2" colwidth="7*" /> |
| |
| <tbody> |
| <row> |
| <entry><code>WARNING</code></entry> |
| |
| <entry>If the constraint fails, the specified message is |
| printed, but the workflow execution is not |
| stopped.</entry> |
| </row> |
| |
| <row> |
| <entry><code>ERROR</code></entry> |
| |
| <entry>If the constraint fails, the specified message is |
| printed and all further processing is stopped.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table></para> |
| </listitem> |
| |
| <listitem> |
| <para>Now, the message that is put in case that the constraint |
| fails is specified as a string. It is possible to include the |
| value of attributes or the return value of functions into the |
| message in order to make the message more clear. For example, it |
| would be possible to improve the above example by rewriting it |
| like this:</para> |
| |
| <programlisting language="check">import data; |
| context Attribute ERROR |
| "Name of '" + name + "too short. Names have to be more than one character long." : |
| name.length > 1;</programlisting> |
| </listitem> |
| |
| <listitem> |
| <para>Finally, there is the condition itself, which is specified |
| by an expression, which has been discussed in detail in the |
| previous section. If this expression is <varname>true</varname>, |
| the constraint is fulfilled.</para> |
| </listitem> |
| </orderedlist></para> |
| |
| <para><important> |
| <para>Please always keep in mind that the message that is associated |
| with the constraint is printed, if the condition of the constraint |
| is <varname>false</varname>! Thus, if the specified constraint |
| condition is <varname>true</varname>, nothing will be printed out |
| and the constraint will be fulfilled.</para> |
| </important></para> |
| |
| <section id="Guard_conditions" xreflabel="Guard Conditions"> |
| <title>Guard Conditions</title> |
| |
| <para>The <emphasis>Check</emphasis> language of |
| <emphasis>Xpand</emphasis> also provides so called <indexterm> |
| <primary>Guard conditions</primary> |
| </indexterm>. These conditions allow to apply a check constraint |
| only to model elements that meet certain criteria. Specifying such a |
| guard condition is done by adding an <emphasis>if</emphasis> clause to |
| the check constraint. The <emphasis>if</emphasis> clause has to be |
| added after the <emphasis>context</emphasis> clause as demonstrated by |
| the following example: <programlisting language="check">import data; |
| context Attribute if name.length > 1 ERROR |
| "Attribute names have to start with an 'a'" : |
| name.startsWith("a");</programlisting></para> |
| </section> |
| </section> |
| |
| <section id="check_checkcomponent" |
| xreflabel="The workflow component CheckComponent"> |
| <title>The workflow component |
| <emphasis>CheckComponent</emphasis></title> |
| |
| <para>The workflow component |
| <classname>org.eclipse.xtend.check.CheckComponent</classname> allows to |
| integrate model validation constraints using the |
| <emphasis>Check</emphasis> into a modeling workflow using MWE.</para> |
| |
| <para>This component provides the following configuration |
| properties:</para> |
| |
| <table frame="all" id="properties_checkcomponent"> |
| <title>Properties</title> |
| |
| <tgroup align="left" cols="2" colsep="1" rowsep="1"> |
| <colspec colname="checkcomponent_property_name" /> |
| |
| <colspec colname="checkcomponent_property_description" /> |
| |
| <thead> |
| <row> |
| <entry>Name of property</entry> |
| |
| <entry>Description</entry> |
| </row> |
| </thead> |
| |
| <tbody> |
| <row> |
| <entry><varname>checkFile</varname></entry> |
| |
| <entry>This property allows to add files containing constraints |
| written in the <emphasis>Check</emphasis> language to the |
| validation component.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>emfAllChildrenSlot</varname></entry> |
| |
| <entry>Name of a workflow slot that contains an EMF object, |
| which has to be validated including all child elements that it |
| contains. <emphasis>This property only works in conjunction with |
| EMF based models.</emphasis></entry> |
| </row> |
| |
| <row> |
| <entry><varname>expression</varname></entry> |
| |
| <entry>This property allows to set a check expression for the |
| validation component. <emphasis role="strong">This property only |
| works in conjunction with non-EMF based |
| models.</emphasis></entry> |
| </row> |
| |
| <row> |
| <entry><varname>abortOnError</varname></entry> |
| |
| <entry>This boolean property determines if the workflow will be |
| aborted or not if one of the validation constraints |
| fails.</entry> |
| </row> |
| |
| <row> |
| <entry><varname>warnIfNothingChecked</varname></entry> |
| |
| <entry>If this boolean property will be set to |
| <emphasis>true</emphasis>, a warning will be generated if there |
| were no validation checks. Otherwise, no warning will be |
| issued.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| </section> |
| |
| <section id="Xtend_language" xreflabel="Xtend"> |
| <title><emphasis>Xtend</emphasis></title> |
| |
| <indexterm> |
| <primary>Xtend</primary> |
| |
| <secondary>Language</secondary> |
| </indexterm> |
| |
| <para>Like the expressions sublanguage that summarizes the syntax of |
| expressions for all the other textual languages delivered with the |
| <emphasis>Xpand</emphasis> framework, there is another commonly used |
| language called <emphasis>Xtend</emphasis>.</para> |
| |
| <para>This language provides the possibility to define rich libraries of |
| independent operations and non-invasive metamodel extensions<indexterm> |
| <primary>Metamodel</primary> |
| |
| <secondary>(non-invasive) extension</secondary> |
| </indexterm> based on either Java methods or <emphasis>Xtend</emphasis> |
| expressions. Those libraries can be referenced from all other textual |
| languages that are based on the expressions framework.</para> |
| |
| <section> |
| <title>Xtend files</title> |
| |
| <indexterm> |
| <primary>*.ext</primary> |
| </indexterm> |
| |
| <para><indexterm> |
| <primary>Xtend</primary> |
| |
| <secondary>File extension</secondary> |
| </indexterm>An Xtend file must reside in the Java class path of the |
| used execution context. File extension must be |
| <filename>*.ext</filename>. Let us have a look at an Xend file.</para> |
| |
| <programlisting>import my::metamodel;extension other::ExtensionFile; |
| |
| /** |
| * Documentation |
| */ |
| anExpressionExtension(String stringParam) : |
| doingStuff(with(stringParam)) |
| ; |
| |
| /** |
| * java extensions are just mappings |
| */ |
| String aJavaExtension(String param) : JAVA |
| my.JavaClass.staticMethod(java.lang.String) |
| ; |
| </programlisting> |
| |
| <para>The example shows the following statements:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>import statements</para> |
| </listitem> |
| |
| <listitem> |
| <para>extension import statements</para> |
| </listitem> |
| |
| <listitem> |
| <para>expression or java extensions</para> |
| </listitem> |
| </orderedlist> |
| </section> |
| |
| <section> |
| <title>Comments<indexterm> |
| <primary>Xtend</primary> |
| |
| <secondary>Comments</secondary> |
| </indexterm></title> |
| |
| <para>We have single- and multi-line comments. The syntax for single |
| line comments is:</para> |
| |
| <programlisting>// my comment</programlisting> |
| |
| <para>Multi line comments are written like this:</para> |
| |
| <programlisting>/* My multi line comment */</programlisting> |
| </section> |
| |
| <section> |
| <title>Import Statements</title> |
| |
| <para>Using the import<indexterm> |
| <primary>import</primary> |
| </indexterm> statement one can import name spaces of different |
| types.(see expressions framework reference documentation).</para> |
| |
| <para>Syntax is:</para> |
| |
| <programlisting>import my::imported::namespace;</programlisting> |
| |
| <para>Xtend does not support static imports or any similar concept. |
| Therefore, the following is incorrect syntax:</para> |
| |
| <programlisting>import my::imported::namespace::*; // WRONG! import my::Type; // WRONG!</programlisting> |
| </section> |
| |
| <section> |
| <title>Extension Import Statement</title> |
| |
| <indexterm> |
| <primary>Extension</primary> |
| </indexterm> |
| |
| <para>You can import another Xtend file using the extension statement. |
| The syntax is:</para> |
| |
| <programlisting>extension fully::qualified::ExtensionFileName;</programlisting> |
| |
| <para>Note, that no file extension (<filename>*.ext</filename>) is |
| specified.</para> |
| |
| <section> |
| <title>Reexporting Extensions</title> |
| |
| <para>If you want to export extensions from another extension file |
| together with your local extensions, you can add the keyword |
| <methodname>reexport</methodname> <indexterm> |
| <primary>Reexport</primary> |
| </indexterm> to the end of the respective extension import |
| statement.</para> |
| |
| <programlisting>extension fully::qualified::ExtensionFileName reexport;</programlisting> |
| </section> |
| </section> |
| |
| <section> |
| <title>Extensions</title> |
| |
| <para>The syntax of a simple expression extension is as follows:</para> |
| |
| <programlisting>ReturnType extensionName(ParamType1 paramName1, ParamType2...): expression-using-params;</programlisting> |
| |
| <para><emphasis role="bold">Example:</emphasis></para> |
| |
| <programlisting>String getterName(NamedElement ele) : 'get'+ele.name.firstUpper();</programlisting> |
| |
| <section> |
| <title>Extension Invocation<indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>invocation</secondary> |
| </indexterm></title> |
| |
| <para>There are two different ways of how to invoke an extension. It |
| can be invoked like a function:</para> |
| |
| <programlisting>getterName(myNamedElement)</programlisting> |
| |
| <para>The other way to invoke an extension is through the "member |
| syntax":</para> |
| |
| <programlisting>myNamedElement.getterName()</programlisting> |
| |
| <para>For any invocation in member syntax, the target expression (the |
| member) is mapped to the first parameter. Therefore, both syntactical |
| forms do the same thing.</para> |
| |
| <para>It is important to understand that extensions are not members of |
| the type system, hence, they are not accessible through reflection and |
| you cannot specialize or overwrite operations using them.</para> |
| |
| <para>The expression evaluation engine first looks for an appropriate |
| operation before looking for an extension, in other words operations |
| have higher precedence.</para> |
| </section> |
| |
| <section> |
| <title>Type Inference<indexterm> |
| <primary>Type inference</primary> |
| </indexterm></title> |
| |
| <para>For most extensions, you do not need to specify the return |
| type,<indexterm> |
| <primary>Return type</primary> |
| </indexterm> because it can be derived from the specified |
| expression. The special thing is, that the static return type of such |
| an extension depends on the context of use.</para> |
| |
| <para>For instance, if you have the following extension</para> |
| |
| <programlisting>asList(Object o): {o};</programlisting> |
| |
| <para>the invocation of</para> |
| |
| <programlisting>asList('text')</programlisting> |
| |
| <para>has the static type <classname>List[String]</classname>. This |
| means you can call</para> |
| |
| <programlisting>asList('text').get(0).toUpperCase()</programlisting> |
| |
| <para>The expression is statically type safe, because its return type |
| is derived automatically.</para> |
| |
| <para>There is <emphasis>always</emphasis> a return value, whether you |
| specify it or not, even if you specify explicitly |
| '<classname>Void</classname>'.</para> |
| |
| <para>See the following example.</para> |
| |
| <programlisting>modelTarget.ownedElements.addAllNotNull(modelSource.contents.duplicate())</programlisting> |
| |
| <para>In this example <methodname>duplicate()</methodname> dispatches |
| polymorphically<indexterm> |
| <primary>Polymorphism</primary> |
| </indexterm>. Two of the extensions might look like:</para> |
| |
| <programlisting>Void duplicate(Realization realization): |
| realization.Specifier().duplicate()-> |
| realization.Realizer().duplicate() |
| ; |
| |
| create target::Class duplicate(source::Class): |
| ... |
| ;</programlisting> |
| |
| <para>If a '<classname>Realization</classname>' is contained in the |
| '<methodname>contents</methodname>' list of |
| '<varname>modelSource</varname>', the |
| '<methodname>Realizer</methodname>' of the |
| '<classname>Realization</classname>' will be added to the |
| '<varname>ownedElements</varname>' list of the |
| '<varname>modelTarget</varname>'. If you do not want to add in the |
| case that the contained element is a 'Realization' you might change |
| the extension to:</para> |
| |
| <programlisting>Void duplicate(Realization realization): |
| realization.Specifier().duplicate()-> |
| realization.Realizer().duplicate() -> |
| {} |
| ;</programlisting> |
| </section> |
| |
| <section> |
| <title>Recursion</title> |
| |
| <para>There is only one exception: For recursive extensions <indexterm> |
| <primary>Recursive extensions</primary> |
| </indexterm><indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>recursion</secondary> |
| </indexterm> the return type cannot be inferred, therefore you need |
| to specify it explicitly:</para> |
| |
| <programlisting>String fullyQualifiedName(NamedElement n) : n.parent == null ? n.name : |
| fullyQualifiedName(n.parent)+'::'+n.name |
| ;</programlisting> |
| |
| <para>Recursive extensions are non-deterministic in a static context, |
| therefore, it is necessary to specify a return type.</para> |
| </section> |
| |
| <section> |
| <title>Cached Extensions<indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>caching</secondary> |
| </indexterm></title> |
| |
| <para>If you call an extension without side effects very often, you |
| would like to cache the result for each set of parameters, in order |
| improve the performance. You can just add the keyword |
| '<code>cached</code>'<indexterm> |
| <primary>cached</primary> |
| </indexterm> to the extension in order to achieve this:</para> |
| |
| <programlisting>cached String getterName(NamedElement ele) : |
| 'get'+ele.name.firstUpper() |
| ;</programlisting> |
| |
| <para>The <methodname>getterName</methodname> will be computed only |
| once for each <classname>NamedElement</classname>.</para> |
| </section> |
| |
| <section> |
| <title>Private Extensions<indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>private</secondary> |
| </indexterm></title> |
| |
| <para>By default all extensions are public, i.e. they are visible from |
| outside the extension file. If you want to hide extensions you can add |
| the keyword '<methodname>private</methodname>'<indexterm> |
| <primary>private</primary> |
| </indexterm> in front of them:</para> |
| |
| <programlisting>private internalHelper(NamedElement ele) : |
| // implementation.... |
| ;</programlisting> |
| </section> |
| </section> |
| |
| <section> |
| <title>Java Extensions</title> |
| |
| <para>In some cases one does want to call a Java method from inside an |
| expression. This can be done by providing a Java extension<indexterm> |
| <primary>Java extension</primary> |
| </indexterm><indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>Java</secondary> |
| </indexterm>:</para> |
| |
| <programlisting>Void myJavaExtension(String param) : |
| JAVA my.Type.someMethod(java.lang.String) |
| ;</programlisting> |
| |
| <para>The signature is the same as for any other extension. Its syntax |
| is:</para> |
| |
| <programlisting>JAVA fully.qualified.Type.someMethod(my.ParamType1, |
| my.ParamType2, |
| ...) |
| ;</programlisting> |
| |
| <para>Note that you cannot use any imported namespaces. You have to |
| specify the type, its method and the parameter types in a fully |
| qualified way.</para> |
| |
| <para><emphasis role="bold">Example:</emphasis></para> |
| |
| <para>If you have defined the following Java extension:</para> |
| |
| <programlisting>String concat (String a, String b): |
| JAVA my.Helper.concat(java.lang.String, java.lang.String);</programlisting> |
| |
| <para>and you have the following Java class:</para> |
| |
| <programlisting>package my; |
| |
| public class Helper { |
| public String concat(String a, String b){ |
| return a + b; |
| } |
| }</programlisting> |
| |
| <para>the expressions</para> |
| |
| <programlisting>concat('Hello ',"world!") |
| "Hello ".concat('world!')</programlisting> |
| |
| <para>both result are invoking the Java method <methodname>void |
| concat(String a, String b).</methodname></para> |
| |
| <section> |
| <title>static vs non-static invocation</title> |
| |
| <para>The implementation of a Java extension is redirected to a public |
| method in a Java class. If the method is not declared static it is |
| required that the Java class has a default constructor. Xtend will |
| instantiate the class for each invocation.</para> |
| </section> |
| |
| <section> |
| <title>IExecutionContextAware<indexterm> |
| <primary>IExecutionContextAware</primary> |
| </indexterm></title> |
| |
| <para>It is possible with a Java Extension to gain access to the |
| ExecutionContext<indexterm> |
| <primary>ExecutionContext</primary> |
| </indexterm>, which enables to retrieve detailed runtime information |
| on invocation. To use the current ExecutionContext in a Java extension |
| the class must implement |
| <classname>org.eclipse.xtend.expression.IExecutionContextAware</classname></para> |
| |
| <para><programlisting>public interface IExecutionContextAware { |
| void setExecutionContext (ExecutionContext ctx); |
| } |
| </programlisting></para> |
| |
| <para>The invoked method must not be static.</para> |
| </section> |
| </section> |
| |
| <section id="create_extension"> |
| <title>Create Extensions (Model Transformation)</title> |
| |
| <para>The <emphasis>Xtend</emphasis> language supports additional |
| support for model transformations<indexterm> |
| <primary>Model transformation</primary> |
| </indexterm>. The concept is called <emphasis>create |
| extension</emphasis> and <indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>create</secondary> |
| </indexterm><indexterm> |
| <primary>create</primary> |
| </indexterm> it is explained a bit more comprehensive as usual.</para> |
| |
| <para>Elements contained in a model are usually referenced multiple |
| times. Consider the following model structure:</para> |
| |
| <programlisting> P |
| / \ |
| C1 C2 |
| \ / |
| R |
| </programlisting> |
| |
| <para>A package <varname>P</varname> contains two classes |
| <varname>C1</varname> and <varname>C2</varname>. <varname>C1</varname> |
| contains a reference <varname>R</varname> of type <varname>C2</varname> |
| (<varname>P</varname> also references <varname>C2</varname>).</para> |
| |
| <para>We could write the following extensions in order to transform an |
| Ecore (EMF) model to our metamodel (Package, Class, Reference).</para> |
| |
| <programlisting>Package toPackage(EPackage x) : |
| let p = new Package : |
| p.ownedMember.addAll(x.eClassifiers.toClass()) -> |
| p; |
| |
| Class toClass(EClass x) : |
| let c = new Class : |
| c.attributes.addAll(x.eReferences.toReference()) -> |
| c; |
| |
| Reference toReference(EReference x) : |
| let r = new Reference : |
| r.setType(x.eType.toClass()) -> |
| r; |
| </programlisting> |
| |
| <para>For an Ecore model with the above structure, the result would |
| be:</para> |
| |
| <programlisting> P |
| / \ |
| C1 C2 |
| | |
| R - C2 |
| </programlisting> |
| |
| <para>What happened? The <varname>C2</varname> class has been created 2 |
| times (one time for the package containment and another time for the |
| reference <varname>R</varname> that also refers to |
| <varname>C2</varname>). We can solve the problem by adding the |
| '<methodname>cached</methodname>' keyword <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>cached</secondary> |
| </indexterm> to the second extension:</para> |
| |
| <programlisting>cached toClass(EClass x) : |
| let c = new Class : |
| c.attributes.addAll(c.eAttributes.toAttribute()) -> |
| c; |
| </programlisting> |
| |
| <para>The process goes like this:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>P</varname></para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>C1</varname> (contained in |
| <varname>P</varname>)</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>R</varname> (contained in |
| <varname>C1</varname>)</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>C2</varname> (referenced |
| from <varname>R</varname>)</para> |
| </listitem> |
| |
| <listitem> |
| <para>end (result <varname>C2</varname> is |
| cached)</para> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| |
| <listitem> |
| <para>end <varname>R</varname></para> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| |
| <listitem> |
| <para>end <varname>C1</varname></para> |
| </listitem> |
| |
| <listitem> |
| <para>start get cached <varname>C2</varname> (contained in |
| <varname>P</varname>)</para> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| |
| <listitem> |
| <para>end P</para> |
| </listitem> |
| </orderedlist> |
| |
| <para>So this works very well. We will get the intended structure. But |
| what about circular dependencies? For instance, <varname>C2</varname> |
| could contain a <classname>Reference</classname> <varname>R2</varname> |
| of type <varname>C1</varname> (bidirectional references):</para> |
| |
| <para>The transformation would occur like this:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>P</varname></para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>C1</varname> (contained in |
| <varname>P</varname>)</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>R</varname> (contained in |
| <varname>C1</varname>)</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>C2</varname> (referenced |
| from <varname>R</varname>)</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>R2</varname> (contained |
| in <varname>C2</varname>)</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>start create <varname>C1</varname> (referenced |
| from <varname>R1</varname>)... OOPS!</para> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| </orderedlist> |
| </listitem> |
| </orderedlist> |
| |
| <para><varname>C1</varname> is already in creation and will not complete |
| until the stack is reduced. Deadlock! The problem is that the cache |
| caches the return value, but <varname>C1</varname> was not returned so |
| far, because it is still in construction.</para> |
| |
| <para>The solution: create extensions!</para> |
| |
| <para>The syntax is as follows:</para> |
| |
| <programlisting>create Package toPackage(EPackage x) : |
| this.classifiers.addAll(x.eClassifiers.toClass()); |
| |
| create Class toClass(EClass x) : |
| this.attributes.addAll(x.eReferences.toReference()); |
| |
| create Reference toReference(EReference x) : |
| this.setType(x.eType.toClass()); |
| </programlisting> |
| |
| <para>This is not only a shorter syntax, but it also has the needed |
| semantics: The created model element will be added to the cache before |
| evaluating the body. The return value is always the reference to the |
| created and maybe not completely initialized element.</para> |
| </section> |
| |
| <section> |
| <title>Calling Extensions From Java</title> |
| |
| <para>The previous section showed how to implement Extensions in Java. |
| This section shows how to call Extensions from Java.<indexterm> |
| <primary>XtendFacade</primary> |
| </indexterm></para> |
| |
| <programlisting>// setup |
| XtendFacade f = XtendFacade.create("my::path::MyExtensionFile"); |
| |
| // use |
| f.call("sayHello",new Object[]{"World"}); |
| </programlisting> |
| |
| <para>The called extension file looks like this: <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>call</secondary> |
| </indexterm></para> |
| |
| <programlisting>sayHello(String s) : |
| "Hello " + s;</programlisting> |
| |
| <para>This example uses only features of the |
| <classname>BuiltinMetaModel</classname>, in this case the |
| "<methodname>+</methodname>" feature from the |
| <classname>StringTypeImpl</classname>.</para> |
| |
| <para>Here is another example, that uses the |
| <classname>JavaBeansMetaModel</classname><indexterm> |
| <primary>JavaBeansMetaModel</primary> |
| </indexterm> strategy. This strategy provides as additional feature: |
| the access to properties using the getter and setter methods.</para> |
| |
| <para>For more information about type systems, see the <emphasis><xref |
| linkend="r10_expressions_language" /></emphasis> reference |
| documentation.</para> |
| |
| <para>We have one JavaBean-like metamodel class:</para> |
| |
| <programlisting>package mypackage; |
| public class MyBeanMetaClass { |
| private String myProp; |
| public String getMyProp() { return myProp; } |
| public void setMyProp(String s) { myProp = s;} |
| }</programlisting> |
| |
| <para>in addition to the built-in metamodel type system, we register the |
| <classname>JavaMetaModel</classname><indexterm> |
| <primary>JavaMetaModel</primary> |
| </indexterm> with the |
| <classname>JavaBeansStrategy</classname><indexterm> |
| <primary>JavaBeansStrategy</primary> |
| </indexterm> for our facade. Now, we can use also this strategy in our |
| extension:</para> |
| |
| <programlisting>// setup facade |
| |
| XtendFacade f = XtendFacade.create("myext::JavaBeanExtension"); |
| |
| // setup additional type system |
| JavaMetaModel jmm = |
| new JavaMetaModel("JavaMM", new JavaBeansStrategy()); |
| |
| f.registerMetaModel(jmm); |
| |
| // use the facade |
| MyBeanMetaClass jb = MyBeanMetaClass(); |
| jb.setMyProp("test"); |
| f.call("readMyProp", new Object[]{jb}));</programlisting> |
| |
| <para>The called extension file looks like this:</para> |
| |
| <programlisting>import mypackage; |
| |
| readMyProp(MyBeanMetaClass jb) : |
| jb.myProp |
| ; |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>WorkflowComponent<indexterm> |
| <primary>WorkflowComponent</primary> |
| </indexterm></title> |
| |
| <para>With the additional support for model transformation, it makes |
| sense to invoke <emphasis>Xtend</emphasis> within a workflow. A typical |
| workflow configuration of the <emphasis>Xtend</emphasis> component |
| <indexterm> |
| <primary>XtendComponent</primary> |
| </indexterm>looks like this:</para> |
| |
| <programlisting language="xml"><component class="org.eclipse.xtend.XtendComponent"> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel"> |
| <metaModelFile value="metamodel1.ecore"/> |
| </metamodel> |
| <metaModel class="org.eclipse.xtend.typesystem.type.emf.EmfMetaModel"> |
| <metaModelFile value="metamodel2.ecore"/> |
| </metaModel> |
| <invoke value="my::example::Trafo::transform(inputSlot)"/> |
| <outputSlot value="transformedModel"/> |
| </component> |
| </programlisting> |
| |
| <para>Note that you can mix and use any kinds of metamodels (not only |
| EMF metamodels).</para> |
| </section> |
| |
| <section> |
| <title>Aspect-Oriented Programming in |
| <emphasis>Xtend</emphasis><indexterm> |
| <primary>Aspect-Oriented Programming</primary> |
| </indexterm><indexterm> |
| <primary>AOP</primary> |
| </indexterm></title> |
| |
| <para>Using the workflow engine, it is now possible to package (e.g. |
| zip) a written generator and deliver it as a kind of black box. If you |
| want to use such a generator but need to change some things without |
| modifying any code, you can make use of around advices that are |
| supported by <emphasis>Xtend</emphasis>.</para> |
| |
| <para>The following advice is weaved<indexterm> |
| <primary>Weaving advices</primary> |
| </indexterm> around every invocation of an extension whose name starts |
| with '<package>my::generator::</package>':</para> |
| |
| <programlisting>around my::generator::*(*) : |
| log('Invoking ' + ctx.name) -> ctx.proceed() |
| ; |
| </programlisting> |
| |
| <para>Around advices<indexterm> |
| <primary>Advice</primary> |
| </indexterm> let you change behaviour in an non-invasive way (you do |
| not need to touch the packaged extensions).</para> |
| |
| <section> |
| <title>Join Point and Point Cut Syntax</title> |
| |
| <para>Aspect orientaton is basically about weaving code into different |
| points inside the call graph of a software module. Such points are |
| called <emphasis>join points</emphasis>. In <emphasis>Xtend</emphasis> |
| the join points are the extension invocations (Note that |
| <emphasis>Xpand</emphasis> offers a similar feature, see the |
| <emphasis>Xpand</emphasis> documentation).</para> |
| |
| <para>One specifies on which join points <indexterm> |
| <primary>Join point</primary> |
| </indexterm> the contributed code should be executed by specifying |
| something like a 'query' on all available join points. Such a query is |
| called a point cut.<indexterm> |
| <primary>Point cut</primary> |
| </indexterm></para> |
| |
| <programlisting>around [pointcut] : |
| expression;</programlisting> |
| |
| <para>A point cut consists of a fully qualified name and a list of |
| parameter declarations.</para> |
| |
| <section> |
| <title>Extensions Name</title> |
| |
| <para>The extension name part of a point cut must match the fully |
| qualified name of the definition of the join point. Such expressions |
| are case sensitive. The asterisk character is used to specify |
| wildcards.</para> |
| |
| <para>Some examples:</para> |
| |
| <programlisting>my::Extension::definition // extensions with the specified name |
| org::eclipse::xpand2::* //extensions prefixed with 'org::eclipse::xpand2::' |
| *Operation* // extensions containing the word 'Operation' in it. |
| * // all extensions</programlisting> |
| |
| <warning> |
| <para>Be careful when using wildcards, because you will get an |
| endless recursion, in case you weave an extension, which is called |
| inside the advice.</para> |
| </warning> |
| </section> |
| |
| <section> |
| <title>Parameter Types</title> |
| |
| <para>The parameters of the extensions that we want to add our |
| advice to, can also be specified in the point cut. The rule is, that |
| the type of the specified parameter must be the same or a supertype |
| of the corresponding parameter type (the dynamic type at runtime) of |
| the definition to be called.</para> |
| |
| <para>Additionally, one can set the wildcard at the end of the |
| parameter list, to specify that there might be none or more |
| parameters of any kind.<indexterm> |
| <primary>Type</primary> |
| |
| <secondary>Parameter</secondary> |
| </indexterm></para> |
| |
| <para>Some examples:</para> |
| |
| <programlisting>my::Templ::extension() // extension without parameters |
| my::Templ::extension(String s) // extension with exactly one parameter of type String |
| my::Templ::extension(String s,*) // templ def with one or more parameters, |
| // where the first parameter is of type String |
| my::Templ::extension(*) // templ def with any number of parameters |
| </programlisting> |
| </section> |
| |
| <section> |
| <title>Proceeding</title> |
| |
| <para>Inside an advice, you might want to call the underlying |
| definition. This can be done using the implicit variable |
| <varname>ctx</varname>, which is of the type |
| <type>xtend::AdviceContext</type><indexterm> |
| <primary>AdviceContext</primary> |
| </indexterm> and provides an operation |
| <methodname>proceed()</methodname><indexterm> |
| <primary>proceed</primary> |
| </indexterm> which invokes the underlying definition with the |
| original parameters (Note that you might have changed any mutable |
| object in the advice before).</para> |
| |
| <para>If you want to control what parameters are to be passed to the |
| definition, you can use the operation |
| <methodname>proceed(List[Object] params)</methodname>. You should be |
| aware, that in advices, no type checking is done.</para> |
| |
| <para>Additionally, there are some inspection properties (like |
| <varname>name</varname>, <varname>paramTypes</varname>, etc.) |
| available.</para> |
| </section> |
| </section> |
| |
| <section> |
| <title>Workflow configuration</title> |
| |
| <para>To weave the defined advices into the different join |
| points<indexterm> |
| <primary>Join point</primary> |
| </indexterm>, you need to configure the |
| <classname>XtendComponent</classname><indexterm> |
| <primary>XtendComponent</primary> |
| |
| <secondary>Advices</secondary> |
| </indexterm> with the qualified names of the Extension files |
| containing the advices.</para> |
| |
| <para>Example:</para> |
| |
| <programlisting language="xml"><component class="org.eclipse.xtend.XtendComponent"> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel"> |
| <metaModelFile value="metamodel1.ecore"/> |
| </metamodel> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel"> |
| <metaModelFile value="metamodel2.ecore"/> |
| </metaModel> |
| |
| <invoke value="my::example::Trafo::transform(inputSlot)"/> |
| <outputSlot value="transformedModel"/> |
| <advices value="my::Advices,my::Advices2"/> |
| </component> |
| </programlisting> |
| </section> |
| |
| <section id="xtend_example_introduction"> |
| <title>Model-to-Model transformation with |
| <emphasis>Xtend</emphasis></title> |
| |
| <para>This example uses Eclipse EMF as the basis <indexterm> |
| <primary>Model-to-model transformation</primary> |
| </indexterm>for model-to-model transformations. It builds on the |
| <emphasis>emfExample</emphasis> documented elsewhere. Please read and |
| install the <emphasis>emfExample</emphasis> first.</para> |
| |
| <para>The idea in this example is to transform the data model |
| introduced in the EMF example into itself. This might seem boring, but |
| the example is in fact quite illustrative.</para> |
| </section> |
| |
| <section id="xtend_example_workflow"> |
| <title>Workflow</title> |
| |
| <para>By now, you should know the role and structure of workflow |
| files. Therefore, the interesting aspect of the workflow file below is |
| the <emphasis><classname>XtendComponent</classname></emphasis>.</para> |
| |
| <programlisting language="xml"><workflow> |
| <property file="workflow.properties"/> |
| ... |
| <component class="org.eclipse.xtend.XtendComponent"> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel"> |
| <metaModelPackage value="data.DataPackage"/> |
| </metaModel> |
| <invoke value="test::Trafo::duplicate(rootElement)"/> |
| <outputSlot value="newModel"/> |
| </component> |
| ... |
| </workflow></programlisting> |
| |
| <para>As usual, we have to define the metamodel that should be used, |
| and since we want to transform a data model into a data model, we need |
| to specify only the <classname>data.DataPackage</classname> as the |
| metamodel.</para> |
| |
| <para>We then specify which function to invoke for the transformation. |
| The statement |
| <classname>test::Trafo::duplicate(rootElement)</classname> means to |
| invoke: <itemizedlist> |
| <listitem> |
| <para>the <classname>duplicate</classname> function taking the |
| contents of the <classname>rootElement</classname> slot as a |
| parameter</para> |
| </listitem> |
| |
| <listitem> |
| <para>the function can be found in the |
| <filename>Trafo.ext</filename> file</para> |
| </listitem> |
| |
| <listitem> |
| <para>and that in turn is in the classpath, in the |
| <package>test</package>package.</para> |
| </listitem> |
| </itemizedlist></para> |
| </section> |
| |
| <section id="xtend_example_the_transformation"> |
| <title>The transformation</title> |
| |
| <para>The transformation, as mentioned above, can be found in the |
| <filename>Trafo.ext</filename> file in the <classname>test</classname> |
| package in the <classname>src</classname> folder. Let us walk through |
| the file.</para> |
| |
| <para>So, first we import the metamodel.</para> |
| |
| <programlisting language="xtend">import data;</programlisting> |
| |
| <para>The next function is a so-called create extension<indexterm> |
| <primary>Extension</primary> |
| |
| <secondary>create</secondary> |
| </indexterm><indexterm> |
| <primary>Create extension</primary> |
| </indexterm>. Create extensions, as a side effect when called, |
| create an instance of the type given after the |
| <classname>create</classname> keyword. In our case, the |
| <classname>duplicate</classname> function creates an instance of |
| <classname>DataModel</classname>. This newly created object can be |
| referred to in the transformation <indexterm> |
| <primary>Transformation</primary> |
| </indexterm>by <classname>this</classname> (which is why |
| <classname>this</classname> is specified behind the type). Since |
| <classname>this</classname> can be omitted, we do not have to mention |
| it explicitly in the transformation.</para> |
| |
| <para>The function also takes an instance of |
| <classname>DataModel</classname> as its only parameter. That object is |
| referred to in the transformation as <varname>s</varname>. So, this |
| function sets the name of the newly created |
| <classname>DataModel</classname> to be the name of the original one, |
| and then adds duplicates of all entities of the original one to the |
| new one. To create the duplicates of the entities, the |
| <classname>duplicate()</classname> operation is called for each |
| <classname>Entity</classname>. This is the next function in the |
| transformation.</para> |
| |
| <programlisting language="xtend">create DataModel this duplicate(DataModel s): |
| entity.addAll(s.entity.duplicate()) -> |
| setName(s.name);</programlisting> |
| |
| <para>The duplication function for entities is also a create |
| extension. This time, it creates a new <classname>Entity</classname> |
| for each old <classname>Entity</classname> passed in. Again, it copies |
| the name and adds duplicates of the attributes and references to the |
| new one.</para> |
| |
| <programlisting language="xtend">create Entity this duplicate(Entity old): |
| attribute.addAll(old.attribute.duplicate()) -> |
| reference.addAll(old.reference.duplicate()) -> |
| setName(old.name);</programlisting> |
| |
| <para>The function that copies the attribute is rather straight |
| forward, but ...</para> |
| |
| <programlisting language="xtend">create Attribute this duplicate(Attribute old): |
| setName(old.name) -> |
| setType(old.type);</programlisting> |
| |
| <indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>create</secondary> |
| </indexterm> |
| |
| <para>... the one for the references is more interesting. Note that a |
| reference, while being owned by some <classname>Entity</classname>, |
| also references another Entity as its target. So, how do you make sure |
| you do not duplicate the target twice? <emphasis>Xtend</emphasis> |
| provides explicit support for this kind of situation. <emphasis>Create |
| extensions are only executed once per tuple of parameters!</emphasis> |
| So if, for example, the <emphasis>Entity</emphasis> behind the target |
| reference had already been duplicated by calling the |
| <methodname>duplicate</methodname> function with the respective |
| parameter, the next time it will be called <emphasis>the exact same |
| object will be returned</emphasis>. This is very useful for graph |
| transformations.</para> |
| |
| <programlisting language="xtend">create EntityReference this duplicate(EntityReference old): |
| setName( old.name ) -> |
| setTarget( old.target.duplicate() );</programlisting> |
| |
| <para>For more information about the <emphasis>Xtend</emphasis> |
| language please see the <emphasis><xref |
| linkend="Xtend_language" /></emphasis> reference documentation.</para> |
| </section> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_introduction"> |
| <title><emphasis>Xpand2</emphasis></title> |
| |
| <para>The <emphasis>Xpand</emphasis><indexterm> |
| <primary>Xpand</primary> |
| |
| <secondary>Language</secondary> |
| </indexterm> language is used in templates to control the output |
| generation. This documentation describes the general syntax and semantics |
| of the <emphasis>Xpand</emphasis> language.</para> |
| |
| <para>Typing the <foreignphrase>guillemets</foreignphrase><indexterm> |
| <primary>Guillemet</primary> |
| </indexterm> (« and ») used in the templates is supported by the Eclipse |
| editor, which provides keyboard shortcuts with <keycombo action="simul"> |
| <keycap>Ctrl</keycap> |
| |
| <keycap><</keycap> |
| </keycombo> and <keycombo action="simul"> |
| <keycap>Ctrl</keycap> |
| |
| <keycap>></keycap> |
| </keycombo>.</para> |
| |
| <section id="xpand_reference_template_files_and_ecoding"> |
| <title>Template files and encoding</title> |
| |
| <para>Templates are stored in files with the extension |
| <filename>.xpt</filename><indexterm> |
| <primary>File extension</primary> |
| |
| <secondary>.xpt</secondary> |
| </indexterm>.<indexterm> |
| <primary>.xpt</primary> |
| </indexterm> Template files<indexterm> |
| <primary>Template</primary> |
| |
| <secondary>File</secondary> |
| </indexterm> must reside on the Java classpath of the generator |
| process.</para> |
| |
| <para>Almost all characters used in the standard syntax are part of |
| <emphasis>ASCII</emphasis> and should therefore be available in any |
| encoding<indexterm> |
| <primary>File encoding</primary> |
| |
| <secondary>encoding</secondary> |
| </indexterm><indexterm> |
| <primary>Encoding</primary> |
| |
| <see>File encoding</see> |
| </indexterm>. The only limitation are the tag brackets |
| (<emphasis>guillemets</emphasis>), for which the characters "«" (Unicode |
| <varname>00AB</varname>) and "»" (Unicode <varname>00BB</varname>) are |
| used. So for reading templates, an encoding should be used that supports |
| these characters (e.g. <varname>ISO-8859-1</varname> or |
| <varname>UTF-8</varname>).</para> |
| |
| <para>Names of properties, templates, namespaces etc. must only contain |
| letters, numbers and underscores.</para> |
| </section> |
| |
| <section id="xpand_reference_general_structure_of_template_files"> |
| <title>General structure of template files</title> |
| |
| <para>Here is a first example of a template:<programlisting>«IMPORT meta::model» |
| «EXTENSION my::ExtensionFile» |
| |
| «DEFINE javaClass FOR Entity» |
| «FILE fileName()» |
| package «javaPackage()»; |
| |
| public class «name» { |
| // implementation |
| } |
| «ENDFILE» |
| «ENDDEFINE»</programlisting>A template file consists of any number of IMPORT |
| statements, followed by any number of EXTENSION statements, followed by |
| one or more DEFINE blocks (called definitions).</para> |
| </section> |
| |
| <section id="xpand_reference_statements_of_the_expand_language"> |
| <title>Statements of the <emphasis>Xpand</emphasis> language</title> |
| |
| <section id="xpand_reference_import"> |
| <title>IMPORT<indexterm> |
| <primary>IMPORT</primary> |
| </indexterm></title> |
| |
| <para>If you are tired of always typing the fully qualified names of |
| your types and definitions, you can import a namespace using the |
| IMPORT statement. <programlisting>«IMPORT meta::model»</programlisting>This |
| one imports the namespace <varname>meta::model</varname>. If your |
| template contains such a statement, you can use the unqualified names |
| of all types and template files contained in that namespace. This is |
| similar to a Java import statement <varname>import |
| meta.model.*</varname>.</para> |
| </section> |
| |
| <section id="xpand_reference_extension"> |
| <title>EXTENSION<indexterm> |
| <primary>EXTENSION</primary> |
| </indexterm></title> |
| |
| <para>Metamodels are typically described in a structural way |
| (graphical, or hierarchical, etc.) . A shortcoming of this is that it |
| is difficult to specify additional behaviour (query operations, |
| derived properties, etc.). Also, it is a good idea not to pollute the |
| metamodel with target platform specific information (e.g. Java type |
| names, packages, getter and setter names, etc.).</para> |
| |
| <para>Extensions provide a flexible and convenient way of defining |
| additional features of metaclasses. You do this by using the <link |
| linkend="???"><emphasis>Xtend</emphasis><indexterm> |
| <primary>Xtend</primary> |
| </indexterm> language</link>.</para> |
| |
| <para>An <classname>EXTENSION</classname> import points to the |
| <emphasis>Xtend</emphasis> file containing the required extensions: |
| <programlisting>«EXTENSION my::ExtensionFile»</programlisting> Note |
| that extension files have to reside on the Java classpath<indexterm> |
| <primary>Classpath</primary> |
| </indexterm>, too. Therefore, they use the same namespace mechanism |
| (and syntax) as types and template files.</para> |
| </section> |
| |
| <section id="xpand_reference_define"> |
| <title>DEFINE<indexterm> |
| <primary>DEFINE</primary> |
| </indexterm></title> |
| |
| <para>The central concept of <emphasis>Xpand</emphasis> is the |
| <code>DEFINE</code> block, also called a template. This is the |
| smallest identifiable unit in a template file<indexterm> |
| <primary>Template</primary> |
| |
| <secondary>File</secondary> |
| </indexterm>. The tag consists of a name, an optional |
| comma-separated parameter list, as well as the name of the metamodel |
| class for which the template is defined. <programlisting>«DEFINE templateName(formalParameterList) FOR MetaClass» |
| a sequence of statements |
| «ENDDEFINE»</programlisting>To some extend, templates can be seen as special |
| methods of the metaclass. There is always an implicit |
| <varname>this</varname> parameter which can be used to address the |
| "underlying" model element; in our example above, this model element |
| is of type "<classname>MetaClass</classname>".</para> |
| |
| <para>As in Java, a formal parameter list entry consists of the type |
| followed by the name of that parameter.</para> |
| |
| <para>The body of a template can contain a sequence of other |
| statements including any text.</para> |
| |
| <para>A full parametric polymorphism<indexterm> |
| <primary>Polymorphism</primary> |
| </indexterm> <indexterm> |
| <primary>Template</primary> |
| |
| <secondary>Polymorphism</secondary> |
| </indexterm> is available for templates. If there are two templates |
| with the same name that are defined for two metaclasses which inherit |
| from the same superclass, <emphasis>Xpand</emphasis> will use the |
| corresponding subclass template, in case the template is called for |
| the superclass. Vice versa, the template of the superclass would be |
| used in case a subclass template is not available. Note that this not |
| only works for the target type, but for all parameters. Technically, |
| the target type is handled as the first parameter.</para> |
| |
| <para>So, let us assume you have the following metamodel: <figure> |
| <title>Sample metamodel</title> |
| |
| <mediaobject> |
| <imageobject role="fo"> |
| <imagedata fileref="images/XPand/metamodelexample.gif" |
| scale="80" /> |
| </imageobject> |
| |
| <imageobject role="html"> |
| <imagedata fileref="images/XPand/metamodelexample.gif" /> |
| </imageobject> |
| </mediaobject> |
| </figure></para> |
| |
| <para>Assume further, you would have a model which contains a |
| collection of <classname>A</classname>, <classname>B</classname> and |
| <classname>C</classname> instances in the property |
| <methodname>listOfAs</methodname>. Then, you can write the following |
| template: <programlisting>«DEFINE someOtherDefine FOR SomeMetaClass» |
| «EXPAND implClass FOREACH listOfAs» |
| «ENDDEFINE» |
| |
| «DEFINE implClass FOR A» |
| // this is the code generated for the superclass A |
| «ENDDEFINE» |
| |
| «DEFINE implClass FOR B» |
| // this is the code generated for the subclass B |
| «ENDDEFINE» |
| |
| «DEFINE implClass FOR C» |
| // this is the code generated for the subclass C |
| «ENDDEFINE»</programlisting>So for each <classname>B</classname> in the list, |
| the template defined for <classname>B</classname> is executed, for |
| each <classname>C</classname> in the collection the template defined |
| for <emphasis><classname>C</classname></emphasis> is invoked, and for |
| all others (which are then instances of <classname>A</classname>) the |
| default template is executed.</para> |
| </section> |
| |
| <section id="xpand_reference_file"> |
| <title>FILE<indexterm> |
| <primary>FILE</primary> |
| </indexterm></title> |
| |
| <para>The <varname>FILE</varname> statement redirects the output |
| generated from its body statements to the specified target. |
| <programlisting>«FILE expression [outletName]» |
| a sequence of statements |
| «ENDFILE»</programlisting>The target is a file in the file system whose name |
| is specified by the expression (relative to the specified target |
| directory for that generator run). The expression for the target |
| specification can be a concatenation (using the + operator). |
| Additionally, you can specify an identifier (a legal Java identifier) |
| for the name of the outlet<indexterm> |
| <primary>Outlet</primary> |
| </indexterm>. (See the configuration section for a description of |
| outlets). To produce the target file into subdirectories use "/" in |
| the expression result as separator for the directory structure.</para> |
| |
| <para>The body of a <varname>FILE</varname> statement can contain any |
| other statements.</para> |
| |
| <para><emphasis role="bold">Example: </emphasis><programlisting>«FILE InterfaceName + ".java"» |
| package «InterfacePackageName»; |
| |
| /* generated class! Do not modify! */ |
| public interface «InterfaceName» { |
| «EXPAND Operation::InterfaceImplementation FOREACH Operation» |
| } |
| «ENDFILE» |
| |
| |
| «FILE ImplName + ".java" MY_OUTLET» |
| package «ImplPackageName»; |
| |
| public class «ImplName» extends «ImplBaseName» |
| implements «InterfaceName» { |
| //TODO: implement it |
| } |
| «ENDFILE»</programlisting></para> |
| </section> |
| |
| <section id="xpand_reference_expand"> |
| <title>EXPAND<indexterm> |
| <primary>EXPAND</primary> |
| </indexterm></title> |
| |
| <para>The <varname>EXPAND</varname> statement "expands" another |
| <varname>DEFINE</varname> block (in a separate variable context), |
| inserts its output at the current location and continues with the next |
| statement. This is similar in concept to a subroutine call. |
| <programlisting>«EXPAND definitionName [(parameterList)] |
| [FOR expression | FOREACH expression [SEPARATOR expression] ] [ONFILECLOSE]»</programlisting>The |
| various alternative syntaxes are explained below.</para> |
| |
| <section id="xpand_reference_names"> |
| <title>Names</title> |
| |
| <para>If the <emphasis>definitionName</emphasis> is a simple |
| unqualified name, the corresponding <varname>DEFINE</varname> block |
| must be in the same template file.</para> |
| |
| <para>If the called definition is not contained in the same template |
| file, the name of the template file must be specified. As usual, the |
| double colon is used to delimit namespaces. <programlisting>«EXPAND TemplateFile::definitionName FOR myModelElement»</programlisting>Note |
| that you would need to import the namespace<indexterm> |
| <primary>Namespace</primary> |
| |
| <secondary>Import</secondary> |
| </indexterm> of the template file (if there is one). For instance, |
| if the template file resides in the java package |
| <varname>my.templates</varname>, there are two alternatives. You |
| could either write <programlisting>«IMPORT my::templates» |
| ... |
| «EXPAND TemplateFile::definitionName FOR myModelElement»</programlisting> or |
| <programlisting>«EXPAND my::templates::TemplateFile::definitionName |
| FOR myModelElement»</programlisting></para> |
| </section> |
| |
| <section> |
| <title>Lazy evaluation</title> |
| |
| <para>Appending the <indexterm> |
| <primary>ONFILECLOSE</primary> |
| </indexterm><classname>ONFILECLOSE</classname> statement defers |
| evaluation of the expanded definition until the current file is |
| closed with <classname>ENDFILE</classname>. This is of use when the |
| state required to create the text is collected during the evaluation |
| of the processed definition.<programlisting>«FILE ...» |
| ... |
| «EXPAND LazyEvaluatedDefinition FOREACH myCollection ONFILECLOSE» |
| ... |
| «ENDFILE» «REM»Now 'LazyEvaluatedDefinition' is called«ENDFILE»</programlisting></para> |
| |
| <para>A typical example for usage of the |
| <classname>ONFILECLOSE</classname> statement is when you want to |
| create a list of imports in a Java class, but the types that are |
| used should be added when they are used in the templates |
| later.</para> |
| |
| <para>The state, usually a collection, that is used for the lazy |
| expanded evaluation must be valid until the file is closed. This can |
| be achieved in two ways:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Span a <classname>LET</classname> statement around the |
| <classname>FILE</classname> statement that bounds an empty |
| collection</para> |
| |
| <para><programlisting>«LET (List[MyType]) {} AS importedTypes» |
| «FILE ...» |
| ... |
| «EXPAND ImportStatement FOREACH importedTypes ONFILECLOSE» |
| ... |
| «importedTypes.add(someType) -> ""-» |
| ... |
| «ENDFILE» |
| «ENDLET»</programlisting></para> |
| </listitem> |
| |
| <listitem> |
| <para>Use a <link linkend="create_extension"><emphasis>create |
| extension</emphasis></link> which returns an empty collection |
| and append elements to it. Since it is a create extension the |
| empty collection will be returned on first call and for each |
| subsequent call a reference to this collection will be returned |
| and not a new collection created.</para> |
| |
| <para><emphasis role="bold">Example:</emphasis></para> |
| |
| <para><filename>some/path/InsertionPoints.ext</filename>:</para> |
| |
| <para><programlisting>create List[Type] importedTypes (SomeType context) : (List[Type]) {}; </programlisting></para> |
| |
| <para>In Xpand use this as follows:</para> |
| |
| <para><programlisting>«EXTENSION some::path::InsertionPoints» |
| «FILE ...» |
| ... |
| «EXPAND ImportStatement FOREACH importedTypes() ONFILECLOSE» |
| ... |
| «importedTypes().add(someType) -> ""-» |
| ... |
| «ENDFILE» |
| «ENDLET»</programlisting></para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_for_vs_foreach"> |
| <title>FOR vs. FOREACH<indexterm> |
| <primary>FOR</primary> |
| </indexterm><indexterm> |
| <primary>FOREACH</primary> |
| </indexterm></title> |
| |
| <para>If <varname>FOR</varname> or <varname>FOREACH</varname> is |
| omitted the other template is called <varname>FOR this</varname>. |
| <programlisting>«EXPAND TemplateFile::definitionName»</programlisting> |
| equals <programlisting>«EXPAND TemplateFile::definitionName FOR this»</programlisting> |
| If <varname>FOR</varname> is specified, the definition is executed for |
| the result of the target expression. <programlisting>«EXPAND myDef FOR entity»</programlisting>If |
| <varname>FOREACH</varname> is specified, the target expression must |
| evaluate to a collection type<indexterm> |
| <primary>collection type</primary> |
| </indexterm>. In this case, the specified definition is executed for |
| each element of that collection. <programlisting>«EXPAND myDef FOREACH entity.allAttributes» </programlisting></para> |
| |
| <para>An <varname>EvaluationException</varname> will be thrown if the |
| specified target expression cannot be evaluated to an existing element |
| of the instantiated model or no suitable <varname>DEFINE</varname> |
| block can be found.</para> |
| |
| <section id="xpand_reference_specifying_a_separator"> |
| <title>Specifying a Separator<indexterm> |
| <primary>SEPARATOR</primary> |
| </indexterm></title> |
| |
| <para>If a definition is to be expanded <varname>FOREACH</varname> |
| element of the target expression it is possible to specify a |
| <varname>SEPARATOR</varname> expression: <programlisting>«EXPAND paramTypeAndName FOREACH params SEPARATOR ','»</programlisting>The |
| result of the separator expression<indexterm> |
| <primary>Expression</primary> |
| |
| <secondary>separator</secondary> |
| </indexterm> will be written to the output between each evaluation |
| of the target definition. Not <emphasis>after</emphasis> each one, |
| but rather only in <emphasis>between</emphasis> two elements. This |
| comes in handy for things such as comma-separated parameter |
| lists.</para> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_foreach"> |
| <title>FOREACH</title> |
| |
| <para>This statement expands the body of the |
| <varname>FOREACH</varname> block for each element of the target |
| collection<indexterm> |
| <primary>Collection</primary> |
| </indexterm> that results from the expression. The current element |
| is bound to a variable with the specified name in the current context. |
| <programlisting>«FOREACH expression AS variableName [ITERATOR iterName] [SEPARATOR expression]» |
| a sequence of statements using variableName to access the |
| current element of the iteration |
| «ENDFOREACH»</programlisting>The body of a <varname>FOREACH</varname> block |
| can contain any other statements; specifically |
| <varname>FOREACH</varname> statements may be nested.</para> |
| |
| <para>If <varname>ITERATOR</varname><indexterm> |
| <primary>ITERATOR</primary> |
| </indexterm> name is specified, an object of the type |
| <classname>xpand2::Iterator</classname> (see API doc for details) is |
| accessible using the specified name.</para> |
| |
| <para>The <varname>SEPARATOR</varname> expression works in the same |
| way as the one for <link |
| linkend="xpand_reference_specifying_a_separator"><varname>EXPAND</varname></link>.</para> |
| |
| <para><emphasis role="bold">Example: </emphasis><programlisting>«FOREACH {'A','B','C'} AS c ITERATOR iter SEPARATOR ','» |
| «iter.counter1» : «c» |
| «ENDFOREACH»</programlisting>The evaluation of the above statement results in |
| the following text: <programlisting>1 : A, |
| 2 : B, |
| 3 : C</programlisting></para> |
| </section> |
| |
| <section id="xpand_reference_if"> |
| <title>IF<indexterm> |
| <primary>IF</primary> |
| </indexterm></title> |
| |
| <para>The <varname>IF</varname> statement supports conditional |
| expansion. Any number of <varname>ELSEIF</varname><indexterm> |
| <primary>ELSEIF</primary> |
| </indexterm> statements is allowed. The <varname>ELSE</varname> |
| block is optional. Every <varname>IF</varname> statement must be |
| closed with an <varname>ENDIF</varname><indexterm> |
| <primary>ENDIF</primary> |
| </indexterm>. The body of an <varname>IF</varname> block can contain |
| any other statement, specifically, <varname>IF</varname> statements |
| may be nested. <programlisting>«IF expression» |
| a sequence of statements |
| [ «ELSEIF expression» ] |
| a sequence of statements ] |
| [ «ELSE» |
| a sequence of statements ] |
| «ENDIF»</programlisting></para> |
| </section> |
| |
| <section id="xpand_reference_protect"> |
| <title>PROTECT<indexterm> |
| <primary>PROTECT</primary> |
| </indexterm></title> |
| |
| <para>Protected Regions<indexterm> |
| <primary>Protected region</primary> |
| </indexterm> are used to mark sections in the generated code that |
| shall not be overridden again by the subsequent generator run. These |
| sections typically contain manually written code. <programlisting>«PROTECT CSTART expression CEND expression ID expression (DISABLE)?» |
| a sequence of statements |
| «ENDPROTECT»</programlisting>The values of |
| <classname>CSTART</classname><indexterm> |
| <primary>CSTART</primary> |
| </indexterm> and <classname>CEND</classname><indexterm> |
| <primary>CEND</primary> |
| </indexterm> expressions are used to enclose the protected regions |
| marker in the output. They should build valid comment beginning and |
| comment end strings corresponding to the generated target language |
| (e.g. <emphasis>"/*"</emphasis> and <emphasis>"*/"</emphasis> for |
| Java).</para> |
| |
| <para>The following is an example for Java: <programlisting>«PROTECT CSTART "/*" CEND "*/" ID ElementsUniqueID» |
| here goes some content |
| «ENDPROTECT»</programlisting>The ID is set by the <varname>ID</varname> |
| expression and must be <emphasis>globally unique</emphasis> (at least |
| for one complete pass of the generator). To assure this these IDs are |
| usually concatenated. Some model types (e.g. UML2 models) contain |
| identifiers that could be used, which can be read using the <link |
| linkend="stdlib_uid_xmlid"><methodname>xmlId()</methodname> function |
| from stdlib</link>.</para> |
| |
| <para>Generated target code looks like this: <programlisting>public class Person { |
| /*PROTECTED REGION ID(Person) ENABLED START*/ |
| This protected region is enabled, therefore the contents will |
| always be preserved. If you want to get the default contents |
| from the template you must remove the ENABLED keyword (or even |
| remove the whole file :-)) |
| /*PROTECTED REGION END*/ |
| }</programlisting>Protected regions are generated in enabled state<indexterm> |
| <primary>Protected region</primary> |
| |
| <secondary>Enable</secondary> |
| </indexterm> by default. Unless you manually disable<indexterm> |
| <primary>Protected region</primary> |
| |
| <secondary>Disable</secondary> |
| </indexterm> them, by removing the <varname>ENABLED</varname> |
| keyword, they will always be preserved.</para> |
| |
| <para>If you want the generator to generate disabled protected |
| regions, you need to add the <varname>DISABLE</varname> keyword inside |
| the declaration: <programlisting>«PROTECT CSTART '/*' CEND '*/' ID this.name DISABLE»</programlisting></para> |
| |
| <para>The produced target code won't contain the |
| <classname>ENABLED</classname> flag then. In this case |
| <classname>ENABLED</classname> has to be added to the target region to |
| activate the protected region. Disabling protected regions by default |
| has the advantage that the protected region default content in the |
| template can be changed and all not yet activated regions would |
| contain the changed code after regeneration.</para> |
| </section> |
| |
| <section id="xpand_reference_let"> |
| <title>LET<indexterm> |
| <primary>LET</primary> |
| </indexterm></title> |
| |
| <para><varname>LET</varname> lets you specify local |
| variables:<programlisting>«LET expression AS variableName» |
| a sequence of statements |
| «ENDLET»</programlisting>During the expansion of the body of the |
| <varname>LET</varname><indexterm> |
| <primary>LET</primary> |
| </indexterm> block, the value of the expression is bound to the |
| specified variable. Note that the expression will only be evaluated |
| once, independent from the number of usages of the variable within the |
| <varname>LET</varname> block.</para> |
| |
| <para><emphasis role="bold">Example:</emphasis> <programlisting>«LET packageName + "." + className AS fqn» |
| the fully qualified name is: «fqn»; |
| «ENDLET»</programlisting></para> |
| |
| <para>The variable value can not be reassigned within a |
| <classname>LET</classname> block.</para> |
| </section> |
| |
| <section id="xpand_reference_error"> |
| <title>ERROR<indexterm> |
| <primary>ERROR</primary> |
| </indexterm></title> |
| |
| <para>The <varname>ERROR</varname> statement aborts the evaluation of |
| the templates by throwing an |
| <varname>XpandException</varname><indexterm> |
| <primary>XpandException</primary> |
| </indexterm> with the specified message. <programlisting>«ERROR expression»</programlisting>Note |
| that you should use this facility very sparingly, since it is better |
| practice to check for invalid models using constraints on the |
| metamodel, and not in the templates!</para> |
| </section> |
| |
| <section id="xpand_reference_comments"> |
| <title>Comments<indexterm> |
| <primary>Xpand</primary> |
| |
| <secondary>Comments</secondary> |
| </indexterm></title> |
| |
| <para>Comments are only allowed outside of tags. <programlisting>«REM» |
| text comment |
| «ENDREM»</programlisting>Comments may not contain a REM<indexterm> |
| <primary>REM</primary> |
| </indexterm> tag, this implies that comments are not nestable. A |
| comment may not have a white space between the |
| <classname>REM</classname> keyword and its brackets.</para> |
| |
| <para><emphasis role="bold">Example:</emphasis> <programlisting>«REM»«LET expression AS variableName»«ENDREM» |
| a sequence of statements |
| «REM» «variableName.stuff» |
| «ENDLET»«ENDREM»</programlisting></para> |
| </section> |
| |
| <section id="xpand_reference_expression_statement"> |
| <title>Expression Statement<indexterm> |
| <primary>Xpand</primary> |
| |
| <secondary>Expression statements</secondary> |
| </indexterm></title> |
| |
| <para>Expressions support processing of the information provided by |
| the instantiated metamodel. <emphasis>Xpand</emphasis> provides |
| powerful expressions for selection, aggregation, and navigation. |
| <emphasis>Xpand</emphasis> uses the expressions sublanguage in almost |
| any statement that we have seen so far. The expression statement just |
| evaluates the contained expression and writes the result to the output |
| (using the <varname>toString()</varname> method of |
| <varname>java.lang.Object</varname>). Example: <programlisting>public class «this.name» {</programlisting>All |
| expressions defined by the expressions sublanguage are also available |
| in <emphasis>Xpand</emphasis>. You can invoke imported extensions. |
| (See the <emphasis><xref |
| linkend="r10_expressions_language" /></emphasis> and <emphasis><xref |
| linkend="Xtend_language" /> language reference</emphasis> for more |
| details).</para> |
| </section> |
| |
| <section id="xpand_reference_controlling_generation_of_white_space"> |
| <title>Controlling generation of whitespace</title> |
| |
| <para>If you want to omit the output of superfluous |
| whitespace<indexterm> |
| <primary>Whitespace</primary> |
| |
| <secondary>Omit</secondary> |
| </indexterm> you can add a minus sign just before any closing |
| bracket.</para> |
| |
| <para><emphasis role="bold">Example:</emphasis> <programlisting>«FILE InterfaceName + ".java"-» |
| «IF hasPackage-» |
| package «InterfacePackageName»; |
| «ENDIF-» |
| ... |
| «ENDFILE»</programlisting>The generated file would start with two new lines |
| (one after the <varname>FILE</varname> and one after the |
| <varname>IF</varname> statement) if the minus characters had not been |
| set.</para> |
| |
| <para>In general, this mechanism works as follows: If a statement (or |
| comment) ends with such a minus all preceding whitespace up to the |
| newline<indexterm> |
| <primary>Newline</primary> |
| </indexterm> character (excluded!) is removed. Additionally all |
| following whitespace including the first newline character |
| (<varname>\r\n</varname> is handled as one character) is also |
| removed.</para> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_aspect-oriented_programming_in_xpand"> |
| <title>Aspect-Oriented Programming in |
| <emphasis>Xpand</emphasis><indexterm> |
| <primary>AOP</primary> |
| </indexterm></title> |
| |
| <para>Using the workflow engine it is now possible to package |
| (<emphasis>e.g.</emphasis> zip) a written generator and deliver it as a |
| kind of black box (this is often called a cartridge<indexterm> |
| <primary>cartridge</primary> |
| </indexterm>). If you want to use such a generator but need to change |
| some small generation stuff, you can make use of the |
| <varname>AROUND</varname><indexterm> |
| <primary>AROUND</primary> |
| </indexterm> aspects. <programlisting>«AROUND qualifiedDefinitionName(parameterList)? FOR type» |
| a sequence of statements |
| «ENDAROUND» </programlisting><varname>AROUND</varname> lets you add templates |
| in an non-invasive way (you do not need to touch the generator |
| templates). Because aspects are invasive, a template file containing |
| <varname>AROUND</varname> aspects must be wrapped by configuration (see |
| next section).</para> |
| |
| <section id="xpand_reference_join_point_and_cut_syntax"> |
| <title>Join Point<indexterm> |
| <primary>Join point</primary> |
| </indexterm><indexterm> |
| <primary>AOP</primary> |
| |
| <secondary>Join point</secondary> |
| </indexterm> and Point Cut<indexterm> |
| <primary>Point cut</primary> |
| </indexterm><indexterm> |
| <primary>AOP</primary> |
| |
| <secondary>Point cut</secondary> |
| </indexterm> Syntax</title> |
| |
| <para>AOP is basically about weaving code into different points inside |
| the call graph of a software module. Such points are called |
| <emphasis>Join Points</emphasis><indexterm> |
| <primary>Join point</primary> |
| </indexterm>. In <emphasis>Xpand</emphasis>, there is only one join |
| point so far: a call to a definition.</para> |
| |
| <para>You specify on which join points the contributed code should be |
| executed by specifying something like a 'query' on all available join |
| points. Such a query is called a <emphasis>point |
| cut</emphasis><indexterm> |
| <primary>Join point</primary> |
| </indexterm>. <programlisting>«AROUND [pointcut]» |
| do stuff |
| «ENDAROUND»</programlisting> A point cut consists of a fully qualified name, |
| parameter types and the target type.</para> |
| |
| <section id="xpand_reference_definition_name"> |
| <title>Definition Name</title> |
| |
| <para>The definition name part of a point cut must match the fully |
| qualified name of the join point definition. Such expressions are |
| <emphasis>case sensitive</emphasis>. The asterisk character is used |
| to specify wildcards.</para> |
| |
| <para>Some examples: <programlisting>my::Template::definition // definitions with the specified name |
| org::eclipse::xpand2::* // definitions prefixed with 'org::eclipse::xpand2::' |
| *Operation* // definitions containing the word 'Operation' in it. |
| * // all definitions</programlisting></para> |
| </section> |
| |
| <section id="xpand_reference_parameter_types"> |
| <title>Parameter Types</title> |
| |
| <para>The parameters of the definitions we want to add our advice |
| to, can also be specified in the point cut. The rule is that the |
| type of the specified parameter must be the same or a supertype of |
| the corresponding parameter type (the dynamic type at runtime!) of |
| the definition to be called.</para> |
| |
| <para>Additionally, one can set a wildcard at the end of the |
| parameter list, to specify that there might be an arbitrary number |
| of parameters of any kind.</para> |
| |
| <para>Some examples: <programlisting>my::Templ::def() // templ def without parameters |
| my::Templ::def(String s) // templ def with exactly one parameter |
| // of type String |
| my::Templ::def(String s,*) // templ def with one or more parameters, |
| // where the first parameter is of type String |
| my::Templ::def(*) // templ def with any number of parameters</programlisting></para> |
| </section> |
| |
| <section id="xpand_reference_target_type"> |
| <title>Target Type</title> |
| |
| <para>Finally, we have to specify the target type. This is |
| straightforward: <programlisting>my::Templ::def() FOR Object// templ def for any target type |
| my::Templ::def() FOR Entity// templ def objects of type Entity</programlisting></para> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_proceeding"> |
| <title>Proceeding</title> |
| |
| <para>Inside an advice, you might want to call the underlying |
| definition. This can be done using the implicit variable |
| <varname>targetDef</varname>, which is of the type |
| <type>xpand2::Definition</type> and which provides an operation |
| <methodname>proceed()</methodname>that invokes the underlying |
| definition with the original parameters (Note that you might have |
| changed any mutable object in the advice before).</para> |
| |
| <para>If you want to control which parameters are to be passed to the |
| definition, you can use the operation <methodname>proceed</methodname> |
| (<classname>Object</classname> <varname>target</varname>, |
| <classname>List</classname> <varname>params</varname>). Please keep in |
| mind that no type checking is done in this context.</para> |
| |
| <para>Additionally, there are some inspection properties (like |
| <varname>name</varname>, <varname>paramTypes</varname>, etc.) |
| available.</para> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_generator_workflow_component"> |
| <title>Generator Workflow Component<indexterm> |
| <primary>Generator</primary> |
| |
| <secondary>Workflow component</secondary> |
| </indexterm></title> |
| |
| <para>This section describes the workflow component that is provided to |
| perform the code generation, i.e. run the templates. You should have a |
| basic idea of how the workflow engine works. A simple generator |
| component configuration could look as follows:<programlisting><component class="org.eclipse.xpand2.Generator"> |
| <fileEncoding value="ISO-8859-1"/> |
| <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel"> |
| <metaModelPackage value="org.eclipse.emf.ecore.EcorePackage"/> |
| </metaModel> |
| <expand value="somenamespace::example::Java::all FOR myModel"/> |
| |
| <!-- aop configuration --> |
| <advices value='somenamespace::example::Advices1, example::Advices2'/> |
| |
| <!-- output configuration --> |
| <outlet path='main/src-gen'> |
| <postprocessor class="org.eclipse.xpand2.output.JavaBeautifier"/> |
| <postprocessor class="org.eclipse.xtend.typesystem.xsd.XMLBeautifier"/> |
| </outlet> |
| <outlet name='TO_SRC' path='main/src' overwrite='false'> |
| <postprocessor class="org.eclipse.xpand2.output.JavaBeautifier"/> |
| <postprocessor class="org.eclipse.xtend.typesystem.xsd.XMLBeautifier"/> |
| </outlet> |
| |
| <!-- optional: protected regions configuration --> |
| <prSrcPaths value="main/src"/> |
| <prDefaultExcludes value="false"/> |
| <prExcludes value="*.xml"/> |
| </component></programlisting>Now, let us go through the different |
| properties one by one.</para> |
| |
| <section id="xpand_reference_main_configuration"> |
| <title>Main configuration</title> |
| |
| <para>The first thing to note is that the qualified Java name of the |
| component is <varname>org.eclipse.xpand2.Generator</varname>.</para> |
| </section> |
| |
| <section id="xpand_reference_encoding"> |
| <title>Encoding</title> |
| |
| <para>For <emphasis>Xpand</emphasis> it is important to have the file |
| encoding<indexterm> |
| <primary>File encoding</primary> |
| |
| <secondary>encoding</secondary> |
| </indexterm> in mind because of the |
| <foreignphrase>guillemet</foreignphrase> characters <indexterm> |
| <primary>Guillemet</primary> |
| </indexterm> « » used to delimit keywords and property access. The |
| <varname>fileEncoding</varname> property<indexterm> |
| <primary>Generator</primary> |
| |
| <secondary>fileEncoding property</secondary> |
| </indexterm> specifies the file encoding to use for reading the |
| templates, reading the protected regions and writing the generated |
| files. This property defaults to the default file encoding of your |
| JVM.</para> |
| |
| <para>In a team that uses different operating systems or locales it is |
| a good idea to set the file encoding fixed for the Xpand project and |
| share the settings. Typical encodings used are UTF-8 or ISO-8859-1, |
| but any encoding having guillemet brackets is fine also.<footnote> |
| <para>On Mac OSX the default encoding is MacRoman, which is not a |
| good choice, since other operating systems are not aware of this |
| encoding. It is recommended to set the encoding to some more |
| common encoding, e.g. UTF-8, maybe even for the whole |
| workspace.</para> |
| </footnote></para> |
| |
| <para>An false encoding can result in an error message of the |
| generator during runtime:</para> |
| |
| <programlisting>1108 ERROR WorkflowRunner - [ERROR]: no viable alternative at input 'Â' on line 1</programlisting> |
| |
| <para>In this case you have to configure the input encoding. A |
| <interface>ResourceManager</interface> is used to set the input |
| encoding. Use the <code>fileEncoding</code> property of the |
| <code>ResourceManager</code> inside the generator component to |
| configure the encoding of templates and extensions.</para> |
| |
| <para>Example for <emphasis>MWE</emphasis>:</para> |
| |
| <programlisting><component class="org.eclipse.xpand2.Generator"> |
| <metaModel idRef="mm_emf"/> |
| <expand |
| value="template::Template::main FOR model" /> |
| <outlet path="${src-gen}" > |
| <postprocessor class="org.eclipse.xpand2.output.JavaBeautifier" /> |
| </outlet> |
| <resourceManager class ="org.eclipse.xtend.expression.ResourceManagerDefaultImpl"> |
| <fileEncoding value="ISO-8859-1"/> |
| </resourceManager> |
| </component></programlisting> |
| |
| <para>Example for <emphasis>MWE2</emphasis>:</para> |
| |
| <programlisting>component = org.eclipse.xpand2.Generator { |
| metaModel = org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel {} |
| expand = "templates::Template::main FOREACH model" |
| outlet = { |
| path = targetDir |
| } |
| resourceManager = org.eclipse.xtend.expression.ResourceManagerDefaultImpl { |
| fileEncoding = "ISO-8859-1" |
| } |
| } |
| </programlisting> |
| |
| <para>The section <emphasis><xref |
| linkend="xpand_reference_output_configuration" /></emphasis> describes |
| how to configure the encoding of the generated files.</para> |
| </section> |
| |
| <section id="xpand_reference_metamodel"> |
| <title>Metamodel</title> |
| |
| <para>The property <varname>metaModel</varname><indexterm> |
| <primary>Generator</primary> |
| |
| <secondary>Metamodel configuration</secondary> |
| </indexterm> is used to tell the generator engine on which |
| metamodels the <emphasis>Xpand</emphasis> templates should be |
| evaluated. One can specify more than one metamodel here. Metamodel |
| implementations are required by the expression framework (see |
| <emphasis><xref linkend="r10_expressions_language" /></emphasis>) used |
| by <emphasis>Xpand2</emphasis>. In the example above we configured the |
| Ecore metamodel using the <classname>EMFMetaModel</classname> |
| implementation shipped with the core part of the |
| <emphasis>Xpand</emphasis> release.</para> |
| |
| <para>A mandatory configuration is the <varname>expand</varname> |
| property. It expects a syntax similar to that of the |
| <varname>EXPAND</varname> statement (described above). The only |
| difference is that we omit the <varname>EXPAND</varname><indexterm> |
| <primary>EXPAND</primary> |
| </indexterm> keyword. Instead, we specify the name of the |
| property.</para> |
| |
| <para>Examples: <programlisting><expand value="some::namespace::Template::define FOR mySlot"/></programlisting> |
| or: <programlisting><expand value="some::namespace::Template::define('foo') FOREACH {mySlot1,mySlot2}"/></programlisting>The |
| expressions are evaluated using the workflow context. Each slot is |
| mapped to a variable. For the examples above the workflow context |
| needs to contain elements in the slots <varname>'mySlot'</varname>, |
| <varname>'mySlot1'</varname> and <varname>'mySlot2'</varname>. It is |
| also possible to specify some complex expressions here. If, for |
| instance, the slot <varname>myModel</varname> contains a collection of |
| model elements one could write:<indexterm> |
| <primary>typeSelect</primary> |
| </indexterm> <programlisting><expand value="some::namespace::Template::define FOREACH myModel.typeSelect(Entity)"/></programlisting>This |
| selects all elements of type <emphasis>Entity</emphasis> contained in |
| the collection stored in the <varname>myModel</varname> slot.</para> |
| </section> |
| |
| <section id="xpand_reference_output_configuration" |
| xreflabel="Output configuration"> |
| <title>Output configuration</title> |
| |
| <para>The second mandatory configuration is the specification of so |
| called outlets (a concept borrowed from AndroMDA). Outlets<indexterm> |
| <primary>Outlet</primary> |
| </indexterm> are responsible for writing the generated files to |
| disk.</para> |
| |
| <para>Example <emphasis>MWE</emphasis>: <programlisting><component class="org.eclipse.xpand2.Generator"> |
| ... |
| <outlet path='main/src-gen'/> |
| <outlet name='TO_SRC' path='main/src' overwrite='false'> |
| <fileEncoding value='ISO-8859-1'/> |
| </outlet> |
| <fileEncoding value='ISO-8859-1'/> |
| ... |
| </component></programlisting>Example <emphasis>MWE2</emphasis>: |
| <programlisting>component = org.eclipse.xpand2.Generator { |
| metaModel = org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel {} |
| expand = "templates::Template::main FOREACH model" |
| outlet = {path = 'main/src-gen'} |
| outlet = { |
| name='TO_SRC' |
| path='main/src' |
| overwrite= false |
| fileEncoding = 'ISO-8859-1' |
| } |
| fileEncoding = 'ISO-8859-1' |
| ... |
| } |
| </programlisting>In the examples there are two outlets configured. The first |
| one has no name and is therefore handled as the default outlet. |
| Default outlets are triggered by omitting an outlet name: |
| <programlisting>«FILE 'test/note.txt'» |
| # this goes to the default outlet |
| «ENDFILE»</programlisting>The configured base path is |
| '<filename>main/src-gen</filename>', so the file from above would go |
| to '<filename>main/src-gen/test/note.txt</filename>'.</para> |
| |
| <para>The second outlet has a <varname>name</varname> ('TO_SRC') |
| specified. Additionally the flag <varname>overwrite</varname> is set |
| to <varname>false</varname> (defaults to <varname>true</varname>). The |
| following <emphasis>Xpand</emphasis> fragment <programlisting>«FILE 'test/note.txt' TO_SRC» |
| # this goes to the TO_SRC outlet |
| «ENDFILE»</programlisting>would cause the generator to write the contents to |
| '<filename>main/src/test/note.txt</filename>' if the file does not |
| already exist (the <varname>overwrite</varname> flag).</para> |
| |
| <para>Another option called <varname>append</varname> (defaults to |
| <varname>false</varname>) causes the generator to append the generated |
| text to an existing file. If <varname>overwrite</varname> is set to |
| <varname>false</varname> this flag has no effect.</para> |
| |
| <para>The encoding<indexterm> |
| <primary>File encoding</primary> |
| |
| <secondary>encoding</secondary> |
| </indexterm> of the generated files can be configured at two |
| different levels. A file encoding can be defined for the complete |
| generator component. Therefore the <emphasis>fileEncoding</emphasis> |
| property inside the component definition has to be used (see the |
| examples above). You can also define a file encoding at outlet level. |
| Therefore the <emphasis>fileEncoding</emphasis> property inside the |
| outlet definition has to be used.</para> |
| </section> |
| |
| <section id="xpand_reference_beautifier"> |
| <title>PostProcessor <indexterm> |
| <primary>PostProcessor</primary> |
| </indexterm></title> |
| |
| <para>Beautifying the generated code is a good idea. It is very |
| important that generated code looks good, because developers should be |
| able to understand it. On the other hand template files should look |
| good, too. It is thus best practice to write nice looking template |
| files and not to care how the generated code looks - and then you run |
| a beautifier over the generated code to fix that problem. Of course, |
| if a beautifier is not available, or if white space has syntactical |
| meaning (as in Python), you would have to write your templates with |
| that in mind (using the minus character before closing brackets as |
| described in a preceding section).</para> |
| |
| <para>The <emphasis>Xpand</emphasis> workflow component can be |
| configured with multiple beautifiers:<programlisting><outlet ...> |
| <postprocessor class="org.eclipse.xpand2.output.JavaBeautifier"/> |
| <postprocessor class="org.eclipse.xtend.typesystem.xsd.XMLBeautifier"/> |
| </outlet> |
| </programlisting>These are the two beautifiers delivered with |
| <emphasis>Xpand</emphasis>. If you want to use your own beautifier, |
| you would just need to implement the |
| <classname>PostProcessor</classname> Java interface<indexterm> |
| <primary>PostProcessor</primary> |
| </indexterm>: <programlisting>package org.eclipse.xpand2.output; |
| |
| public interface PostProcessor { |
| public void beforeWriteAndClose(FileHandle handle); |
| public void afterClose(FileHandle handle); |
| }</programlisting>The <varname>beforeWriteAndClose</varname> method is called |
| for each <varname>ENDFILE</varname> statement.</para> |
| |
| <para>PostProcessors can also be used for othermeans than formatting, |
| like line counting.</para> |
| |
| <section id="xpand_reference_javabeautifier"> |
| <title>JavaBeautifier</title> |
| |
| <para>The JavaBeautifier<indexterm> |
| <primary>JavaBeautifier</primary> |
| </indexterm> is based on the Eclipse Java formatter provides base |
| beautifying for Java files.</para> |
| </section> |
| |
| <section id="xpand_reference_xmlbeautifier"> |
| <title>XmlBeautifier</title> |
| |
| <para>The XmlBeautifier is based on <emphasis>dom4j</emphasis> and |
| provides a single option <varname>fileExtensions</varname> (defaults |
| to "<filename>.xml</filename>, <filename>.xsl</filename>, |
| <filename>.wsdd</filename>, <filename>.wsdl</filename>") used to |
| specify which files should be pretty-printed.</para> |
| </section> |
| |
| <section> |
| <title>CppBeautifier</title> |
| |
| <para>The CppBeautifier leverages CDT for formatting C/C++ sources. |
| Thus CDT is required to use this code formatter. To use this |
| beautifier the plugin |
| <package>org.eclipse.xpand.support.cdt</package> must be added to |
| the plugin dependencies.</para> |
| </section> |
| </section> |
| |
| <section id="xpand_reference_protected_region_configuration"> |
| <title>Protected Region Configuration</title> |
| |
| <para>Finally, you need to configure the protected region resolver, if |
| you want to use protected regions<indexterm> |
| <primary>Protected region</primary> |
| </indexterm>. <programlisting><prSrcPaths value="main/src"/> |
| <prDefaultExcludes value="false"/> |
| <prExcludes value="*.xml"/></programlisting>The |
| <emphasis>prSrcPaths</emphasis><indexterm> |
| <primary>prSrcPaths</primary> |
| </indexterm>property points to a comma-separated list of |
| directories. The protected region resolver will scan these directories |
| for files containing activated protected regions.</para> |
| |
| <para>There are several file names which are excluded by default: |
| <programlisting>RCS, SCCS, CVS, CVS.adm, RCSLOG, cvslog.*, tags, TAGS, .make.state, .nse_depinfo, *~, #*, |
| .#*, ',*', _$*,*$, *.old, *.bak, *.BAK, *.orig, *.rej, .del-*, *.a, *.olb, *.o, *.obj, |
| *.so, *.exe, *.Z,* .elc, *.ln, core, .svn</programlisting> If you do not want |
| to exclude any of these, you must set |
| <varname>prDefaultExcludes</varname> to false. <programlisting><prDefaultExcludes value="false"/></programlisting> |
| If you want to add additional excludes, you should use the prExcludes |
| property. <programlisting><prExcludes value="*.xml,*.hbm"/></programlisting></para> |
| |
| <note> |
| <para>It is bad practice to mix generated and non-generated code in |
| one artifact. Instead of using protected regions, you should try to |
| leverage the extension features of the used target language |
| (inheritance, inclusion, references, etc.) wherever possible. It is |
| very rare that the use of protected regions is an appropriate |
| solution.</para> |
| </note> |
| </section> |
| |
| <section> |
| <title>VetoStrategy<indexterm> |
| <primary>VetoStrategy</primary> |
| </indexterm></title> |
| |
| <para>The <emphasis>Xpand</emphasis> engine will generate code for |
| each processed <property>FILE</property> statement. This implies that |
| files are written that might not have changed to the previous |
| generator run. Normally it does not matter that files are rewritten. |
| There are at least two good reasons when it is better to avoid |
| rewriting of files:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>The generated source code will be checked in. In general it |
| is not the recommended way to go to check in generated code, but |
| sometimes you will have to. Especially with CVS there is the |
| problem that rewritten files are recognized as modified, even if |
| they haven't changed. So the problem arises that identical files |
| get checked in again and again (or you revert it manually). When |
| working in teams the problem even becomes worse, since team |
| members will have conflicts when checking in.</para> |
| </listitem> |
| |
| <listitem> |
| <para>When it can be predicted that the generator won't produce |
| different content before a file is even about to be created by a |
| FILE statement then this can boost performance. Of course it is |
| not trivial to predict that a specific file won't result in |
| different content before it is even created. This requires |
| information from a prior generator run and evaluation against the |
| current model to process. Usually a diff model would be used as |
| input for the decision.</para> |
| </listitem> |
| </orderedlist> |
| |
| <para>Case 1) will prevent file writing after a |
| <property>FILE</property> statement has been evaluated, case 2) will |
| prevent creating a file at all.</para> |
| |
| <para>To achieve this it is possible to add Veto Strategies to the |
| generator, which are implementations of interface |
| <classname>org.eclipse.xpand2.output.VetoStrategy</classname> or |
| <classname>org.eclipse.xpand2.output.VetoStrategy2</classname>. Use |
| <classname>VetoStrategy2</classname> if you implement your own.</para> |
| |
| <para><classname>VetoStrategy2</classname> declares two |
| methods:</para> |
| |
| <itemizedlist> |
| <listitem> |
| <para><methodname>boolean hasVetoBeforeOpen |
| (FileHandle)</methodname></para> |
| |
| <para>This method will be called before a file is being opened and |
| generated. Return true to suppress the file creation.</para> |
| </listitem> |
| |
| <listitem> |
| <para><methodname>boolean hasVeto (FileHandle)</methodname></para> |
| |
| <para>This method will be called after a file has been produced |
| and after all configured PostProcessors have been invoked. Return |
| true to suppress writing the file.</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>Veto Strategies are configured per Outlet. It is possible to add |
| multiple stratgy instances to each Outlet.</para> |
| |
| <para><programlisting> <component id="generator" class="org.eclipse.xpand2.Generator" skipOnErrors="true"> |
| <metaModel class="org.eclipse.xtend.typesystem.uml2.UML2MetaModel"/> |
| <expand value="templates::Root::Root FOR model"/> |
| <fileEncoding value="ISO-8859-1"/> |
| <outlet path="src-gen"> |
| <postprocessor class="org.eclipse.xpand2.output.JavaBeautifier"/> |
| <emphasis role="bold"><vetoStrategy class="org.eclipse.xpand2.output.NoChangesVetoStrategy"/></emphasis> |
| </outlet> |
| </component> |
| </programlisting>One <classname>VetoStrategy</classname> is already provided. |
| The |
| <classname>org.eclipse.xpand2.output.NoChangesVetoStrategy</classname> |
| <indexterm> |
| <primary>NoChangesVetoStrategy</primary> |
| </indexterm>is a simple implementation that will compare the |
| produced output, after it has been postprocessed, with the target |
| file. If the content is identical the strategy vetoes the file |
| writing. This strategy is effective, but has two severe |
| drawbacks:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>The file has been created at least in memory before. This |
| consumes time and memory. If applying code formatting this usually |
| implies that the file is temporarily written.</para> |
| </listitem> |
| |
| <listitem> |
| <para>The existing file must be read into memory. This also costs |
| time and memory.</para> |
| </listitem> |
| </orderedlist> |
| |
| <para>Much better would be to even prevent the creation of files by |
| having a valid implementation for the |
| <classname>hasVetoBeforeOpen()</classname> method. Providing an |
| implementation that predicts that files do not have to be created |
| requires domain knowledge, thus a standard implementation is not |
| available.</para> |
| |
| <para>The number of skipped files will be reported by the Generator |
| component like this:</para> |
| |
| <para><programlisting>2192 INFO - Generator(generator): generating <...> |
| 3792 INFO - <emphasis role="bold">Skipped writing of 2 files to outlet</emphasis> [default](src-gen) |
| </programlisting></para> |
| </section> |
| </section> |
| |
| <section id="aop_template_introduction"> |
| <title>Example for using Aspect-Oriented Programming in |
| <emphasis>Xpand</emphasis></title> |
| |
| <para><indexterm> |
| <primary>AOP</primary> |
| |
| <secondary>Xpand</secondary> |
| </indexterm>This example shows how to use aspect-oriented programming |
| techniques in <emphasis>Xpand</emphasis> templates. It is applicable to |
| EMF based and <emphasis>Classic</emphasis> systems. However, we explain |
| the idea based on the <emphasis>emfExample</emphasis>. Hence you should |
| read that before.</para> |
| </section> |
| |
| <section id="aop_template_the_problem"> |
| <title>The Problem</title> |
| |
| <para>There are many circumstances when template-AOP is useful. Here are |
| two examples:</para> |
| |
| <para><emphasis role="bold">Scenario 1:</emphasis> Assume you have a |
| nice generator that generates certain artifacts. The generator (or |
| cartridge) might be a third party product, delivered in a single JAR |
| file. Still you might want to adapt certain aspects of the generation |
| process <emphasis>without modifying the original |
| generator</emphasis>.</para> |
| |
| <para><emphasis role="bold">Scenario 2:</emphasis> You are building a |
| family of generators that can generate variations of the generate code, |
| e.g. Implementations for different embedded platforms. In such a |
| scenario, you need to be able to express those differences |
| (variabilities) sensibly without creating a non-understandable chaos of |
| <emphasis>if</emphasis> statements in the templates.</para> |
| </section> |
| |
| <section id="aop_template_example"> |
| <title>Example</title> |
| |
| <para>To illustrate the idea of extending a generator without "touching" |
| it, let us create a new project called |
| <classname>org.eclipse.demo.emf.datamodel.generator-aop</classname>. The |
| idea is that it will "extend" the original |
| <classname>org.eclipse.demo.emf.datamodel.generator</classname> project |
| introduced in the <emphasis>emfExample</emphasis>. So this new projects |
| needs to have a project dependency to the former one.</para> |
| |
| <section id="aop_template_example_templates"> |
| <title>Templates</title> |
| |
| <para>An AOP system always needs to define a join point<indexterm> |
| <primary>join point</primary> |
| </indexterm> model; this is, you have to define, at which locations |
| of a (template) program you can add additional (template) code. In |
| <emphasis>Xpand</emphasis>, the join points are simply templates (i.e. |
| <emphasis>DEFINE .. ENDDEFINE</emphasis>) blocks. An "aspect template" |
| can be declared <emphasis>AROUND</emphasis><indexterm> |
| <primary>AROUND</primary> |
| </indexterm> previously existing templates. If you take a look at |
| the <classname>org.eclipse.demo.emf.datamodel.generator</classname> |
| source folder of the project, you can find the |
| <filename>Root.xpt</filename> template file. Inside, you can find a |
| template called <classname>Impl</classname> that generates the |
| implementation of the JavaBean.</para> |
| |
| <programlisting language="Xpand">«DEFINE Entity FOR data::Entity» |
| «FILE baseClassFileName() » |
| // generated at «timestamp()» |
| public abstract class «baseClassName()» { |
| «EXPAND Impl» |
| } |
| «ENDFILE» |
| «ENDDEFINE» |
| |
| «DEFINE Impl FOR data::Entity» |
| «EXPAND GettersAndSetters» |
| «ENDDEFINE» |
| |
| «DEFINE Impl FOR data::PersistentEntity» |
| «EXPAND GettersAndSetters» |
| public void save() { |
| |
| } |
| «ENDDEFINE»</programlisting> |
| |
| <para>What we now want to accomplish is this: Whenever the |
| <emphasis>Impl</emphasis> template is executed, we want to run an |
| additional template that generates additional code (for example, some |
| kind of meta information for a given framework. The specific code at |
| this place is not important for the example here).</para> |
| |
| <para>So, in our new project, we define the following template |
| file:</para> |
| |
| <programlisting language="Xpand">«AROUND Impl FOR data::Entity» |
| «FOREACH attribute AS a» |
| public static final AttrInfo «a.name»Info = new AttrInfo( |
| "«a.name»", «a.type».class ); |
| «ENDFOREACH» |
| «targetDef.proceed()» |
| «ENDAROUND»</programlisting> |
| |
| <para>So, this new template wraps around the existing template called |
| <classname>Impl</classname> It first generates additional code and |
| then forwards the execution to the original template using |
| <methodname>targetDef.proceed()</methodname>. So, in effect, this is a |
| <varname>BEFORE</varname> advice. Moving the |
| <methodname>proceed</methodname> statement to the beginning makes it |
| an <varname>AFTER</varname> advice, omitting it, makes it an |
| override.</para> |
| </section> |
| |
| <section id="aop_template_example_workflow_file"> |
| <title>Workflow File<indexterm> |
| <primary>AOP</primary> |
| |
| <secondary>Workflow</secondary> |
| </indexterm></title> |
| |
| <para>Let us take a look at the workflow file to run this |
| generator:</para> |
| |
| <programlisting language="xml"><workflow> |
| <cartridge file="workflow.mwe"/> |
| <component adviceTarget="generator" |
| id="reflectionAdvice" |
| class="org.eclipse.xpand2.GeneratorAdvice"> |
| <advices value="templates::Advices"/> |
| </component> |
| </workflow></programlisting> |
| |
| <para>Mainly, what we do here, is to call the original workflow file. |
| It has to be available from the classpath. After this cartridge call, |
| we define an additional workflow component, a so called |
| <emphasis>advice component</emphasis>. It specifies |
| <emphasis>generator</emphasis> as its |
| <emphasis>adviceTarget</emphasis>. That means, that all the properties |
| we define inside this advice component will be added to the component |
| referenced by name in the <emphasis>adviceTarget</emphasis> instead. |
| In our case, this is the generator. So, in effect, we add the |
| <classname><advices value="templates::Advices" /></classname> to |
| the original generator component (without invasively modifying its own |
| definition). This contributes the advice templates to the |
| generator.</para> |
| </section> |
| |
| <section id="aop_template_example_running_the_new_generator"> |
| <title>Running the new generator</title> |
| |
| <para>Running the generator produces the following code:</para> |
| |
| <programlisting language="Java">public abstract class PersonImplBase { |
| public static final AttrInfo |
| nameInfo = new AttrInfo("name", String.class); |
| public static final AttrInfo |
| name2Info = new AttrInfo("name2", String.class); |
| private String name; |
| private String name2; |
| |
| public void setName(String value) { |
| this.name = value; |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| |
| public void setName2(String value) { |
| this.name2 = value; |
| } |
| |
| public String getName2() { |
| return this.name2; |
| } |
| }</programlisting> |
| </section> |
| </section> |
| |
| <section id="aop_template_more_ao"> |
| <title>More Aspect Orientation</title> |
| |
| <para>In general, the syntax for the |
| <emphasis>AROUND</emphasis><indexterm> |
| <primary>AROUND</primary> |
| </indexterm> construct is as follows:</para> |
| |
| <programlisting language="Expand">«AROUND fullyQualifiedDefinitionNameWithWildcards |
| (Paramlist (*)?) FOR TypeName» |
| do Stuff |
| «ENDAROUND»</programlisting> |
| |
| <para>Here are some examples:</para> |
| |
| <programlisting>«AROUND *(*) FOR Object»</programlisting> |
| |
| <para>matches all templates</para> |
| |
| <programlisting>«AROUND *define(*) FOR Object»</programlisting> |
| |
| <para>matches all templates with <emphasis>define</emphasis> at the end |
| of its name and any number of parameters</para> |
| |
| <programlisting>«AROUND org::eclipse::xpand2::* FOR Entity»</programlisting> |
| |
| <para>matches all templates with namespace |
| <emphasis>org::eclipse::xpand2::</emphasis> that do not have any |
| parameters and whose type is Entity or a subclass</para> |
| |
| <programlisting>«AROUND *(String s) FOR Object»</programlisting> |
| |
| <para>matches all templates that have exactly one |
| <classname>String</classname> parameter</para> |
| |
| <programlisting>«AROUND *(String s,*) FOR Object»</programlisting> |
| |
| <para>matches all templates that have at least one |
| <classname>String</classname> parameter</para> |
| |
| <programlisting>«AROUND my::Template::definition(String s) FOR Entity»</programlisting> |
| |
| <para>matches exactly this single definition</para> |
| |
| <para>Inside an <varname>AROUND</varname>, there is the variable |
| <varname>targetDef</varname>, which has the type |
| <classname>xpand2::Definition</classname>. On this variable, you can |
| call <methodname>proceed</methodname>, and also query a number of other |
| things:</para> |
| |
| <programlisting>«AROUND my::Template::definition(String s) FOR String» |
| log('invoking '+«targetDef.name»+' with '+this) |
| «targetDef.proceed()» |
| «ENDAROUND»</programlisting> |
| </section> |
| </section> |
| |
| <section id="r10_profiler"> |
| <title>Profiler</title> |
| |
| <para>The <emphasis>ProfilerComponent</emphasis> allows you to measure the |
| time each check, Xtend function or Xpand define needed to be executed in |
| your workflow. It does so by acting as a callback of the |
| <emphasis>CheckComponent</emphasis>, <emphasis>XtendComponent</emphasis> |
| and <emphasis>XpandComponent</emphasis> where the time of each call will |
| be stored in a profiling model. From this data the profiler eventually |
| derives execution times with and without children, callers/callees with |
| the corresponding call counts and finally a call graph with respect to |
| recursive calls. A set of Xpand templates can transform the model to an |
| HTML report or a text file in the GNU GProf format.</para> |
| |
| <figure> |
| <mediaobject> |
| <imageobject role="fo"> |
| <imagedata fileref="images/Xpand/profiler.png" scale="30" /> |
| </imageobject> |
| |
| <imageobject role="html"> |
| <imagedata fileref="images/Xpand/profiler.png" scale="95" /> |
| </imageobject> |
| </mediaobject> |
| |
| <title>Sample HTML output of the profiler</title> |
| </figure> |
| |
| <para>Use the <emphasis>ProfilerComponent</emphasis> to wrap other |
| components inside a workflow. Denote a <emphasis>resultSlot</emphasis> |
| where the profiler stores the model in the end. Then, refer to this |
| component via <emphasis>idRef</emphasis> as a callback. As soon as the |
| component-tag of the profiler closes, it stores the derived profiling |
| model in the given slot. You are free to transform this model or you can |
| re-use one of the templates that come with profiler.</para> |
| |
| <programlisting> |
| <component id="profiler" class="org.eclipse.xtend.profiler.ProfilerComponent"> |
| <resultSlot value="profilingResult" /> |
| |
| <component class="org.eclipse.xtend.check.CheckComponent"> |
| <vetoableCallback idRef="profiler" /> |
| ... |
| </component> |
| <component class="org.eclipse.xtend.XtendComponent"> |
| <vetoableCallback idRef="profiler" /> |
| ... |
| </component> |
| <component class="org.eclipse.xpand2.Generator"> |
| <vetoableCallback idRef="profiler" /> |
| ... |
| </component> |
| </component> |
| |
| <component class="org.eclipse.xpand2.Generator" fileEncoding="ISO-8859-1"> |
| <metaModel idRef="mm"/> |
| <expand value="org::eclipse::xtend::profiler::templates::Html::Main FOR profilingResult"/> |
| <outlet overwrite="true" path="profiling"/> |
| </component> |
| </programlisting> |
| |
| <para>Currently, there are two different templates available to render the |
| profiling model <itemizedlist> |
| <listitem> |
| <para>org::eclipse::xtend::profiler::templates::Html::Main</para> |
| </listitem> |
| |
| <listitem> |
| <para>org::eclipse::xtend::profiler::templates::GProf::Main</para> |
| </listitem> |
| </itemizedlist></para> |
| |
| <para>The Xpand Wizard will produce a workflow called |
| <emphasis>workflowWithProfiler.mwe</emphasis> that demonstrates the |
| capabilities of the profiler. It puts the result in the folder |
| <emphasis>profiling</emphasis>.</para> |
| </section> |
| </chapter> |