| <!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> |