How to Create a Swing CRUD Application on NetBeans Platform 6.8
This article shows you how to integrate a Java DB database into a NetBeans Platform application. We start by exploring a Java DB database, from which we create entity classes. Next, we wrap the entity classes into a module, together with modules for the related JPA JARS.
Note: These instructions are not applicable to Java DB only. Rather, they are relevant to any relational database, such as Oracle or MySQL. Several applications on the NetBeans Platform, many of which are listed here, use these databases too. Java DB was chosen for this article because it is easiest to get started with, since it comes with the JDK.
Once the above modules are part of our application, we create a new module that provides the user interface for our application. The new module gives the user a tree hierarchy showing data from the database. We then create another module that lets the user edit the data displayed by the first module. By separating the viewer from the editor in distinct modules, we will enable the user to install a different editor for the same viewer, since different editors could be created by external vendors, some commercially and some for free. It is this flexibility that the modular architecture of the NetBeans Platform makes possible.
When we have a module for our editor, we begin adding CRUD functionality. First, the "R", standing for "Read", is handled by the viewer described above. Next, the "U" for "Update" is handled, followed by the "C" for "Create", and the "D" for "Delete".
At the end of the article, you will have learned about a range of NetBeans Platform features that help you in creating applications of this kind. For example, you will have learned about the UndoRedo.Manager and the ExplorerManager, as well as NetBeans Platform Swing components, such as TopComponent and BeanTreeView.
Contents
- Setting Up the Application
- Integrating the Database
- Creating Entity Classes from a Database
- Wrapping the Entity Class JAR in a Module
- Creating Other Related Modules
- Designing the User Interface
- Setting Dependencies
- Running the Prototype
- Integrating CRUD Functionality
The application you create in this article will look as follows:
Source code: http://kenai.com/projects/nbcustomermanager
Once you're at the stage shown above, you can simply download a NetBeans module that provides Office LAF support (described here), add it to your application, and then when you redeploy the application, you will see this:
Note: It is advisable to watch the screencast series Top 10 NetBeans APIs before beginning to work on this article. Many of the concepts addressed in this article are discussed in more detail within the screencast series.
Setting up the Application
Let's start by creating a new NetBeans Platform application.
- Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. Under Projects, select NetBeans Platform Application. Click Next.
- In the Name and Location panel, type DBManager in the Project Name field. Click Finish.
The IDE creates the DBManager project. The project
is a container for all the other modules you will create.
Run the application and notice that you have quite a few features out of the box already. Open some of the windows, undock them, and get to know the basic components that the NetBeans Platform provides without you doing any work whatsoever:
Integrating the Database
In order to integrate the database, you need to create entity classes from your database and integrate those entity classes, together with their related JARs, into modules that are part of your NetBeans Platform application.
Creating the Entity Classes
In this section, you generate entity classes from a selected database.
- For purposes of this example, use the Services window to
connect to the sample database that is included with
NetBeans IDE:
Note: Alternatively, use any database you like and adapt the steps that follow to your particular use case. In the case of MySQL, see Connecting to a MySQL Database.
- In the IDE, choose File | New Project, followed by Java | Java Class Library to create a new library project named CustomerLibrary.
- In the Projects window, right-click the library project
and choose File | New File, followed by Persistence | Entity
Classes from Database. In the wizard, select your database and the tables you
need. Here we choose "Customer", and then "Discount Code" is added automatically, since
there is a relationship between these two tables.
- Specify the persistence strategy, which can
be any of the available options. Here, since we need
to choose something, we'll
choose EclipseLink:
- Specify "demo" as the name of
the package where the entity classes will be generated.
- Click Finish. Once you have completed this step, look at the generated code and notice
that, among other things, you now have a persistence.xml file in a folder
called META-INF, as well as entity classes for each of your tables:
- Build the Java Library and you will have a JAR file in the library
project's "dist" folder, which you can view in the Files window:




Comments
Craig Ringer replied on Wed, 2009/12/09 - 12:17am
Geertjan Wielenga replied on Wed, 2009/12/09 - 12:27am
Excellent feedback, ringerc. That will be fixed. Thank you. One approach is to register actions in the layer file which then enables you to add an attribute to the layer entry. That attribute causes the action to be processed asynchronously, (which is a new feature in 6.8, i.e., the ability to mark an action as being asynchronous). These asynchronous actions can simulate SwingWorker:
class MyAction implements ActionListener, Runnable {
public MyAction(MyContext c) {
assert EventQueue.isEventThread();
// setup inside AWT thread, get what is important from c
}
public void actionPerformed(AE ev) {
assert !EventQueue.isEventThread();
// run off AWT thread
// perform the work
SwingUtilities.invokeLater(this);
}
public void run() {
assert EventQueue.isEventThread();
// finish in AWT and update the UI
}
}
Another approach would be to use SwingWorker. These approaches will be added to the article, though note that threading on the NetBeans Platform is also discussed here: http://wiki.netbeans.org/NetBeansDeveloperFAQ#Threading
Something else that's possible is to integrate with the NetBeans progress bar, which can be achieved with, literally, 3 lines of code.
Suraj Chhetry replied on Wed, 2009/12/09 - 4:04am
Thanks for great toturail. Could you tell me how can I create flollowing type of menu at TopComponent how can i do this ?
Root
----Customers
- Greetjan
-Orders
+Raw-12092009
+Raw-11091009
+Balance
+Reports
Florian Brunner replied on Thu, 2009/12/10 - 5:42am
Hi Geertjan,
great to have another tutorial about this topic. Thanks!
Though I haven't read all of it yet, I already have one enhancement question:
As you know, the NetBeans IDE provides a project template to create the skeleton of a CRUD application based on the Swing Application Framework.
Maybe it would be useful to have a project template to create the skeleton of a CRUD application based on the NetBeans Platform, too. What do you think?
-Florian
Geertjan Wielenga replied on Sun, 2009/12/13 - 6:51am
Dans Cut replied on Mon, 2009/12/14 - 10:40am
Geertjan Wielenga replied on Mon, 2009/12/14 - 12:06pm
in response to:
Dans Cut
Geertjan Wielenga replied on Mon, 2009/12/14 - 6:56pm
Hi surajchchetry, that's a great idea. If I understand it correctly. This is the kind of project structure I am creating at the moment, for a new tutorial, based on your suggestion above.
A new tutorial should appear within the next week or two, to explain how to create project structures like the above, with a bunch of additional features too, as described here in my blog!
Nguyen Khiem replied on Mon, 2009/12/21 - 7:23am
Kevin Jaques replied on Sun, 2010/01/03 - 12:25pm
Kevin Jaques replied on Sun, 2010/01/03 - 12:47pm
em.setRootContext(new AbstractNode(Children.create(new CustomerChildFactory(resultList), true)));"
That also drives home part of the reason for the change.Kevin Jaques replied on Sun, 2010/01/03 - 1:02pm
Farouk Alhassan replied on Tue, 2010/01/19 - 3:08pm
Hi Geertjan
Thank you very much for such a great tutorial. Following the tutorials from here and the JPA intergration in the Definitive guide to Netbeans Platform I am trying to develop a real database application from the concepts explained. I am however not getting a any success.
In this tutorial, the EntityManager is created in the constructor of the TopComponent class which is not very efficient for obvious reasons and will also be a night mare to maintain if every TopComponent creates its own Entitymanager. I therefore tried the Installer approach used in the Netbeans Platform book but that didn't work. I kept getting ClasscastException when retreiving the objects via creating the nodes for the Viewer with ExplorerManager.
protected boolean createKeys(List<Pupilidentifiers> list) {
for (Pupilidentifiers identifier : resultList) {
list.add(identifier);
}
return true;
}
Que 1. What is the recommended way of using these API's and JPA in a production environment?
To get my application off the ground,
I have now moved the Node creation code to the componentOpened() method and calling the entity manager creation directly but that is throwing the following errors with regards
associateLookup(ExplorerUtils.createLookup(exm, map));
java.lang.IllegalStateException: Trying to set lookup ProxyLookup(class=class org.openide.explorer.DefaultEMLookup)->[org.openide.explorer.DefaultEMLookup$NoNodeLookup@5b695ffa, org.openide.util.Lookup$Empty@375212bc, org.openide.util.lookup.SingletonLookup@631c44f8] but there already is java.lang.ref.WeakReference@54f4289d for component: PupilViewer.PupilTopComponent[Pupil Window,0,0,0x0,invalid,layout=javax.swing.GroupLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=256,maximumSize=,minimumSize=,preferredSize=]
at org.openide.windows.TopComponent.setLookup(TopComponent.java:1252)
Que 2. Is it not possible to call that method in the componentOpened() method?
Vladimír Duša replied on Tue, 2010/02/09 - 3:29pm
Hi Geertjan,
thanks for this super tutorial - it helped me a lot.
I still have a problem with saving the customer. The save button works as I expect, but the save action is not invoked during closing the TopComponent and switching between customers. After few hours of googling I have no Idea how to do it using SaveCookie and SaveCookieImpl model. Is there a possibility, to manually invoke the same save action as the save button? It would be good to invoke this save action in componentClosed() and resultChanged() methods.
Thank you very much
Vladimír Duša
John Hetherington replied on Wed, 2010/05/26 - 8:16pm
Started working through this article on Netbeans 6.8, completed the read section successfuly and got the tree displaying with the properties synchronised. Commenced on the update section and got down to Step 4 which states Go back to the Customer Viewer module and change the layer.xml file and specify that the CustomerTopComponent window will appear in the explorer mode.
Has anyone the neccessary xml code to add here to make this happen as none is included in the article??
Kind Regards
John In New Zealand
Ralph Lance replied on Tue, 2010/06/29 - 4:38am
in response to:
John Hetherington
Hadi Setyono replied on Thu, 2010/07/01 - 5:32am
Andreas Niepsch replied on Tue, 2010/07/20 - 6:02am
Hi Geertjan,
thank's for this tutorial. It's a very good start for developing Rcp and Database-Applikations.
I have two questions:
1. If i close "Customer Window" the content of "Editor Window" isn't clear, wy??? or what should i do?
I think if a TComponent is closed the Lookup of is is not longer in the Global Context and not displayed in
the "Editor Windows" ????
2. The save-button is enabled if i mouseClicked in "Editor Window". Enabling if changed content of the
form is better in this sample.
Thank you
Andreas
Craig Ringer replied on Tue, 2010/07/27 - 2:41am
There are issues with driving Swing directly with JPA entities when you start doing anything non-trivial, involving larger amounts of data. You start to need to lazily load parts of entities or entity relationships, and have to worry about how much data you're retaining in memory at once. This gives rise to issues with EDT blocking again, and major problems with managing JPA session lifetimes.
If you're going to be working with enough data that you don't want to download it from the database server all at once, think very carefully about whether this is the approach for you.
Anyone considering writing a non-trivial app driven directly by JPA data access should read this excellent article:
http://blog.schauderhaft.de/2008/09/28/hibernate-sessions-in-two-tier-rich-client-applications/
... and possibly my own inferior writing on the topic, which covers some issues not considered by the above link:
http://soapyfrogs.blogspot.com/2010/07/jpa-and-hibernateeclipselinkopenjpaetc.html
The only solutions I've found to the issues involve writing a (probably complex and boilerplate-heavy) mid-tier to buffer between Swing and JPA.
Craig Ringer replied on Tue, 2010/07/27 - 2:57am
in response to:
Farouk Alhassan
@gcameo: I'm not the smartest developer around, nor the strongest JPA expert, but my personal advice after recent experience trying to use JPA in a Swing app is: run, run, as fast as you can.
You'll have to write a midlayer to mediate between Swing and your JPA data access to get acceptable performance, avoid blocking the UI, etc. Even then it'll be "interesting" to manage JPA session lifetimes. I'm currently seriously considering ripping JPA out of my app entirely and going back to JDBC, because I'm finding it creates more problems than it solves in a 2-tier Swing app.
I'd be glad to be proved wrong, of course. Just so long as that "wrong" doesn't involve some comment about how you should "obviously" write a 3-teir appserver based monstrosity that communicates with the Swing rich client via RMI. I don't have an army of bored coders who need make-work, I need to get a real application written ;-)
I have direct personal messages enabled, and my email address is:
python -c "print 'Y3JhaWdAcG9zdG5ld3NwYXBlcnMuY29tLmF1\n'.decode('base-64')"I don't seem to get email comment reply notifications, though.
Tj Harple replied on Tue, 2011/02/15 - 5:05pm
Hi Geertjan
Thank you very much for such a great tutorial. This is only my 2nd tutorial with Java 1.6.0_23 & NetBeans 6.9.1 on Windows 7. I was following the tutorial here : http://platform.netbeans.org/tutorials/nbm-crud.html
and had a strange issue for which only by chance I found the work around here on dzone.
My issue:
cannot find symbol
symbol : method actionsGlobalContext()
location: class javax.swing.text.Utilities
result = Utilities.actionsGlobalContext().lookupResult(Customer.class);
Which was worked around by the change:
result = WindowManager.getDefault().findTopComponent("CustomerTopComponent").getLookup().lookupResult(Customer.class);
But my question...
Clearly it looks like I was missing a library dependencey. But when looking all over the internet, no one else had this issue, or spoke about using actionsGlobalContext with a specific dependency.
Is this a resent change that you may be aware of, or does it sound like my configuration may be suspect.
Can you suggest or point me to a resource which would allow me to figure out these types of dependencies on my own. In other words which file located in which directory contains this method.
Also, I have noted a few minor changes needed in the netbean.org tutroial based on my configuration and would be willing to update or provide suggestion if that was appropriate. Is that work done here on dzone or via netbeans.org?
Thanks in Advance
Terry Harple
Mark Green replied on Sat, 2011/07/30 - 8:18pm
Johnson Eyo replied on Wed, 2011/08/24 - 5:48am
Johnson Eyo replied on Tue, 2011/09/13 - 3:50am
my program still refuses to build the customerlibrary to a jar file,i get these errors onh the console window,
init:
deps-clean:
Updating property file: C:\CustomerLibrary\build\built-clean.properties
Deleting directory C:\CustomerLibrary\build
clean:
init:
deps-jar:
Created dir: C:\CustomerLibrary\build
Updating property file: C:\CustomerLibrary\build\built-jar.properties
Created dir: C:\CustomerLibrary\build\classes
Created dir: C:\CustomerLibrary\build\classes\META-INF
Copying 1 file to C:\CustomerLibrary\build\classes\META-INF
Created dir: C:\CustomerLibrary\build\empty
Created dir: C:\CustomerLibrary\build\generated-sources\ap-source-output
Compiling 2 source files to C:\CustomerLibrary\build\classes
Note: Creating non-static metadata factory ...
An annotation processor threw an uncaught exception.
Consult the following stack trace for details.
java.lang.NoSuchMethodError: javax.annotation.processing.RoundEnvironment.getRootElements()Ljava/util/Set;
at org.eclipse.persistence.internal.jpa.modelgen.MetadataMirrorFactory.setEnvironments(MetadataMirrorFactory.java:297)
at org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor.process(CanonicalModelProcessor.java:368)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:634)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:565)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:704)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:913)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:659)
at com.sun.tools.javac.main.Main.compile(Main.java:327)
at com.sun.tools.javac.main.Main.compile(Main.java:253)
at com.sun.tools.javac.main.Main.compile(Main.java:244)
at com.sun.tools.javac.Main.compile(Main.java:69)
at com.sun.tools.javac.Main.main(Main.java:54)
C:\CustomerLibrary\nbproject\build-impl.xml:603: The following error occurred while executing this line:
C:\CustomerLibrary\nbproject\build-impl.xml:245: Compile failed; see the compiler error output for details.
BUILD FAILED (total time: 7 seconds)
please help with these, because of this i can continue the rest of the tutorial
http://platform.netbeans.org/tutorials/nbm-crud.html
Carla Brian replied on Sun, 2012/05/06 - 7:32am
Berton Jain replied on Sat, 2012/07/14 - 2:07am
Steve Sdas replied on Tue, 2012/09/25 - 9:06am
Steve Sdas replied on Wed, 2012/09/26 - 2:44pm
Steve Sdas replied on Thu, 2012/10/04 - 5:24am
Steve Sdas replied on Sun, 2012/10/07 - 1:04pm