| <!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>Creating NetBeans Platform CRUD Application Using Maven</title> |
| <link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css"/> |
| <meta name="AUDIENCE" content="NBUSER"/> |
| <meta name="TYPE" content="ARTICLE"/> |
| <meta name="EXPIRES" content="N"/> |
| <meta name="indexed" content="y"/> |
| <meta name="description" |
| content="This tutorial demonstrates how to use the the Maven build framework to create a simple |
| NetBeans Platform application that can read and write to a database."/> |
| <!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. --> |
| <!-- Use is subject to license terms.--> |
| </head> |
| <body> |
| |
| <h1>Creating NetBeans Platform CRUD Application Using Maven</h1> |
| |
| <p>Welcome to the <a href="https://platform.netbeans.org/"><b>NetBeans Platform</b></a>!</p> |
| |
| <p>This document demonstrates how to use the Maven build framework to create a simple |
| NetBeans Platform application that can read and write to a database. |
| In this document you will use Maven archetypes to create the NetBeans Platform application and module, |
| and the Swing UI toolkit and "Matisse" GUI Builder to create window components. |
| </p> |
| |
| <p>This document is based on the Ant-based <a href="nbm-crud.html">NetBeans CRUD Application Tutorial for NetBeans Platform</a> |
| and illustrates some of the differences between using Ant and Maven to develop NetBeans Platform applications. |
| After you understand how Maven is different from Ant, you can easily proceed through other |
| tutorials on the <a href="https://netbeans.org/kb/trails/platform.html">NetBeans Platform Learning Trail</a>. |
| </p> |
| |
| <p class="tips">The CRUD Sample Application is one of the Maven samples available in the New Project wizard.</p> |
| |
| <p class="tips">If you are new to the NetBeans Platform, you might want 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>Contents</b></p> |
| <p><img src="../images/articles/69/netbeans-stamp69.png" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8" title="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8"/></p> |
| <ul class="toc"> |
| <li><a href="#config">Configuring Maven</a></li> |
| <li><a href="#01">Creating the NetBeans Platform Application Project</a> |
| <ul> |
| <li><a href="#01b">Creating a Module</a></li> |
| <li><a href="#01c">Making the Module a Dependency</a></li> |
| <li><a href="#01d">Branding the Application</a></li> |
| </ul> |
| </li> |
| <li><a href="#02">Creating the Entity Classes</a> |
| <ul> |
| <li><a href="#02a">Adding the DerbyClient as a Runtime Dependency</a></li> |
| <li><a href="#02b">Generating Entity Classes From the Database</a></li> |
| </ul> |
| </li> |
| <li><a href="#03">READ: Reading and Displaying a Record</a> |
| <ul> |
| <li><a href="#03b">Adding a Tree View to the Window</a></li> |
| <li><a href="#03c">Creating a Factory Class</a></li> |
| <li><a href="#03d">Modifying the Dependencies</a></li> |
| </ul> |
| </li> |
| <li><a href="#04">UPDATE: Editing a Record</a> |
| <ul> |
| <li><a href="#04b">Using a LookupListener</a></li> |
| <li><a href="#04c">Adding the Undo and Redo Functions</a></li> |
| <li><a href="#04d">Adding the Save Function</a></li> |
| <li><a href="#04e">Persisting Changes</a></li> |
| <li><a href="#04f">Adding a Refresh Function</a></li> |
| </ul> |
| </li> |
| <li><a href="#05">CREATE: Adding a New Record</a> |
| <ul> |
| <li><a href="#05b">Creating and Saving a New Object</a></li> |
| </ul> |
| </li> |
| <li><a href="#06">Running the Application</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="http://download.netbeans.org/netbeans/6.9/beta/">NetBeans IDE</a></td> |
| <td class="tbltd1">version 6.9 (Java)</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</td> |
| </tr> |
| <tr> |
| <td class="tbltd1"><a href="http://maven.apache.org/">Maven</a></td> |
| <td class="tbltd1">Version 2.0.9 or higher</td> |
| </tr> |
| <tr> |
| <td class="tbltd1">JavaDB or other database server and database</td> |
| <td class="tbltd1"> </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <p><strong class="notes">Note:</strong></p> |
| <ul> |
| <li>The JavaDB database server and a sample database is included with the bundled GlassFish Server Open Source Edition 3.0.1.</li> |
| <li>You do not need to download a separate version |
| of the NetBeans Platform to develop applications for the NetBeans Platform. |
| Typically, you develop the applications and modules in the NetBeans IDE and |
| then only include the modules that are necessary to run the NetBeans Platform and your application.</li> |
| </ul> |
| <p>Before starting this tutorial you may want to familiarize yourself with |
| the following documentation.</p> |
| <ul> |
| <li><a href="http://wiki.netbeans.org/MavenBestPractices">Best Practices for Apache Maven in NetBeans 6.x</a></li> |
| <li><a href="http://www.sonatype.com/books/maven-book/reference/introduction.html">Chapter 1. Introducing Apache Maven</a> |
| (from <a href="http://www.sonatype.com/books/maven-book/reference/public-book.html">Maven: The Definitive Guide</a>)</li> |
| <li><a href="https://netbeans.org/kb/docs/java/gui-functionality.html">Introduction to GUI Building</a></li> |
| </ul> |
| |
| |
| <!-- =================================================================== --> |
| <!-- +++++++++++++++ Configuring Maven +++++++++++++++++++++++++++++++++ --> |
| |
| <h2><a name="config"></a>Configuring Maven</h2> |
| <p>If this is your first Maven project you will want to check the Maven configuration settings in the Options window. |
| To complete this tutorial you must have Maven installed on your local system. |
| You can download the installer from the <a href="http://maven.apache.org/">Maven site</a>.</p> |
| |
| <ol> |
| <li>Select the Miscellaneous category in the Options window and click the Maven tab.</li> |
| <li>Specify the location of your local Maven installation (requires 2.0.9 or newer).</li> |
| <li>Check that the location of the local Maven repository is correct.</li> |
| <li>Click OK.</li> |
| </ol> |
| <p>In most cases, if your Maven configuration is typical the information in the Options window should already be correct.</p> |
| |
| <p>The IDE uses Maven SCM to checkout Maven artifacts. |
| You might want to check that any clients necessary for checking out sources are installed on your local machine and configured correctly.</p> |
| <p class="tips">For details on Maven SCM, see the |
| <a href="http://maven.apache.org/scm/index.html">Maven SCM page</a>.</p> |
| |
| <div class="indent"> |
| <h3><a name="config1"></a>Viewing the Maven Repositories</h3> |
| <p>The artifacts that are used by Maven to build all your projects are stored in your local Maven repository. |
| When an artifact is declared as a project dependency, the artifact is downloaded to your local repository |
| from one of the registered remote repositories.</p> |
| |
| <p>The NetBeans repository and several well-known indexed Maven repositories are registered and listed in the Repository Browser window by default. |
| The NetBeans repository contains most of the public artifacts necessary for you to build your project. |
| You can use the Maven Repository Browser to view the contents of your local and remote repositories. |
| You can expand the Local Repository node to see the artifacts that are present locally. |
| The artifacts listed under the NetBeans repository nodes can be added as project dependencies, but not all of |
| them are present locally. They are only added to the Local Repository when they are declared as project |
| dependencies.</p> |
| |
| <p>To open the Maven Repository Browser:</p> |
| <ul> |
| <li>Choose Window > Other > Maven Repository Browser from the main menu.<br/> |
| <img src="../images/tutorials/maven-quickstart68/maven-nbm-netbeans-repo.png" alt="Screenshot of Maven Repository Browser" title="Screenshot of Maven Repository Browser" class="margin-around b-all" /> |
| </li> |
| </ul> |
| |
| |
| <p>When your cursor is over an artifact, the IDE displays a tooltip with the artifact's coordinates. |
| You can view additional details about an artifact by double-clicking the artifact's JAR file in the browser.</p> |
| |
| <p class="tips">You can search for an artifact by clicking the Find button in the toolbar of the Maven Repository Browser |
| or by using the Quicksearch textfield in the main toolbar.</p> |
| <p class="tips">For more about managing Maven classpath dependencies and working with Maven repositories in the IDE, |
| see the <a href="http://wiki.netbeans.org/MavenBestPractices#Dependency_management">Dependency Management</a> |
| section of <a href="http://wiki.netbeans.org/MavenBestPractices">Best Practices for Apache Maven in NetBeans 6.x</a>. |
| </p> |
| <p class="tips">To see a demonstration of using the Artifact Viewer, see the <a href="https://netbeans.org/kb/docs/java/maven-dependencies-screencast.html"> Working with Maven Dependencies</a> screencast.</p> |
| |
| </div> |
| |
| <!-- =================================================================== --> |
| <!-- +++++++++++++++ Creating the Platform Application +++++++++++++++++ --> |
| |
| <h2><a name="01"></a>Creating the NetBeans Platform Application Project</h2> |
| |
| <p>In this section you use the New Project wizard to create a NetBeans Platform Application from a Maven archetype. |
| The wizard will create the Maven module projects that you need to develop a NetBeans Platform application. |
| You will also use the New Project wizard to create the NetBeans module. |
| </p> |
| |
| <div class="indent"> |
| <h3><a name="01a"></a>Creating the Project</h3> |
| |
| <p>Perform the following steps to create the NetBeans Platform application using the New Project wizard. |
| </p> |
| <ol> |
| <li>Choose File > New Project (Ctrl-Shift-N) to open the New Project wizard.</li> |
| <li>Select Maven NetBeans Application from the Maven category. Click Next.</li> |
| <li>Type <strong>MavenPlatformCRUDApp</strong> for the Project Name and set the Project Location. Click Finish.</li> |
| </ol> |
| |
| <p class="notes"><strong>Note.</strong> You can click Next and create a module project in the wizard when you create the platform application, |
| but for demonstration purposes in this tutorial you will create the application and module separately.</p> |
| |
| <img src="../images/tutorials/maven-crud/mavencrud-new-project.png" alt="Screenshot of New Project wizard" title="Screenshot of New Project wizard" class="margin-around b-all" /> |
| |
| <p>When you click Finish, by default the IDE creates the following Maven project types.</p> |
| <ul> |
| <li><strong>NetBeans Platform Application.</strong> |
| This project is a container project for the Platform application and lists the modules to include and the location of the project's repositories. This project does not contain any sources. |
| The IDE generates the modules containing the sources and resources in sub-directories of this project.</li> |
| <li><strong>NetBeans Platform based application.</strong> |
| This project specifies the artifacts (sources) needed for compiling the application. |
| The required dependencies (IDE artifacts, module artifacts) are specified in the <tt>pom.xml</tt> file |
| of the project.</li> |
| <li><strong>Platform application branding resources.</strong> |
| This project contains the resources used for branding the application. </li> |
| </ul> |
| <img src="../images/tutorials/maven-crud/mavencrud-projects-window1.png" alt="Screenshot of project structure in Projects window" title="Project structure in Projects window" class="margin-around b-all" /> |
| |
| <p class="notes"><strong>Notes.</strong></p> |
| <ul> |
| <li>If this is your first NetBeans Platform application using Maven, |
| it can take some time to create the projects because the IDE needs to download any necessary artifacts |
| from the NetBeans repository.</li> |
| <li>When you create the project, you will see that some of the projects |
| (for example, the NetBeans Platform based application project) are badged |
| because some dependencies declared in the <tt>pom.xml</tt> file (POM) are unavailable.</li> |
| </ul> |
| |
| |
| |
| <h3><a name="01b"></a>Creating a Module</h3> |
| <p>In this exercise you will use the New Project wizard to create a NetBeans module. |
| </p> |
| |
| <ol> |
| <li>Choose File > New Project (Ctrl-Shift-N) to open the New Project wizard.</li> |
| <li>Select Maven NetBeans Module from the Maven category. Click Next.</li> |
| <li>Type <strong>MavenPlatformCRUDApp-dbaccess</strong> for the Project Name.</li> |
| <li>Specify the Project Location by clicking Browse and locating the directory <strong>MavenPlatformCRUDApp</strong>. Click Open.<br/> |
| <img src="../images/tutorials/maven-crud/mavencrud-select-location.png" alt="Screenshot of Select Location dialog showing location" title="Select Project Location dialog showing project directory" class="margin-around b-all" /> |
| </li> |
| <li>Click Finish. </li> |
| </ol> |
| |
| <p>When you click Finish, the wizard creates a NetBeans module project named <strong>MavenPlatformCRUDApp-dbaccess</strong>. |
| The module is automatically configured to be included in the application when you save it in a sub-directory. |
| If you open the POM for the project, you can see that the MavenPlatformCRUDApp is declared as the parent project. |
| </p> |
| <pre class="examplecode"><parent> |
| <artifactId>MavenPlatformCRUDApp</artifactId> |
| <groupId>com.mycompany</groupId> |
| <version>1.0-SNAPSHOT</version> |
| </parent> |
| <artifactId>MavenPlatformCRUDApp-dbaccess</artifactId> |
| <packaging>nbm</packaging> |
| <version>1.0-SNAPSHOT</version> |
| <name>MavenPlatformCRUDApp - dbaccess NetBeans Module</name> |
| </pre> |
| |
| <p class="tips">You can change the display name for the module by editing the <tt><name></tt> element in |
| the POM or by modifying the name in the project's Properties window. |
| The default display name is the project's artifactId <tt>MavenPlatformCRUDApp-dbaccess</tt>.</p> |
| |
| <p>If you look at the POM for the NetBeans Platform Application under the Project Files node in the Projects window, |
| you can see that three modules are listed as modules in the application.</p> |
| <pre class="examplecode"> |
| <modules> |
| <module>branding</module> |
| <module>application</module> |
| <module>MavenPlatformCRUDApp-dbaccess</module> |
| </modules> |
| </pre> |
| |
| |
| <h3><a name="01c"></a>Making the Module a Dependency</h3> |
| <p>You now need to add the module as a dependency of the NetBeans Platform based application. |
| You can add the dependency by editing <tt>pom.xml</tt> in the editor or by using the Add Dependency dialog box.</p> |
| <ol> |
| <li>Expand the <strong>NetBeans Platform based application</strong> node in the Projects window.</li> |
| <li>Right-click the Libraries node and choose Add Dependency.</li> |
| <li>Click the Open Projects tab and select <strong>MavenPlatformCRUDApp - dbaccess</strong>. Click OK.<br/> |
| <img src="../images/tutorials/maven-crud/mavencrud-add-dependency1.png" alt="Screenshot of Add Dependency dialog" title="Open Projects tab in Add Dependency dialog" class="margin-around b-all" /> |
| </li> |
| </ol> |
| |
| |
| <p>If you expand the Libraries node of the NetBeans Platform based application in the Projects window, |
| you can see that MavenPlatformCRUDApp-dbaccess is now listed as a dependency.</p> |
| |
| <p>If you look at the POM of the NetBeans Platform based application, |
| you can see that the module artifact <tt>MavenPlatformCRUDApp-dbaccess</tt> |
| is listed as a required dependency for compiling the application. |
| The artifact will be available after you build the module project and install the artifact |
| in your local repository.</p> |
| |
| <pre class="examplecode"><dependency> |
| <groupId>${project.groupId}</groupId> |
| <artifactId><strong>MavenPlatformCRUDApp-dbaccess</strong></artifactId> |
| <version>${project.version}</version> |
| </dependency></pre> |
| |
| |
| |
| <h3><a name="01d"></a>Branding the Application</h3> |
| <p>The branding module specifies the branding resources that are used when building the Platform application. |
| The branding dialog enables you to easily specify the name of the application, the splash screen and the |
| application icon and to modify the values of text elements.</p> |
| |
| <p>In this exercise you will replace the default splash image. |
| By default the branding module generated by the IDE contains an image that is displayed when the platform application starts. |
| You can replace this with a different image by performing the following steps.</p> |
| <ol> |
| <li>Right-click the <strong>Platform application branding resources</strong> module in the Projects window and choose Branding.</li> |
| <li>In the Splash Screen tab, specify an image to use as the splash screen by clicking the Browse |
| button next to the default splash screen image and locating the image you want to use. Click OK.</li> |
| </ol> |
| |
| <p>For example, you can copy the image below to your local system and specify the image in the Branding dialog.</p> |
| <img src="../images/tutorials/maven-crud/splash-crud.gif" alt="Example of default splash image" title="Example of default splash image" class="margin-around b-all" /> |
| |
| <p>When you launch the application, the new image will appear during startup.</p> |
| </div> |
| |
| |
| <!-- =================================================================== --> |
| <!-- +++++++++++++++++++++++ Creating the Entity Classes +++++++++++++++++++ --> |
| |
| |
| <h2><a name="02"></a>Creating the Entity Classes</h2> |
| |
| <p>In this section you will generate some entity classes from tables in the Java DB database. |
| To create the entity classes and to use the Java Persistence API (JPA) in your application, |
| you need to have access to a database server and the JPA persistence provider libraries. |
| This tutorial uses the JavaDB database server, but you can configure the application to use other database servers.</p> |
| |
| <p>The easiest way to make the resources available is to register an instance of GlassFish Server Open Source Edition 3.0.1 |
| that is bundled with the IDE. |
| The Java DB database server, a sample database and the JPA persistence provider are included with the GlassFish server. |
| Before you create the entity classes, start the Java DB by performing the following steps.</p> |
| |
| <ol> |
| <li>In the Services window, expand the Servers node and check that a GlassFish instance is registered.</li> |
| <li>Expand the Database node, right-click the database connection node for the <strong>app</strong> database |
| on Java DB (<tt>jdbc:derby://localhost:1527/sample [app on APP]</tt>) and choose Connect. </li> |
| </ol> |
| |
| <p>When you choose Connect, the IDE will start the database if not already started.</p> |
| <div class="indent"> |
| <h3><a name="02a"></a>Adding the DerbyClient as a Runtime Dependency</h3> |
| |
| <p>In this section you will add the derbyclient-10.5.3.0_1 library as a dependency.</p> |
| |
| <ol> |
| <li>Right-click the Libraries node of the <strong>dbaccess</strong> module and choose Add Dependency.</li> |
| <li>Add the library by typing <strong>org.apache.derby</strong> for the GroupId, |
| <strong>derbyclient</strong> for the ArtifactId and |
| <strong>10.5.3.0_1</strong> for the Version.</li> |
| <li>Select <strong>Runtime</strong> from the Scope dropdown list. Click OK.<br/> |
| <img src="../images/tutorials/maven-crud/mavencrud-add-dependency-derby.png" alt="Example of Add Dependency dialog" title="Adding derbyclient JAR in Add Dependency dialog" class="margin-around b-all" /> |
| </li> |
| </ol> |
| |
| <p>If you expand the Runtime Libraries node in the Projects window, you can see that the <tt>derbyclient</tt> library is listed as a dependency.</p> |
| <p class="tips">You can also modify the POM in the editor to specify the value of the <tt><scope></tt> element of a dependency.</p> |
| |
| <pre class="examplecode"><dependency> |
| <groupId>org.apache.derby</groupId> |
| <artifactId>derbyclient</artifactId> |
| <version>10.5.3.0_1</version> |
| <scope>runtime</scope> |
| </dependency></pre> |
| |
| <h3><a name="02b"></a>Generating Entity Classes From the Database</h3> |
| <p>In this section you will use a wizard to generate entity classes in the <strong>dbaccess</strong> module. |
| </p> |
| |
| <ol> |
| <li>Right-click the Source Packages of the <strong>dbaccess</strong> module and choose New > Other.</li> |
| <li>Select Entity Classes from Database in the Persistence category. Click Next.</li> |
| <li>Select the Java DB sample database from the Database Connection dropdown list.</li> |
| <li>Select the Customer table from the Available Tables list and click Add. |
| When you click Add, the related table DiscountCode is also added to the list of Selected Tables list. Click Next.</li> |
| <li>Type <strong>com.mycompany.mavenplatformcrudapp.dbaccess</strong> for the Package name. |
| Make sure that Create Perisistence Unit and Generate Named Query Annotations are selected. Click Finish.</li> |
| </ol> |
| <p>When you click Finish, the IDE generates the Customer and DiscountCode entity classes. |
| The IDE also generates the <tt>persistence.xml</tt> file in the <tt>META-INF</tt> package under the Other Sources node in the <tt>src/main/resources</tt> directory.</p> |
| |
| |
| |
| |
| |
| |
| |
| |
| </div> |
| |
| <!-- =================================================================== --> |
| <!-- +++++++++++++++++++ Implementing CRUD : READ ++++++++++++++++++++++ --> |
| |
| |
| <h2><a name="03"></a>READ: Reading and Displaying a Record</h2> |
| <p>In this section you will use a wizard to add a Window Component to the <strong>dbaccess</strong> module. |
| You will enable a tree view in the window component to display |
| the objects as nodes. You can view the data for each record in the node's properties window.</p> |
| |
| <div class="indent"> |
| |
| <h3><a name="03a"></a>Adding a Window Component</h3> |
| <p>In this exercise you will create the window component.</p> |
| <ol> |
| <li>Right-click the project node in the Projects window and choose New > Window.</li> |
| <li>Select <strong>editor</strong> in the Window Position dropdown list and select <strong>Open on application startup</strong>. Click Next.<br/> |
| <img src="../images/tutorials/maven-crud/mavencrud-new-window-customer.png" alt="Screenshot of New Window wizard" title="Basic Setting page of New Window wizard" class="margin-around b-all" /> |
| </li> |
| <li>Type <strong>Customer</strong> as the Class Name Prefix.</li> |
| <li>Type <strong>com.mycompany.mavenplatformcrudapp.viewer</strong> for the Package. Click Finish. |
| <p>The wizard displays a list of the files that will be created and the files that will be modified.</p></li> |
| </ol> |
| <p>When you click Finish, in the Projects window you can see that the IDE generated the class |
| <tt>CustomerTopComponent.java</tt> in <tt>com.mycompany.mavenplatformcrudapp.viewer</tt> under Source Packages. |
| You can view the structure of the project in the Files window. |
| To compile a Maven project, only source files can be located under Source Packages |
| (<tt>src/main/java</tt> directory in the Files window). |
| Resource files (e.g., XML files) need to be located under Other Sources |
| (<tt>src/main/resources</tt> directory in the Files window).</p> |
| |
| |
| <h3><a name="03b"></a>Adding a Tree View</h3> |
| |
| <p>You will now modify the window component to display the database records in a tree view. |
| You will add the entity manager to the constructor and enable a bean tree view.</p> |
| <ol> |
| <li>Click the Source tab of <tt>CustomerTopComponent.java</tt> to view the source code in the editor.</li> |
| <li>Modify the constructor to add the following. |
| <pre class="examplecode">public CustomerTopComponent() { |
| initComponents(); |
| setName(NbBundle.getMessage(CustomerTopComponent.class, "CTL_CustomerTopComponent")); |
| setToolTipText(NbBundle.getMessage(CustomerTopComponent.class, "HINT_CustomerTopComponent")); |
| // setIcon(ImageUtilities.loadImage(ICON_PATH, true)); |
| |
| <strong>EntityManager entityManager = Persistence.createEntityManagerFactory("com.mycompany_MavenPlatformCRUDApp-dbaccess_nbm_1.0-SNAPSHOTPU").createEntityManager(); |
| Query query = entityManager.createQuery("SELECT c FROM Customer c"); |
| List<Customer> resultList = query.getResultList();</strong> |
| }</pre> |
| |
| <p class="tips">Check that the name of the persistence unit in the code is correct by comparing it to |
| the name specified in <tt>persistence.xml</tt>.</p> |
| </li> |
| <li>Modify the class signature to implement <tt>ExplorerManager.Provider.</tt> |
| <pre class="examplecode">public final class CustomerTopComponent extends TopComponent <strong>implements ExplorerManager.Provider</strong></pre> |
| </li> |
| <li>Fix your imports to import <tt><strong>javax.persistence.Query</strong></tt> and <tt><strong>javax.util.List</strong></tt>.</li> |
| <li>Declare and initialize the ExplorerManager: |
| <pre class="examplecode">private static ExplorerManager em = new ExplorerManager();</pre> |
| </li> |
| <li>Implement the abstract methods and modify the <tt>getExplorerManager</tt> method to return <tt>em</tt>. |
| <pre class="examplecode">@Override |
| public ExplorerManager getExplorerManager() { |
| return em; |
| }</pre> |
| <p class="tips">You can put the insert cursor in the class signature and press Alt+Enter to implement the abstract methods.</p> |
| </li> |
| <li>Add the following to the constructor to enable the tree view. |
| <pre class="examplecode">BeanTreeView beanTreeView = new BeanTreeView(); |
| add(beanTreeView, BorderLayout.CENTER);</pre> |
| </li> |
| |
| <li>In Design view, right-click the component and select Set Layout > Border Layout. Save your changes.</li> |
| |
| </ol> |
| |
| <h3><a name="03c"></a>Creating a Factory Class</h3> |
| |
| <p>You will now create a new class <strong>CustomerChildFactory</strong> in the <tt>com.mycompany.mavenplatformcrudapp.viewer</tt> package |
| that creates a new BeanNode for each customer in your database.</p> |
| <ol> |
| |
| <li>Right-click the <tt><strong>com.mycompany.mavenplatformcrudapp.viewer</strong></tt> package and choose New > Java Class.</li> |
| <li>Type <strong>CustomerChildFactory</strong> for the Class Name. Click Finish.</li> |
| <li>Modify the signature to extend <tt>ChildFactory<Customer></tt>.</li> |
| <li>Declare the field <tt>resultList</tt> for the list of items in the table and add the <tt>CustomerChildFactory</tt> method. |
| <pre class="examplecode">private List<Customer> resultList; |
| |
| public CustomerChildFactory(List<Customer> resultList) { |
| this.resultList = resultList; |
| }</pre> |
| </li> |
| <li>Implement and then modify the <tt>createKeys</tt> abstract method. |
| <pre class="examplecode">@Override |
| protected boolean createKeys(List<Customer> list) { |
| for (Customer customer : resultList) { |
| list.add(customer); |
| } |
| return true; |
| }</pre></li> |
| <li>Add a method to create the nodes. |
| <pre class="examplecode">@Override |
| protected Node createNodeForKey(Customer c) { |
| try { |
| return new BeanNode(c); |
| } catch (IntrospectionException ex) { |
| Exceptions.printStackTrace(ex); |
| return null; |
| } |
| }</pre> |
| </li> |
| <li>Fix your imports to import <tt>org.openide.nodes.Node</tt> and <tt>java.beans.InstrospectionException</tt>. Save your changes.</li> |
| </ol> |
| |
| |
| <p>The class will look like the following:</p> |
| |
| <pre class="examplecode">package com.mycompany.mavenplatformcrudapp.viewer; |
| |
| import com.mycompany.mavenplatformcrudapp.dbaccess.Customer; |
| import java.beans.IntrospectionException; |
| import java.util.List; |
| import org.openide.nodes.BeanNode; |
| import org.openide.nodes.ChildFactory; |
| import org.openide.nodes.Node; |
| import org.openide.util.Exceptions; |
| |
| public class CustomerChildFactory extends ChildFactory<Customer> { |
| |
| private List<Customer> resultList; |
| |
| public CustomerChildFactory(List<Customer> resultList) { |
| this.resultList = resultList; |
| } |
| |
| @Override |
| protected boolean createKeys(List<Customer> list) { |
| for (Customer customer : resultList) { |
| list.add(customer); |
| } |
| return true; |
| } |
| |
| @Override |
| protected Node createNodeForKey(Customer c) { |
| try { |
| return new BeanNode(c); |
| } catch (IntrospectionException ex) { |
| Exceptions.printStackTrace(ex); |
| return null; |
| } |
| } |
| |
| }</pre> |
| |
| <p>You now need to modify the <strong>CustomerTopComponent</strong> to use the ExplorerManager to pass the result list from the JPA query to the Node.</p> |
| <ol> |
| <li>Add the following lines to the CustomerTopComponent constructor to set the root context for the |
| nodes and to add the TopComponent's ActionMap and ExplorerManager to the Lookup of the TopComponent. |
| |
| <pre class="examplecode"> |
| EntityManager entityManager = Persistence.createEntityManagerFactory("com.mycompany_MavenPlatformCRUDApp-dbaccess_nbm_1.0-SNAPSHOTPU").createEntityManager(); |
| Query query = entityManager.createQuery("SELECT c FROM Customer c"); |
| List<Customer> resultList = query.getResultList(); |
| <strong>em.setRootContext(new AbstractNode(Children.create(new CustomerChildFactory(resultList), true))); |
| associateLookup(ExplorerUtils.createLookup(em, getActionMap()));</strong></pre> |
| <!-- <li>Expand the Libraries node and change the dependency on <tt>org-openide-nodes</tt> and <tt>org-openide-explorer</tt> from transitive to direct.--> |
| |
| <p>This will synchronize properties window and tooltip text for each selected Node.</p> |
| </li> |
| <li>Fix your imports and save your changes.</li> |
| </ol> |
| |
| |
| |
| <h3><a name="03d"></a>Running the Application</h3> |
| <p>In this exercise you will test the application to confirm that the application is able to access and read the database tables correctly. |
| Before you can build and run the application, you need to modify the POM because |
| the application requires a direct dependency on the <tt>org-openide-nodes</tt> and <tt>org-openide-explorer</tt> JARs. |
| You can modify the dependency in the Projects window.</p> |
| |
| <ol> |
| <li>Expand the Libraries node of the <strong>dbaccess</strong> module.</li> |
| <li>Right-click the <tt>org-openide-nodes</tt> JAR and choose Declare as Direct Dependency.</li> |
| <li>Right-click the <tt>org-openide-explorer</tt> JAR and choose Declare as Direct Dependency.</li> |
| <li>Right-click the <strong>MavenPlatformCRUDApp NetBeans Platform based application</strong> and choose Build with Dependencies. |
| <p>The Output window displays the modules that will be included.</p> |
| <img src="../images/tutorials/maven-crud/mavencrud-build-output1.png" alt="Screenshot of Output window - top half" title="Output window showing build order" class="margin-around b-all" /> |
| <p>The Output window also displays the build status.</p> |
| <img src="../images/tutorials/maven-crud/mavencrud-build-output2.png" alt="Screenshot of Output window - bottom half" title="Output window showing build was successfull" class="margin-around b-all" /> |
| </li> |
| <li>Right-click the application and choose Run.</li> |
| </ol> |
| <p>When the application launches, the Customer window will appear with a node for each of the records in the database table.</p> |
| |
| <img src="../images/tutorials/maven-crud/mavencrud-customer-window1.png" alt="Screenshot of Customer window in application" title="Customer window in application" class="margin-around b-all" /> |
| <p>You can right-click a node in the Customer window tree and choose Properties to view additional details about the item.</p> |
| |
| |
| <img src="../images/tutorials/maven-crud/mavencrud-read-properties.png" alt="Screenshot of Properties window in application" title="Properties window showing details of selected node" class="margin-around b-all" /> |
| |
| </div> |
| |
| |
| |
| <!-- =================================================================== --> |
| <!-- +++++++++++++++++++ Implementing CRUD : UPDATE ++++++++++++++++++++ --> |
| |
| <h2><a name="04"></a>UPDATE: Editing a Record</h2> |
| |
| |
| <p>In this section you will add a window component for editing the details of a record.</p> |
| <div class="indent"> |
| <h3><a name="04a"></a>Creating the Editor Window</h3> |
| <p>In this exercise you will create a new window MyEditor that will contain two text fields for editing the name and city fields |
| of the selected node. You will then modify the <tt>layer.xml</tt> file so that the Customer window opens in the |
| explorer mode instead of the editor mode.</p> |
| <ol> |
| <li>Right-click the <strong>dbaccess</strong> module and choose New > Window.</li> |
| <li>Select <strong>editor</strong> in the dropdown list and select <strong>Open on application startup</strong>. Click Next.</li> |
| <li>Type <strong>MyEditor</strong> as the Class Name Prefix.</li> |
| <li>Type <strong>com.mycompany.mavenplatformcrudapp.editor</strong> as the package. Click Finish.</li> |
| <li>Add two JLabels and two JTextFields in the Design view of <tt>MyEditorTopComponent</tt>. </li> |
| <li>Set the texts of the labels to "Name" and "City" and set the variable names of the two JTextFields to |
| <tt><strong>jTextField1</strong></tt> and <tt><strong>jTextField2</strong></tt>. |
| Save your changes.<br/> |
| <img src="../images/tutorials/maven-crud/mavencrud-myeditor-window.png" alt="Screenshot of Window component in Design view" title="Window component in Design view" class="margin-around b-all" /> |
| </li> |
| <li>Expand the Important Files node in the Projects window and double-click <strong>XML Layer</strong> to open the <tt>layer.xml</tt> file in the editor.</li> |
| <li>Modify <tt>layer.xml</tt> to specify that the CustomerTopComponent window will appear in the explorer mode. Save your changes. |
| <pre class="examplecode"> |
| <folder name="Modes"> |
| <folder name="editor"> |
| <file name="MyEditorTopComponent.wstcref" url="MyEditorTopComponentWstcref.xml"/> |
| </folder> |
| <strong><folder name="explorer"> |
| <file name="CustomerTopComponent.wstcref" url="CustomerTopComponentWstcref.xml"/> |
| </folder></strong> |
| </folder> |
| </pre> |
| </li> |
| </ol> |
| |
| |
| <p>You can now test the application to check that the windows open and that they are in the correct location.</p> |
| <p class="tips">Remember to Clean the application before you Build with Dependencies.</p> |
| |
| <p>You can now start adding code so that when you select a node in the Customer window, |
| the name and city fields of the object are displayed in the editor.</p> |
| |
| |
| <h3><a name="04b"></a>Using a LookupListener</h3> |
| <p>In this exercise you will modify the Customer window so that a when a node is selected |
| a new <tt>Customer</tt> object is added to the Lookup of the Node. |
| You will then modify MyEditor so that the window will implement |
| <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-util-lookup/org/openide/util/LookupListener.html">LookupListener</a></tt> |
| to listen for <tt>Customer</tt> objects that are added to the Lookup.</p> |
| |
| <ol> |
| <li>Modify the <tt>createNodeForKey</tt> method in <strong>CustomerChildFactory</strong> |
| to create an <tt>AbstractNode</tt> instead of a <tt>BeanNode</tt>. |
| <!--Do this by creating an AbstractNode, instead of a BeanNode, in the CustomerChildFactory class. |
| That enables you to add the current Customer object to the Lookup of the Node, as follows (note the part in bold):--> |
| <pre class="examplecode"> |
| @Override |
| protected Node createNodeForKey(Customer c) { |
| <strong>Node node = new AbstractNode(Children.LEAF, Lookups.singleton(c)); |
| node.setDisplayName(c.getName()); |
| node.setShortDescription(c.getCity()); |
| return node;</strong> |
| // try { |
| // return new BeanNode(c); |
| // } catch (IntrospectionException ex) { |
| // Exceptions.printStackTrace(ex); |
| // return null; |
| // } |
| }</pre> |
| <p>When you select a new node in the Customer window, the selected <tt>Customer</tt> object is added to the window's Lookup.</p> |
| </li> |
| <!-- First, set a dependency in the editor module on the module that provides the entity class, |
| as well as the module that provides the persistence JARs. |
| --> |
| <li>Click the Source tab of <strong>MyEditorTopComponent</strong> and modify the class signature to implement <tt>LookupListener</tt>. |
| <pre class="examplecode">public final class MyEditorTopComponent extends TopComponent <strong>implements LookupListener</strong></pre> |
| </li> |
| <li>Add a variable for storing the results. |
| <pre class="examplecode">private Lookup.Result result = null;</pre> |
| </li> |
| <li>Implement the required abstract methods to add the <tt>resultChanged</tt> method.</li> |
| <li>Modify the <tt>resultChanged</tt> method to update the jTextFields each time a new <tt>Customer</tt> |
| object is introduced into the Lookup. |
| <pre class="examplecode"> |
| @Override |
| public void resultChanged(LookupEvent le) { |
| Lookup.Result r = (Lookup.Result) le.getSource(); |
| Collection<Customer> coll = r.allInstances(); |
| if (!coll.isEmpty()) { |
| for (Customer cust : coll) { |
| jTextField1.setText(cust.getName()); |
| jTextField2.setText(cust.getCity()); |
| } |
| } else { |
| jTextField1.setText("[no name]"); |
| jTextField2.setText("[no city]"); |
| } |
| } |
| </pre> |
| |
| |
| <p>After defining the LookupListener, you can add it to the <tt>Lookup.Result</tt> obtained from the global context. |
| The global context proxies the context of the selected Node. |
| For example, if "Ford Motor Co" is selected in the tree hierarchy, |
| the <tt>Customer</tt> object for "Ford Motor Co" is added to the Lookup of the Node. |
| Because it is the currently selected Node, the <tt>Customer</tt> object for |
| "Ford Motor Co" is now available in the global context. |
| That is what is then passed to the <tt>resultChanged</tt>, causing the text fields to be populated.</p> |
| </li> |
| <li>Modify the <tt>componentOpened</tt> and <tt>componentClosed</tt> methods to make |
| LookupListener active when the editor window is opened. |
| <pre class="examplecode"> |
| @Override |
| public void componentOpened() { |
| result = WindowManager.getDefault().findTopComponent("CustomerTopComponent").getLookup().lookupResult(Customer.class); |
| result.addLookupListener(this); |
| resultChanged(new LookupEvent(result)); |
| } |
| |
| @Override |
| public void componentClosed() { |
| result.removeLookupListener(this); |
| result = null; |
| }</pre> |
| <p>Because the editor window is set to open when the application starts, |
| the LookupListener will also be available at the time that the application starts up.</p> |
| |
| <p>In this example you are using the local Lookup provided by the Customer window. |
| The window is identified explicitly in this case by the string "<tt>CustomerTopComponent</tt>". |
| The string is specified in the source code of <tt>CustomerTopComponent</tt> as the ID of the CustomerTopComponent. |
| This approach only works if the MyEditorTopComponent can find a TopComponent with the ID "CustomerTopComponent". |
| </p> |
| |
| <p class="tips">A more flexible approach that involves rewriting the selection model is described in this |
| <a href="http://weblogs.java.net/blog/timboudreau/archive/2007/01/how_to_replace.html">blog entry by Tim Boudreau</a>.</p> |
| </li> |
| </ol> |
| |
| <p>You can run the application again after performing Clean and Build with Dependencies. |
| The editor window is now updated when you select a new Node in the Customer window. |
| No properties are displayed in a node's Properties window because you are now using <tt>AbstractNode</tt> instead of <tt>BeanNode</tt>.</p> |
| |
| |
| |
| |
| <h3><a name="04c"></a>Adding Undo and Redo</h3> |
| <p>In this exercise you will enable the Undo and Redo functions by implementing the |
| <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/UndoRedo.html">UndoRedo</a></tt> manager. |
| The Undo and Redo buttons in the toolbar and the Undo and Redo menu items will be enabled when |
| a user makes a change to one of the fields in the Editor window.</p> |
| |
| <ol> |
| <li>Declare and instantiate a new UndoRedoManager at the top of the MyEditorTopComponent. |
| <pre class="examplecode">private UndoRedo.Manager manager = new UndoRedo.Manager();</pre> |
| </li> |
| <li>Create a <tt>getUndoRedo()</tt> method in the MyEditorTopComponent: |
| <pre class="examplecode"> |
| @Override |
| public UndoRedo getUndoRedo() { |
| return manager; |
| }</pre> |
| </li> |
| <li>Add the following to the constructor. |
| <!--In the constructor of MyEditorTopComponent, add a KeyListener to the jTextFields and, |
| within the related methods that you need to implement, add the UndoRedoListeners: |
| |
| what is happening here? |
| |
| |
| --> |
| <pre class="examplecode"> |
| jTextField1.getDocument().addUndoableEditListener(manager); |
| jTextField2.getDocument().addUndoableEditListener(manager);</pre> |
| </li> |
| </ol> |
| <p>You can run the application to test that the buttons and menu items for the Undo and Redo functionality are working.</p> |
| |
| |
| <h3><a name="04d"></a>Adding the Save Function</h3> |
| |
| <p>In this exercise you will integrate the NetBeans Platform's Save functionality. |
| You will modify the <tt>layer.xml</tt> file to hide the "Save All" button in the toolbar |
| and to add the "Save" button. |
| You will then add listeners to detect changes in the textfields and a <tt>fire</tt> method that is triggered when a change is detected. |
| |
| </p> |
| <ol> |
| <li>Open and modify the <tt>layer.xml</tt> file of the <strong>dbaccess</strong> module to add a Toolbar element. |
| <pre class="examplecode"> |
| <strong><folder name="Toolbars"> |
| <folder name="File"> |
| <file name="org-openide-actions-SaveAction.shadow"> |
| <attr name="originalFile" stringvalue="Actions/System/org-openide-actions-SaveAction.instance"/> |
| <attr name="position" intvalue="444"/> |
| </file> |
| <file name="org-openide-actions-SaveAllAction.shadow_hidden"/> |
| </folder> |
| </folder></strong> |
| </filesystem></pre> |
| </li> |
| <li>In the <strong>MyEditorTopComponent</strong> constructor, add the following call to fire a method when a change is detected |
| in the text fields. |
| <pre class="examplecode"> |
| public MyEditorTopComponent() { |
| |
| ... |
| jTextField1.getDocument().addUndoableEditListener(manager); |
| jTextField2.getDocument().addUndoableEditListener(manager); |
| |
| <strong>jTextField1.getDocument().addDocumentListener(new DocumentListener() { |
| public void insertUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| public void removeUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| public void changedUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| }); |
| |
| jTextField2.getDocument().addDocumentListener(new DocumentListener() { |
| public void insertUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| public void removeUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| public void changedUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| }); |
| |
| //Create a new instance of our SaveCookie implementation: |
| impl = new SaveCookieImpl(); |
| |
| //Create a new instance of our dynamic object: |
| content = new InstanceContent(); |
| |
| //Add the dynamic object to the TopComponent Lookup: |
| associateLookup(new AbstractLookup(content));</strong> |
| |
| ... |
| }</pre> |
| </li> |
| <li>Add the <tt>fire</tt> method that is called whenever a change is detected. |
| |
| <pre class="examplecode"> |
| public void fire(boolean modified) { |
| if (modified) { |
| //If the text is modified, |
| //we add SaveCookie impl to Lookup: |
| content.add(impl); |
| } else { |
| //Otherwise, we remove the SaveCookie impl from the lookup: |
| content.remove(impl); |
| } |
| }</pre> |
| </li> |
| <li>Add the following implementation of |
| <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/cookies/SaveCookie.html">SaveCookie</a></tt> |
| that is added to the <tt>InstanceContent</tt> by the <tt>fire</tt> method. |
| <pre class="examplecode"> |
| private class SaveCookieImpl implements SaveCookie { |
| |
| @Override |
| public void save() throws IOException { |
| |
| Confirmation message = new NotifyDescriptor.Confirmation("Do you want to save \"" |
| + jTextField1.getText() + " (" + jTextField2.getText() + ")\"?", |
| NotifyDescriptor.OK_CANCEL_OPTION, |
| NotifyDescriptor.QUESTION_MESSAGE); |
| |
| Object result = DialogDisplayer.getDefault().notify(message); |
| //When user clicks "Yes", indicating they really want to save, |
| //we need to disable the Save action, |
| //so that it will only be usable when the next change is made |
| //to the JTextArea: |
| if (NotifyDescriptor.YES_OPTION.equals(result)) { |
| fire(false); |
| //Implement your save functionality here. |
| } |
| } |
| }</pre> |
| </li> |
| <li>Add the following fields to MyEditorTopComponent. |
| <pre class="examplecode"> |
| private final SaveCookieImpl impl; |
| private final InstanceContent content; |
| </pre> |
| </li> |
| <li>Fix your imports and save your changes.</li> |
| <li>Right-click the <tt>org-openide-dialogs</tt> JAR under the Libraries node in the |
| Projects window and choose Declare as Direct Dependency.</li> |
| </ol> |
| <p>You can now clean, build with dependencies and run the application to confirm that the Save button |
| is enabled when you modify a text field.</p> |
| |
| |
| <h3><a name="04e"></a>Persisting Changes</h3> |
| |
| <p>In the next exercise you will add code to persist the changes. |
| At the moment, the application correctly recognizes when a change is made to a field |
| and enables the option to save the changes. |
| When you click Save, a dialog appears prompting you to confirm that you want to save the changes. |
| However, the changes are not persisted when you click OK in the dialog. |
| To persist the changes, you need to add some JPA code to handle persistence to the database.</p> |
| |
| <ol> |
| <li>Add the following field to <strong>MyEditorTopComponent</strong>. |
| <pre class="examplecode">private Customer customer;</pre> |
| </li> |
| <li>Add the JPA code for persisting changes by modifying the <tt>save</tt> method to replace the comment |
| <tt>"//Implement your save functionality here." </tt> with the following code. |
| <pre class="examplecode">@Override |
| public void save() throws IOException { |
| ... |
| if (NotifyDescriptor.YES_OPTION.equals(result)) { |
| fire(false); |
| <strong>EntityManager entityManager = Persistence.createEntityManagerFactory("com.mycompany_MavenPlatformCRUDApp-dbaccess_nbm_1.0-SNAPSHOTPU").createEntityManager(); |
| entityManager.getTransaction().begin(); |
| Customer c = entityManager.find(Customer.class, customer.getCustomerId()); |
| c.setName(jTextField1.getText()); |
| c.setCity(jTextField2.getText()); |
| entityManager.getTransaction().commit();</strong> |
| } |
| }</pre> |
| <p class="tips">Check that the name of the peristence unit is correct.</p> |
| <p>The "customer" in <tt>customer.getCustomerId()</tt> is currently undefined. |
| In the next step you set <tt>customer</tt> to the current <tt>Customer</tt> object used to get the the Customer ID.</p> |
| </li> |
| <li>Add the following line in bold to the <tt>resultChanged</tt> method. |
| <pre class="examplecode"> |
| @Override |
| public void resultChanged(LookupEvent le) { |
| Lookup.Result r = (Lookup.Result) le.getSource(); |
| Collection<Customer> coll = r.allInstances(); |
| if (!coll.isEmpty()) { |
| for (Customer cust : coll) { |
| <strong>customer = cust;</strong> |
| jTextField1.setText(cust.getName()); |
| jTextField2.setText(cust.getCity()); |
| } |
| } else { |
| jTextField1.setText("[no name]"); |
| jTextField2.setText("[no city]"); |
| } |
| }</pre> |
| </li> |
| <li>Fix your imports and save your changes.</li> |
| </ol> |
| <p>You can run the application and change some data to test if the save function is working correctly and persists the changes. |
| At the moment, the editor does not update the fields to reflect the changed data. |
| To check if the data is persisted you will need to restart the application.</p> |
| |
| <p>In the next exercise you will add a "Refresh" function that will reload the data from the |
| database and enable you to see the changes in the editor.</p> |
| |
| |
| |
| <h3><a name="04f"></a>Adding a Refresh Function</h3> |
| <p>In this exercise you will add functionality for updating the Customer viewer by adding a "Refresh" menu item to the root node |
| in the Customer window.</p> |
| |
| <ol> |
| <li>Right-click the <tt><strong>com.mycompany.mavenplatformcrudapp.viewer</strong></tt> package and choose New > Java Class |
| and create a class named <strong>CustomerRootNode</strong>.</li> |
| <li>Modify the class to extend <tt>AbstractNode</tt> and add the following methods. |
| <pre class="examplecode"> |
| public class CustomerRootNode extends AbstractNode { |
| |
| <strong>public CustomerRootNode(Children kids) { |
| super(kids); |
| setDisplayName("Root"); |
| } |
| |
| @Override |
| public Action[] getActions(boolean context) { |
| Action[] result = new Action[]{ |
| new RefreshAction()}; |
| return result; |
| } |
| |
| private final class RefreshAction extends AbstractAction { |
| |
| public RefreshAction() { |
| putValue(Action.NAME, "Refresh"); |
| } |
| |
| public void actionPerformed(ActionEvent e) { |
| CustomerTopComponent.refreshNode(); |
| } |
| }</strong> |
| |
| }</pre> |
| <p class="tips">Note that a "Refresh" action is bound to the new Root node.</p> |
| </li> |
| <li>Fix your imports to import <strong><tt>javax.swing.Action</tt></strong>. Save your changes.</li> |
| <li>Modify <strong>CustomerTopComponent</strong> to add the following method for refreshing the view: |
| <pre class="examplecode"> |
| public static void refreshNode() { |
| EntityManager entityManager = Persistence.createEntityManagerFactory("com.mycompany_MavenPlatformCRUDApp-dbaccess_nbm_1.0-SNAPSHOTPU").createEntityManager(); |
| Query query = entityManager.createQuery("SELECT c FROM Customer c"); |
| List<Customer> resultList = query.getResultList(); |
| em.setRootContext(new <strong>CustomerRootNode</strong>(Children.create(new CustomerChildFactory(resultList), true))); |
| }</pre> |
| <p>Notice that the method uses <strong>CustomerRootNode</strong> for setting the root context.</p> |
| <p class="tips">In the <tt>CustomerRootNode</tt> class, you can press Alt+Enter in the line |
| containing <tt>refreshNode</tt> if you want the IDE to generate the method skeleton for you.</p> |
| </li> |
| <li>Modify the code in the constructor of the CustomerTopComponent with a call to <strong>CustomerRootNode</strong> |
| instead of <strong>AbstractNode</strong>. |
| <p>Calling <tt>CustomerRootNode</tt> automatically calls the <tt>refreshNode</tt> method and invokes a "Refresh".</p> |
| </li> |
| |
| <li>Fix your imports and save your changes.</li> |
| </ol> |
| |
| <p>If you run the application you will see that there is a new root node with a "Refresh" action |
| available in the popup menu.</p> |
| |
| |
| <p class="tips">You can reuse the <tt>refreshNode</tt> method and implement an automatic refresh by calling the <tt>refreshNode</tt> method |
| from the <tt>save</tt> method. |
| Alternatively, you could create a separate module containing the refresh action |
| and the module could be shared between the modules.</p> |
| </div> |
| |
| |
| |
| <!-- =================================================================== --> |
| <!-- +++++++++++++++++++ Implementing CRUD : CREATE ++++++++++++++++++++ --> |
| |
| <h2><a name="05"></a>CREATE: Adding a New Record</h2> |
| |
| <p>In this section, you allow the user to create a new entry in the database.</p> |
| <div class="indent"> |
| <h3><a name="05a"></a>Adding the Create Action</h3> |
| <ol> |
| <li>Right-click the <strong>dbaccess</strong> module and choose New > Action.</li> |
| <li>Select Always Enabled. Click Next.</li> |
| <li>Select <strong>File</strong> in the Category dropdown list.</li> |
| <li>Select Global Toolbar Button. Click Next.<br/> |
| <img src="../images/tutorials/maven-crud/mavencrud-new-action.png" alt="Screenshot of New Action wizard" title="GUI Registration in New Action wizard" class="margin-around b-all" /> |
| |
| </li> |
| <li>Type <strong>NewAction</strong> for the Class Name.</li> |
| <li>Type <strong>My New Action</strong> for the Display Name.</li> |
| <li>Click Browse and select an image that will be used in the toolbar. |
| <p>You can copy the following image <tt>abc16.png</tt> to your desktop and specify the image in the wizard. |
| ( <img src="../images/tutorials/maven-crud/abc16.png" alt="Sample 16 x 16 icon" title="Sample 16 x 16 icon" /> ) |
| </p> |
| </li> |
| <li>Select the <strong>com.mycompany.mavenplatformcrudapp.editor</strong> package. Click Finish.</li> |
| <li>Modify the <tt>NewAction</tt> class to open the MyEditorTopComponent and clear the fields. |
| <pre class="examplecode"> |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| |
| public final class NewAction implements ActionListener { |
| |
| public void actionPerformed(ActionEvent e) { |
| MyEditorTopComponent tc = MyEditorTopComponent.getDefault(); |
| tc.resetFields(); |
| tc.open(); |
| tc.requestActive(); |
| } |
| |
| }</pre> |
| |
| <p>The action implements the ActionListener class, which is bound to the application |
| via entries in the layer file, put there by the New Action wizard.</p> |
| </li> |
| </ol> |
| |
| <!-- ++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
| <!-- I am still hitting issue 186876 in the RC2 build --> |
| <!-- ++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
| |
| <h3><a name="05b"></a>Creating and Saving a New Object</h3> |
| <ol> |
| <li>In the <strong>MyEditorTopComponent</strong>, add the following method for resetting |
| the JTextFields and creating a new <tt>Customer</tt> object. |
| <pre class="examplecode"> |
| public void resetFields() { |
| customer = new Customer(); |
| jTextField1.setText(""); |
| jTextField2.setText(""); |
| }</pre> |
| <p class="tips">In the <tt>NewAction</tt> class you can press Alt+Enter in the call to <tt>resetFields</tt> |
| if you want the IDE to generate a method skeleton in MyEditorTopComponent.</p> |
| </li> |
| <li>In the SaveCookie, ensure that a return of null indicates that a new entry is saved, instead of an existing entry being updated: |
| <pre class="examplecode"> |
| public void save() throws IOException { |
| |
| Confirmation message = new NotifyDescriptor.Confirmation("Do you want to save \"" |
| + jTextField1.getText() + " (" + jTextField2.getText() + ")\"?", |
| NotifyDescriptor.OK_CANCEL_OPTION, |
| NotifyDescriptor.QUESTION_MESSAGE); |
| |
| Object result = DialogDisplayer.getDefault().notify(msg); |
| |
| //When user clicks "Yes", indicating they really want to save, |
| //we need to disable the Save button and Save menu item, |
| //so that it will only be usable when the next change is made |
| //to the text field: |
| if (NotifyDescriptor.YES_OPTION.equals(result)) { |
| fire(false); |
| EntityManager entityManager = Persistence.createEntityManagerFactory("CustomerLibraryPU").createEntityManager(); |
| entityManager.getTransaction().begin(); |
| <strong>if (customer.getCustomerId() != null) {</strong> |
| Customer c = entityManager.find(Customer.class, cude.getCustomerId()); |
| c.setName(jTextField1.getText()); |
| c.setCity(jTextField2.getText()); |
| entityManager.getTransaction().commit(); |
| <strong>} else { |
| Query query = entityManager.createQuery("SELECT c FROM Customer c"); |
| List<Customer> resultList = query.getResultList(); |
| customer.setCustomerId(resultList.size()+1); |
| customer.setName(jTextField1.getText()); |
| customer.setCity(jTextField2.getText()); |
| //adds more fields that will populate the zip and discountCode columns |
| customer.setZip("12345"); |
| customer.setDiscountCode(entityManager.find(DiscountCode.class, 'H')); |
| |
| entityManager.persist(customer); |
| entityManager.getTransaction().commit(); |
| }</strong> |
| } |
| |
| }</pre> |
| <p>The code also writes some arbitrary data to DiscountCode because the field cannot be empty.</p> |
| </li> |
| <li>Fix your imports to import <tt><strong>javax.persistence.Query</strong></tt>. Save your changes.</li> |
| </ol> |
| |
| </div> |
| |
| |
| <!-- =================================================================== --> |
| <!-- ++++++++++++++++++++ Running the Application ++++++++++++++++++++++ --> |
| |
| <h2><a name="06"></a>Building and Running the Application</h2> |
| <p>The application now performs three of the CRUD functions: Create, Read and Update. |
| You can now build and run the application to check that all the functions are performing correctly.</p> |
| <ol> |
| <li>Right-click the project node of the <strong>MavenPlatformCRUDApp NetBeans Platform based application</strong> and choose Clean.</li> |
| <li>Right-click the project node of the <strong>MavenPlatformCRUDApp NetBeans Platform based application</strong> and choose Build with Dependencies.</li> |
| <li>Right-click the project node of the <strong>MavenPlatformCRUDApp NetBeans Platform based application</strong> and choose Run.</li> |
| </ol> |
| |
| <p>When you click Run, the IDE launches the platform application. |
| The application populates the tree in the Customer window with the names of the customers in the database. |
| When you select a node in the Customer window, the My Editor window displays the name and city of the selected customer. |
| You can modify and save the data in the Name and City fields. |
| To create a new customer, click the My Action button in the toolbar and enter a name in city in the empty text fields in the |
| My Editor window and then click Save.</p> |
| <p> |
| <img src="../images/tutorials/maven-crud/mavencrud-finished-app.png" alt="Screenshot of Finished application" title="Finished application showing Customer and MyEditor windows" class="margin-around b-all" /> |
| </p> |
| <p class="tips">After you create or modify a customer, you will need to refresh the Root node in the Customer window |
| if you did not implement the Refresh action on Save.</p> |
| |
| <p>This tutorial demonstrated how creating a NetBeans Platform application using Maven |
| is not very different from creating an application using Ant. |
| The major difference is understanding how the Maven POM controls how the application is assembled. |
| For more examples on how to build NetBeans Platform applications and modules, |
| see the tutorials listed in the <a href="https://netbeans.org/kb/trails/platform.html">NetBeans Platform Learning Trail</a>.</p> |
| |
| <!-- ======================================================================================== --> |
| |
| <div class="feedback-box"><a name="feedback"></a> |
| <a href="https://netbeans.org/about/contact_form.html?to=3&subject=Feedback:%20NetBeans%20Platform%20CRUD%20Application%20Using%20Maven"> |
| Send Us Your Feedback</a></div> |
| |
| <p> </p> |
| <!-- ======================================================================================== --> |
| <h2><a name="nextsteps"></a>See Also</h2> |
| |
| <p>This concludes the CRUD Tutorial. This document has described |
| how to use the Maven build framework to create a new NetBeans Platform application with CRUD functionality. |
| For more information about creating and developing applications, see the following resources.</p> |
| <ul> |
| <li><a href="https://netbeans.org/kb/trails/platform.html">NetBeans Platform Learning Trail</a></li> |
| <li><a href="http://bits.netbeans.org/dev/javadoc/">NetBeans API Javadoc</a></li> |
| </ul> |
| |
| <p>If you have any questions about the NetBeans Platform, feel free |
| to write to the mailing list, dev@platform.netbeans.org, or view the |
| <a href="https://netbeans.org/projects/platform/lists/dev/archive">NetBeans Platform mailing list archive</a>.</p> |
| |
| |
| <!-- ======================================================================================== --> |
| |
| |
| </body> |
| |
| </html> |