| h2(#OCLinEcoreTutorial). OCLinEcore tutorial |
| |
| This tutorial was updated for Eclipse Indigo; Eclipse 3.7, EMF 2.7, OCL 3.1. |
| * Since it was prepared before release, the precise 3.1.0.v20110nnnn qualification in screenshots is earlier than final release. |
| |
| h3. Overview |
| |
| In this example you will |
| * Create an Ecore model using the OCLinEcore text editor |
| * Create a dynamic instance of that Ecore model |
| * Enrich the Ecore model with OCL using the OCLinEcore text editor |
| * Validate the model and observe the OCL enrichments |
| * Use the Interactive OCL Console to execute the OCL enrichments |
| |
| The above is all performed without generating any Java code; |
| the models exploit EMF's dynamic capabilities and the OCL integration. |
| |
| You may then |
| * Create an Ecore genmodel |
| * Generate Java code for the Ecore model that invokes the OCL expressions. |
| |
| h3. References |
| |
| This tutorial assumes that the reader is familiar with generating models using EMF. |
| The reader is referred to "Generating an EMF Model":../../org.eclipse.emf.doc/tutorials/clibmod/clibmod.html. |
| |
| Other references: |
| * The Object Constraint Language: Getting Your Models Ready for MDA. Jos Warmer and Anneke Kleppe. (Addison-Wesley Object Technology) |
| * "OCL specification":http://www.omg.org/technology/documents/modeling_spec_catalog.htm#OCL. |
| * "OCLinEcore wiki page":http://wiki.eclipse.org/MDT/OCLinEcore. |
| |
| h3(#Installation). Installing the Eclipse OCL Examples |
| |
| The OCLinEcore editor is not part of the core OCL functionality included in the |
| Eclipse Modeling Tools Package, so although you may have OCL installed and be able |
| to read this tutorial via the *Help->Help Contents->OCL Documentation*, you may |
| not have the OCL examples installed. |
| |
| An easy way to test whether you have the OCL Examples installed is |
| to right click on a *.ecore file and see whether *OCLinEcore (Ecore) Editor* |
| appears in the *Open With* submenu. |
| |
| If OCL is not installed at all, or if just the examples are not installed, |
| the following installation step will automatically install the OCL Examples |
| and all required projects such as *EMF*, *UML2*, *MWE2*, *Xpand* |
| and *Xtext*. |
| |
| Left-click on *Help* in the title-bar then left-click on *Install New Software...* |
| and select the *Indigo - http://download.eclipse.org/releases/indigo* update site |
| from the pull-down menu to *Work with* and be patient while the available updates |
| are identified. Then select *OCL Examples and Editors* from the *Modeling* |
| category. |
| |
| !{width:50%}images/4100-install_software_top.png(Install Software Top Half)! |
| |
| !{width:50%}images/4100-install_software_bottom.png(Install Software Bottom Half)! |
| |
| Select *Next*. |
| |
| !{width:50%}images/4100-install_details.png(Install Details)! |
| |
| Select *Next* again and read the license agreement. Set to accept it. |
| |
| !{width:50%}images/4100-install_license.png(Install License)! |
| |
| Select *Finish* and be patient while the software is downloaded and installed. |
| Select *Restart Now* when prompted to do so. |
| |
| h3. Troubleshooting |
| |
| Eclipse Modeling Projects have a large number of classes and so require a |
| large amount of PermGen space on a Sun JVM. If you are using default Eclipse |
| startup settings you are liable to encounter OutOfMemoryExceptions. Therefore |
| follow the advice in "How do I start Eclipse":http://wiki.eclipse.org/IRC_FAQ#How_do_I_start_Eclipse.3F |
| and set XX:PermSize to at least 64M, either on your Eclipse command line, or your |
| Eclipse shortcut or in the *eclipse.ini* adjacent to *eclipse.exe*. |
| |
| The editor currently provides syntax and semantic validation. It does not yet apply |
| the well-formedness validation, so some problems may be unreported. This is work in progress. Sometimes spurious errors are displayed, which may go away with a *Save*, |
| but may require an editor close and reopen. |
| |
| h3. Using the OCLinEcore text editor for Ecore |
| |
| There are many different (compatible) ways to create and edit Ecore models. |
| * An Ecore Model may be created from an XSD schema file |
| * An Ecore Model may be created from a Rose model file |
| * An Ecore Model may be created from annotated Java file |
| * The Sample Ecore Editor provides tree editing |
| * The Ecore Tools project provides graphical editing |
| * Papyrus provides UML editing that may be converted to Ecore |
| |
| Here we introduce the OCLinEcore editor that provides text editing, which is |
| appropriate when a non-trivial amount of OCL enrichment is required. |
| |
| All the above approaches update a *.ecore file, so the user is free to choose |
| whichever editing approach is best suited for the planned changes. |
| |
| h4. Create a New EMF Project |
| |
| We will first create a new project for this example; so invoke *File->New->Project...* |
| (left-click the *File* menu, then left-click *New*, then left-click *Project...*). |
| |
| In the *New Project* dialog left-click to expand *Eclipse Modeling Framework*, then left-click to select |
| *Empty EMF Project*. |
| |
| !{width:50%}images/4100-new_project.png(New Project)! |
| |
| Left-click on *Next* and in the *New Empty EMF Project* dialog type *Tutorial* as the project name. |
| |
| !{width:50%}images/4100-new_empty_emf_project.png(New Empty EMF Project)! |
| |
| Left-click on *Finish*. |
| |
| h4. Create a New Ecore Model |
| |
| We will now create a new model for this example. |
| |
| With many alternative editors for *.ecore files, the Eclipse platform is not always sure which to use; it seems to prefer the OCLinEcore editor over the Sample Ecore Editor, so there is an easy and harder way to create a new file. |
| |
| For either approach, first right-click on the *model* folder |
| in the *Tutorial* project to define the target folder and pop-up the context-sensitive menu. |
| |
| The easy was is to select *New->File...* and enter *Tutorial.ecore*. If this opens up a text editor showing "package Tutorial" ... then the easy way works. You may skip the 'harder way' since you have already successfully opened your Ecore file with the OCLinEcore editor. |
| |
| The harder way is to select *New->Other...*. |
| |
| In the *New* dialog left-click to expand *Eclipse Modeling Framework*, then left-click to select |
| *Ecore Model*. |
| |
| !{width:50%}images/4100-new_ecore_model.png(New Ecore Model)! |
| |
| Left-click on *Next* and then in the *New Ecore Model* dialog type *Tutorial.ecore* as the file name. |
| |
| !{width:50%}images/4100-new_ecore_model_dialog.png(New Ecore Model Dialog)! |
| |
| Left-click on *Finish*; The *Sample Ecore* editor for *Tutorial.ecore* may open showing a tree view of a single unnamed @EPackage@. Alternatively the *OCLinEcore* editor may be opened by default, so you can skip the next change-editor step. |
| |
| !{width:50%}images/4100-empty_ecore.png(Empty Ecore Editor)! |
| |
| Close the editor by left-clicking the cross on the editor tab. |
| |
| h4(#OCLinEcoreMetamodel). Edit Ecore Model as OCLinEcore |
| |
| We will now open the Ecore model using the OCLinEcore text editor and provide some |
| initial content. |
| |
| Right-click on the *Tutorial.ecore* file to pop-up the context-sensitive menu |
| and select *Open With->OCLinEcore (Ecore) Editor*. |
| |
| An almost empty text file appears showing the module, the package keyword and an empty name and conbsequently an error. |
| |
| !{width:50%}images/4100-empty_oclinecore.png(Empty OCLinEcore Editor)! |
| |
| Now type (or cut and paste) the following text into the editor and save the file. |
| |
| !images/4100-metamodel.png(Example Metamodel)! |
| "[Text for cut and paste]":../references/4100-metamodel.oclinecore |
| |
| The syntax is defined in "OCLinEcore":#OCLinEcore. It emulates OMG specifications with |
| 'name : type[multiplicity] { properties }'. |
| |
| * @import@ associates an alias with an external EPackage. |
| * @package@ introduces an EPackage with name, nsPrefix and nsURI. |
| * @class@ introduces an EClass with name and optional superclasses. |
| * @attribute@ introduces a property with a datatype type (an EAttribute). |
| * @property@ introduces a property with a class type (an EReference). |
| * @#@ introduces an opposite role name. |
| * @_'xxx'@ escapes an awkward or reserved word identifier. |
| |
| The import URI is the URI of a Package, so in the example the @http://www.eclipse.org/emf/2002/Ecore@ |
| is the URI of the model, @#@ is the fragment separator and @/@ is the path to |
| the Package at the root of the XMI document. |
| |
| Completion assist (Ctrl Space) may be used for syntax assistance. |
| |
| Format (Ctrl-Shift F) may be used to auto-format a selected range. |
| |
| In order to discover a syntax for which completion assist is insufficient, |
| you may use the Sample Ecore Editor on a test file to create the kind of Ecore element |
| that you require, and then open the test file with the OCLinEcore editor to see the |
| corresponding textual syntax. |
| |
| h4. The Tutorial Meta-Model |
| |
| The example meta-model models a library with members and books |
| and loans of books to members. It may be viewed graphically using the Ecore Tools |
| (not part of this tutorial). |
| |
| !{width:50%}images/4100-ecore_diagram.png(Ecore Diagram)! |
| |
| Note that this diagram is an Ecore Diagram rather than a UML Diagram and so the default multiplicities for attributes is Ecore's [0..1] rather than OCLinEcore's and UML's [1..1]. |
| |
| Note also that the OCL types @String@ and @Integer@ map |
| to @EString@ and @EBigInteger@ in Ecore. |
| |
| h3. Create a Dynamic Model Instance |
| |
| At this point a corresponding EMF tutorial would show how to generate Java code for |
| the meta-model and an editor for the meta-model. Here we are concerned with modeling, so we will |
| continue with the models alone. |
| |
| In order to create a model from the meta-model, we require the meta-model to exist as a file so that both meta-model and model editors can reference it. Therefore save the meta-model to a file by clicking the close cross on the editor tab and answering *Yes* when prompted to save changes. Now reopen the metamodel by selecting *Tutorial.ecore* and selecting *Open With->OCLinEcore (Ecore) editor*. |
| |
| bq.. |
| It is necessary to explicitly specify *Open With->OCLinEcore (Ecore) editor* once to ensure that the Eclipse platform registers your preference for the OCLinEcore rather than Sample Ecore Editor. |
| p. |
| |
| In the outline, double-click on *Library* to select it and then right-click to show the context-sensitive menu |
| and then left-click on *Create Dynamic Instance...* to start to create a |
| new Dynamic Model with @Library@ at its root. |
| |
| (If the Outline is not visible, it may be made visible by *Window->Show View->Outline*.) |
| |
| (If @Library@ is not visible in the Outline, left-click on *OCLinEcore Document* |
| to expand it, then on *tutorial* to expand it.) |
| |
| !{width:50%}images/4100-create_dynamic_instance.png(Create Dynamic Instance)! |
| |
| In the *Create Dynamic Instance* dialog select *Tutorial/model* as |
| the parent folder for the *Tutorial.xmi* dynamic model instance and left-click *Finish*. |
| |
| !{width:50%}images/4100-create_dynamic_instance_dialog.png(Create Dynamic Instance Dialog)! |
| |
| The model is automatically opened for editing using the Sample Reflective Ecore Editor, |
| which gives a tree-like presentation of the model. The properties of each node can |
| be seen in the Properties View. |
| |
| !{width:50%}images/4100-initial_model.png(Initial Model)! |
| |
| (If the Properties View is not visible, right-click within the editor and left-click on |
| *Show Properties View*.) |
| |
| From the right-button menu for @Library@ use *New Child->Books Book* twice, |
| use *New Child->Loans Loan* once and *New Child->Members Member* three times |
| to populate the model with two books, one loan and three members. |
| |
| Left-click to select each of the Books and Members in turn and enter a name |
| such as @b1@ or @m2@ using the Properties View. Specify that b1 |
| has one copy and that b2 has 2 copies. |
| |
| !{width:50%}images/4100-model_copies.png(Model Showing Copies)! |
| |
| The books and members now have distinct titles in the outline. |
| When you left-click to select the Loan and edit its Book and Member attributes, |
| the associated pull-down has meaningful entries. Specify that the Loan is for |
| @b2@ by @m3@. |
| |
| !{width:50%}images/4100-model_pull_down.png(Model Pull-Down Menu)! |
| |
| The configuration so far is simple, three members, two books and one loan. We can |
| validate that this by right-clicking on the @Library@ node, and left-clicking |
| to *Validate* @Library@ and all its children. |
| |
| !{width:50%}images/4100-validate_menu.png(Validate Menu)! |
| |
| Since the model is so simple, it is difficult to have anything wrong; most of |
| the illegal modeling options such as a Loan composing rather than referencing a |
| Book are prevented by the Editor's enforcement of the meta-model. |
| |
| !{width:50%}images/4100-validation_successful.png(Validation Successful)! |
| |
| (If you have an error at this point, a *Details* button will lead you to some |
| diagnostics that may clarify the problem. Pasting the following XMI should also |
| resolve an entry problem.) |
| |
| bc.. |
| <?xml version="1.0" encoding="ASCII"?> |
| <tut:Library xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xmlns:tut="http://www.eclipse.org/mdt/ocl/oclinecore/tutorial" |
| xsi:schemaLocation="http://www.eclipse.org/mdt/ocl/oclinecore/tutorial |
| Tutorial.ecore"> |
| <books name="b1" copies="1"/> |
| <books name="b2" copies="2"/> |
| <loans book="//@books.1" member="//@members.2"/> |
| <members name="m1"/> |
| <members name="m2"/> |
| <members name="m3"/> |
| </tut:Library> |
| p. |
| |
| We will now create two further identical loans of @b2@ by @m3@. This |
| may conveniently be performed by left-clicking to select the existing loan, |
| typing Ctrl-C to copy it, left-clicking to select the @Library@ as the new parent, |
| then typing Ctrl-V to paste it on the library. Repeat so that there are three |
| identical loans. |
| |
| Validating the library should still be successful, although it is clearly wrong for |
| the two copies of @b2@ to participate in three loans. |
| |
| h3. Enrich the meta-model with OCL |
| |
| The semantic constraint that a book cannot be borrowed more times than there are books |
| is a simple example of a constraint that cannot be expressed by simple multiplicities; |
| a more powerful capability is required that may potentially require evaluation |
| of functions of almost arbitrary complexity. The Object Constraint Language |
| provides this capability. |
| |
| The constraint can be realized as an invariant on a book that specifies that |
| that (the size of the (selection of loans involving the book)) is less than or equal |
| to (the number of copies of the book). |
| |
| Close the *Tutorial.xmi* editor before modifying its meta-model. (Beware that |
| a wide variety of unpleasant errors can occur if the meta-model is changed after |
| the model is loaded.) |
| |
| Add the invariant shown below to the meta-model. |
| |
| !images/4100-metamodel2.png(Example Metamodel with Invariant)! |
| "[Text for cut and paste]":../references/4100-metamodel2.oclinecore |
| |
| The required semantic is expressed by the @SufficientCopies@ invariant constraint for a Book. |
| For a valid model the SufficientCopies invariant must always be true. |
| |
| If you reopen the *Tutorial.xmi* editor and invoke *Validate* for the @Library@, |
| you will now get a validation error. Left click *Details* for details. |
| |
| !{width:50%}images/4100-validation_unsuccessful.png(Validation Unsuccessful)! |
| |
| The *Details* identifies that the @SufficientCopies@ invariant is not |
| satisfied for the @b2@ book. |
| |
| If you now change the first loan so that @b1@ is borrowed and then validate |
| again, the problem is resolved. It is alright for @m3@ to borrow |
| the one copy of @b1@ and the two copies of @b2@. |
| |
| Before introducing a further constraint of no duplicate loans, we will show |
| how OCL expressions can be exercised. OCL is a very powerful compact language; |
| the example hides a loop over all the loans. More complex examples may easily |
| involve three or four levels of hidden loops on a single line, but may equally |
| easily have simple errors. It is therefore helpful to simplify expressions |
| and use helper operations and properties to modularise them. These may then be |
| exercised using the OCL Console. |
| |
| h3(#OCLinEcoreTutorial-Console). The OCL Console |
| |
| The OCL Console supports interactive execution of an OCL expression in the |
| context of a model instance. |
| |
| To make the OCL Console visible, first make the *Console* view visible by |
| *Window->Show View->Console*. Then right click on the *Open Console* and |
| left click on *Interactive OCL*. |
| |
| !{width:50%}images/4100-ocl_console_menu.png(OCL Console menu)! |
| |
| Alternatively, you can just invoke *Show OCL Console* from the right button menu |
| within the *Sample Ecore Editor* or *Sample Reflective Ecore Editor*. |
| |
| The *Interactive OCL* console comprises two main text panes. The upper pane |
| displays results. The lower pane supports entry of queries. |
| |
| Left-click to select the @Library@ in the *Tutorial.xmi* as the context |
| for a query, and then type @books@ followed by a new line into the lower |
| pane of the console. |
| |
| The result of evaluating this query for the Library is shown. |
| |
| !{width:50%}images/4100-books_query.png(Books Query)! |
| |
| Substantial OCL queries spanning many lines may be entered and so the cursor up |
| and cursor down keys move across lines. If you want to access an earlier query, |
| you may use the *Page Up* or *Page Down* keys to save typing them again. |
| |
| You can examine the execution of the earlier query by selecting each of the books |
| in turn and executing @library.loans->select(book=self)@, to see that @b1@ |
| has one Loan and @b2@ two. |
| |
| h3(#OCLinEcoreTutorialHelpers). Helper Features and Operations |
| |
| We will now introduce some helper attributes and operations to make |
| the OCL clearer and provide a richer meta-model API. |
| Close the *Tutorial.xmi* editor and modify the meta-model to include |
| the derived @loans@ property and the helper operation @isAvailable()@. |
| Simplify the invariant to use the derived property. |
| |
| !images/4100-metamodel3.png(Example Metamodel with Features)! |
| "[Text for cut and paste]":../references/4100-metamodel3.oclinecore |
| |
| Note that the derived property must also be volatile to avoid problems when |
| a model is loaded but has no content. |
| |
| The derived property is visible in the *Properties* view. |
| |
| !{width:50%}images/4100-derived_property.png(Derived Property)! |
| |
| The helper operation can be evaluated in the *Console* view by selecting book @b2@ and typing @isAvailable()@ for execution. |
| |
| !{width:50%}images/4100-helper_operation.png(Helper Operation)! |
| |
| We will now add further helpers and constraints to enforce an |
| at most two loans per member policy and to require loans to be unique. |
| |
| (Don't forget to close *Tutorial.xmi* while changing its meta-model.) |
| |
| !images/4100-metamodel4.png(Example Metamodel with More Features)! |
| "[Text for cut and paste]":../references/4100-metamodel4.oclinecore |
| |
| The additional @books@ property may be evaluated in the OCL |
| Console to show which books each member has on loan. The property may also be seen in the *Properties* view. |
| |
| Select the library again and invoke *Validate* from the right button menu. |
| There are now two validation failures. |
| |
| !{width:50%}images/4100-two_validation_errors.png(Two Validation Errors)! |
| |
| h3. Generating Java Code |
| |
| We have shown how OCL may be used to enrich Ecore meta-models, how model instances can be created |
| and validated and how expressions can be evaluated, all without generating any Java code. |
| |
| Exactly the same facilities are available if you do generate Java code and as a result you gain some speed |
| benefits. In the Eclipse OCL 3.1.0 (Indigo) release the generated Java code for OCL is |
| interpreted and so the speed gains occur only for the EMF models. In a future release, |
| the OCL will be converted to Java giving significant speed improvements. |
| |
| Generating Java code is exactly the same as for any other EMF project; with one important |
| difference; you must set *Operation Reflection* |
| to true. |
| |
| Select the *Tutorial.ecore* file and invoke *New->Other...* from the right button menu |
| and select *Eclipse Modeling Framework* and *EMF Generator Model*. |
| |
| !{width:50%}images/4100-new_emf_generator.png(New EMF Generator)! |
| |
| Select *Next*. |
| |
| !{width:50%}images/4100-new_emf_generator_model.png(New EMF Generator Model)! |
| |
| Select *Next*. |
| |
| !{width:50%}images/4100-new_emf_generator_model_ecore.png(New EMF Generator Model for Ecore)! |
| |
| Select *Next*. |
| |
| !{width:50%}images/4100-new_emf_generator_model_load.png(New EMF Generator Model Load)! |
| |
| Select *Load* and *Next*. |
| |
| !{width:50%}images/4100-new_emf_generator_model_packages.png(New EMF Generator Model Packages)! |
| |
| Select *Finish*. |
| |
| The *Tutorial.genmodel* editor opens. |
| |
| !{width:50%}images/4100-gen_model.png(Gen Model)! |
| |
| Most of the default settings are suitable. The one that is not is highlighted. Select the |
| root *Tutorial* and scroll down the *Properties* view and set *Operation Reflection* |
| to true. |
| |
| You may now invoke *Generate Model Code* from the right button menu of either *Tutorial* |
| to generate Java models that invoke OCL. |
| |
| !{width:50%}images/4100-gen_model_menu.png(Gen Model Menu)! |
| |
| h4. Java Details |
| |
| You can check that the OCL appears in your Java by looking at *TutorialValidator.java* |
| where you'll find the OCL expression as a String awaiting compilation at run-time, and |
| the validate invocation that triggers that compilation and execution. |
| |
| bc.. |
| protected static final String MEMBER__AT_MOST_TWO_LOANS__EEXPRESSION = "\n" + |
| "\t\t\tloans->size() <= 2"; |
| |
| public boolean validateMember_AtMostTwoLoans(Member member, DiagnosticChain |
| diagnostics, Map<Object, Object> context) { |
| return |
| validate |
| (TutorialPackage.Literals.MEMBER, |
| member, |
| diagnostics, |
| context, |
| "http://www.eclipse.org/emf/2002/Ecore/OCL", |
| "AtMostTwoLoans", |
| MEMBER__AT_MOST_TWO_LOANS__EEXPRESSION, |
| Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| 0); |
| } |
| p. |
| |
| Similarly in *BookImpl* you will find the declaration of a cached delegate and |
| the dynamic invocation that provokes the first time compilation. |
| |
| bc.. |
| protected static final EOperation.Internal.InvocationDelegate |
| IS_AVAILABLE__EINVOCATION_DELEGATE = ((EOperation.Internal) |
| TutorialPackage.Literals.BOOK___IS_AVAILABLE).getInvocationDelegate(); |
| |
| public boolean isAvailable() { |
| try { |
| return (Boolean) |
| IS_AVAILABLE__EINVOCATION_DELEGATE.dynamicInvoke(this, null); |
| } |
| catch (InvocationTargetException ite) { |
| throw new WrappedException(ite); |
| } |
| } |
| p. |
| |
| The OCL expression for the invocation delegate may be found in *TutorialPackageImpl.createOCLAnnotations()*. |
| |
| bc.. |
| addAnnotation |
| (getBook__IsAvailable(), |
| source, |
| new String[] { |
| "body", "loans->size() < copies" |
| }); |
| p. |
| |
| h4. API Invariants |
| |
| The invariants we have used so far do not contribute to the class API. |
| |
| If you want to have fine grain control of which validations are performed, |
| perhaps because in some incremental context not all are appropriate, you |
| may use the operation form of an invariant. |
| |
| bc.. |
| class Book |
| { |
| operation sufficientCopies(diagnostics : ecore::EDiagnosticChain, |
| context : ecore::EMap<ecore::EJavaObject,ecore::EJavaObject>) : Boolean |
| { |
| body: library.loans->select(book=self)->size() <= copies; |
| } |
| attribute name : String; |
| attribute copies : Integer; |
| property library#books : Library; |
| } |
| p. |
| |
| Note that the operation must have a Boolean return (true for valid) and |
| diagnostics and context arguments. |
| |
| h3. Summary |
| |
| To illustrate how to work with the OCL and Ecore as models we have |
| * Created an Ecore meta-model using the OCLinEcore text editor |
| * Created a dynamic model instance from that meta-model |
| * Enriched the meta-model with embedded OCL |
| * Used the embedded OCL while validating the model |
| * Queried the model usng the Interactive OCL Console. |
| * Evaluated OCL embedded in the meta-model in the Console. |
| |
| To use OCL and Ecore as generated Java models we have |
| |
| * Generated Java that exploits the embedded OCL. |
| |