<!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ü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<? 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<? extends TextFilter> 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<String> 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<? extends String> 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> |