Web Service Passing Binary Data, pt 5: Creating the Swing Client

This tutorial needs a review. You can edit it in GitHub following these contribution guidelines.

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 NetBeans Samples Catalog.

Lessons In This Tutorial

netbeans stamp 74 73 72
Figure 1. Content on this page applies to the NetBeans IDE 7.2, 7.3 and 7.4

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.

ws client wiz
  1. 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.

client generated sources
Figure 2. Projects view showing new web service client

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

opened flowerform
  1. Drag a JPanel from the Swing Containers section of the Palette to the FlowerFrame . Expand it to fill the entire FlowerFrame .

add panel
  1. Right-click the Panel in the Design View. Select Change Variable Name…​ from the context menu. Name the panel gardenFlowersPanel .

  1. 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.

  1. Drag a Button Group into the design view. Accept the button group’s default variable name of buttonGroup1 .

  1. 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

  1. 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 .

  1. Drag a Panel into the mainScrollPane . Change the Panel’s variable name to mainPanel .

  1. In the Design view, right-click the mainPanel and select Set Layout > Border Layout.

  1. 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…​"

  1. 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 .

  1. Drag a Panel into the thumbnailScrollPane . Change the Panel’s variable name to thumbnailPanel . Set the thumbnailPanel 's layout to Grid Layout.

  1. 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.

designed form
Figure 3. 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.

ff empty constructor
  1. At the top of the class body of FlowerFrame , before the constructor, create an array of strings of the names of every flower.

protected static final String[] FLOWERS = {"aster", "honeysuckle", "rose", "sunflower"};
  1. Between the FLOWERS string array and the constructor, add a line that initializes a java.util.Map named flowers . The map takes a String and maps it to an Image .

private Map<String, Image> flowers;
  1. Add import statements for java.util.Map and java.awt.Image .

  2. Add code to the FlowerFrame constructor to associate a specific Image with a specific String for a specific instance of the flowers map

public FlowerFrame(Map<String, Image> flowers) {

    this.flowers = flowers;
    for (String flower:FLOWERS) {
        flowers.put(flower,null);
    }

    initComponents();
}
  1. Initialize ItemListener s for the radio buttons and ActionListener s for the four flower buttons, and set the default title.

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);
}

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.)

    1. 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.

private class RBListener implements ItemListener {
    public void itemStateChanged(ItemEvent e) {
        showFlower();
    }
}
  1. Add an import statement for java.awt.event.ItemEvent .

  2. 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:

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);
    }
}
  1. Add an import statement for java.awt.event.ActionEvent .

  1. 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.

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("");
}
  1. Add an import statement for javax.swing.ImageIcon .

  1. Write the setThumbnails method. This method gets an image for each thumbnail from the flowers map. The Main class calls this method.

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("");
    }
}
  1. 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:

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.

main empty
  1. In the class body, before the main method, initialize an int variable for the number of downloaded pictures.

 private static int downloadedPictures;
  1. In the main method body, create a HashMap of four flowers and another HashMap of four thumbnails.

final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
  1. Add import statements for java.awt.Image , java.util.Map , and java.util.HashMap .

  1. In the main method body, add code to show the FlowerFrame .// Show the FlowerFrame.

final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);
  1. In the main method body, add code to connect the client to the service.// The client connects to the service with this code.

FlowerServiceService service = new FlowerServiceService();
final FlowerService port = service.getFlowerServicePort();
  1. Add import statements for org.flower.service.FlowerService and org.flower.service.FlowerServiceService .

  1. 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

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();
}
  1. Add an import statement for org.flower.service.IOException_Exception .

  1. 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

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();
  1. 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:

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.

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.

]]

To send comments and suggestions, get support, and keep informed about the latest developments on the NetBeans IDE Java EE development features, join the nbj2ee@netbeans.org mailing list.