Search This Blog

Sunday, February 26, 2012

How to Communicate between Silverlight Client and Java Application

Summary: Simple example showing how Silverlight application can communicate with Java application.



Introduction
The example bellow implements a simple request-response communication between Silverlight application and Java desktop application.
The Silverlight client application sends a request to calculate two numbers. The Java service application receives the request, performs the calculation and sends back the result.

The example can be downloaded from here.

The example bellow uses Eneter Messaging Framework that provides functionality for various communication scenarios.
(The framework is free for non-commercial use (License) and can be downloaded from http://www.eneter.net. More detailed technical info can be found at technical info.)

Policy Server
The Policy Server is a special service listening on the port 943. The service receives <policy-file-request> and responses the policy file that says who is allowed to communicate.

Silverlight automatically uses this service when creates the Tcp connection. It sends the request on the port 943 and expects the policy file. If the policy server is not there or the content of the policy file does not allow the communication, the Tcp connection is not created.


Silverlight Client Application
The client is a simple Silverlight application containing a button to send the request to calculate numbers.
The whole implementation is very simple.
using System;
using System.Windows;
using System.Windows.Controls;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;

namespace CalculatorClient
{
    public partial class MainPage : UserControl
    {
        public class MyRequestMsg
        {
            public double Number1 { get; set; }
            public double Number2 { get; set; }
        }

        public class MyResponseMsg
        {
            public double Result { get; set; }
        }

        // Sender sending MyRequestMsg and receiving responses of type MyResponseMsg.
        private IDuplexTypedMessageSender<MyResponseMsg, MyRequestMsg> mySender;

        public MainPage()
        {
            InitializeComponent();

            OpenConnection();
        }

        private void OpenConnection()
        {
            // Create message sender.
            IDuplexTypedMessagesFactory aSenderFactory = new DuplexTypedMessagesFactory();
            mySender = aSenderFactory.CreateDuplexTypedMessageSender<MyResponseMsg, MyRequestMsg>();

            // Subscribe to receive response messages.
            mySender.ResponseReceived += OnResponseReceived;

            // Create TCP messaging.
            IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
            IDuplexOutputChannel anOutputChannel = aMessaging.CreateDuplexOutputChannel("tcp://127.0.0.1:4502/");

            // Attach the output channel to the message sender and be able to
            // send messages and receive responses.
            mySender.AttachDuplexOutputChannel(anOutputChannel);
        }

        private void UserControl_Unloaded(object sender, RoutedEventArgs e)
        {
            // Detach the output channel and stop listening to responses.
            mySender.DetachDuplexOutputChannel();
        }

        private void CalculateBtn_Click(object sender, RoutedEventArgs e)
        {
            // Create the request message.
            MyRequestMsg aRequestMsg = new MyRequestMsg();
            aRequestMsg.Number1 = Double.Parse(Number1TextBox.Text);
            aRequestMsg.Number2 = Double.Parse(Number2TextBox.Text);

            // Send request to calculate two numbers.
            mySender.SendRequestMessage(aRequestMsg);
        }

        // It is called when a response message is received.
        // Note: By defaulut the response comes in the silverlight thread.
        //       If it is not desired, the routing to the Silverlight thread can be disabled.
        private void OnResponseReceived(object sender, TypedResponseReceivedEventArgs<MainPage.MyResponseMsg> e)
        {
            // Display the result.
            ResultTextBox.Text = e.ResponseMessage.Result.ToString();
        }
    }
}

Java Service Application
The service application is a simple Java application communicating via TCP and calculating numbers.
It also contains the TCP Policy Server requested for the communication with Silverlight.
Here is the whole implementation:
package calculator;

import java.io.*;

import eneter.messaging.diagnostic.EneterTrace;
import eneter.messaging.endpoints.typedmessages.*;
import eneter.messaging.messagingsystems.messagingsystembase.*;
import eneter.messaging.messagingsystems.tcpmessagingsystem.*;
import eneter.net.system.EventHandler;

public class Program
{
    public static class MyRequestMsg
    {
        public double Number1;
        public double Number2;
    }
    
    public static class MyResponseMsg
    {
        public double Result;
    }
    
    // Receiver receiving MyResponseMsg and responding MyRequestMsg
    private static IDuplexTypedMessageReceiver<MyResponseMsg, MyRequestMsg> myReceiver;

    public static void main(String[] args) throws Exception
    {
        // Start the TCP Policy server.
        // Note: Silverlight requests the policy xml to check if the connection
        //       can be established.
        TcpPolicyServer aPolicyServer = new TcpPolicyServer();
        aPolicyServer.startPolicyServer();
        
        // Create receiver that receives MyRequestMsg and
        // responses MyResponseMsg
        IDuplexTypedMessagesFactory aReceiverFactory = new DuplexTypedMessagesFactory();
        myReceiver = aReceiverFactory.createDuplexTypedMessageReceiver(MyResponseMsg.class, MyRequestMsg.class);
        
        // Subscribe to handle incoming messages.
        myReceiver.messageReceived().subscribe(myOnMessageReceived);
        
        // Create input channel listening to TCP.
        // Note: Silverlight can communicate only on ports: 4502 - 4532
        IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
        IDuplexInputChannel anInputChannel = aMessaging.createDuplexInputChannel("tcp://127.0.0.1:4502/");

        // Attach the input channel to the receiver and start the listening.
        myReceiver.attachDuplexInputChannel(anInputChannel);
        
        System.out.println("Calculator service is running. Press ENTER to stop.");
        new BufferedReader(new InputStreamReader(System.in)).readLine();
        
        // Detach the duplex input channel and stop the listening.
        // Note: it releases the thread listening to messages.
        myReceiver.detachDuplexInputChannel();
        
        // Stop the TCP policy server.
        aPolicyServer.stopPolicyServer();
    }
    
    private static void onMessageReceived(Object sender, TypedRequestReceivedEventArgs<MyRequestMsg> e)
    {
        // Calculate incoming numbers.
        double aResult = e.getRequestMessage().Number1 + e.getRequestMessage().Number2;
        
        System.out.println(e.getRequestMessage().Number1 + " + " + e.getRequestMessage().Number2 + " = " + aResult);
        
        // Response back the result.
        MyResponseMsg aResponseMsg = new MyResponseMsg();
        aResponseMsg.Result = aResult;
        try
        {
            myReceiver.sendResponseMessage(e.getResponseReceiverId(), aResponseMsg);
        }
        catch (Exception err)
        {
            EneterTrace.error("Sending the response message failed.", err);
        }
    }
    

    // Handler used to subscribe for incoming messages.
    private static EventHandler<TypedRequestReceivedEventArgs<MyRequestMsg>> myOnMessageReceived
            = new EventHandler<TypedRequestReceivedEventArgs<MyRequestMsg>>()
    {
        @Override
        public void onEvent(Object sender, TypedRequestReceivedEventArgs<MyRequestMsg> e)
        {
            onMessageReceived(sender, e);
        }
    };
}

And here are applications communicating together.

No comments:

Post a Comment