blob: f8bde07fe3df28c7d7ca3541115279b11f9b5de3 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>NetBeans Platform EMF Integration Tutorial</title>
<link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css"/>
<meta name="AUDIENCE" content="NBUSER"/>
<meta name="TYPE" content="ARTICLE"/>
<meta name="EXPIRES" content="N"/>
<meta name="indexed" content="y"/>
<meta name="description"
content="A short guide to getting started with EMF on the NetBeans Platform."/>
<!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -->
<!-- Use is subject to license terms.-->
</head>
<body>
<h1>NetBeans Platform EMF Integration Tutorial</h1>
<p>This document shows you how to incorporate an <a href="http://www.eclipse.org/modeling/emf/">EMF model</a>
into a NetBeans Platform application.
</p>
<p>
You will start by setting up Eclipse, together with its modeling tools.
Then you will set up one of the example EMF models provided by Eclipse.
Next, you will use NetBeans IDE to create a new NetBeans Platform
application on top of Equinox. You will import the OSGi bundles
needed for Equinox to work with EMF. Then you will create two new
OSGi bundles in NetBeans IDE. The first will contain the sources of the EMF model,
while the second will provide a window for displaying values that,
for purposes of this tutorial, you will hardcode in the application.
</p>
<p>At the end of the tutorial, you will have a NetBeans Platform application that looks as follows,
based on the "Extended Library Model Example" provided by Eclipse:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-015.png" alt="result"/></p>
<p>Once you have gone through this simple scenario, you should be able
to incorporate your own EMF models into your NetBeans Platform applications.</p>
<p><b>Contents</b></p>
<p><img src="../../images/articles/69/netbeans-stamp69.png" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8" title="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8"/></p>
<ul class="toc">
<li><a href="#emf">Creating the EMF Model</a></li>
<li><a href="#create">Creating the NetBeans Platform Application</a></li>
<li><a href="#import">Importing the OSGi Bundles</a></li>
<li><a href="#model">Creating an OSGi Bundle to Contain the Model</a></li>
<li><a href="#viewer">Creating an OSGi Bundle to Provide the Window</a></li>
<li><a href="#run">Running the Application</a></li>
<li><a href="#further">Further Reading</a></li>
</ul>
<p><b>To follow this tutorial, you need the software and resources listed in the following table.</b></p>
<table>
<tbody>
<tr>
<th class="tblheader" scope="col">Software or Resource</th>
<th class="tblheader" scope="col">Version Required</th>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td>
<td class="tbltd1">version 6.9</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">Java Developer Kit (JDK)</a></td>
<td class="tbltd1">version 6 or above</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://eclipse.org">Eclipse</a></td>
<td class="tbltd1"></td>
</tr>
</tbody>
</table>
<!-- ===================================================================================== -->
<p></p>
<h2><a name="emf"></a>Creating the EMF Model</h2>
<p>In this section, you create an EMF model in Eclipse.</p>
<ol>
<li>Install EMF via the Eclipse update manager. Select "Modeling" and
install "EMF - Eclipse Modeling Framework SDK". Also select the
"Ecore Tools", which will let you create UML diagrams from your EMF model.</li>
<li><p>In the New Project wizard, create the "Extended Library Model Example",
as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-001.png" alt="result"/></p>
</li>
<li><p>In the next step, click Finish:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-002.png" alt="result"/></p>
</li>
<li><p>You now have the model that you will use throughout the rest of the tutorial:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-003.png" alt="result"/></p>
</li>
</ol>
<p>On disk, in your workspace, you have the sources of the EMF model you created. Later
in this tutorial, you will copy the sources into an OSGi bundle created in
NetBeans IDE. That way, you will be able to work with the sources in the IDE,
and tweak them where necessary.</p>
<h2><a name="create"></a>Creating the NetBeans Platform Application</h2>
<p>Once you have all the required OSGi bundles available,
create your new NetBeans Platform application, as described below.</p>
<ol>
<li><p>Choose File | New Project and choose to
create a NetBeans Platform application atop Equinox, via the Equinox template:</p>
<p><img src="http://netbeans.dzone.com/sites/all/files/sudokugame-5.png"/></p>
<p>Click Next.</p>
</li>
<li><p>Name the application <code>LibraryManager</code> and click Finish.</p></li>
<li><p>The application you now have is already deployable.
Right-click the application to run it. When the application
starts up, you'll first see the default splash screen:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-010.png" alt="result"/></p>
<p>Then you will see the main window containing a window that
displays all the NetBeans modules and OSGi bundles that have
been deployed.</p></li>
<li><p>Optionally, before continuing, remove the "Show OSGi Bundle List" module that the template
provided by default. If you keep it, you will continue to have the
window displaying the deployed modules and bundles as part
of your application. To remove it, expand the application node in the
Projects window, then expand the Modules node,
right-click the "Show OSGi Bundle List" node, and select Remove.</p></li>
</ol>
<h2><a name="import"></a>Importing the OSGi Bundles</h2>
<p>In this section, you create a new folder on disk. Within that folder,
you copy several general Equinox JARs, together with EMF-related JARs,
from the Eclipse distribution. You then import these into your
NetBeans Platform application.</p>
<ol>
<li><p>Create a folder on disk, name it anything you like, such as "emf-jars".</p></li>
<li><p>Copy the following JARs into your new folder, where "xxx" is
a placeholder for the version number:</p>
<p></p>
<ul>
<li><p>Core bundles:</p>
<pre class="examplecode">org.eclipse.core.expressions_xxx.jar
org.eclipse.core.filebuffers_xxx.jar
org.eclipse.core.filesystem_xxx.jar
org.eclipse.core.jobs_xxx.jar
org.eclipse.core.net_xxx.jar
org.eclipse.core.resources_xxx.jar
org.eclipse.core.runtime_xxx.jar
org.eclipse.core.runtime.compatibility_xxx.jar
</pre></li>
<li><p>EMF bundles:</p>
<pre class="examplecode">org.eclipse.emf.cdo.common_xxx.jar
org.eclipse.emf.cdo_xxx.jar
org.eclipse.emf.common_xxx.jar
org.eclipse.emf.ecore.change_xxx.jar
org.eclipse.emf.ecore.edit_xxx.jar
org.eclipse.emf.ecore.xmi_xxx.jar
org.eclipse.emf.ecore_xxx.jar
org.eclipse.emf.edit_xxx.jar
org.eclipse.emf.query_xxx.jar
org.eclipse.emf.transaction_xxx.jar
org.eclipse.emf.validation_xxx.jar
org.eclipse.emf_xxx.jar
</pre></li>
<li><p>Equinox bundles:</p>
<pre class="examplecode">org.eclipse.equinox.app_xxx.jar
org.eclipse.equinox.common_xxx.jar
org.eclipse.equinox.preferences_xxx.jar
org.eclipse.equinox.registry_xxx.jar
org.eclipse.equinox.security_xxx.jar
</pre></li>
<li><p>Miscellaneous bundles:</p>
<pre class="examplecode">com.ibm.icu_xxx.jar
org.eclipse.net4j.util_xxx.jar
org.eclipse.net4j_xxx.jar
</pre></li></ul>
</li>
<li><p>Right-click the application's node and choose Properties.
Open the Libraries panel of the Project Proprties dialog, as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-016.png" alt="result"/></p>
</li>
<li><p>Click "Add Cluster". Browse to the "emf" folder you created earlier.
When you select it, the NetBeans IDE will not recognize its content. It will ask
you to let it add metadata to the folder, so that it will be able
to recognize the OSGi bundles it finds there,
as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-017.png" alt="result"/></p>
</li>
<li><p>When you click Next, the NetBeans IDE presents a list of OSGi bundles
found in the selected folder. You are then asked to specifiy when
the bundles should be loaded:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-018.png" alt="result"/></p>
<p>Select "Autoload" in the first column, so that "Autoload" is selected
in all the other columns too. "Autoload" means that a module is
turned on only when needed. In contrast to regular modules, which require some
manual action, the autoload modules are opaque for users and are
managed solely by the infrastructure. As soon as there is a module needing,
via its dependencies, an autoload module, the infrastructure enables it. </p>
</li>
<li><p>At the end of the previous step, the OSGi bundles are registered and available
to be used within the application, as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-019.png" alt="result"/></p>
</li>
<li><p>Look at the "emf" folder on disk. The OSGi bundles are untouched and unchanged.
However, two folders are added, providing the metadata needed for the OSGi
support in the NetBeans Platform to recognize the JARs as OSGi bundles, as shown below:</p>
<p><img style="border: 1px solid" src="../../images/tutorials/emf/emf-library-model-020.png" alt="result"/></p>
<p>For example, in the "config" folder, you will find an XML file as follows,
for each of the OSGi bundles imported into the application:</p>
<pre class="examplecode">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE module PUBLIC "-//NetBeans//DTD Module Status 1.0//EN"
"https://netbeans.org/dtds/module-status-1_0.dtd"&gt;
&lt;module name="com.ibm.icu"&gt;
&lt;param name="autoload"&gt;true&lt;/param&gt;
&lt;param name="eager"&gt;false&lt;/param&gt;
&lt;param name="jar"&gt;com.ibm.icu_4.0.1.v20090822.jar&lt;/param&gt;
&lt;param name="reloadable"&gt;false&lt;/param&gt;
&lt;/module&gt;</pre>
</li>
</ol>
<p>Now that you have all the OSGi bundles you'll need for working with EMF
in the NetBeans Platform, let's create a new OSGi bundle in the IDE. The
new OSGi bundle will contain the sources of the EMF model you created earlier.</p>
<h2><a name="model"></a>Creating an OSGi Bundle to Contain the Model</h2>
<p>Now we create a new OSGi bundle in NetBeans IDE. Into the OSGi bundle,
we copy the Java source files making up our EMF model. Then we set
dependencies on the EMF-related bundles, so that the OSGi bundle can
compile. Finally, we make the package containing the API classes
public to the rest of the application.</p>
<ol>
<li><p>Create a new module named <code>LibraryModel</code>, as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-004.png" alt="library model 1"/></p>
</li>
<li><p>In the next step, set "org.eclipse.emf.examples.extlibrary" as the code name base,
"Library Model" as the display name, and check the "Generate OSGi Bundle" checkbox,
as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-005.png" alt="library model 2"/></p>
<p>Click Finish. The IDE creates an OSGi bundle, with appropriate entries in the manifest.</p>
</li>
<li><p>Copy the source packages from the EMF model into the OSGi
bundle in the IDE, as shown below:</p>
<p><img style="border: 1px solid" src="../../images/tutorials/emf/emf-library-model-006.png" alt="library model 3"/></p>
<p>As you can see, there are many error markings shown in the IDE. That
is because you have not set dependencies on the required bundles yet.</p>
</li>
<li><p>In the Projects window, right-click the "Libraries" node in the Library Model project.
Then choose "Add Module Dependency". In the dialog, select all the EMF-related
bundles:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-007.png" alt="library model 4"/></p>
</li>
<li><p>Now that you have dependencies set on the EMF-related bundles,
you should notice that the error markings are gone:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-008.png" alt="library model 5"/></p>
</li>
<li><p>Right-click the LibraryModel project in the Projects window
and choose Properties. In the API Versioning panel, publish
the "org.eclipse.emf.examples.extlibrary" package to the
rest of the application:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-012.png" alt="library model 6"/></p>
<p>After checking the above checkbox, only the Java classes in the
specified package will be available to other modules and bundles
in the application.</p>
</li>
</ol>
<h2><a name="viewer"></a>Creating an OSGi Bundle to Provide the Window</h2>
<p>Now we add a new OSGi bundle that provides a window for the application. The
window will display a <code><a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/Node.html">Node</a></code> class for the Library object, together
with <code><a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/Children.html">Children</a></code> for each Book object and Borrower object in the
Library. For demonstration purposes, we will hardcode some values to define
a dummy Library, together with dummy Books and dummy Borrowers.</p>
<ol>
<li><p>Create a new module named <code>LibraryViewer</code>, as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-013.png" alt="feedreader result"/></p>
</li>
<li><p>In the next step, set "org.library.viewer" as code name base,
"LibraryViewer" as display name, check the "Generate XML Layer" checkbox,
and check the "Generate OSGi Bundle" checkbox, as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-014.png" alt="feedreader result"/></p>
</li>
<li><p>Set dependencies on the LibraryModel created in the previous section and
two of the EMF-related OSGi bundles ("org.eclipse.emf.common" and
"org.eclipse.emf.ecore") that you imported, as shown below:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-021.png" alt="feedreader result"/></p>
<p>In addition, for the functionality you will be creating in this section,
add dependencies on the following modules too:</p>
<ul>
<li>Explorer & Property Sheet API</li>
<li>Lookup</li>
<li>Nodes API</li>
<li>UI Utilities API</li>
<li>Utilities API</li>
<li>Window System API</li>
</ul>
<p>The other OSGi-related dependencies you see in the screenshot above
were added by the Equinox project template you created as the basis
of the application earlier in this tutorial.</p>
</li>
<li><p>Create a new Java class named <code>LibraryNode</code>, which provides
a new Node for the Library object, as well as a new Node for the
Book object and Borrower object:</p>
<pre class="examplecode">public class LibraryNode extends <a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/AbstractNode.html">AbstractNode</a> {
public LibraryNode(Library library) {
super(Children.create(new BookOrBorrowerChildFactory(library), true));
setDisplayName(library.getName());
}
private static class BookOrBorrowerChildFactory extends <a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/ChildFactory.html">ChildFactory</a>&lt;Object&gt; {
private final Library library;
private BookOrBorrowerChildFactory(Library library) {
this.library = library;
}
@Override
protected boolean createKeys(List list) {
EList&lt;Book&gt; books = library.getBooks();
for (Book book : books) {
list.add(book);
}
EList&lt;Borrower&gt; borrowers = library.getBorrowers();
for (Borrower borrower : borrowers) {
list.add(borrower);
}
return true;
}
@Override
protected Node createNodeForKey(Object key) {
<a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/BeanNode.html">BeanNode</a> childNode = null;
try {
childNode = new BeanNode(key);
if (key instanceof Book) {
Book book = (Book) key;
childNode.setDisplayName(book.getTitle());
childNode.setIconBaseWithExtension("org/library/viewer/book.png");
} else if (key instanceof Borrower) {
Borrower borrower = (Borrower) key;
childNode.setDisplayName(borrower.getLastName());
childNode.setIconBaseWithExtension("org/library/viewer/borrower.png");
}
} catch (IntrospectionException ex) {
Exceptions.printStackTrace(ex);
}
return childNode;
}
}
}</pre>
</li>
<li><p>Create a new Java class named <code>LibraryChildFactory</code>, which is
a factory class for creating new <code>LibraryNode</code>s:</p>
<pre class="examplecode">public class LibraryChildFactory extends <a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/ChildFactory.html">ChildFactory</a>&lt;Library&gt; {
@Override
protected boolean createKeys(List&lt;Library&gt; list) {
EXTLibraryFactory factory = EXTLibraryFactory.eINSTANCE;
Writer writer1 = factory.createWriter();
writer1.setName("William Shakespeare");
Book book1 = factory.createBook();
book1.setAuthor(writer1);
book1.setTitle("Romeo and Juliet");
Book book2 = factory.createBook();
book2.setAuthor(writer1);
book2.setTitle("Othello");
Borrower borrower1 = factory.createBorrower();
borrower1.setFirstName("Jack");
borrower1.setLastName("Smith");
Borrower borrower2 = factory.createBorrower();
borrower2.setFirstName("John");
borrower2.setLastName("Sykes");
Borrower borrower3 = factory.createBorrower();
borrower3.setFirstName("Lucy");
borrower3.setLastName("Williams");
Library library1 = factory.createLibrary();
library1.setName("New York Public Library");
EList&lt;Borrower&gt; borrowers1 = library1.getBorrowers();
EList&lt;Book&gt; books1 = library1.getBooks();
borrowers1.add(borrower1);
books1.add(book1);
Library library2 = factory.createLibrary();
library2.setName("London Public Library");
EList&lt;Borrower&gt; borrowers2 = library2.getBorrowers();
EList&lt;Book&gt; books2 = library2.getBooks();
borrowers2.add(borrower2);
borrowers2.add(borrower3);
books2.add(book2);
list.add(library1);
list.add(library2);
return true;
}
@Override
protected Node createNodeForKey(Library key) {
return new LibraryNode(key);
}
}</pre>
</li>
<li><p>Create a new Java class named <code>LibraryViewer</code>, which provides
the window where the <code>LibraryNode</code> will be displayed:</p>
<pre class="examplecode">public class LibraryViewer extends <a href="http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/TopComponent.html">TopComponent</a> implements <a href="http://bits.netbeans.org/dev/javadoc/org-openide-explorer/org/openide/explorer/ExplorerManager.Provider.html">ExplorerManager.Provider</a> {
private ExplorerManager em = new ExplorerManager();
public LibraryViewer() {
//Text displayed in the tab of the window:
setDisplayName("Library Viewer");
//Set the layout of the window:
setLayout(new BorderLayout());
//Create a new BeanTreeView:
<a href="http://bits.netbeans.org/dev/javadoc/org-openide-explorer/org/openide/explorer/view/BeanTreeView.html">BeanTreeView</a> btv = new BeanTreeView();
//Hide the root node:
btv.setRootVisible(false);
//Add the BeanTreeView:
add(btv, BorderLayout.CENTER);
//Set the root node of the ExplorerManager:
em.setRootContext(new AbstractNode(Children.create(new LibraryChildFactory(), true)));
//Hook up the synchronization between the views:
associateLookup(ExplorerUtils.createLookup(em, getActionMap()));
}
@Override
public ExplorerManager getExplorerManager() {
return em;
}
}</pre>
</li>
<li><p>Create a new Java class named <code>OpenLibraryViewerAction</code>, which will let
the user open the viewer:</p>
<pre class="examplecode">public class OpenLibraryViewerAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
LibraryViewer window = new LibraryViewer();
window.open();
window.requestActive();
}
}
</pre>
</li>
<li>In the layer file, register the Action you created in the previous step.
Let it be always enabled and let it be displayed as a menu item in the
File menu:
<pre class="examplecode">&lt;folder name="Actions"&gt;
&lt;folder name="File"&gt;
&lt;file name="org-library-viewer-OpenLibraryViewerAction.instance"&gt;
&lt;attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/&gt;
&lt;attr name="delegate" newvalue="org.library.viewer.OpenLibraryViewerAction"/&gt;
&lt;attr name="displayName" bundlevalue="org.library.viewer.Bundle#CTL_OpenLibraryViewerAction"/&gt;
&lt;/file&gt;
&lt;/folder&gt;
&lt;/folder&gt;
&lt;folder name="Menu"&gt;
&lt;folder name="File"&gt;
&lt;file name="OpenLibraryViewerWindowAction.shadow"&gt;
&lt;attr name="originalFile" stringvalue="Actions/File/org-library-viewer-OpenLibraryViewerAction.instance"/&gt;
&lt;/file&gt;
&lt;/folder&gt;
&lt;/folder&gt;</pre>
<p>Look at line 6 above and then register an appropriate display name for the
Action, in the <code>Bundle.properties</code> file:</p>
<pre class="examplecode">CTL_OpenLibraryViewerAction=Open Library Viewer</pre>
</li>
</ol>
<h2><a name="run"></a>Running the Application</h2>
<p>The application is now ready to be deployed, as described below.</p>
<ol>
<li><p>Run the application. All the OSGi bundles and NetBeans modules in your application
will be deployed. The Output window of the IDE should not show any bundle warnings,
because Equinox should resolve everything correctly:</p>
<p><img style="border: 1px solid" src="../../images/tutorials/emf/emf-library-model-011.png" alt="output"/></p>
</li>
<li><p>The application starts up. Under the File menu, select the menu item
for opening the viewer. Open the Properties window, from the Window menu,
browse a few nodes and you should see the following:</p>
<p><img src="../../images/tutorials/emf/emf-library-model-015.png" alt="result"/></p>
</li>
</ol>
<p>Congratulations, you have integrated your EMF model into your NetBeans Platform application.</p>
<div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&amp;subject=Feedback:%20EMF%20Integration%20Tutorial">Send Us Your Feedback</a></div>
<br style="clear:both;" />
<h2><a name="further"></a>Further Reading</h2>
<p>Now that you have completed the tutorial and understand the steps to take when you want
to reuse an OSGi bundle in your NetBeans Platform application, take a look at these
related documents and more
advanced scenarios:</p>
<ul>
<li><a href="http://www.osgi.org/blog/2006_09_01_archive.html">Peter Kriens and the Sudoku Game</a></li>
<li><a href="http://wiki.apidesign.org/wiki/NetbinoxTutorial">Jaroslav Tulach and Netbinox</a></li>
<li>Toni Epple's OSGi/NetBeans <a href="http://eppleton.sharedhost.de/blog/?p=662">blog entry</a> and <a href="http://eppleton.sharedhost.de/blog/?s=Frankenstein%27s+IDE">presentation</a></li>
<li>Gunnar Reinseth's NetBeans-EMF integration (<a href="http://eclipse.dzone.com/emf-on-netbeans-rcp">part 1</a>, <a href="http://eclipse.dzone.com/emf-on-netbeans-rcp-2">part 2</a>)</li>
<li>Also read <a href="http://java.dzone.com/news/new-cool-tools-osgi-developers">New Cool Tools for OSGi Developers</a></li>
</ul>
</body>
</html>