Thursday, April 10, 2008

ODA Ecore Getting Started Guide

Overview


Now that the ODA Ecore enablement plug-ins are in the Data Tools Project incubator at Eclipse, a quick-start guide seems in order.
The Oda Ecore enablement plug-in provides a JDBC-like interface for querying object models defined with EMF. These queries are written with OCL and use the EMF Model Query OCL bridge.
The Oda Ecore UI plug-in contributes two Wizards for configuring BIRT reports: the first allows specification of a Data Source; the second provides a graphical interface for constructing queries.

Dependencies


In order to use the Oda Ecore enablement plug-in, you will need to install the following dependencies:

Datatools Connectivity
EMF Query
EMF Model Query OCL Integration
The Data Tools Platform Enablement for JDBC

In addition, to run the example, you will need to install the following plug-ins:
BIRT (for reporting query results)
EMF Examples (for the extlibrary sample)

This example has been tested so far with Ganymede M5 and M6.

Enablement Plug-ins In CVS


First, we will need to download the Oda Ecore enablement plug-ins from CVS.
File -> Import -> Projects from CVS
The Host is dev.eclipse.org
The Repository path is /cvsroot/datatools
Unless you are a committer, the User is anonymous.
Checkout from CVS at dev.eclipse.org

Browse to org.eclipse.datatools.incubator/plugins, select
org.eclipse.datatools.enablement.oda.ecore
org.eclipse.datatools.enablement.oda.ecore.ui
and check them out to your workspace.
Find the ODA Ecore enablement plug-ins in the datatools incubator.

Model File


You will also need a model file. You can create one yourself using New -> Other -> Example EMF Model Creation Wizards -> EXTLibrary Model or you can use the sample model below, which sets up two libraries with an assortment of books, some of which are in one library or both libraries, and authors, some of whom are also in one or both libraries:

my.extlibrary


<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:extlib="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0">
<extlib:Library address="1000 4th Ave, Seattle, WA 98104" name="Seattle Public Library">
<stock xsi:type="extlib:Book" title="David Copperfield" category="Biography" author="/0/@writers.1"/>
<stock xsi:type="extlib:Book" title="Nicholas Nickleby" category="Biography" author="/0/@writers.1"/>
<stock xsi:type="extlib:Book" title="The Deerslayer" category="Biography" author="/1/@writers.0"/>
<stock xsi:type="extlib:Book" title="The Last of the Mohicans" category="Biography"/>
<writers firstName="James" lastName="Fenimore Cooper"/>
<writers firstName="Charles" lastName="Dickens" books="/0/@stock.1 /1/@stock.3 /0/@stock.0"/>
</extlib:Library>
<extlib:Library address="308 Kirkland Ave, Kirkland, WA 98033" name="Kirkland Public Library">
<stock xsi:type="extlib:Book" title="The Last of the Mohicans" category="Biography" author="/1/@writers.0"/>
<stock xsi:type="extlib:Book" title="The Pioneers"/>
<stock xsi:type="extlib:Book" title="Around The World In 80 Days" category="ScienceFiction" author="/1/@writers.2"/>
<stock xsi:type="extlib:Book" title="The Pickwick Papers" author="/0/@writers.1"/>
<writers firstName="James Fenimore" lastName="Cooper" books="/0/@stock.2 /1/@stock.0"/>
<writers firstName="Charles" lastName="Dickens"/>
<writers address="" firstName="Jules" lastName="Verne" books="/1/@stock.2"/>
</extlib:Library>
</xmi:XMI>



my.extlibrary example file
Feel free to modify the model file with the extlibrary example editor.

Launch Eclipse


There is nothing special to do here. Just open the Run Configurations Dialog, create a new Eclipse Application runtime configuration, if you do not already have one, and hit Run.
An example Eclipse runtime configuration.

BIRT Report


In this new Eclipse runtime, create a new General project. Here we can call it hello.world.oda.ecore. Drop your .extlibrary sample file into the new project. Now create a new Blank BIRT Report and switch to the Reporting perspective. Here we use the Wizard's default name for the report. It should be automatically opened in an editor.
A new BIRT report in your worspace.

Data Source


In the Data Explorer View, specify a new Data Source. From the Wizard, select Ecore ODA Data Source on the first page.
Select a new Ecore Data Source.

On the second page, select the sample .extlibrary file in your workspace and "Ping" it to make sure that it can be loaded.
Select and test the sample file.

Data Set


Again in the Data Explorer View, specify a new Data Set. The Data Source that we just created should be automatically selected on the first page of the Wizard, and the Wizard should know that the Data Set Type is Ecore ODA Data Set.
Select the Ecore Data Source we just created.

On the next two pages, we will choose the Model Object that we are querying from, the columns that we are selecting to use for the query result, and we will fill in the OCL Condition that will restrict the query results.
A very simple query would be to find the names of all writers in all libraries. For this, we will
select Writer -> name,
from the invariant Writer,
where self.oclIsKindOf(Writer)

Add the OCL Conditional Query and select an Invariant.
If you do not select an invariant from the combo, then all EAttributes and EReferences in the Model will be available for selection. Try it out!

Select the Columns for the Report.
The EAttributes and EReferences displayed are based on the invariant selection on the previous Wizard page. Here, a Writer is also an Addressable Person, so the EStructuralFeatures for those model elements are also available.


After we are finished with the Wizard, we can Edit the Data Set properties, preview the results of the query, and modify our query conditional, selected columns and invariant.
Edit the Invariant and Query condition.
Edit the Invariant and the conditional query.

Edit the Columns for reporting.
Edit the columns that will appear in the report.

Preview the Query Results.
Preview the query results. You can switch among the pages, so preview different conditional queries, different invariants and different column selections if you feel adventurous!

Run a Report


Now that we have a Data Set, we can drag it into our report to add all the column data (in this case, there is just one column name). From the Preview subtab, we can then preview the report and see our query results!
Drag the Data Set into the report to set up the result set table.

Backport


A backport of these plug-ins for Eclipse 3.2, JDK 1.4 and EMF 2.2 is also available, but future support is not guaranteed. A description of these plug-ins and a comparison between the latest version and the backport is available here.

Part Two


Continue to part 2 of this guide for more advanced features ->

33 comments:

Joheinz said...

Tim,

could you give me an update about the status of the ODA ecore project. I think it is brilliant, got it working with the latest CVS version and BIRT 2.3.1 so that I can define datasets and datasources. the datasets work as a preview. However if I drag even the simplest dataset into an empty report I get an exception "the choice value any is not allowed" and the report reports a problem about the column databinding being not defined. Any suggestions? Thanks Markus

Tim Myer said...

Hi Markus,
Thanks for your feedback on the ODA Ecore enablement plug-in. I will admit that not much development has happened in the last couple of months, but lately we have resumed talks about what more woud be necessary to mark the plug-in as feature-complete.
What you are seeing sounds like a bug, however. I will try to re-create the issue locally.
I do have a few questions, first: what is the EMF model you are using? what is the query? which columns have you selected?
You might also consider opening the issue in Eclipse Bugzilla so that it gets more traction and can be tracked.
Thanks again.
-----Tim-----

Tim Myer said...

Hi Markus,
I just installed a clean version of Eclipse 3.4.1 with the latest version of BIRT and I am seeing the error you wrote about.
Thank you for bringing this to our attention. It appears that something may have changed in the latest BIRT release that is causing the problem. I will admit that these plug-ins were last tested with the Ganymede 3.4.0 release and we do not have a CI environment or automated tests. They are on our radar. I will investigate this specific error over the weekend and give you more information then.
Thank you for your patience.
--------Tim--------

Tim Myer said...

Hi Markus,
Please take a look at the latest code in CVS, and if you could give it a try, I would be grateful. The issue was that, in the recent past, BIRT must have made the column type mandatory, but the Ecore-Oda plug-in had been non-specific about column types. For now, all column types are treated explicitly as Strings (as they had been implicitly previously).
This change has been made in HEAD and in the driver backport (although, that is probably not necessary considering the nature of the bug).
Let me know if you have any more questions, and many thanks for your support and your bug report!
------Tim------

RubenL said...

Hi Tim,
Very nice work this plugin.
I am trying to get the latest SVN version to work on Ganymede, all goes well except when creating a Data Set, I can't get it to show the library entities, it seems to only show ecore's metatypes (EClass EAttribute, EClass EAnnotation and so on).
Do you have an idea of what it could be?
Thanks already, Ruben

Tim Myer said...

Hi Ruben,

Thanks for your interest in the ODA Ecore Enablement plug-in. I am not entirely sure what might be causing only Ecore types to show up. Do you mind if I ask what model file you are using as your Data Source?
Thanks.

-----Tim-----

RubenL said...

Hello Tim,

I am using the exact same file as was in your original post. I am using these versions:
- Eclipse Version: 3.4.0 Build id: I20080617-2000
- BIRT 2.3.1

Do you have any idea?
Thanks, Ruben

Tim Myer said...

Hi Ruben,

Off the top of my head, I am not sure. I just did a clean install of Eclipse 3.4.1 with all the dependencies and did not have thesame problem -- I see EClass Writer, EAttribute name, etc.
Just a couple of other questions: which version of the EMF Examples plug-in do you have installed; did you install the EMF Examples from the update site or from a zip download?

Could you set the following flags on the Arguments tab of your runtime configuration:

Program arguments: -os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -console -consoleLog

VM arguments: -Xms40m -Xmx512m -XX:PermSize=128m

Do you see any errors in the console output when you run the second Eclipse instance and setup the Data Source and Data Set?

Thanks,
-----Tim-------

Boj said...

Hi Tim,

You've saved my life with this plugin XD. I'm doing a report generator which uses ecore files as sources. I'm doing it by code but I don't know how to create by code a datasource with your plugin. Can you help me?

Thx in advance,

Borja

Boj said...

Hi,

Problem solved, thx.

Tim Myer said...

Hi Borja,
Thank you for your interest in the ODA Ecore Enablement plug-in. I am not entirely sure what your use-case is, as I have never created a DataSource programmatically, but perhaps the following code snippet might help. It is a very simple Plugin test that sets up the ODA Ecore Driver by pointing it to a sample library file; then it sets up query parameters programmatically as in the demo: an invariant, a query and some columns; finally it runs the query and iterates over the result set. If this is NOT what you were looking for, then perhaps you might take a look at ProfileManager#createProfile using "org.eclipse.datatools.enablement.oda.ecore" as the data source ID.

package org.eclipse.datatools.enablement.oda.ecore.impl;

import java.util.Properties;
import org.eclipse.datatools.connectivity.oda.IConnection;
import org.eclipse.datatools.connectivity.oda.IQuery;
import org.eclipse.datatools.connectivity.oda.IResultSet;
import org.eclipse.datatools.enablement.oda.ecore.Constants;
import org.junit.Test;

public class DriverTest {
@Test
public void testCreateProfile() throws Exception {
final Driver driver = new Driver();
final IConnection connection = driver.getConnection(null);
final Properties properties = new Properties();
properties.setProperty(Constants.CONNECTION_MODEL_URI,
"file:/C:/programming/workspaces/runtime-Oda-Ecore-3.4.1/hello.world.oda.ecore/my.extlibrary");
connection.open(properties);
final IQuery query = connection.newQuery(null);
query.setProperty(Constants.OCL_ECORE_INVARIANT, "Writer");
query.setProperty(Constants.CONNECTION_COLUMN_DEFINITIONS, "Person::firstName,Person::lastName");
query.prepare("self.oclIsKindOf(Writer)");
final IResultSet resultSet = query.executeQuery();
while (resultSet.next()) {
final String firstName = resultSet.getString("Person::firstName");
final String lastName = resultSet.getString("Person::lastName");
System.out.println("firstName=[" + firstName + "] lastName=[" + lastName + "]");
}
}
}

Let me know if that helps! Thanks.
-----Tim----

Tim Myer said...

Hi Borja,

Darn. I posted just a few minutes too late. How did you end up solving the problem?
Thanks.

-----Tim-----

Boj said...

Hi Tim,

I solved the problem getting plugin.xml and going to Extensions. I see u have a MODEL_URI as property and I'm using it with the setProperty method.

Thx

Boj said...

Hi Tim,

I have my rptdesign file created through birt graphic editors. Then I modify the path to ecore file by code. When I generate the report I get an error cause connection cannot be opened. Any idea? I put my code below. Thx in advance.

ReportDesignHandle design = null;

//Create a design engine configuration object.
DesignConfig dConfig = new DesignConfig( );
DesignEngine dEngine = new DesignEngine( dConfig );

// Create a session handle, using the system locale.
SessionHandle session = dEngine.newSessionHandle( null );

// Create a handle for an existing report design.
try {
design = session.openDesign( DESIGN );
} catch (DesignFileException e) {
this.exceptionCaught( e, "Report " + DESIGN + " not opened!\nReason is " + e.toString( ) );
return false;
}

// Find the data source by name
DataSourceHandle dso = design.findDataSource( "Glossary" );
String source = "";
try {
source = FileLocator.toFileURL(
org.eclipse.core.runtime.Platform
.getBundle("TestPlugin").
getResource("sources")).getPath() + SOURCE;
} catch (IOException e2) {
this.exceptionCaught( e2, "IO Problem!!" );
return false;
}
try {
dso.setProperty(Constants.CONNECTION_MODEL_URI, new String(source));
} catch (SemanticException e1) {
this.exceptionCaught( e1, "Wrong Path!!" );
return false;
}
MODEL_URI = dso.getProperty( Constants.CONNECTION_MODEL_URI ).toString();

// Save the design
try {
design.save();
} catch (IOException e) {
this.exceptionCaught( e, "Report " + DESIGN + " not saved!" );
return false;
}

// Close the design
design.close();
return true;

Tim Myer said...

Hi Borja,
I was able to get your example code running without the following block:

try {
source = FileLocator.toFileURL(
org.eclipse.core.runtime.Platform
.getBundle("TestPlugin").
getResource("sources")).getPath() + SOURCE;
} catch (IOException e2) {
this.exceptionCaught( e2, "IO Problem!!" );
return false;
}

It is not clear to me what the purpose of this code is. It looks like you are getting a file path and using that as the Model URI, but I am not entirely sure what this URI looks like, if the URI can be parsed by EMF, or if the bundle would be available in the instance of Eclipse that is running the test. Could you perhaps do a println of the source String and post it?
Thanks.

----Tim----

Boj said...

Hi, Tim

The source String looks like this:
/home/boj/Documents/workspace/TestPlugin/sources/My.glossary

My.glossary is an ecore file that represents a project glossary.

Boj said...

Hi Tim,

Is there any way I can test if EMF can parse the path I'm using?

Thx

Tim Myer said...

Hi Borja,

Great question. Actually, your question contains the answer: write a JUnit plug-in test case! You can write such a test just as you would write any other JUnit test case, but you would run it as a JUnit plug-in test. A sample test case is a few comments above.
By the way, have you tried to use the URI file://home/boj/Documents/workspace/TestPlugin/sources/My.glossary
In your own test case, you might try to instantiate a ResourceSetImpl, load your Resource into the resource set and then introspect its elements.
Let me know if that works!
Thanks.

----Tim----

Boj said...

Hi Tim,

I get the problem solved. When using the setProperty method of the data source handle, I set the second parameter as EMF URI instead of setting it as String and... that's it!!

Thx for your help.

Joheinz said...

Tim,

this is Markus again from the original post. Somehow I did not receive notifications for answers, but would like to thank you that you took care. I will try if I get along now. Thanks Markus

Joel Rosi-Schwartz said...

Hi Tim,,

I plan on using CDO to persist the EMF for our project. Is it possible to point your ODA datasouce to CDO or do you rely on the ecore being in a serialised file?

Thanks,
Joel

Tim Myer said...

Hi Joel,
Thanks for your interest in the ODA Ecore enablement plug-ins.
As far as I know, there is nothing specific in the loading of EMF Resources by the plug-in that would require the EMF model to be serialized. You should be able to use any model as a data source, as long as that model can be reached through a URI. In the data source selection wizard, a user is presented with 3 options for loading a model: file system, workspace, and other URI. I have not tried it myself, but I would imagine CDO resources are available by loading them by URI into a ResourceSet. I do not know what the protocol or form of that URI might be, so you might need to do some experimenting.
Hope that helps, and I look forward to hearing about anything you might discover or any uses you might have for this plug-in.
Thanks!
-------Tim--------

Tim Myer said...

Hi Markus,
Sorry to hear that you did not receive notification -- I usually try to respond within a couple of days (depending on workload at my paying job).
In any case, I hope the updates fixed the problem that you were seeing and look forward to hearing other suggestions for improving the plug-ins.
Thanks again for your find!
------Tim------

Joel Rosi-Schwartz said...

Thanks Tim. I am a bit away from being able to experiment with this, but I will certainly give you feedback when I do.

Fyi, CDO uses the Net4J protocol to access the model along these lines:

CDOSession session = ...;
CDOView view = session.openView();
CDOResource resource = view.getResource("/path/to/resource");
...
view.close();

So it will not be as straightforward as simply providing a URI. I can imagine, though, that a custom URI implementation could be registered to massage away the underlying details.

Joel

Boj said...

Hi Tim,

I have my first birt-ecore plugin done. Thnx for your help.

Now I need to generate a report based on a complex ecore model -I mean that this ecore model references some other ecore models and I need to process them as a whole. So I'm trying to access referenced models throught the datasource pointed to the main model. Is this possible?

Thnx in advance,

Borja

Boj said...

Hi Tim,

I forgot one important thing. I'm doing the report throught BIRT's Design Editor, not by code. I'm using Eclipse Ganymede (3.4.1) and BIRT 2.3.1

Thnx.

Boj said...

Hi Tim,

This is Borja. I've solved my problem. I couldn't read the whole model because EMF does a lazy load. Now, I can read the whole model forcing an instant load.

Thnx

Tim Myer said...

Hi Borja,
Nice find! Thanks for following up with the status.
---Tim---

Joheinz said...

Hi oda-ecore maniacs :-),

did someone ever try to run the engine ouside of a eclipse context. I did setup the report engine, but I get an exception like:


5.04.2009 16:55:41 org.eclipse.birt.data.engine.odaconsumer.Driver doGetDriverManifest
SCHWERWIEGEND: Cannot process data source extension configuration.
java.lang.IllegalArgumentException: org.eclipse.datatools.enablement.oda.ecore
at org.eclipse.datatools.connectivity.oda.util.manifest.ManifestExplorer.getExtensionManifest(ManifestExplorer.java:200)
at org.eclipse.birt.data.engine.odaconsumer.Driver.doGetDriverManifest(Driver.java:147)
at org.eclipse.birt.data.engine.odaconsumer.Driver.findDataSourceExtensionConfig(Driver.java:123)
at org.eclipse.birt.data.engine.odaconsumer.Driver.getDriverExtensionConfig(Driver.java:78)
at org.eclipse.birt.data.engine.odaconsumer.Driver.getExtensionConfig(Driver.java:60)
at org.eclipse.birt.data.engine.odaconsumer.Driver.getDriverHelper(Driver.java:93)
at org.eclipse.birt.data.engine.odaconsumer.DriverManager.getDriverHelper(DriverManager.java:98)
at org.eclipse.birt.data.engine.odaconsumer.ConnectionManager.openConnection(ConnectionManager.java:144)
at org.eclipse.birt.data.engine.executor.DataSource.newConnection(DataSource.java:188)
at org.eclipse.birt.data.engine.executor.DataSource.open(DataSource.java:176)
at org.eclipse.birt.data.engine.impl.DataSourceRuntime.openOdiDataSource(DataSourceRuntime.java:209)
at org.eclipse.birt.data.engine.impl.QueryExecutor.openDataSource(QueryExecutor.java:390)
at org.eclipse.birt.data.engine.impl.QueryExecutor.prepareExecution(QueryExecutor.java:309)
at org.eclipse.birt.data.engine.impl.PreparedQuery.doPrepare(PreparedQuery.java:493)
at org.eclipse.birt.data.engine.impl.PreparedDataSourceQuery.produceQueryResults(PreparedDataSourceQuery.java:189)
at org.eclipse.birt.data.engine.impl.PreparedDataSourceQuery.execute(PreparedDataSourceQuery.java:177)
at org.eclipse.birt.data.engine.impl.PreparedOdaDSQuery.execute(PreparedOdaDSQuery.java:143)
at org.eclipse.birt.report.data.adapter.impl.DataRequestSessionImpl.execute(DataRequestSessionImpl.java:480)
at org.eclipse.birt.report.engine.data.dte.DteDataEngine.doExecuteQuery(DteDataEngine.java:115)
at org.eclipse.birt.report.engine.data.dte.AbstractDataEngine.execute(AbstractDataEngine.java:253)
at org.eclipse.birt.report.engine.executor.ExecutionContext.executeQuery(ExecutionContext.java:1755)
at org.eclipse.birt.report.engine.executor.QueryItemExecutor.executeQuery(QueryItemExecutor.java:76)
at org.eclipse.birt.report.engine.executor.TableItemExecutor.execute(TableItemExecutor.java:62)
at org.eclipse.birt.report.engine.internal.executor.dup.SuppressDuplicateItemExecutor.execute(SuppressDuplicateItemExecutor.java:43)
at org.eclipse.birt.report.engine.internal.executor.wrap.WrappedReportItemExecutor.execute(WrappedReportItemExecutor.java:46)
at org.eclipse.birt.report.engine.internal.executor.l18n.LocalizedReportItemExecutor.execute(LocalizedReportItemExecutor.java:34)
at org.eclipse.birt.report.engine.layout.html.HTMLBlockStackingLM.layoutNodes(HTMLBlockStackingLM.java:64)
at org.eclipse.birt.report.engine.layout.html.HTMLPageLM.layout(HTMLPageLM.java:90)
at org.eclipse.birt.report.engine.layout.html.HTMLReportLayoutEngine.layout(HTMLReportLayoutEngine.java:99)
at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.doRun(RunAndRenderTask.java:157)
at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.run(RunAndRenderTask.java:70)
....


I added the birt runtime libs to the classpath as well as the two oda-ecore jars, but to no avail so far. I would be grateful for any hint.

Markus

Unknown said...

Are there any news on your problem Joheinz. I also have the same problem when I try to create the report with the Birt runtime.

Joheinz said...

Hi Gabriel,

no, I do not have a solution, mostly because I did not investigate it much further. It is a long time ago :-)

JSP said...
This comment has been removed by the author.
JSP said...

I have a problem with a register ecore, because this one is not found it... throw a exception like that when I want define a data set EMF

org.eclipse.emf.ecore.xmi.PackageNotFoundException: Package with uri 'http:///XXX_Metamodel.ecore' not found. (platform:/resource/XXX, 2, 167)

Anyone can help me, because I dont know how register a ecore file at RSA, RDA, InfoSphere...