Il presente tutorial presuppone che siano stati seguiti prima i seguenti altri articoli nell’ordine indicato:
ed ha l’obiettivo di dimostrare come, con pochissime modifiche al codice generato da EMF, sia possibile ottenere la persistenza del solito modello usato nei tutorial precedenti su un database relazionale. Useremo MySQL come target database, quindi verificate di averlo a disposizione (in locale o in rete) e di potervi accedere (eventualmente potete scaricarlo all’indirizzo http://www.mysql.com/downloads/mysql). Assumeremo di usare il database schema “test” (precaricato vuoto durante l’installazione di MySQL), tuttavia potete usare uno schema diverso semplicemente modificando le proprietà di connessione al database.
Per poter seguire questo tutorial è necessario disporre di alcuni plugin aggiuntivi per Eclipse. In questa guida trovate tutti i dettagli su come aggiornare correttamente il vostro IDE:
Setup Teneo per Eclipse 4.2 ÔÇô Juno
Partiamo quindi dal punto in cui eravamo rimasti dall’ultimo tutorial e apriamo il file plugin.xml del plugin di editor generato in modo automatico da EMF (it.rcpvision.rcptutorial.model.editor).
Selezioniamo il tab Dependencies
e aggiungiamo le seguenti dipendenze (premendo il bottone Add… nella sezione Required Plug-ins):
- org.eclipse.emf.teneo.hibernate
- org.hibernate
- com.mysql.jdbc
salviamo (Ctrl-S) e apriamo la classe LibraryEditorAdvisor.java, in corrispondenza del metodo initialize().
introducendo le seguenti modifiche:
innanzitutto marchiamo il metodo come @generated not, in modo tale che una eventuale successiva rigenerazione del codice (ad es. resa necessaria da una modifica del modello) non sovrascriva le modifiche che andremo ad apportare
e aggiugiamo il seguente blocco di codice dopo l’istruzione
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(); } } });
Le import necessarie sono:
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;
Non entreremo nel dettaglio delle singole operazioni che esegue questa parte di codice (questo sarà eventualmente oggetto di altri articoli), ma ecco sintetizzate le azioni che vengono effettuate:
- viene inizializzato l’Hibernate DataStore di Teneo indicando le coordinate del database (URL, credenziali, tipo, ecc…). Qui potreste ritenere opportuno modificare il parametro Environment.URL per farlo corrispondere al nome dello schema MySQL (nell’esempio “test“) che intendete utilizzare, mentre dovete assicurarvi che le credenziali (USER e PASS) per l’accesso al database siano le quelle giuste per voi.
Il parametro HBM2DDL_AUTO impostato al valore “update” permette al database di “adattarsi” (per quanto possibile attraverso opportune istruzioni SQL di ALTER TABLE automatiche) all’evoluzione del modello. Un valore di “create-drop” invece provocherebbe una creazione da zero del database ad ogni avvio (sebbene questa operazione possa sembrare inutile, risulta invece fondamentale durante le sessioni di test in quanto le condizioni iniziali in quel caso devono essere sempre le stesse) - viene realizzata una connessione al ResourceSet (un concetto proprio di EMF e trasversale rispetto all’implementazione scelta per la persistenza!) verso il DataStore appena inizializzato. Questo viene fatto in quanto, prima di partire, dobbiamo assicurarci di avere un oggetto Library persistito, che farà da contenitore per tutto ciò che gestiremo. Quindi carichiamo, con resource.load(null), le risorse e verifichiamo che esista una Library; in caso negativo (la prima volta) la creiamo.
- viene aperto un Editor (proprio quello generato da EMF per il nostro modello) passando come input l’URI verso il DataStore creato.
Ecco fatto: non vi resta che lanciare l’applicazione.
Nota: dovreste avere a disposizione il lancio in Run
-> Run History
-> it.rcpvision.rcptutorial.model.editor.LibraryEditorAdvisorApplication
dall’ultimo tutorial.
In ogni caso potete sempre effettuare il lancio aprendo il file plugin.xml dell’Editor, tab Overview, hyperlink Launch an Eclipse Application.
Se il lancio avviene con successo (altrimenti effettuate un Clean e un Controllo del lancio) dovreste vedere, la prima volta, i seguenti messaggi sulla console
questo significa che l’inserimento iniziale dell’oggetto Library è avvenuto con successo.
L’applicazione invece dovrebbe presentarsi così:
e a questo punto potete iniziare a popolare la Library con oggetti di tipo Author e Book opportunamente relazionati fra loro, come nel precedente tutorial Eclipse EMF: un CRUD a costo zero.
Solo che stavolta i dati vengono resi persistenti sul database, come potete verificare dai messaggi in console e sul database stesso!
Vedremo prossimamente come sviluppare velocemente applicazioni RCP basate su EMF utilizzando il designer visuale WindowBuilder.
org.hibernate.cfg.
Environment
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