blob: c3e3860461ee02b9f05bc04b999550f6bf88f9f8 [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 Quick Start for NetBeans Platform 7.0</title>
<meta name="AUDIENCE" content="NBUSER"/>
<meta name="TYPE" content="ARTICLE"/>
<meta name="EXPIRES" content="N"/>
<meta name="developer" content="gwielenga@netbeans.org"/>
<meta name="indexed" content="y"/>
<meta name="description"
content="A short guide to getting started with the NetBeans Platform."/>
<!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -->
<!-- Use is subject to license terms.-->
</head>
<body>
<style>
.examplecode {
background-color:#FFF8E4;
overflow:auto;
width:550px;
white-space:pre;
}
</style>
<h1>NetBeans Platform Quick Start</h1>
<p>Welcome to the <a href="https://platform.netbeans.org/"><b>NetBeans Platform</b></a>!</p>
<p>The key benefit of the NetBeans Platform is its modular architecture. Secondary
benefits are the NetBeans Platform's reliance on the Swing UI toolkit, which is the
official toolkit for creating user interfaces in Java, in combination with the
NetBeans IDE's award winning "Matisse" GUI Builder.</p>
<p>In this quick start, you are introduced to the benefits and usages of modularity via
a very simple example, contributed by Thomas W&#252;rthinger, who is currently a
PhD student at the Johannes Kepler University in Linz, Austria. Once you have
grasped the concepts introduced in this quick start, you will be ready to
step onto the <a href="https://netbeans.org/kb/trails/platform.html">NetBeans Platform Learning Trail</a>,
providing a very rich variety of tutorials for many different scenarios
relating to the NetBeans Platform.</p>
<p class="tips"> If you are new to the NetBeans Platform, it is highly
recommended to watch the screencast series <a href="https://platform.netbeans.org/tutorials/nbm-10-top-apis.html">Top 10 NetBeans APIs</a>.</p>
<p><b class="notes">Note:</b> This document uses the NetBeans IDE 7.0 Release or above. If you
are using an earlier version, see <a href="691/nbm-quick-start.html">the previous version
of this document</a>.</p>
<p><b>Contents</b></p>
<p><img src="../../images/articles/70/netbeans-stamp.gif" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 7.0" title="Content on this page applies to NetBeans IDE 7.0"/></p>
<ul class="toc">
<li><a href="#single">A Single Module NetBeans Platform Application</a></li>
<li><a href="#lookup">A Modular Application Using Lookup</a></li>
<li><a href="#listener">LookupListener and InstanceContent</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 7.0 or above</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>
</tbody>
</table>
<p><b class="notes">Note:</b> Even though it is a separate product, there is no
need to download the NetBeans Platform separately. Typically, you develop the
application in NetBeans IDE and then exclude the modules that are specific to
the IDE but that are superfluous to your application.</p>
<!-- ===================================================================================== -->
<h2 class="tutorial"><a name="single"></a>A Single Module NetBeans Platform Application</h2>
<p>We start by simply creating a new NetBeans Platform application,
containing a single module.</p>
<ol>
<li><p>Choose File | New Project and then choose NetBeans Modules.
Select "NetBeans Platform Application". You should see this:</p>
<p><img src="../../images/tutorials/quickstart-platform/70/wordapp01.png" alt="Fig 1"/></p>
<p>Click Next.</p></li>
<li><p>Name your new application "WordApp" and make it the IDE's main project:</p>
<p><img src="../../images/tutorials/quickstart-platform/70/wordapp02.png" alt="Fig 2"/></p>
<p class="tips"> The IDE's main project is started when the
global project command "Run Project" is invoked.</p>
<p>Click Finish. The new project appears as follows in the Projects window:</p>
<p><img src="../../images/tutorials/quickstart-platform/70/wordapp021.png" alt="Fig 2-1"/></p></li>
<li><p>Right-click the Modules node, shown above, and choose "Add New". Call the new
module "WordEditorCore":</p>
<p><img alt="create new module" src="../../images/tutorials/quickstart-platform/70/wordapp03.png"/></p>
<p>Click Next.</p></li>
<li><p>Specify a unique name for the module, which is its code name
base, together with a project display name that will be shown in the Projects window:</p>
<p><img alt="specify a name" src="../../images/tutorials/quickstart-platform/70/wordapp04.png"/></p>
<p>Click Finish. The new module is created and its structure is
shown in the Projects window:</p>
<p><img alt="specify a name" src="../../images/tutorials/quickstart-platform/70/wordapp04a.png"/></p></li>
<li><p>Right-click the "Word Editor Core" module and choose New | Other.
In the Module Development category, select "Window":</p>
<p><img alt="create new window" src="../../images/tutorials/quickstart-platform/70/wordapp05.png"/></p>
<p>Click Next. You should now see this:</p>
<p><img alt="create new window" src="../../images/tutorials/quickstart-platform/70/wordapp06.png"/></p></li>
<li>Select "editor" and "Open on Application Start", as shown below:
<p><img alt="create new window" src="../../images/tutorials/quickstart-platform/70/wordapp06a.png"/></p>
<p>Then click Next.</p></li>
<li>Set the class name prefix to "Text" and the package to "org.word.editor.core":
<p><img alt="set definitions" src="../../images/tutorials/quickstart-platform/70/wordapp07.png"/></p>
<p>Click Finish. The new window is added to the source structure
of your module:</p>
<p><img alt="set definitions" src="../../images/tutorials/quickstart-platform/70/wordapp08.png"/></p></li>
<li>Now double click on the file "TextTopComponent.java" to open
it in the Design view of the "Matisse" GUI Builder. Use the Palette (Ctrl-Shift-8) to
drag and drop a button and a text area onto the window:
<p><img alt="palette" style="border: 1px solid black;" src="../../images/tutorials/quickstart-platform/70/wordapp15.png"/></p>
<p>Do the following to make the new GUI components meaningful:</p>
<ul>
<li>Right-click the text area, choose "Change Variable Name", and then
name it "text". That is the name that will enable you to access the
component from your code.</li>
<li>Right-click the button, choose "Edit Text", and then set the text of the button to "Filter!"</li>
</ul></li>
<li>Double click on the button, causing an event handling method
to automatically be created in the Source editor. The method is called whenever the button is clicked. Change the body
of the method to the following code.
<pre class="examplecode">private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String s = text.getText();
s = s.toUpperCase();
text.setText(s);
}</pre></li>
<li>Right-click the application and choose Run. Doing so will start up your
new NetBeans Platform application and install your module. You will have a new
window, as well as a new menu item for opening it, as shown below:
<p><img alt="show new app" src="../../images/tutorials/quickstart-platform/70/wordapp081.png"/></p></li>
<li>Enter a text in the text area, and click "Filter!".
You should see that the text is now shown in uppercase:
<p><img alt="uppercase" src="../../images/tutorials/quickstart-platform/70/wordapp082.png"/></p></li>
</ol>
<p>You have learned how to create a new NetBeans Platform application and how
to add new modules to it. In the next section, you will be introduced
to the NetBeans Platform's pluggable service infrastructure.</p>
<!-- ===================================================================================== -->
<h2 class="tutorial"><a name="lookup"></a>A Modular Application Using Lookup</h2>
<p>In this section, you create two additional modules. The first
new module, "TextFilterAPI",
contains a service provider interface. The second module,
"UppercaseFilter", is a service provider for the interface.
The GUI module, defined above, will be loosely coupled with
the "UppercaseFilter" service provider, since the GUI module
will not refer to any code from the "UppercaseFilter" service provider.
That will be possible because the "UppercaseFilter"
service provider will be registered in the META-INF/services folder
and loaded via the NetBeans Lookup class, which is comparable to
the JDK 6 ServiceLoader class. You will then
create another loosely coupled service provider,
named "LowercaseFilter".</p>
<ol>
<li>Expand the new application in the Projects window,
right-click the Modules node, and choose "Add New". Name the new
module "TextFilterAPI":
<p><img alt="uppercase" src="../../images/tutorials/quickstart-platform/70/wordapp083.png"/></p>
<p>Click Next. Use code name base "org.word.editor.api" and
complete the wizard, which adds the module to your previously created
application, as you did in the previous section:</p>
<p><img alt="uppercase" src="../../images/tutorials/quickstart-platform/70/wordapp084.png"/></p></li>
<li>Right-click the "TextFilterAPI" module and choose
New | Java Interface. Name the Java interface "TextFilter",
in the package "org.word.editor.api", and use the editor
to define it as follows:
<pre class="examplecode">package org.word.editor.api;
public interface TextFilter {
String process(String s);
}
</pre></li>
<li>Right-click the "TextFilterAPI" module,
choose Properties, and use the "API Versioning"
tab to specify that the package containing the
interface should be available throughout the
application:
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp10.png"/></p></li>
<li>Create a third module in your application,
name it "UppercaseFilter":
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp11.png"/></p></li>
<li>
<p>Click Next. Use "org.word.editor.uppercase" as the
code name base:</p>
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp12.png"/></p>
<p>Click Finish.</p>
</li>
<li>Right-click the "UppercaseFilter" module,
choose Properties, and use the "Libraries"
tab to add a dependency on the "TextFilterAPI" module:
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp13.png"/></p>
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp14.png"/></p></li>
<li>In the same way as shown in the previous step,
set a dependency on the Lookup API module, which provides the
ServiceProvider annotation that you will use in the next step.</li>
<li>Because of the Lookup API dependency you defined above,
you can now implement the
interface defined in the second module. Do so by creating
a new class named "UppercaseFilter", in the "org.word.editor.uppercase" package,
as shown below:
<pre class="examplecode">package org.word.editor.uppercase;
import org.openide.util.lookup.ServiceProvider;
import org.word.editor.api.TextFilter;
@ServiceProvider(service=TextFilter.class)
public class UppercaseFilter implements TextFilter {
public String process(String s) {
return s.toUpperCase();
}
}</pre>
<p class="tips"> At compile time, the @ServiceProvider annotation will create a META-INF/services
folder with a file that registers your implementation of the
TextFilter interface, following the JDK 6 ServiceLoader mechanism.</p></li>
<li>The code that handles a click on the
filter button now needs to be changed, so that an
implementation of the interface "TextFilter" is located
and loaded.
When such an implementation is found, it is invoked to
filter the text.
<p>Before we can do this, we need to
add a dependency in the Project Properties dialog of
the "WordEditorCore" module to the "TextFilterAPI" module:</p>
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp12a.png"/></p>
<p>Now, you can load implementations of the
"TextFilter" class, as shown below:</p>
<pre class="examplecode">private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String enteredText = text.getText();
<b>Collection&lt;? extends TextFilter> allFilters = Lookup.getDefault().lookupAll(TextFilter.class);</b>
StringBuilder sb = new StringBuilder();
for (TextFilter textFilter : allFilters) {
String processedText = textFilter.process(enteredText);
sb.append(processedText).append("\n");
}
text.setText(sb.toString());
}</pre>
<p class="tips"> The above could be achieved via the
JDK 6 "ServiceLoader" class, except that the
"Lookup" class can be used in JDK's prior
to JDK 6. Aside from that, the "Lookup" class
has a number of additional features, as the
next section will illustrate.</p>
</li>
<li>Now you can run the application again and check
that everything works just as before. While the functionality
is the same, the new modular design offers a clear separation
between the GUI and the implementation
of the filter. The new application can also be extended
quite easily, simply by adding new service providers to
the application's classpath.</li>
<li>As an exercise, add a new module that provides a "LowercaseFilter"
implementation of the API to the application.</li>
</ol>
<p>You have now used the default Lookup, that is, "Lookup.getDefault()", to load
implementations of an interface from the META-INF/services folder.</p>
<!-- ===================================================================================== -->
<h2 class="tutorial"><a name="listener"></a>LookupListener and InstanceContent</h2>
<p>In this section, we create a fourth module, which receives texts
dynamically whenever we click the "Filter!" button
in our first module.</p>
<ol>
<li>In the "Word Editor Core" module, change the
constructor of the "TextTopComponent" as follows:
<pre class="examplecode"><b>private InstanceContent content;</b>
private TextTopComponent() {
initComponents();
setName(NbBundle.getMessage(TextTopComponent.class, "CTL_TextTopComponent"));
setToolTipText(NbBundle.getMessage(TextTopComponent.class, "HINT_TextTopComponent"));
// setIcon(Utilities.loadImage(ICON_PATH, true));
<b>content = new InstanceContent();
associateLookup(new AbstractLookup(content));</b>
}</pre></li>
<li>Change the code of the filter
button so that the old value is added to
the <tt>InstanceContent</tt> object when the button is clicked.
<pre class="examplecode">private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String enteredText = text.getText();
Collection&lt;? extends TextFilter&gt; allFilters = Lookup.getDefault().lookupAll(TextFilter.class);
StringBuilder sb = new StringBuilder();
for (TextFilter textFilter : allFilters) {
String processedText = textFilter.process(enteredText);
sb.append(processedText).append("\n");
<b>content.add(enteredText);</b>
}
text.setText(sb.toString());
}</pre>
</li>
<li>Create another module in your application and name it "WordHistory":
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp16.png"/></p>
<p>Click Next. Use code name base "org.word.editor.history":</p>
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp16a.png"/></p>
</li>
<li>In the WordHistory module, create a
new window component:
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp17.png"/></p>
<p>Use prefix "History",
in the "org.word.editor.history" package. Specify that
it should appear in the "explorer" position. </p>
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp17a.png"/></p></li>
<li>Once
you have created the window, add a
"JTextArea" to it. Change the variable
name of the text area to "historyText".</li>
<li>Add code to the constructor of the HistoryTopComponent class so
that it listens to the lookup of the <tt>String</tt> class
of the current active window. It displays all retrieved
<tt>String</tt> objects in the text area:
<pre class="examplecode">...
...
...
public final class HistoryTopComponent extends TopComponent implements LookupListener {
private org.openide.util.Lookup.Result&lt;String&gt; result;
public HistoryTopComponent() {
initComponents();
}
@Override
public void componentOpened() {
result = org.openide.util.Utilities.actionsGlobalContext().lookupResult(String.class);
result.addLookupListener(this);
}
@Override
public void componentClosed() {
result.removeLookupListener(this);
}
@Override
public void resultChanged(LookupEvent le) {
Collection&lt;? extends String&gt; allStrings = result.allInstances();
StringBuilder sb = new StringBuilder();
for (String string : allStrings) {
sb.append(string).append("\n");
}
historyText.setText(sb.toString());
}
...
...
...
</pre></li>
<li>Then you can start the application and
experiment with it. The result should look similar
to the one shown in the screenshot below:
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp19.png"/></p></li>
<li>As an exercise, redesign the user interface of the "TextTopComponent"
in such a way that a "JComboBox" displays the filters, as shown below:
<p><img alt="" src="../../images/tutorials/quickstart-platform/70/wordapp022.png"/></p>
<p>The "Filter!" button should use the currently selected filter
to process the text in the "JTextField".</p>
</li>
</ol>
<p>Congratulations! At this stage, with very little coding,
you have created a small example of a modular
application:</p>
<p><img alt="" style="border: 1px solid black;" src="../../images/tutorials/quickstart-platform/70/wordapp20.png"/></p>
<p>The application consists of 4 modules. Code from one module can only
be used by another module if (1) the first module explicitly exposes
packages and (2) the second module sets a dependency on the first module.
In this way, the NetBeans Platform helps to organize your code in a
strict modular architecture, ensuring that code isn't reused randomly
but only when there are contracts set between the modules that provide
the code.</p>
<p>Secondly, the <tt>Lookup</tt> class has been introduced as
a mechanism for communicating between modules, as an extension of the
JDK 6 ServiceLoader approach. Implementations are loaded via their
interfaces. Without using any code from an implementation, the "WordEditorCore"
module is able to display the service provided by the implementor. Loose
coupling is provided to NetBeans Platform applications in this way.</p>
<p class="tips"> To continue learning about modularity
and the NetBeans Platform, head on to
the four-part "NetBeans Platform Selection
Management" series, <a href="https://platform.netbeans.org/tutorials/nbm-selection-1.html">which starts here</a>.
After that, get started with the <a href="https://netbeans.org/kb/trails/platform.html">NetBeans Platform Learning Trail</a>, choosing
the tutorials that are most relevant to your particular business scenario. Also,
whenever you have questions about the NetBeans Platform, of any kind, feel free
to write to the mailing list, dev@platform.netbeans.org; its related
archive <a href="https://netbeans.org/projects/platform/lists/dev/archive">is here</a>.</p>
<p>Have fun with the NetBeans Platform and see you on the mailing list!</p>
</body>
</html>