Friday, August 14, 2009

.Net Service Bus, another proposal between java and C# in REST approach

In this tutorial i will show you how to communicate between java techology and C# technology in REST Approach

Scenario:

A console C# application want to provide service onto internet, so register an endpoint in the .Net Service bus, which allow people making REST request.

After knowing there is a service in the .Net Service Bus, someone include such service into there java application with the help of HttpClient library.


C# service :
In this part, we are going to create a REST service provider by using WCF framework.

1) Create a normal C# console project from Visual Stuido, choose what even name you like.


2) Within the project, create a service contract.

3) Leave the contract blank first, coz we need to import some WCF reference.

4) Now we can implement our contact with WCF annotation.

5) After we have the contract, it is time to do the Implementation for the contract.


6) Bravo ... After all the boring jobs above, we now can create endpoint onto .Net Service Bus.
So here we include the Service Bus reference into our project first.



7) Create endpoint onto .Net Service Bus.
This time i will do something different. If you have read my previous articles, you would find that we normally need a App.config file, however it is not a must, we can do everything in programmatical way, just the matter which way u want.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ServiceBus;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
using System.ServiceModel;
using Microsoft.ServiceHosting.ServiceRuntime;

namespace ProposalService
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Host starting ...");

//Console.Write("Your Solution Name: ");
string solutionName = "shrimpy";

//Console.Write("Your Solution Password: ");
string solutionPassword = "password";

// create the endpoint address in the solution's namespace
Uri address = ServiceBusEnvironment.CreateServiceUri(
"http",
solutionName,
"proposal");

// create the credentials object for the endpoint
TransportClientEndpointBehavior userNamePasswordServiceBusCredential =
new TransportClientEndpointBehavior();
userNamePasswordServiceBusCredential.CredentialType =
TransportClientCredentialType.UserNamePassword;
userNamePasswordServiceBusCredential.Credentials.UserName.UserName =
solutionName;
userNamePasswordServiceBusCredential.Credentials.UserName.Password =
solutionPassword;

WebServiceHost host = new WebServiceHost(typeof(ProposalContractImpl), address);

ContractDescription contractDescription =
ContractDescription.GetContract(typeof(ProposalContract), typeof(ProposalContractImpl));
ServiceEndpoint serviceEndPoint = new ServiceEndpoint(contractDescription);

serviceEndPoint.Address = new EndpointAddress(address);
serviceEndPoint.Binding = new WebHttpRelayBinding();

serviceEndPoint.Behaviors.Add(userNamePasswordServiceBusCredential);

ServiceRegistrySettings settings = new ServiceRegistrySettings();
settings.DiscoveryMode = DiscoveryType.Public;
serviceEndPoint.Behaviors.Add(settings);

host.Description.Endpoints.Add(serviceEndPoint);
host.Open();

Console.WriteLine("Service address: " + address);

Console.ReadLine();

host.Close();
}
}
}


Testing our service.
Now the service is ready to go. Launch it, and go to your browser to test it.
Theoretically, you should see something like this:

Still remember how our C# contract look like???
I beg u must forget all about it...


[OperationContract()]
[WebGet(UriTemplate = "/{words}")]
string says(string words);

In the contract we said that, anything follow by the link will tread as input of method "says"
So as in the pic, if we type something following the "proposal" should trigger method "says".

Let`s do it. See the location in my browser:


And then hit enter

Oooops.......
Don`t be scared, this page is from Microsoft, asking for valid login. Type in our solution name and password, it will first ask the Access Control service to do a check up, whether we have the right to get into the service on the other side. If the solution name and password are all good, it will return us a security token. For browser, the token will put into cookie, so that we can continue to visit our service.

Bingo............ we get what we expected.......


Java RESTful subscriber
Now we have already half way to Rome. We just need to do a rest request from the java side.

1) Create a empty maven project. Choose any name u want.

2) Modify the POM, add HttpClient dependency, so that we can make REST request later.
3) It would be good to do logging when doing coding.
So create a folder "resources", and create log4j.properties file under the folder


Content of log4j.properties:


log4j.rootLogger=OFF, STDIO

log4j.logger.org.apache.commons=ERROR

log4j.logger.com.blogspot.cloudyshrimpy=DEBUG
log4j.appender.STDIO=org.apache.log4j.ConsoleAppender
log4j.appender.STDIO.layout=org.apache.log4j.PatternLayout
log4j.appender.STDIO.layout.ConversionPattern=%14p [Cloudy Shrimpy] %30.30F:%L| %x %m%n

4) So good so far, now it is time to do some real coding.
Let think of what should we do first.

From the white paper, it said that, in REST approach, we first need to ask for security token from Access Control Service by providing solution name and password.
After we obtain the token, attache the token in http request header, then we can visit the REST service on the other side.

So very straight forward i will do things like this:


public static void main(String[] args) {
App app = new App();

/**
* Get Authentication Token
*/
String security_token = app.getAuthenticationToken();

/**
* Send message
*/
app.sendMessage(security_token, "Will you marry me");
}


Then we implement method "getAuthenticationToken" and "sendMessage"


private void sendMessage(String token, String words) {
// replace space with '%20'
String endpoint = String.format(SERVICE_URI, words.replaceAll(" ", "%20"));
log.debug("Endpont is : " + endpoint);

GetMethod get = new GetMethod(endpoint);
get.addRequestHeader(HEADER_KEY, token);
try {
int status = client.executeMethod(get);
log.debug("Request status is : " + status);

if (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED) {
byte[] responseBody = get.getResponseBody();
String responseContent = new String(responseBody);
log.debug(String.format("Response is : %s", responseContent));
}
} catch (Exception ex) {
log.error("Failed to send request to service is : " + endpoint, ex);
}
}

/**
* https://accesscontrol.windows.net/issuetoken.aspx?u=SolutionName&p=SolutionPassword
*/
public String getAuthenticationToken() {
String token = null;
try {
String uri = String.format(ACCESS_CONTROL_LINK_TEMPLATE, USERNAME, PASSWORD);
GetMethod get = new GetMethod(uri);
int status = client.executeMethod(get);
if (status == HttpStatus.SC_OK) {
byte[] responseBody = get.getResponseBody();
token = new String(responseBody);
log.debug(String.format("Token is : %s", token));
}
} catch (Exception ex) {
log.error("Failed to obtain authentication token.", ex);
}
return token;
}



You will see lots of upper case words in my code, just because i don`t want to hardcode string. So below are all the magic strings i used.


private static final Logger log = LoggerFactory.getLogger(App.class);
/**
* Solution name and password
*/
public static final String USERNAME = "shrimpy";
public static final String PASSWORD = "password";
/**
* Link to get security token
*/
public static final String ACCESS_CONTROL_LINK_TEMPLATE = "https://accesscontrol.windows.net/issuetoken.aspx?u=%s&p=%s";
/**
* Target endpoint that message we are going to sent to
*/
public static final String SERVICE_URI = "http://shrimpy.servicebus.windows.net/proposal/%s";
/**
* Attribute that going to be add into the http header
*/
public static final String HEADER_KEY = "X-MS-Identity-Token";
/**
* Client that use for making REST request
*/
private HttpClient client = new HttpClient();




Good now keep your C# service launching, and run your java application.


Do u get what i got?????

No comments:

Post a Comment