Silverlight Accessing Java JAX-WS/CXF Web services

1. Overview

This guidance is a part of a Java-Silverlight interoperability guidance series to help developers create a Silverlight application in ESL, which enables the utilization of interoperability scenarios using the following protocols:

This guidance walks through how to build a Silverlight application in the Eclipse environment on the Apache CXF SOAP stack accessing JAX-WS Web Services over HTTP transport. Web Services development on JAX-WS can be used in two ways:

  1. Bottom-up development
  2. Top-down development

In Web services terminology, Bottom Up (Code First) is used when developers start with business logic in a programming language, and then develop and deploy is as a Web service.

Bottom-up

The Top Down (Contract First) approach starts from Web service descriptions in WSDL, and then goes on to expose Web services.

Top-down

This guidance focuses only on the bottom-up approach. It covers preparation, development, deployment, and testing of a Data access application via Web services:

This guidance is intended for software architects and software developers who are building interoperable Web services across platforms and applications.

For your convenience, the JAX-WS/CXF service Eclipse project and the Silverlight Eclipse projects are available as an attachment here.

2. Pre-requisites and Product installation

The implementation of this guidance extends the Silverlight DataGrid sample by accessing the application data directly from REST Web service developed in Java. The following knsowledge is required:

If you are new in Silverlight development in eclipse with ESL, we recommend you go through the following tutorial first:

  1. Data Binding example in ESL

Some softwares need be installed on your machine to work with this guidance:

2.1 Eclipse Ganymede with eclipse4SL 1.0.0 M2

Please read this page to install ESL in "Pure Eclipse configuration" mode. If you have already installed the Eclipse IDE for Java EE Developers distribution, all necessary tools are already installed and you can skip to next paragraph.

Otherwise, it is really straightforward to install Java EE development tools via Eclipse Update Manager. In Eclipse, call the menu Help → "Software updates ...". In the next dialog you will need to perform the following steps:

  1. Select the Tab "Available Softwares"
  2. Select the option "Java EE Developer tools" under "Web and Java EE Development" in the "Ganymede Update Site"
  3. And then click on the "Install" button;
  4. Accept the standard options in the remaining pages of this wizard to complete the installation.

2.3 Tomcat 6 Installation

The installation of Tomcat consists of three steps:

  1. Download the installer of version 6.x for Windows from http://tomcat.apache.org/
  2. Run the installer to install Tomcat on your local hard disk: e.g. d:\products\tomcat6
  3. Create a server runtime configuration in eclipse via Windows → Preferences → Server

Click on the button "Add" to add a new runtime environment. In the next dialog, select the entry "Apache Tomcat v6.0" of the "Apache" category.

Click on the "Browse..." button to set up the Tomcat installation location. And then click on the "Finish" button to complete the setting.

 

2.4 CXF framework

Apache CXF is an open source services framework, designed for building and developing services using frontend programming APIs, like JAX-WS. This guidance relies on the JAX-WS over the SOAP protocol and HTTP transport.

The installation is simple: you need to download the archive zip apache-cxf-2.1.3.zip and unzip it somewhere in your hard disk: e.g. d:\products\apache-cxf-2.1.3.

2.5 CXF plugins for Eclipse

There was a CFX plug-in for Eclipse provided by Eclipse STP for Eclipse Europa (version 3.3). But this development is moving to Eclipse WTP and Eclipse Ganymede doesn't provide such support yet.

In this guidance, we use a WTP plug-in for Eclipse that is still an incubation project, which is not yet available from the Eclipse Update Site. It is possible to get it from Eclipse Bugzilla here. For your convenience, we have bundled it along with our contribution plug-ins for JAX-WS SOAP development. You can install "CXF Web Services" and "eclipse4SL Web service utilities" via Eclipse Update manager using following URL: http://www.eclipse4sl.org/update.

 

The plug-ins provided under the "Contribution" category are not part of the ESL product. It contains user-contributed software. Since we cannot guarantee its quality, you use them at your own risk.

Now, to integrate the Apache CXF runtime in Eclipse, we need to set up the Preferences of Eclipse:

  1. Click on the menu Window → Preferences
  2. Select "Web Services" category at left side and select CXF 2.x Preferences entry
  3. Click on the "Browse..." button under the CXF Runtime Tab to point the CXF runtime location.

 

3. Web service development in Java

Our application is a simple Customer contact management tool. Suppose we have three customers:

Contact Name Company Country
Luc Forrest EDF France
Scott Bizien Sun United States
Jean Pierret SAGEM France

The image below describes the UI and interaction scenario of our Web application to develop:

In the Bottom Up Approach, we start with the service implementation in programming language and then build the deployable Web service component. The development process will be:

3.1 Web Project creation

First of all, we need to create a Web project: New → Project, select "Dynamic Web project" under the Web category in the new wizard:

Put the "DataGridCXFService" in the "Project name:" field, and then select "CXF Web Services Project v2.5" in the Configuration group and click on the "Finish" button.

3.2 Service implementation in Java

We will be using the CustomerService class as the service implementation class for developing, deploying, and testing the Web service.

This class keeps a list of customers as a property, and provides one public method findCustomers(String country).

package dataservice;
import java.util.Collection;
import java.util.ArrayList;
/**
 * Resource that manages customers.
 */
public class CustomersService {
    private Customer[] customers = new Customer[]{
                       new Customer("Luc Forrest", "EDF", "France"),
                       new Customer("Scott Bizien", "Sun", "United States"),
                       new Customer("Jean Pierret", "SAGEM", "France")};

    /**
     * Returns a listing of customers.
     */
    public Customer[] findCustomers(String country) {
        if (country != null && country.length() > 0) {
            Collection<Customer> collector = new ArrayList<Customer>();
            for (Customer customer : customers) {
                if (country.equals(customer.getCountry())) {
                    collector.add(customer);
                }
            }
            return collector.toArray(new Customer[collector.size()]);
        }
        return customers;
    }
}

3.3 Transform Java class to Web Service

We need to call a wizard tool to perform this tranformation: File → New → Other...

Select the "Web Service" under the "Web Services" category, and go to next page.

Take the option "Bottom-up POJO Web service" of Web service type, and select the class dataservice.CustomersService for Service implementation. The configuration will be updated automatically as:

If your configuration is not same as above, you will need to change them by clicking on the hyperlinks.

And then click on the "Next >" button to go to the next step.

Click on the "Next >"button to accept the default options.

Click on the "Next >" button to accept the default options. In the next page, check the option "Generate server" to create a Tomcat server configuration. The option "Default SOAP Binding" is very critical. since Silverlight 3 only supports SOAP 1.1.

Click on the "Start server" button to launch the Tomcat server with DataGridCXFService Web service.

Click the "Finish" button to close the wizard.

Now, we can open a Web brower to check the Web service using URL http://localhost:8080/DataGridCXFService/services/CustomersServicePort?wsdl.

Now that the Web Service is implemented and exposed via the Web, it is time to go to the next step: developing the Web service consumer in Silverlight.

4. Web client development in Silverlight

The development of Silverlight Web client consists of three steps:

  1. UI development in XAML
  2. Web client Proxy generation
  3. Data access via Web service

Before going forward, we need to create two projects in Eclipse: a Silverlight project and a Silverlight Web project named as DataGridCXFClient and DataGridCXFClient.Web respectively. If you are not yet familiar with Eclipse development environment for Silverlight, this Data Binding example will be useful to get started.

4.1. UI development in XAML

In DataGridCXFClient project, open the Page.xaml and modify it as follows:

<UserControl x:Class="DataGridCXFClient.Page"
   xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
       <RowDefinition Height="Auto" />
       <RowDefinition />
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0" Grid.Column="0" Name="LayoutRoot" Orientation="Vertical">
      <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
        <TextBlock Margin="10" Text="Filter :" VerticalAlignment="Center"/>
        <TextBox Margin="10" Text="France" Name="country" Width="200"/>
        <Button Margin="10" Name="load" Content="Load" Click="Button_Click"
         Width="50" RenderTransformOrigin="0.5,0.5"/>
      </StackPanel>
    </StackPanel>
    <data:DataGrid Margin="5" Name="grid" Grid.Row="1" Grid.Column="0" 
        AutoGenerateColumns="True" RowBackground="Aquamarine"
        AlternatingRowBackground="White" RenderTransformOrigin="0.5,0.5">
    </data:DataGrid>
  </Grid>
</UserControl>

The first creation of a DataGrid element in XAML editor, by either DnD from palette tool or code completion, automatically updates the project structure by adding the "System.Windows.Control.Data" Reference if this Reference is not already used. However, if you copy and paste this code in the XAML editor, you need to add the reference manually in the following way:

  1. Right click on the References Folder of your Silverlight project in "Project explorer"
  2. Select the "Add Reference" menu entry
  3. Select the System.Windows.Control.Data.dll and click on the "OK" button to confirm the operation.

4.2. Web client proxy generation

Now through the exposed Web Service description in WSDL, we can use our contribution tool to generate the client proxy.

This proxy generation tool is missing in the Silverlight 3 SDK. We have developed this contribution tool specifically for this guidance. Its implementation is not complete. Any contributions to improve this tool are welcome. If you need this tool in a production project it is possible to use Visual Studio 2008.

  1. Open VisualStudio from Project explorer: Open → "Open Visual Studio"
  2. In Visual Studio, right select the project DataGridCXFClient and call "Add Service Reference..." menu
  3. Generate the proxy in the same way as our contribution tool
  4. Save the project in VisualStudio
  5. Come back to Eclipse and refresh the project DataGridCXFClient.

4.3. Data access via Web service

In our application, when we click on the button "Load", the code-behind class will handle this event, invoke the Web service to access the application data and then display the data in the DataGrid.

When we add or change a property event of XAML element in the ESL editor, the event handler is generated automatically in the code behind class. In our case, the generated event handler is Button_Click() in Page.xaml.cs, which will access Web services to get application data. It uses the generated proxy classes from WSDL.

using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace DataGridRESTClient
{


    /**
     * UI view
     */
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
        }
        private void client_FindCustomersCompleted(object sender, DataService.findCustomersCompletedEventArgs e) 
        {
            // Put the list of customers as DataGrid's Data
            grid.ItemsSource = e.Result;
            // Enable the button
            load.IsEnabled = true;
        } 

        /**
         * Load
         */
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Disable the button
            load.IsEnabled = false;
            var client = new DataService.CustomersServiceClient();
            client.findCustomersCompleted += new EventHandler<DataService.findCustomersCompletedEventArgs>(client_FindCustomersCompleted);
            client.findCustomersAsync(country.Text);
        }
    }
}

Now we need to handle the Click event in Button_Click method :

When this operation is completed, the event listener client_FindCustomersCompleted() is executed to process the result of the Web service request.

    private void client_FindCustomersCompleted(object sender, DataService.findCustomersCompletedEventArgs e) 
    {
        // Put the list of customers as DataGrid's Data
        grid.ItemsSource = e.Result;
        // Enable the button
        load.IsEnabled = true;
    }

 

5. Deployment

If the Silverlight application and the Web services are hosted in the same Web server, this deployment mode is called "single domain deployment".

Single domain

In single domain mode, Java Web services and Silverlight applications share the same domain name, port number and transport protocol.

Cross domain

Otherwise, it is a so called "cross domain deployment".

5.1 Single domain Deployment

In this mode, we need first to deploy our Silverlight application on the Web server where the Web services are hosted. It can be done by copying following files from DataGridCXFClient. Web to the WebContent folder of the DataGridRESTService.

To make the DataGridCXFClient.html the default page, you can rename it to index.html.


Now, our server is correctly configured and ready to start. You can start it by clicking on the Run button on the tool bar of the Server view. Then you can open a web browser to test our Silverlight application via the URL http://localhost:8080/DataGridCXFService/

This Silverlight application, launched via the Run configuration of Eclipse environment (see screenshot below), will fail to access the Web services in single domain deployment mode since ESL starts automatically a new Web server to host it. It falls automatically into the cross domain mode.

5.2 Cross domain deployment

In an enterprise with a heterogeneous environment, Silverlight application may be hosted in a different Web server from Web services. Using Silverlight for cross-domain communication requires guarding against several types of security vulnerability that can be used to exploit Web applications.

To enable a Silverlight control to access a service in another domain, the service must explicitly opt-in to allow cross-domain access. By opting-in, a service states that the operations it exposes can safely be invoked by a Silverlight control, without potentially damaging consequences to the data the service stores.

Silverlight 3 supports two different mechanisms for services to opt-in to cross-domain access:

More information about the cross-domain control can be found here.

Cross domain control in a Web server depends on its configuration. Eclipse WTP provides three options:

  1. Use workspace metadata (by default)
  2. Use Tomcat installation
  3. Use customer location

There are two solutions to change the configuration:

1. Right click "Tomcat v6.0 server at localhost" in "Server" View and select "Open" menu

2. Right click "Tomcat v6.0 server at localhost" in "Server" View and select "Properties" menu:

The location of clientaccesspolicy.xml must be in Web server root folder, which depends on server configuration. You can find it by the concatenation of <Server path> and <Deploy path>/ROOT. Taking an example of option N° 1, the Web root should be <workspace>/.metadata/.plugin/org.eclipse.wst.server.core/tmp0/wtpwebapps/ROOT.

To enable cross domain access in this configuration, we need to put a clientaccesspolicy.xml file in the Web root folder.

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

This configuration allows access from any other domain to all resources on the current domain. It is highly recommended to restrict access in a production environment.