# JavaOne Hands-On Lab ## Save Time—Build Desktop Applications Quickly with the NetBeans Platform ## LAB-5540 ### Copyright 2009 Sun Microsystems

# LAB-5540: Save Time—Build Desktop Applications Quickly with the NetBeans Platform

Expected Duration: 100 minutes
Contacts: Jiri Rechtacek, Lukas Hasik

The NetBeans Platform provides a reliable and flexible application architecture for desktop applications. Though it is known principally as the basis of NetBeans IDE, the end result does not need to look anything like it. It can save you years of development time. The NetBeans Platform gives you a time-tested architecture for free, together with a range of useful Swing components. An architecture that encourages sustainable development practices is provided out of the box, because the NetBeans Platform architecture is modular, making it easy to create applications that are robust and extensible.

This Lab will show you the most important APIs of NetBeans Platform. You will port a small Swing application to a new application based on the NetBeans Platform.

Copyright

                                Copyright  2009 Sun Microsystems, Inc. All rights reserved. Sun, Sun Microsystems,
                                the Sun logo, Solaris, Java, the Java Coffee Cup logo, JavaOne, the JavaOne logo,
                                and all Solaris-based and Java-based marks and logos are trademarks or registered
                                trademarks of Sun Microsystems, Inc. in the United States and other countries.

### Prerequisites

This hands-on lab assumes you have some basic knowledge of, or programming experience in, the following technologies:

- Java™ language programming

You will need to refer to the accompanying presentation 5540_netbeansrcp.pdf during the lab.

### System Requirements

- Supported OSes: Solaris™M 8/9/10 Operating System (OS), OpenSolaris™ Operating System (OS), Linux, Windows, Mac OS X 10.4+
- Memory requirement: 512MB
- Disk space requirement: 650MB

System Requirements of NetBeans IDE

### Software Needed For This Lab

Please install the following set of software. If you have any questions on installation, please feel free to send questions to the lab forum mentioned below.

- NetBeans IDE 6.7 - Java or All bundle
- JDK 5.0 Update 14 and higher
- 5540_netbeansrcp.zip file

### Notations Used in This Documentation

- `<lab_root>` - directory into which lab zip file is unzipped
  - This document uses `<lab_root>` to denote the directory under which you have unzipped the lab zip file of this hands-on lab. The name of the lab zip file of this hands-on lab is 5540_netbeansrcp.zip.
  - Once you unzipped the lab zip file under `<lab_root>`, it will create a subdirectory called netbeansrcp. For example, under Solaris, if you have unzipped the lab zip file in the /home/meandmy directory, it will create /home/meandmy /netbeansrcp directory.

- The lab machines are running Java Desktop System over Solaris 10
- In order to open a terminal window in Java Desktop System, right click any point in the background of the desktop, and select Open Terminal in the pop-up menu.
- The following source code editors are provided on the lab machines
  - vi (type vi in a terminal window)
  - emacs (type emacs in a terminal window)
  - jedit (type jedit in a terminal window)
  - NetBeans IDE (either click NetBeans IDE icon or type netbeans in a terminal window)

### Lab Exercises

- Exercise 0: Install and configure the lab environment
- Exercise 1: Port the Anagram Swing application to the NetBeans Platform
- Exercise 2: Extend the NetBeans Platform application using NetBeans IDE
- Exercise 3: Create an admin module for the Anagram Application
- Exercise 4: Package, publish, and update the application

### Additional Resources

- Lab-5540 NetBeans RCP presentation
- NetBeans Platform
- NetBeans Platform Tutorials
- Definitive Guide to NetBeans Platform
- NetBeans Platform API Javadoc

### Where To Go For Help

- For general questions and feedback on JavaOne Hands-On Labs, please use JavaOne_HOL_Forum .
- You can send technical questions via email to the authors of this Hands-on lab (and experts on the subject) or you can send your questions to the public users alias:
  - dev@openide.netbeans.org

### Exercise 0: Install and Configure Lab Environment

In addition to the contents of this lab's ZIP file, you should have the following installed on your computer:

- A Java SE software installation, version 1.5.0_14 or higher. The version can be found by running: `java -version`

- NetBeans IDE 6.7 - Java or All distribution. You can download it from netbeans.org

If `java` is not in your default execution path, you will need to set `JAVA_HOME` to point to the root of its installation on your system.

## Exercise 1: Port the Anagram Swing Application to a NetBeans Platform Application (20 minutes)

This exercise shows how to port an existing application to the NetBeans Platform.

The NetBeans Platform consists of many different modules that, together, form a complex application. Therefore, you should always choose only those pieces that are necessary for your application. By the end of this exercise, attendees will understand the different parts of the NetBeans Platform. They will integrate their own branding to the NetBeans Platform, making their application unique.

### Background Information

#### Introducing to the NetBeans Platform

NetBeans is an open source project that is mostly known because of the NetBeans IDE that is built on top of it. However, NetBeans is more then just an IDE. It is also a rich-client platform that provides components for easy and fast development of new desktop applications. There is also a vibrant community around the NetBeans project. The community uses the NetBeans Platform in many projects that leverage the features and spread the NetBeans framework into areas where you wouldn't expect it to be at all. You can look at several screenshots of applications based on the NetBeans Platform.

List of APIs Used in this Exercise

- Module System API
- Windows System API

In this exercise, you will port a Swing application to an application based on the NetBeans Platform. You will see that such a transition can be relatively simple and fast. It should be quite an interesting experience as well, while in the next exercises you'll see even more of the NetBeans Platform's features.

### Steps to Follow

Step 1: Opening the Anagram Swing Application

1. If NetBeans IDE is not already running, start it.
   - Either click NetBeans IDE icon on your desktop
   - or choose NetBeans IDE from application menu
   - or `netbeans` from command line.

2. When NetBeans has started, select File->Open Project (Ctrl-Shift-O) and browse to the AnagramGame directory that is located in `<lab_root>/exercises/exercise1`.

3. Click the Open Project button.

4. After the project has opened, invoke Run->Run Project (F6). You will see the Anagram Game running. This the Swing Application which we would like to port to an application built on top of the NetBeans Platform in the following exercises.

5. You can close the Anagram Game application.

Step 2: Creating a New NetBeans Platform Application

1. Invoke File->New Project (Crtl-Shift-N) and choose the NetBeans Modules category, then select NetBeans Platform Application.

2. Click Next button and type JavaOne 2009 Anagram Application into Project Name textfield.

3. Click Finish button to create the project.

4. When the project opens in IDE, select the JavaOne 2009 Anagram Application node in the Projects tab. Invoke Properties from a pop-up menu on this node. These Properties allows you to customize the new application.
   If you select the Libraries node then you can specify what NetBeans modules will be available in your NetBeans Platform application. These modules are divided in clusters e.g. platform10.

   For example you can uncheck following modules under platform10 :

       Command Line Parsing API
       Common Annotations
       JavaHelp Integration
       JUnit 4
       KeyMap Options
       Output Window
       Print

Step 3: Brand the application

1. In the Project Properties - JavaOne 2009 Anagram Application dialog, select the Build node. Now you can change the application's title and icon. Click Browse button and choose anagram48.png icon `<lab_root>/exercises/exercise1` directory. This icon you will see in the application status bar when the application is running.

2. Now we would like to show a splash screen while the new Anagram application is launching. To change the default NetBeans Platform splash screen to your splash window select Splash Screen node and browse to `<lab_root>/exercises/exercise1/anagram.png`. Let's also refine color of text and progress bar on the splash screen.

3. Click OK button to save changes.

Step 4: Creating a main module in a NetBeans Platform application

1. Now we have branded the wrapper of the application. We can run empty NetBeans platform but it has no content yet. We need to add a effective module that provides a functionality to the application. Switch again into Projects tab and select a node Modules under JavaOne 2009 Anagram Application. Invoke a pop-up menu by right click on this node.

   Choose Add Existing and select the Anagram project. However NetBeans IDE forbids to do this. Only NetBeans Application modules are allowed to be a part of a NetBeans Platform Application.

2. We will have to create new module and add it to our application. Then we will copy the sources from Anagram Swing application into the new module because we want to modify the behavior and look of the Swing application rapidly.
   Invoke the same pop-up menu and choose Add New... item. Type a name of Platform Module, e.g. Anagram JavaOne 2009.

3. On the next panel you have to provide a Code Name Base. The Code Name Base must be a unique name which identifies the module among other modules or libraries in the NetBeans Platform for NetBeans Module System which loads NetBeans modules. Type Code Name Base org.javaone.anagram.

4. Click Finish button.

Step 5: Copy sources from Anagram Swing application into the NetBeans Platform application

1. Switch the view on packages in Projects view to Tree view. Right click to an empty space in the Project view and select View Java Packages as > Tree.

2. Now Copy the lib and ui packages from original Anagram into org.javaone.anagram package in new Anagram Javaone 2009 project. The NetBeans IDE will automatically refactor packages to make them compilable.

3. Let's try to launch the application now. The application should run but still without any new content. We need to attach the new Anagram module to open new Anagram Game when the application is started.

4. If you want you can switch back to View Java Package As List view. Actually, it depends what view you like more. There is a plenty ways how you can customize the NetBEans IDE to your needs or habbits.

Step 6: Attach existing Anagram frame into the NetBeans Platform application

1. We want to start a new game on each start of the application, the window with this game should cover the whole size of the application, in the same way as was done in the original Swing application. To make that happen, we will use a template Window Component from predefined templates suitable for building application on the NetBeans Platform. The Window Component creates a new singleton Window integrated into NetBeans Window System.
   Invoke New > Window Component on org.javaone.anagram package

2. On the "Basic Settings" panel of New Window wizard dialog we can customize behaviour of this UI component.

   1. First, we have to specify where the window will be placed in the NetBeans Platform application. The space of NetBeans Window System is divided into modes. The central area of application is an Editor area, in a common case.
   2. Then we can make the window to be opened when the application starts.
   3. User cannot close this window.(this option is available from NB 6.7)
   4. Leave default values for rest of options.

3. On the last panel just tell some prefix of classes which will be created to handle behavior of this Window Component, e.g. AnagramGame.

4. Pres Finish button.

5. We have the Window Component (i.e. AnagramGameTopComponent) and UI component of Anagram Game (i.e. Anagram.class frame). Now we need to place Anagram's UI into the new Window Component. If it is not opened already then open the AnagramGameTopComponent source in UI designer, simply by double clicking on AnagramGameTopComponent node in Projects tab.

   In the UI designer place a new Panel by dragging the Panel from the Palette to the free space in AnagramGameTopComponent. Make this panel to cover whole free area and set BorderLayer as layout of this component.

   Change the name of the JPanel component to anagramPanel in Properties window Code > Variable Name.

6. Now, switch into editing source of AnagramGameTopComponent (use the Source button on the top-left corner of editor area). There add new line to the constructor

            public AnagramGameTopComponent() {
                initComponents();
                anagramPanel.add(new Anagrams().getContentPane(), BorderLayout.CENTER);//TODO:[add] place panel to the TC
                setName(NbBundle.getMessage(AnagramGameTopComponent.class, "CTL_AnagramGameTopComponent"));
                setToolTipText(NbBundle.getMessage(AnagramGameTopComponent.class, "HINT_AnagramGameTopComponent"));
                ...

   Don't forget to fix imports if you copy&paste the line to the source code.
   Applying these changes allows us to launch the Anagram Game Application. We can play Anagram Game again in the application built on the NetBeans Platform.
You can see that it was very easy to add your JFrame to the NetBeans Platform. The application still looks almost the same as it did in the original one. In next steps and exercises will we'll show you how to modify the application behaviour to use the other features of NetBeans Platform.

Step 7: Customize face of the application

1. How to remove the toolbar? It's obvious that the toolbar isn't necessary for the Anagram application. NetBeans Platform allows to declare many of UI components in particular layer.xml files. Each module can have such layer.xml in which it declates own UI component. But at least but not last, the module can also hide UI components of other modules.
   In our case, we can delete the declaration of Toolbar in the layer file.

   Expand the Important Files in of Anagram JavaOne 2009 module, choose node this layer in context under XML Layer node. Expland this node and find Toolbars sub-node. Then delete it. It removes the toolbars from Anagram application.
   In the same way you can modify the toolbars, icons, actions in toolbar. But in our case we don't need the toolbar at all.

2. How to clear up menus? Find the node Menu Bar under the this layer in context node. Delete all menu items with the exception of Help > About and File > Exit. You can also move the Help menu to highest level out from Help submenu

3. Run the application.

### Summary

In this exercise, you learned how to create a NetBeans Platform Application from an existing Swing application. You also learned how to brand your application, together with some basics on how to extend the application with NetBeans IDE.

In the following exercises, we will learn about the basics of building applications using the NetBeans Platform, visualizing application data in a tree-like component, and how to add new actions to our application.

At a later point, we will look at the modularization of applications built on top of the NetBeans Platform and how to publish our module to public or private locations.

## Exercise 2: Extend the NetBeans Platform application using NetBeans IDE (25 minutes)

In this exercise we will learn about the basics of building applications using the NetBeans Platform, visualizing application data in a tree-like component, registering your own actions into NetBeans Options framework and else notable skeletons.

We've learned how to brand a NetBeans Platform application to our business needs. We know how to port a Swing Application to the NetBeans Platform. Next, we would like to extend it with a new features.

### Background Information

#### Visualizing data

There are many ways of visualizing data in a NetBeans Platform application. One of the options is to show your data in a tree-like structure with nodes showing values. With the NetBeans Platform, you can use the Nodes API to create your tree-like structure and Explorer & Property Sheet API to show it in the application.
To manipulate the data you'll need some actions. That's where the Actions API comes to play. The Actions API is widely used in NetBeans Platform in many other places.

List of used APIs

- Actions API
  The Actions API allows users to interact with module code, by invoking actions via menus, toolbars or keyboard shortcuts. You do not need to use any special interfaces - just create a `javax.swing.Action` and register it.
- Nodes API
  The Nodes API controls the usage and creation of `nodes`, which are a variant of JavaBeans that may have adjustable property sets; provide interfaces to other capabilities and actions; be visually displayed in the Explorer with full hierarchy support; and other features.
- Explorer API
  Explorer views are UI components which render `nodes` - the most prominent in NetBeans being the Project and Files tabs on the left side of the main window. The Explorer API provides UI components to render nodes in trees, lists, combo boxes, menus, tree tables. These components handle things like cut/copy/paste, drag and drop, displaying popup menus for nodes, which contain the actions the clicked node provides from `getActions()`.
- Preferences API
  NetBeans uses standard Java Preferences API as a way for NetBeans modules to store and retrieve user and system preference, configuration data.

### Steps to Follow

Step 1: Register a new action

1. The Anagram application can start a new Anagram Game on each launch of application. But it's not enough. We would like to allow users to start more games then only once. To do so, we need a new action which opens a new game window and start an new instance of Anagram game.

   NetBeans Platform support offers a template for creating new action in NetBeans module. Invoke File->New File (Crtl-N) or from a pop-up on the org.javaone.anagram sources package. Select Action in Module Development category.

2. On the next panel choose a Always enabled option. It will create action that will be available all the time. The other option "context-sensitive" action would create action that is enabled only under some circumstances. For example when you select a node in Explorer or when a particular file is opened in Editor.

3. 1. Type Anagram into Category field.
   2. Check Global Menu Item and choose File menu item.
   3. Check Separator After option.
4. Click Next button.

5. On the last panel set prefix of action name, e.g. NewGame and then set a display name of this action in the menu bar, e.g.&New Game.
   NetBeans Platform allows to specify mnemonics of menu items, buttons, labels, etc. by the & character before the character of the mnemonic. It means that in our case you can invoke the New Game action by N in menu.

6. Click Finish button.

7. Open the class NewGame in editor. There is generated a method actionPerformed() which will be called on each invocation of File->&New Game in the menu bar.

   The method actionPerformed() should open a next window in the Editor area like the initial Window Component does. Only descendants of org.openide.windows.TopComponent are allowed to be placed in NetBeans Window System. Thus we need to create new instance of TopComponent and then open it in the Editor mode.

            public void actionPerformed(ActionEvent e) {
                Mode editorMode = WindowManager.getDefault ().findMode ("editor");
                assert editorMode != null && WindowManager.getDefault ().isEditorMode (editorMode);
                TopComponent tc = new GameTopComponent (new Anagrams ());
                tc.open();
                tc.requestActive();
            }

            private class GameTopComponent extends TopComponent {
                private Anagrams game;
                public GameTopComponent (Anagrams game) {
                    initComponents ();
                    this.game = game;
                    add (game.getContentPane (), BorderLayout.CENTER);
                }
                private void initComponents() {
                    this.setLayout (new BorderLayout ());
                }

                @Override
                public String getDisplayName() {
                    return "Anagram Game";
                }

                @Override
                public int getPersistenceType () {
                    return PERSISTENCE_NEVER;
                }

                @Override
                protected String preferredID () {
                    return Integer.toString (System.identityHashCode (game));
                }

            }

   Implementation of New Game Action allows users of Anagram application to start another Anagram games when one is finished.

8. Fix Imports. Mode should be `org.openide.windows.Mode`
Step 2: Add a Save Score Button

1. Open Anagrams class from org.javaone.anagram.ui package. You can see that there is Save Score button. We made it invisible. Go to source code and comment out following lines of code in Anagrams constructor

            public Anagrams() {
                wordLibrary = WordLibrary.getDefault();
                passed = 0;
                timer = new Timer ();
                startTime = System.currentTimeMillis ();
                initComponents();
            //        saveScore.setVisible(false);
            //        saveScore.setEnabled(false);
                lScoreTitle.setText("Time: ");
                lScore.setForeground(Color.green);
                timer.schedule (new TimerTask () {

2. We will use Dialogs API to show simple dialog to user. User can then provide name that will be saved into high scores list that we will create at the end of the exercise.
   Furthermore, we will use Preferences API for for storing the high scores in module's preferences storage. There we can store and then load back any primitive data or `Strings`. It will make them persistent across restarts.
   Use `NbPreferences.forModule(Anagrams.class)` to acquire a storage for storing scores. On this storage we will call both methods `getInt`, `setInt` for storing and loading score values.
   Copy and paste following code into saveScoreActionPerformed(...) method in Anagrams.java class. The saveScoreActionPerformed method handles the action binded to the button.

            private void saveScoreActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveScoreActionPerformed
                // setup the text of the dialog
                NotifyDescriptor.InputLine nd = new NotifyDescriptor.InputLine ("What is your name?", "Save Score");
                nd.setInputText(System.getProperty("user.name"));
                DialogDisplayer.getDefault().notify(nd);
                if (NotifyDescriptor.CANCEL_OPTION.equals(nd.getValue())) {
                    // no name
                    return;
                }
                saveScore.setEnabled(false);
                String name = nd.getInputText();
                Preferences pref = NbPreferences.forModule(Anagrams.class);
                int best = pref.getInt(name, -1);
                if (best > passed) {
                    NotifyDescriptor.Confirmation nd2 = new NotifyDescriptor.Confirmation(name +
                           " achieved a better score " + best +
                           ". Overwrite?", "Overwrite best score");
                    DialogDisplayer.getDefault().notify(nd2);
                    if (NotifyDescriptor.YES_OPTION.equals(nd2.getValue())) {
                        pref.putInt(name, passed);
                    }
                } else {
                    pref.putInt(name, passed);
                }
                lScore.setText(name + " has the best score " + pref.getInt(name, 0));
            }

3. You will have to call Source > Fix Imports (Ctrl+Shift+I). It won't fix all the compilations errors because some of the calls need other NetBeans Platform libraries that provide these APIs and their functionality. The API that we need is Dialogs API.

4. How to add new library into module's libraries? Either go to project properties select Libraries and then press the Add Dependency... button or select Add Dependency... from popup on Libraries node under your module's project. You can type name of an class in a library or the library name to find it easier in the list of APIs.

5. Press OK will add the dependency to the Dialogs API and you can finish the Fix Imports in Anagrams class.

Step 3: Visualize Best Scores

1. Create new always-enabled action with display name &Show Score in class org.javaone.anagram.ShowScore class. Follow the same steps as you created the New Game action.
2. The Show Score action creates and opens new TopComponent with list of saved scores in "explorer" area when the actionPerformed method is called. Add following code to the actionPerformed method.
3. Find the "explorer" mode. It is on left side of application.

            public void actionPerformed(ActionEvent e) {
                Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
            }

4. Then create new ExplorerTopComponent and dock it into the explorer's mode.

            public void actionPerformed(ActionEvent e) {
                Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
                TopComponent tc = new ExplorerTopComponent ();
                explorerMode.dockInto(tc);
            }

5. And now we open the TopComponent and request the focus for it. So at the end your actionPerform method will look like

            public void actionPerformed(ActionEvent e) {
                Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
                TopComponent tc = new ExplorerTopComponent ();
                explorerMode.dockInto(tc);
                tc.open();
                tc.requestActive();
            }

6. Now we will add the content to the TopComponent that we opened with the Show Score action.
   As was said before, let's use Explorer API to visualize best scores in views. At first, we need to implement ExplorerManager.Provider which provides an Explorer Manager. It is a class that manages a selection and root context for a set of explorer views
   The next step is building `nodes`, nodes are based on best scores achieved in the Anagram Game. The root node is a simple ″Best Scores″ root node. This node has own children, each child is one of best scores.
   It means, we will implement AbstractNode and Children.Keys.
   Copy and paste following code into the ShowScore class.

        public final class ShowScore implements ActionListener {

            public void actionPerformed(ActionEvent e) {
                Mode explorerMode = WindowManager.getDefault ().findMode("explorer");
                TopComponent tc = new ExplorerTopComponent ();
                explorerMode.dockInto(tc);
                tc.open();
                tc.requestActive();
            }

            private class ExplorerTopComponent extends TopComponent implements ExplorerManager.Provider {
                private ExplorerManager em;

                public ExplorerTopComponent () {
                    initComponents ();
                    em = new ExplorerManager();
                    em.setRootContext(new BestScoresNode());
                }

                private void initComponents() {
                    this.setLayout (new BorderLayout ());
                    TreeView tv = new BeanTreeView ();
                    tv.setRootVisible(true);
                    add (tv, BorderLayout.CENTER);
                }

                @Override
                public String getDisplayName() {
                    return "Best Scores";
                }

                @Override
                public int getPersistenceType () {
                    return PERSISTENCE_NEVER;
                }

                public ExplorerManager getExplorerManager() {
                    return em;
                }

                @Override
                protected String preferredID () {
                    return Integer.toString (System.identityHashCode(em));
                }
            }

            private class BestScoresNode extends AbstractNode {
                private String displayName;
                public BestScoresNode(String name, Children ch) {
                    super(ch);
                    this.displayName = name;
                }

                public BestScoresNode(String name, int score, Children ch) {
                    super(ch);
                    this.displayName = name + " has the best score " + score;
                }

                public BestScoresNode() {
                    super(new BestScoresChildren());
                    this.displayName = "Best Scores";
                }

                @Override
                public String getDisplayName() {
                    return displayName;
                }

            }

            private class BestScoresChildren extends Children.Keys<String> {
                private Preferences pref;
                public BestScoresChildren () {
                    try {
                        pref = NbPreferences.forModule(Anagrams.class);
                        String[] keys = pref.keys();
                        if (keys != null && keys.length > 0) {
                            setKeys(keys);
                        } else {
                            setKeys(Collections.singleton(""));
                        }
                    } catch (BackingStoreException ex) {
                        Exceptions.printStackTrace(ex);
                    }
                }

                @Override
                protected Node[] createNodes(String key) {
                    if (key.length() == 0) {
                        return new Node[] { new BestScoresNode("No scores", Children.LEAF) };
                    } else {
                        return new Node[] { new BestScoresNode(key, pref.getInt(key, -1), Children.LEAF) };
                    }
                }
            }

        }

7. To fix all the imports and dependencies you'll have to add another two libraries with the used APIs.
   Add Dependency on Nodes API and Explorer & Property Sheet API. You should have following libraries under Libraries node of your module.
8. Fix Imports in the SaveScore class.
   - Children - org.openide.nodes.Children
   - Mode - org.openide.windows.Mode
   - Nodes - org.openide.nodes.Node

### Summary

In this exercise we enhanced the simple functionality of the Anagram Game with new actions that makes the game more usable and interesting. We created new action that allows to run more games. User can save their best scores too. And the best scores are visualized in nice tree-like structure. All these new features benefited from the NetBeans APIs.

## Exercise 3: Create a admin module for Anagram Application (30 minutes)

### Background Information

In the previous exercise we prepared the JavaOne 2009 Anagram Application built on top of NetBeans Platform. It allows to start new game and store, visualize the best results.
We will create new module Word Scrambler to improve the functionality of this application. Word Scrambler will serve as admin module for the Anagram Application.
We prepared this module for you as its functionality is very complex to be covered in the HOL.
What does Word Scrambler provide? It can read a text from file, makes pairs of scrambled and unscrambled words from the read text. And in addition it makes words with fixed length by a given parameter that express the complexity.
We need to provide some UI for calling this code and then establish a way to exchange words between Anagram Application and Word Scrambler.

### Steps to Follow

Step 1: Add new module into application

1. Open project Word Scrambler in `<lab_root>/exercises/exercise3/` in NetBeans IDE
2. Add Existing Module Word Scrambler to the JavaOne 2009 Anagram Application module.
3. Double click the new module to open it in NetBeans IDE.

Step 2: Run the test in Unit Test packages

1. To run all tests of project just open the popup menu of Word Scrambler project and choose Test menu item or use a short cut Alt-F6.
   Check the test results. All test should pass.

Step 3: Create a main window of Word Scrambler module

1. Create new Window Component in org.javaone.scrambler package in Word Scrambler module like in Exercise 1, Step 6. Component should be docked into editor mode. It should open on application start. Use prefix AnalyzeText.

2. Open the class `AnalyzeTextTopComponent` that was created by the Window Component wizard. Use Design button and sketch out UI. The UI should like on following picture:
   Use following naming and components, please

   Swing Component | Text | Variable Name
   --- | --- | ---
   JLable | File | lFile
   JTextField | <none> | tfFile
   JButton | &Browse | bBrowse
   JButton | &Analyze | bAnalyze
   JButton | &Upload to Anagram Game | bUpload
   JLabel | Word Scrambler has 4 complexity | lComplexity
   JList | <No words> | lWords

3. Add new private fields to the AnalyzeTextTopComponent class.

            private File textFile;
            private Scrambler scrambler;

4. Add a handling of `actionPerformed` event for the Browse button.
   Tip: Invoke a popup over Browse button in UI designer and then choose Events|Action|actionPerformed. It will create the actionPerform method and give focus into the right place in editor.
   In editor type following code that opens `JFileChooser` when you press Browse button.

            private void bBrowseActionPerformed(java.awt.event.ActionEvent evt) {
                JFileChooser chooser = new JFileChooser();
                chooser.setFileSelectionMode (JFileChooser.FILES_ONLY);
                chooser.setMultiSelectionEnabled (false);
                chooser.setFileHidingEnabled (true);
                chooser.setDialogTitle ("Select a text file");
                if (chooser.showOpenDialog (this) == JFileChooser.APPROVE_OPTION) {
                    textFile = chooser.getSelectedFile ();
                    tfFile.setText(textFile.getPath());
                    bAnalyze.setEnabled(true);
                }
            }

   It also sets the chosen file as content of the File textfield.
5. Fix imports.
   - File - java.io.File
6. Using as same way as before now to add a code handling the bAnalyze button.
   Analyze button should scramble text of given file.
   Tip: You can use `<lab_root>/words.txt` file to play with the Analyze functionality.

            private void bAnalyzeActionPerformed(java.awt.event.ActionEvent evt) {
                File f = new File(tfFile.getText());
                if (! f.exists()) {
                    NotifyDescriptor.Message nd = new NotifyDescriptor.Message
                            ("The file " + f.getPath() + " doesn't exist!", NotifyDescriptor.ERROR_MESSAGE);
                    DialogDisplayer.getDefault().notify(nd);
                    bUpload.setEnabled(false);
                    bAnalyze.setEnabled(false);
                    return;
                }
                String text = File2String.file2string(f);
                scrambler = new Scrambler(text, pref.getInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, 4));
                lWords.setListData(scrambler.getWords());
                bUpload.setEnabled(true);
                bAnalyze.setEnabled(false);
            }

7. Please, do not bother about the error of missing pref variable. We will fix it in next steps.

Step 4: Add new options to NetBeans Options framework

1. Invoke New > Other on org.javaone.scrambler package in WordScrambler module. Choose Options Panel in Module Development category.
2. Select Create Primary Panel radio button. Use value as on picture bellow. Browse the icon anagram32.png in `<lab_root>/exercise3` directory.
3. Class Name Prefix should be ScramblerComplexity.
4. Design the Scrambler Options Panel. Open ScramblerComplexityPanel. Add one label and one combo box to design.
5. Change the model of the combo box in Properties.
6. Implement both effective methods load() and store() of the options panel in source code of ScramblerComplexityPanel class. These methods store and load the options to be persistent even during several starts of the application. As you can see from the following code we used NbPreferences functionality that makes it quite simple.

            private final Preferences pref = NbPreferences.forModule(ScramblerComplexityPanel.class);

            void load() {
                int complex = pref.getInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, 4);
                jComboBox1.setSelectedItem(Integer.toString(complex));
            }

            void store() {
                String complex = (String) jComboBox1.getSelectedItem();
                pref.putInt(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, new Integer (complex));
                AnalyzeTextTopComponent.getDefault().setComplexity(complex);
            }

            boolean valid() {
                return true;
            }

7. Add new SCRAMBLER_COMPLEXITY field into the ScramblerComplexityOptionsPanelController class.

            public static final String SCRAMBLER_COMPLEXITY = "scrambler_complexity";

8. Create new method setComplexity(String complex) in AnalyzeTextTopComponent class.

            void setComplexity(String complex) {
                lComplexity.setText("Word Scrambler has " + complex + " complexity.");
                boolean canAnalyze = new File(tfFile.getText()).exists();
                bAnalyze.setEnabled(canAnalyze);
                bUpload.setEnabled(false);
            }

9. Now we have to modify the constructor of the AnalyzeTextTopComponent class to setup the complexity according to value selected in Options.

            public AnalyzeTextTopComponent() {
                initComponents();
                setComplexity(pref.get(ScramblerComplexityOptionsPanelController.SCRAMBLER_COMPLEXITY, "4"));
                bAnalyze.setEnabled(false);
                bUpload.setEnabled(false);
                setName(NbBundle.getMessage(AnalyzeTextTopComponent.class, "CTL_AnalyzeTextTopComponent"));
                setToolTipText(NbBundle.getMessage(AnalyzeTextTopComponent.class, "HINT_AnalyzeTextTopComponent"));
           }

10. Add new private field pref for reading the preferences in the AnalyzeTextTopComponent class.

             private final Preferences pref = NbPreferences.forModule(ScramblerComplexityPanel.class);

11. To be able to Fix Imports you will have to add new dependency on Dialogs API library first.
12. Delete all other instances from OptionsCategory.createCategory except the one that we created from the layer file. The one created by us is in bold. In this way you'll mask out the other Options Panels.

Step 5: Make a relation between Anagram Game module and this Word Scrambler admin module

1. NetBeans Platform Module System discriminates between public and private modules and a module can uses only classes from public part of modules. Only a part of a module is visible to the rest of modules. This public part that is visible to other modules is known as the public packages.
   We have to explicitly indicate that a Java packages of Anagram Game project are visible to Word Scrambler module. Make org.javaone.anagram.lib package public. It will allow us to use it in other modules.
2. Add Anagram Game JavaOne 2009 as a new dependency of Word Scrambler module. Please, note that Anagram is Non-API module, don't forget to check the Show Non-API Modules checkbox.

Step 6: Post new words into Anagram Game

1. Create new class AdditionalWordLibrary extending org.javaone.anagram.lib.WordLibrary in the org.javaone.scrambler package.

        /*
         * To change this template, choose Tools | Templates
         * and open the template in the editor.
         */

        package org.javaone.scrambler;

        import org.javaone.anagram.lib.WordLibrary;

        /**
         *
         * @author jirka
         */
        public class AdditionalWordLibrary extends WordLibrary {
            private final String[] words;
            private final String[] scramblers;
            private final int size;

            public AdditionalWordLibrary (final String [] words, final String [] scramblers) {
                this.words = words;
                this.scramblers = scramblers;
                this.size = words.length;
            }

            @Override
            public String getWord(int idx) {
                assert idx < size;
                return words[idx];
            }

            @Override
            public String getScrambledWord(int idx) {
                assert idx < size;
                return scramblers[idx];
            }

            @Override
            public int getSize() {
                return size;
            }

            @Override
            public boolean isCorrect(int idx, String userGuess) {
                assert idx < size;
                return words [idx].equalsIgnoreCase(userGuess);
            }

        }

2. Now we have to use the dynamic approach of the AdditionalWordLibrary and connect it with the AnalyzeTextTopComponent. Create action handler for the Upload to Anagram Game button at AnalyzeTextTopComponent. Right click the Upload button and choose Events > Action > actionPerformed.
3. Post scrambler words from Scrambler into Anagram Game. Add following code to AnalyzeTextTopComponent.

            private void bUploadActionPerformed(java.awt.event.ActionEvent evt) {
                // upload to Anagram Game
                WordLibrary wd = new AdditionalWordLibrary (scrambler.getWords(), scrambler.getScrambledWords());
                WordLibrary.setDefault(wd);
                bUpload.setEnabled(false);
                bAnalyze.setEnabled(false);
            }

   Fix imports.

Step 6: Run the application

1. We removed all the menu items in Exercise 1 therefore we have to delete following line from XML Layer file under Important Files in Anagram JavaOne 2009 project.

             <file name="Tools_hidden"/>

### Summary

In this exercise we created new module that allows to manage the words in the anagram game. You learned how to design new top component and how to use a module as library. You should know how to add new panel to Options and how to store and load their values.

## Exercise 4: Packaging, publishing, updating (20 minutes)

### Background Information

1. About NBM format

   Every NetBeans module has the capability to create a NetBeans package which contains the project's binaries, together with meta-data describing the author of the plugin and the the license. As well, the meta-data contains a name and a description of the plugin and the category to which it belongs.
   You can find more information at DevFaqWhatIsNbm.

2. About Autoupdate Functionality and the Plugin Manager

   NetBeans Autoupdate functionality provides several services to the IDE: download and install available updates of installed modules, search and then install new features from subscribed Update Centers, browsing and manipulating the modules in IDE installation.

3. What is a Update Center?

   Update Center is a place with own URL containing a set of NetBeans NBM Package files (NBMs) and a descriptor (a XML based file) describing these NBMs. Such Update Center Descriptors can be add into IDE as new NetBeans Update Centers.
   NetBeans uses Update Centers for delivering new features for NetBeans IDE and also for delivering updates to allow users to keep the IDE up to date.

4. What is the NetBeans Plugin Portal?

   The Plugin Portal is a web application that allows the NetBeans community to contribute to the NetBeans plugin eco-system by adding plugins and also commenting on and rating the existing plugins.

### Steps to Follow

Step 1: Create NBM action

Each NetBeans project has Make NBM action in own project's popup. This action allows you build own NBM package from project. You can deliver the NBM file to others: send via mail, publish on you weblog, etc. For installing an NBM into a NetBeans Platform application, use the Plugin Manager, invoke Tools | Plugins in the application.

Step 2: Customize meta-data for visualizing in Plugin Manager

1. Open the NetBeans Project Properties aka project customizer from project's popup. Choose the Display category. There you can select some suitable category if any, or create new one. Let's create Games category for this project.
   Then fill in the Short & Long Descriptions of the project.
   The Plugin Manager will display this information to allow users for searching.
   Important: to ensure a NBM will be visible in NetBeans Plugin Manager you have to check Show in Plugin Manager.
2. Other interesting information is in Packaging category. There you should fill in your name, a home page this project and a license.
   Important: This form contains a check box Needs Restart on Install. If checked this option, the IDE forces restart IDE when this NBM is installing. Use this option carefully. Check it only if you really need to restart whole IDE for setup it completely.

>

Step 3: Invoke Create NBM action and install NBM into IDE

1. Invoke Create NBM and build NBM file from the project. Look at Output tab

   . There is info where the NBM was created.
2. How can I try the NBM out? We need a fresh IDE to test the installation on the newly created NBM. To run a fresh IDE we need to run NetBeans IDE with special option `--userdir`, best would be to use a command line client. Invoke something like:

       [jirka@rechtacek-nb kenai]$ cd $NETBEANS_INSTALLATION_DIR
       [jirka@rechtacek-nb nb_all]$ cd netbeans/bin/
       [jirka@rechtacek-nb nbbuild]$ ./netbeans --userdir /tmp/testnbm

   When IDE starts up we can open Plugin Manager from Tools | Plugins. Switch to the Downloaded tab and press a Add plugins button, browse on the NBM that you built in previous steps.
   The Plugin Manager shows the NBM and we can install it.
   Note: While installing the NBM you are got a warning the NBM aka plugin is not signed. Just ignore it for now, and continue in installation. For more information about signing check out DevFaqSignNbm.

Step 4: Create own Update Center

1. Now switch back into the IDE containing our projects. Beside creating individual NBM files, IDE offers to make own Update Center. As we said before, the Update Center consists a XML file describing a set of NBM files. Action Create NBMs is available for each module suite of NetBeans modules.
   This action when invoked, creates an Update Center which contains both projects:
   - Anagram JavaOne 2009
   - Word Scrambler
   You find the placement of the XML file with both NBMs describing the Update Center in the Output window.

Step 5: Add new Update Center into IDE

1. If we would like to add this new Update Center, we use the second instance of IDE which should be still running. There, open the Plugin Manager again. Switch into Settings tab. In this tab is a button Add for adding new Update Centers.
   Adding new Update Center should add a new item into Available Plugins. Why just only one although the UC contains both modules? Cause, the Anagram JavaOne 2009 is already installed in a previous step. It means, we can install the Word Scrambler into application, Word Scrambler hasn't been installed yet.

Step 6: Publish a NBM on Plugin Portal

1. We created a NBM files, to built own Update Center. It allows to deliver either our plugins as NBM packages or we may expose our Update Center xml on our web site. Then you can provide just URL link to the Update Center.
   On NetBeans site is a additional option how to publish plugins - using NetBeans Plugin Portal.
   For using this portal we need a registration. If you don't have account, you can easily create new one at Join NetBeans. All registered users can upload own plugins at NetBeans Plugin Portal. For uploading a NBM you have to upload the NBM file first and then fill in the form with basic meta-data like project's meta-data which we filling in the previous step 2
   Exposing plugins on the Plugin Portal makes possible to share our contributions with other NetBeans users, moreover to rate these plugins. Note: In the case you would like to promote a plugin for the wider audience, you have request for a verification of quality. If the plugin passed then the plugin will be offered to all users of NetBeans IDE via Plugin Manager. Check out the page FaqPluginVerificationRequest.

### Summary

Congratulations! You have successfully completed Lab-5540: Save Time—Build Desktop Applications Quickly with the NetBeans Platform Hands-on lab.

Where to send questions or feedbacks on this lab and public discussion forums:

- You can send technical questions via email to the authors of this Hands-on lab (and experts on the subject) or you can post the questions to the web.

  Please post questions that are relevant only to this hands-on lab.

  - JavaOne_HOL_Forum

- You can send your other questions to the public users alias:

  - NetBeans Platform Users