blob: 5fceb7e20e70da17b5523b7c7d059cd68ba042b2 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Web Service Passing Binary Data, pt 5: Creating the Swing Client
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Web Service Passing Binary Data, pt 5: Creating the Swing Client - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Web Service Passing Binary Data, pt 5: Creating the Swing Client
The goal of this exercise is to create a client for the web service you previously created and deployed, and then add a GUI interface to that client. The interface displays the images that the web service passes as binary data.
You can download a complete version of the client from the link:https://netbeans.org/projects/samples/downloads/download/Samples%252FWeb%2520Services%252FWeb%2520Service%2520Passing%2520Binary%2520Data%2520--%2520EE6%252FFlowerClient.zip[+NetBeans Samples Catalog+].
*Lessons In This Tutorial*
image::images/netbeans-stamp-74-73-72.png[title="Content on this page applies to the NetBeans IDE 7.2, 7.3 and 7.4"]
1. link:./flower_overview.html[+Overview+]
2. link:./flower_ws.html[+Creating the Web Service+]
3. link:./flower-code-ws.html[+Coding and Testing the Web Service+]
4. link:./flower_wsdl_schema.html[+Modifying the Schema and WSDL Files to Pass Binary Data+]
5. => Creating the Swing Client
[start=1]
1. <<create-client-app,Creating the Client Application>>
[start=2]
. <<design-jframe,Designing the JFrame>>
[start=3]
.
<<bind-jframe,Binding the JFrame Components>>
[start=4]
. <<code-main-class,Coding the Main Class>>
== Creating the Client Application
In this section, you create a web application. Within this application, you create a client that consumes the web service you created and modified in previous tutorials.
*To create the client application: *
1. Choose File > New Project (Ctrl-Shift-N on Linux/Windows, ⌘-Shift-N on MacOS). The New Project wizard appears.
2. Select Java Application from the Java category. Click Next. The New Java Application wizard appears. Type ``FlowerClient`` in Project Name. Select a location for the project and click Finish. The IDE creates a new Java application project.
3. Right-click the ``FlowerClient`` project node and choose New > Web Service Client from the context menu. The New Web Service Client wizard opens.
4. Select the WSDL URL radio button and paste the URL of the WSDL file into that field. (By default, the URL is ``http://localhost:8080/FlowerAlbumService/FlowerServiceService?wsdl`` . Find the URL in the browser by testing the web service and replacing ``?Tester`` with ``?wsdl`` at the end of the URL.) Accept all other default values, including a blank package name.
image::images/ws-client-wiz.png[]
[start=5]
. Click Finish. The IDE downloads the WSDL file, adds client stubs for interacting with the web service, and adds nodes to the Projects window in the Java application project.
image::images/client-generated-sources.png[title="Projects view showing new web service client"]
[[design-jframe]]
== Designing the JFrame Form
In this section, you add a ``JFrame`` to the web application and design a GUI interface within it, using Swing components. Finally, you bind the Swing components to the web service client code.
If you do not want to design the JFrame form yourself, you can download a predesigned JFrame Java file link:https://netbeans.org/projects/www/downloads/download/webservices%252FFlowerFrame.java[+here+].
1. Right-click the ``FlowerClient`` node and select New > JFrame Form. Name the frame ``FlowerFrame`` . Place it in the ``flowerclient`` package.
2. The ``FlowerFrame`` opens in the editor. Open the Palette if it is not open. Extend the bottom boundary of the frame by around one-third.
image::images/opened-flowerform.png[]
[start=3]
. Drag a JPanel from the Swing Containers section of the Palette to the ``FlowerFrame`` . Expand it to fill the entire ``FlowerFrame`` .
image::images/add-panel.png[]
[start=4]
. Right-click the Panel in the Design View. Select Change Variable Name... from the context menu. Name the panel ``gardenFlowersPanel`` .
[start=5]
. Drag a JLabel from the Palette to the top of the `` gardenFlowersPanel`` . Right-click the label, and change the label's variable name to ``titleLabel`` . Right-click the ``titleLabel`` again and select Edit Text. Change the text to Garden Flowers. You may want to explore the ``titleLabel`` 's properties and give it a prominent font.
[start=6]
. Drag a Button Group into the design view. Accept the button group's default variable name of ``buttonGroup1`` .
[start=7]
. Drag four Radio Buttons into a horizontal row beneath the ``titleLabel`` . In the properties of each button, set it as a member of ``buttonGroup1`` . The buttons' other properties are as follows:
|===
|Radio Buttons in buttonGroup1
|Variable Name |Selected |Text
|asterRadioButton |true |Aster
|honeysuckleRadioButton |false |Honeysuckle
|roseRadioButton |false |Rose
|sunflowerRadioButton |false |Sunflower
|===
[start=8]
. Drag a Scroll Pane to below the radio buttons. Expand it to fill all the horizontal space and about two-thirds of the free vertical space. Change the scroll pane's variable name to ``mainScrollPane`` .
[start=9]
. Drag a Panel into the ``mainScrollPane`` . Change the Panel's variable name to ``mainPanel`` .
[start=10]
. In the Design view, right-click the ``mainPanel`` and select Set Layout > Border Layout.
[start=11]
. Drag a Button into the ``mainPanel`` . Because the ``mainPanel`` has border layout, the button automatically fills the entire panel. Change the button's variable name to ``mainPictureButton`` and change the button's text to "Waiting for picture..."
[start=12]
. Drag another Scroll Pane to the space below the ``mainScrollPane`` . Expand the new scroll pane to fill up all remaining free space. Change the new scroll pane's variable name to ``thumbnailScrollPane`` .
[start=13]
. Drag a Panel into the ``thumbnailScrollPane`` . Change the Panel's variable name to ``thumbnailPanel`` . Set the ``thumbnailPanel`` 's layout to Grid Layout.
[start=14]
. Drag four Buttons into the ``thumbnailPanel`` . Because the ``thumbnailPanel`` has Grid Layout, the Buttons are automatically of equal size and completely fill the panel. The buttons' properties are as follows: Buttons in the thumbnailPanel
|===
|Variable Name |Text
|asterButton |Waiting...
|honeysuckleButton |Waiting...
|roseButton |Waiting
|sunflowerButton |Waiting...
|===
The JFrame Form is now completely designed. At this point, the ``FlowerFrame`` looks as follows.
image::images/designed-form.png[title="Completed Flower Frame showing button texts instead of images"]
== Binding the JFrame Components
In this section, you initialize the components in the constructor and bind the components to listeners. The listeners call code that shows the flower images.
=== [[Initializing the Components]]
[[In this section, you fill in the ``FlowerFrame`` constructor
]]
1. Change to the Source view of the editor. Locate the beginning of the ``FlowerFrame`` class body and the ``FlowerFrame`` constructor.
image::images/ff-empty-constructor.png[]
. At the top of the class body of ``FlowerFrame`` , before the constructor, create an array of strings of the names of every flower.
[source,java]
----
protected static final String[] FLOWERS = {"aster", "honeysuckle", "rose", "sunflower"};
----
. Between the FLOWERS string array and the constructor, add a line that initializes a ``link:http://download.oracle.com/javase/6/docs/api/java/util/Map.html[+java.util.Map+]`` named ``flowers`` . The map takes a ``String`` and maps it to an ``Image`` .
[source,java]
----
private Map<String, Image> flowers;
----
. Add import statements for ``java.util.Map`` and ``java.awt.Image`` .
. Add code to the ``FlowerFrame`` constructor to associate a specific ``Image`` with a specific ``String`` for a specific instance of the ``flowers`` map
[source,java]
----
public FlowerFrame(Map<String, Image> flowers) {
this.flowers = flowers;
for (String flower:FLOWERS) {
flowers.put(flower,null);
}
initComponents();
}
----
[start=3]
. Initialize ``ItemListener`` s for the radio buttons and ``ActionListener`` s for the four flower buttons, and set the default title.
[source,java]
----
public FlowerFrame(Map<String, Image> flowers) {
this.flowers = flowers;
for (String flower:FLOWERS) {
flowers.put(flower,null);
}
initComponents();
setTitle("Garden Flowers [waiting for picture]");
ItemListener rbListener = new RBListener();
asterRadioButton.addItemListener(rbListener);
honeysuckleRadioButton.addItemListener(rbListener);
roseRadioButton.addItemListener(rbListener);
sunflowerRadioButton.addItemListener(rbListener);
ActionListener bListener = new ButtonListener();
asterButton.addActionListener(bListener);
honeysuckleButton.addActionListener(bListener);
roseButton.addActionListener(bListener);
sunflowerButton.addActionListener(bListener);
}
----
[start=4]
. Add import statements for ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ItemListener.html[+java.awt.event.ItemListener+]`` and ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionListener.html[+java.awt.event.ActionListener+]`` .
The constructor is now complete. You have compile error warnings in the code because the code does not contain the classes ``RBListener`` and ``ButtonListener`` . These two classes are custom implementations of ``ItemListener`` and ``ActionListener`` , respectively. You write these two classes in the next section.
=== [[Showing the Flowers]]
[[In this section, you write custom listeners for the radio buttons and the flower buttons. You also write a method that determines which flower is selected by the buttons and gets an ``Image`` of that flower from the ``flowers`` map. Lastly, you write a method that is called by the ``Main`` class and that gets an ``Image`` for each thumbnail.
]]
1. Find the ``public static void main(String args[])`` method in the ``FlowerFrame`` class body. Delete this method and its documentation. (The application uses the ``Main`` class instead.)
. In place of the ``main`` method, write a custom ``ItemListener`` for the radio buttons. This listener shows a new flower image when a radio button is chosen.
[source,java]
----
private class RBListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
showFlower();
}
}
----
. Add an import statement for ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ItemEvent.html[+java.awt.event.ItemEvent+]`` .
. Below the custom ``ItemListener`` , write a custom ``ActionListener`` for the 4 flower buttons. When a button is clicked, the listener selects the related radio button:
[source,java]
----
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == asterButton) asterRadioButton.setSelected(true);
else if (e.getSource() == honeysuckleButton) honeysuckleRadioButton.setSelected(true);
else if (e.getSource() == roseButton) roseRadioButton.setSelected(true);
else if (e.getSource() == sunflowerButton) sunflowerRadioButton.setSelected(true);
}
}
----
[start=2]
. Add an import statement for ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html[+java.awt.event.ActionEvent+]`` .
[start=3]
. Below the custom ``ActionListener`` , write the ``showFlower`` method. This method determines which radio button is selected and gets an ``Image`` of the corresponding flower from the ``flowers`` map.
[source,java]
----
void showFlower() {
Image img = null;
if (asterRadioButton.isSelected()) {
img = flowers.get("aster");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Aster]");
}
} else if (honeysuckleRadioButton.isSelected()) {
img = flowers.get("honeysuckle");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Honeysuckle]");
}
} else if (roseRadioButton.isSelected()) {
img = flowers.get("rose");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Rose]");
}
} else if (sunflowerRadioButton.isSelected()) {
img = flowers.get("sunflower");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Sunflower]");
}
}
if (img == null) {
mainPictureButton.setIcon(null);
setTitle("Garden Flowers [waiting for picture]");
} else mainPictureButton.setText("");
}
----
[start=4]
. Add an import statement for ``link:http://download.oracle.com/javase/6/docs/api/javax/swing/ImageIcon.html[+javax.swing.ImageIcon+]`` .
[start=5]
. Write the ``setThumbnails`` method. This method gets an image for each thumbnail from the ``flowers`` map. The ``Main`` class calls this method.
[source,java]
----
void setThumbnails(Map<String, Image> thumbs) {
Image img = thumbs.get("aster");
if (img != null) {
asterButton.setIcon(new ImageIcon(img));
asterButton.setText("");
}
img = thumbs.get("honeysuckle");
if (img != null) {
honeysuckleButton.setIcon(new ImageIcon(img));
honeysuckleButton.setText("");
}
img = thumbs.get("rose");
if (img != null) {
roseButton.setIcon(new ImageIcon(img));
roseButton.setText("");
}
img = thumbs.get("sunflower");
if (img != null) {
sunflowerButton.setIcon(new ImageIcon(img));
sunflowerButton.setText("");
}
}
----
[start=6]
. Fix the imports in ``FlowerFrame`` , if you did not fix them as you pasted in the code. You can fix them all at once by right-clicking in the editor and choosing Fix Imports from the context menu. The complete set of import statements follows:
[source,java]
----
import java.awt.Image;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.ItemEvent;import java.awt.event.ItemListener;import java.util.Map;import javax.swing.ImageIcon;
----
The ``FlowerFrame`` is now complete.
== [[Coding the Main Class]]
[[In this section, you complete the ``Main`` class so that is shows the ``FlowerFrame`` , connects to the web service, and calls the web service operations.
1. Open the ``Main.java`` class in the editor.
image::images/main-empty.png[]
[start=2]
. In the class body, before the ``main`` method, initialize an ``int`` variable for the number of downloaded pictures.
[source,java]
----
private static int downloadedPictures;
----
[start=3]
. In the ``main`` method body, create a ``HashMap`` of four flowers and another ``HashMap`` of four thumbnails.
[source,java]
----
final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
----
[start=4]
. Add import statements for ``java.awt.Image`` , ``java.util.Map`` , and ``java.util.HashMap`` .
[start=5]
. In the ``main`` method body, add code to show the ``FlowerFrame`` .*// Show the FlowerFrame.*
[source,java]
----
final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);
----
[start=6]
. In the ``main`` method body, add code to connect the client to the service.*// The client connects to the service with this code.*
[source,java]
----
FlowerServiceService service = new FlowerServiceService();
final FlowerService port = service.getFlowerServicePort();
----
[start=7]
. Add import statements for ``org.flower.service.FlowerService`` and ``org.flower.service.FlowerServiceService`` .
[start=8]
. In the ``main`` method body, add code that creates an array of four ``Runnable`` threads and calls the web service's ``getFlower`` operation once in each thread.*// The web service getFlower operation
// is called 4 times, each in a separate thread.
// When the operation finishes the picture is shown in
// a specific button.*
[source,java]
----
Runnable[] tasks = new Runnable[4];
for (int i=0; i<4;i++) {
final int index = i;
tasks[i] = new Runnable() {
public void run() {
try {
*// Call the getFlower operation
// on the web service:*
Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
*// Add strings to the hashmap:*
flowers.put(FlowerFrame.FLOWERS[index],img);
*// Call the showFlower operation
// on the FlowerFrame:*
frame.showFlower();
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
downloadedPictures++;
}
};
new Thread(tasks[i]).start();
}
----
[start=9]
. Add an import statement for ``org.flower.service.IOException_Exception`` .
[start=10]
. In the ``main`` method body, add code that calls the web service's ``getThumbnails`` operation in a separate thread.*// The web service getThumbnails operation is called
// in a separate thread, just after the previous four threads finish.
// When the images are downloaded, the thumbnails are shown at
// the bottom of the frame.*
[source,java]
----
Runnable thumbsTask = new Runnable() {
public void run() {
try {
while (downloadedPictures < 4) {
try {Thread.sleep(100);} catch (InterruptedException ex) {}
}
*// Call the getThumbnails operation
// on the web service:*
List<Image> images = port.getThumbnails();
System.out.println("thumbs downloaded");
if (images != null &amp;&amp; images.size() == 4) {
for (int i=0;i<4;i++) {
thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
}
frame.setThumbnails(thumbs);
}
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
}
};
new Thread(thumbsTask).start();
----
[start=11]
. Fix the imports in ``Main.java`` , if you did not fix them as you pasted in the code. You can fix them all at once by right-clicking in the editor and choosing Fix Imports from the context menu. You are given a choice of List classes to import; select ``java.util.List`` . The complete set of import statements follows:
[source,java]
----
import flower.album.FlowerService;import flower.album.FlowerService_Service;import flower.album.IOException_Exception;import java.awt.Image;import java.util.HashMap;import java.util.List;import java.util.Map;
----
The ``Main`` class is now complete.
[source,java]
----
public class Main {
private static int downloadedPictures;
public static void main(String[] args) {
final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
*// Show the FlowerFrame.*
final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);
* // The client connects to the service with this code.*
FlowerService_Service service = new FlowerService_Service();
final FlowerService port = service.getFlowerServicePort();
Runnable[] tasks = new Runnable[4];
*// The web service getFlower operation
// is called 4 times, each in a separate thread.
// When the operation finishes the picture is shown in
// a specific button.*
for (int i=0; i<4;i++) {
final int index = i;
tasks[i] = new Runnable() {
public void run() {
try {
*// Call the getFlower operation
// on the web service:*
Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
*// Add strings to the hashmap:*
flowers.put(FlowerFrame.FLOWERS[index],img);
*// Call the showFlower operation
// on the FlowerFrame:*
frame.showFlower();
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
downloadedPictures++;
}
};
new Thread(tasks[i]).start();
}
*// The web service getThumbnails operation is called
// in a separate thread, just after the previous four threads finish.
// When the images are downloaded, the thumbnails are shown at
// the bottom of the frame.*
Runnable thumbsTask = new Runnable() {
public void run() {
try {
while (downloadedPictures < 4) {
try {Thread.sleep(100);} catch (InterruptedException ex) {}
}
*// Call the getThumbnails operation
// on the web service:*
List<Image> images = port.getThumbnails();
System.out.println("thumbs downloaded");
if (images != null &amp;&amp; images.size() == 4) {
for (int i=0;i<4;i++) {
thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
}
frame.setThumbnails(thumbs);
}
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
}
};
new Thread(thumbsTask).start();
}
}
----
The client application is now complete, with code that interacts with the web service that delegates to the EJB module to exposes its images. Right-click the client and choose Run. The Swing application starts up and, after a moment, is filled with the images received from the web service. If the images do not all appear, clean and build the FlowerService project and run it again. Note that you can change the image that appears in the main frame either by selecting a radio button or by clicking a thumbnail.
]]
link:/about/contact_form.html?to=3&subject=Feedback:%20Flower%20Swing%20Client%20EE6[+Send Feedback on This Tutorial+]
To send comments and suggestions, get support, and keep informed about the latest developments on the NetBeans IDE Java EE development features, link:../../../community/lists/top.html[+join the nbj2ee@netbeans.org mailing list+].