This tutorial assumes that you have followed these other tutorials in the specified order:
the goal here is to show how, with just some extra lines of code added to the EMF generated plugins, we can have our model persisted and maintained on a database.
We will use MySQL as the target database, so make sure you have the access to such a database server (you can always download it at http://www.mysql.com/downloads/mysql). We’ll use the “test” schema (pre-loaded empty while installing MySQL); anyway you can use another schema simply by changing the connection properties (ahead in this tutorial).
In order to follow the next steps we’ll need some additional plugins for Eclipse. Here you can find details on how to install them
Teneo Setup for Eclipse 4.2 ÔÇô Juno
Let’s start from the end of the previous tutorial and open file plugin.xml of the editor plugin which was generated automatically by EMF
(it.rcpvision.rcptutorial.model.editor).
Open tab Dependencies
and add the following plugins among Dependences (press button Add… in section Required Plug-ins):
- org.eclipse.emf.teneo.hibernate
- org.hibernate
- com.mysql.jdbc
save (Ctrl-S) and open class LibraryEditorAdvisor.java, in particular the method initialize().
and proceed with the following changes:
first of all let’s mark the method as @generated not; this way, when a new generation will take place (let’s say for a model evolution), our code change will not be overwritten.
now let’s add the following source code after the instruction
configurer.setSaveAndRestore(true);
//*************** Initialize Teneo Hibernate DataStore ************************************* HbDataStore hbds = (HbDataStore) HbHelper.INSTANCE.createRegisterDataStore("MyDb"); //Set Database properties Properties props = new Properties(); props.setProperty(Environment.DRIVER, "com.mysql.jdbc.Driver"); props.setProperty(Environment.URL, "jdbc:mysql://localhost:3306/test"); props.setProperty(Environment.USER, "root"); props.setProperty(Environment.PASS, "admin"); props.setProperty(Environment.DIALECT, org.hibernate.dialect.MySQL5Dialect.class.getName()); props.setProperty(Environment.SHOW_SQL, "true"); props.setProperty(Environment.HBM2DDL_AUTO, "update"); // props.setProperty(Environment.HBM2DDL_AUTO, "create-drop"); hbds.setDataStoreProperties(props); //Register EMF package hbds.setEPackages(new EPackage[] { LibraryPackage.eINSTANCE }); hbds.initialize(); //*************** Initialize Database Content Data ************************************* // (the first time a new Library object container is persisted, otherwise it is loaded) String uriStr = "hibernate://?"+HibernateResource.DS_NAME_PARAM+"=MyDb"; final URI uri = URI.createURI(uriStr); ResourceSet resourceSet = new ResourceSetImpl(); Resource resource = resourceSet.createResource(uri); try { resource.load(null); if (resource.getContents().size() == 0) { resource.getContents().add(LibraryFactory.eINSTANCE.createLibrary()); resource.save(null); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //*************** Open an Editor instance ************************************* //(avoiding the need of some "File, New..." explicit user operation) Display.getDefault().asyncExec(new Runnable() { @Override public void run() { try { PlatformUI .getWorkbench() .getActiveWorkbenchWindow() .getActivePage() .openEditor(new URIEditorInput(uri), "library.presentation.LibraryEditorID"); } catch (PartInitException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } });
The needed imports are:
import java.util.Properties; import java.io.IOException; import library.LibraryFactory; import library.LibraryPackage; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.teneo.hibernate.HbDataStore; import org.eclipse.emf.teneo.hibernate.HbHelper; import org.eclipse.emf.teneo.hibernate.resource.HibernateResource; import org.hibernate.cfg.Environment;
We will not get into the details of the code above (this will be explained in other articles), but here is a quick description:
- the Teneo Hibernate DataStore is being initializated, giving the database coordinates (URL, credentials, type, etc…). This is the point where you could consider changing parameter Environment.URL in order to match your schema name (“test” in this article), as well as making sure the credentials (USER e PASS) for the database access are correct.
When parameter HBM2DDL_AUTO is set to “update“, it allows the database to “adapt” (when possible, with proper ALTER TABLE automatic statements) to the model evolution. A “create-drop” value will instead lead to a fresh and empty new database at every launch (this may seem a useless option at first, but it becomes very useful when testing, where starting every time from scratch is a key point) - a connection is made to a ResourceSet (a pure EMF concept, independent from the specific implementation choice for the persistence) on the DataStore. This is required in order to assure that there is one Library object persisted, that will act as a container for the data we will manage afterwards.
Then we load the resources, through resource.load(null), and verify that a Library object exists; if not (e.g. the first time) we create it and save. - an Editor (just the one generated from EMF for our model) is opened, fed with a URI input that refers to the created DataStore.
That’s all! Let’s just launch the application.
Note: you should already have the right launch in Run
-> Run History
-> it.rcpvision.rcptutorial.model.editor.LibraryEditorAdvisorApplication
from last tutorial.
However you can always launch it from the Editor project plugin.xml, tab Overview, hyperlink Launch an Eclipse Application.
If the launch is correct (otherwise do a Clean and Launch checking) you should see (just the first time, when the Library object is created) the following messages on the console
this means that the initial insert of the Library object has been performed successfully.
The application should show like this:
now you can start filling the Library with Author e Book objects, linked toghether, as in the previous tutorial Eclipse EMF: a CRUD at no-cost.
This time however, data will be made persistent on the database (instead that on a XMI file). You can verify this on the console and obviously on the database!
Next time we will see how to quickly develop EMF-based RCP applications using the visual designer WindowBuilder.
Hi,
I can’t get this to work with Juno, I keep getting:
org.eclipse.emf.teneo.hibernate.HbMapperException: No HbDataStore can be found using the uri hibernate://dsname=MyDb
at org.eclipse.emf.teneo.hibernate.resource.HibernateResource.(HibernateResource.java:145)
at org.eclipse.emf.teneo.hibernate.resource.HibernateResourceFactory.createResource(HibernateResourceFactory.java:36)
at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.createResource(ResourceSetImpl.java:434)
at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.createResource(ResourceSetImpl.java:423)
The URI is correct in the code (with the ? – in fact I copied and pasted the above code to make sure) but collapses when trying to open the editor.
Any ideas?
Hi Glen,
the URI should be
hibernate://?dsname=MyDb
Do you have a running MySQL instance with the following parameters?
props.setProperty(Environment.DRIVER, "com.mysql.jdbc.Driver");
props.setProperty(Environment.URL, "jdbc:mysql://localhost:3306/test");
props.setProperty(Environment.USER, "root");
props.setProperty(Environment.PASS, "your-password");
props.setProperty(Environment.DIALECT, org.hibernate.dialect.MySQL5Dialect.class.getName());
I am apparently suffering from a work around is to select the Clear (workspace) option on the run configuration.
Glen,
in this cases try to create a brand new workspace and then Import the projects from old workspace.
Sometimes the .metadata folder within the workspace may become inconsistent (especially if you use it with different Eclipse versions or different versions of other plugins). Creating a new workspace (or deleting .metadata in current workspace) will reset the setup.
Tried to post a URL to an Eclipse bug in there; bug 381555, didn’t seem to work.
I couldn’t get this working due to a ClassNotFoundException
java.lang.ClassNotFoundException: org.eclipse.emf.teneo.hibernate.HbMapperException
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:501)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:421)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:412)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at example2.presentation.Example2EditorAdvisor.initialize(Example2EditorAdvisor.java:563)
Whilst doing:
(HbDataStore) HbHelper.INSTANCE
.createRegisterDataStore(“MyDb”);
On closer inspection, the class
org.eclipse.emf.teneo.hibernate.HbMapperException
is not present in the org.eclipse.emf.teneo.hibernate plug-in (which is present as a dependency of my plug-in).
Any idea what this is all about?
Thanks,
Darren
Sorry, I had wrong versions of some stuff loaded. It’s working fine now.
It can be tricky getting a consistent set of features/plug-ins together in Eclipse, but fortunately all is well now.
I must say that the off-the-shelf database integration (hibernate MySQL in this case) is very cool.
Darren
Hi Vincenzo,
So far your tutorials are the only tutorials that I know that are integrating EMF with other tools. However, I still have to do more research in order to get it works beautifully so it have not reached to the ‘one stop solution’ yet. But nonetheless, your tutorials are very great for beginner like myself and I wouldn’t get to experience EMF in a good way without them, so thank you for that.
I use Eclipse 4.2 (Juno) and when I try this one (integrating EMF with Teneo/Hibernate with MySQL), sometimes it works just like your tutorial and sometime I encounter errors and cannot show the runtime (it’s frustrating when I encounter that error). I do find a solution for my problem when I see http://www.eclipse.org/articles/Article-EMF-goes-RCP/rcp.html especially in “Testing the application” section. Using new configuration, the runtime will always work every time, so the first problem is solved now.
Now for the second problem, I try to implement OCL using OCLinEcore with this Teneo/Hibernate but unfortunately I couldn’t do that. If I didn’t use RCP and Teneo (for example Eclipse Runtime or creating Dynamic Instance), my OCL validation works. But when I run this in RCP with Teneo/Hibernate, I got this error when validating (or saving):
“Unable to find delegate to evaluate the ‘….’ constraint on ‘….’: http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot”
Then I searched around and add some code in initialize method of my xxxEditorAdvisor.java:
super.initialize(configurer);
configurer.setSaveAndRestore(true);
//***************** OCL ******************/
org.eclipse.ocl.examples.pivot.model.OCLstdlib.install();
org.eclipse.ocl.examples.pivot.OCL.initialize(null);
String oclDelegateURI = OCLDelegateDomain.OCL_DELEGATE_URI;
EOperation.Internal.InvocationDelegate.Factory.Registry.INSTANCE.put(oclDelegateURI, new OCLInvocationDelegateFactory.Global());
EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE.put(oclDelegateURI, new OCLSettingDelegateFactory.Global());
EValidator.ValidationDelegate.Registry.INSTANCE.put(oclDelegateURI, new OCLValidationDelegateFactory.Global());
//*************** Initialize Teneo Hibernate DataStore *************************************
// The rest are your code for establishing connection with MySQL.
Frankly I didn’t understand what it is, just copy paste it from somewhere. However I get different error when I validate it on runtime:
“an exception occured while delegating evaluation of the ‘…..’ constraint on ‘….’: org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl cannot be cast to org.eclipse.ocl.examples.pivot.utilites.BaseResource”
Basically I’m stuck there and couldn’t combine OCL with Teneo. And I’m not sure whether my added code is doing a good progression with what I’m trying to do or make it worse. In any case, it is still not working right now. I would appreciate if you can help me with my situation.
Thanks,
Leo
Hi Leo,
before getting into code, could you explain better what is your goal with OCL?
Can you simplify this goal and translate it for the Library model of tutorials?
Thanks
Vincenzo
Hi Vincenzo,
For example if I want to add constraint for the length of the author’s name; it must be more than one character. From my understanding is, I can add that constraint in OCL by open the ecore file using OCLinEcore, then add this one line inside the author class:
“invariant nameMustBeMoreThanOneChar : name.size() > 1;”
When I run this as RCP, and do validation, it will give me this error:
“Unable to find delegate to evaluate the ‘nameMustBeMoreThanOneChar’ constraint on ‘Author ab’: http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot”
But if I run it as an IDE (change the runtime platform in genmodel) then validate it, it works just like I expect it.
Little update regarding my first post: It turns out the problem is not with the Teneo/Hibernate, so I’m sorry if it confuses you. The problem is I can’t really integrate OCL in RCP. Is there any way to work around this? Or is it impossible to begin with?
Regards,
Leo
Hi Leo,
I applied the constraint you are referring and obtain correctly the message:
You can follow the instructions here:
http://wiki.eclipse.org/MDT/OCLinEcore
Please note that the URL you are using (http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot) sounds not correct.
If the problem persists, please write me in private: you’ll find my email in Contacts.
Hi Vincenzo,
it turns out there are pivot OCL and non-pivot OCL. I think yours it the non-pivot while mine is using pivot.
After looking around, here is the answer for my OCL problem:
//***************** OCL ******************/
// register Pivot globally (resourceSet == null)
org.eclipse.ocl.examples.pivot.OCL.initialize(null);
String oclDelegateURI = OCLDelegateDomain.OCL_DELEGATE_URI_PIVOT;
EOperation.Internal.InvocationDelegate.Factory.Registry.INSTANCE.put(oclDelegateURI, new OCLInvocationDelegateFactory.Global());
EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE.put(oclDelegateURI, new OCLSettingDelegateFactory.Global());
EValidator.ValidationDelegate.Registry.INSTANCE.put(oclDelegateURI, new OCLValidationDelegateFactory.Global());
// add org.eclipse.ocl.examples.xtext.oclinecore into dependencies in plugin.xml
OCLinEcoreStandaloneSetup.doSetup();
// install the OCL standard library
OCLstdlib.install();
Anyway thank you for your reply even though you don’t explain about OCL in this tutorial. I appreciate it very much 🙂
Regards,
Leo
Hi Vincenzo,
After I looked around carefully, you do have a tutorial about the configuration regarding the launch error.
“If the launch is correct (otherwise do a Clean and Launch checking) you should see (just the first time, when the Library object is created) the following messages on the console”
Well since you have it, I’ll take back my word about not being a one stop solution, I’m very sorry if that somehow offended you. Your tutorial is The one stop solution for my modeling experience 🙂 I’m just a beginner in java, especially EMF. But I have gained so much in knowledge EMF using your tutorials.
Thanks,
Leo
Hi Leo,
I will never be offended by this kind of useful comments 😉
They are key parts in the process of improving tutorials.
So thank to you!
Cheers
Vincenzo