Thursday, February 14, 2008

Virtualbox Being Purchased By Sun

Not sure yet if this is good or bad, but Innotek, the developer brains behind VirtualBox, just announced that Sun Microsystems is purchasing them. I'm betting its a GOOD thing. I've been a _very_ happy user of VirtualBox for over a year now. I use it on Ubuntu. I've found that it has outperformed VMWare Server/Player/Workstation in most of my observations. In the press release, Sun's intentions are that VirtualBox will continue to be aimed at the developer workstation.

Sun already has [recently] entered the server virtualization market with their xVM product. xVM is aimed at server virtualization and I'd bet good money it isn't cheap.

I'm anxious to find out how Sun will market VirtualBox to additional developers.

Things I like about VirtualBox --
1) User experience. Fast. I have no issues with Virtual Box's performance. I recall the last time I rebuilt my virtual machine, I was able to re-install WinXP in about 30 minutes. Seems that for VMWare Workstation 5.5, it always took 2 hours.

2) Shared folders. Fast. Easy. VMWare drives me nuts -- there is a 10 second pause the first time you access a shared folder. That 10 seconds doesn't seem like a lot, but I always catch myself thinking -- "What is faster? Copy to a USB disk or shared folders?" VirtualBox is fast and without delay.

3) Stability. I've had a few BSOD using VirtualBox, but is that because of Windoze or VirtualBox? I'll never know.

4) Free. VMWare has Server and Player versions which are free, but, especially in the case of Player, they are very stripped down. VirtualBox is free. Please keep it that way, Sun.

Anyways, I surely appreciate the developers at Innotek. They've done a fantastic job and I hope Sun treats them well!

Friday, February 08, 2008

Enunciate and REST (with the BT SDK)

In my earlier post, I briefly took a look at enunciate. I was impressed about Ryan's quick comments -- thanks, Ryan!

In this post, I want to further explore how one can use enunciate to provide a RESTful API. To explore, I'm going to use enunciate to put a quick RESTful api for sending a text message on top of the easy-to-use BT SDK.

The BT SDK is a toolkit you can use to interact with BT's global telecom network. It boasts doing things with a single line of code -- sending text sms messages, creating point-to-point calls (both SIP and traditional land lines), conference calls with multiple participants, call-flow/IVR functionality, and more. The SDK is available for Java, .NET, PHP, Python (and a PERL and Ruby version is available if you ask nicely :) It literally should take no more than 15 minutes to get up and running.

Steps:

  • First, go and download the Java BT SDK (you'll have to register which takes 1 minute or less)
  • Unzip the SDK into a directory (BTSDK_HOME)
  • Create a project skeleton in Eclipse with a "lib" directory which contains all of the BTSDK_HOME/lib/*.jar files as well as the BTSDK_HOME/Web21C-JavaSDK-5.0.jar.
  • Copy in ENUNCIATE_HOME/enunciate-full-1.6.jar into the lib directory.
  • Add all jars in the lib directory to your classpath in Eclipse.


Create an "api" and "impl" package in your source folder. In the api package, create the interface as follows:


package com.db.btsdkexamples.api;

import javax.jws.WebService;

import org.codehaus.enunciate.rest.annotations.Adjective;
import org.codehaus.enunciate.rest.annotations.Noun;
import org.codehaus.enunciate.rest.annotations.RESTEndpoint;
import org.codehaus.enunciate.rest.annotations.Verb;
import org.codehaus.enunciate.rest.annotations.VerbType;

@RESTEndpoint
@WebService
public interface MessagingInterface {
@Verb ( VerbType.update )
@Noun ( "message" )
public void sendMessage(
@Adjective(name="endpoint") String endpoint,
@Adjective(name="message") String message);
}



To tell enunciate to produce a RESTful api, all it takes is to put the @RESTEndpoint annotation on the interface and the impl. This annotation just tells enunciate that the methods will be exposed as REST endpoints. The additional method and parameter annotations dictates HOW enunciate exposes the api. Note, that even though I am not interested in creating a SOAP-based web service, I still had to put the @WebService annotation on the interface and the impl class.

The other annotations we need to discuss are on the method and the parameters.

The @Verb annotation dictates what HTTP METHODs must be used. REST is based exclusively upon the HTTP protocol and heavily uses HTTP GETs and POSTs. GET and POST is the most heavily utilized where POST is typically overloaded to also provide PUT and DELETE functionality. This is traditionally due to lack of browser and firewall support for anything other than GET and POST. The @Verb parameter just dictates what HTTP METHOD value will be used to interact with this service. In our example, VerbType.update means an HTTP POST must be used versus an HTTP GET.

The @Noun annotation effectively dictates what "resource" will appear in the URL. For example, a value of "Customer" would indicate the URL will be in the form of "http://localhost/rest/Customer".

Together with a @Verb of VerbType.update and @Noun of "message", this indicates that an HTTP POST to "http://localhost/rest/message" will be mapped to this method.

Next question, how do we map HTTP parameters to method parameters? There are two ways -- a Named Resource (ProperNoun) or standard HTTP query string. I wish there was a third way -- URL Mapping to parameters (maybe there is a way?)

ProperNoun works by taking the last part of the URL to map to a single method parameter. For example, http://localhost/rest/message/17195551212 could map the "17195551212" part of the URL to the "endpoint" parameter. The "message text" would need to be passed as a query parameter. This approach is handled by the @ProperNoun annotation. Note, however, that only a single @ProperNoun annotation can be specified.

HTTP Query parameters (or post data) is the second approach. This is the approach I used in the example above. It effectively means that the named query parameters will be mapped to the given method parameters. The names do not need to match. In my example above, an HTTP POST to http://localhost/rest/message with post data containing "endpoint=17195551212&message=some+message+text" would be necessary to invoke the method. Invoking from cmd line looks like this:


$ curl -d 'endpoint=17195551212&message=test' http://localhost:8080/btsdkexample/rest/message


Similarly, if I had used a @Verb of VerbType.read, then I would be able to just tack on the query-string parameters to the end of the URL and do a simple HTTP GET:


$ curl http://localhost:8080/btsdkexample/rest/message?endpoint=17195551212&message=test


I haven't noticed if there is a way to map a more complex URL to multiple query parameters. For example, I'd like to be able to map customer-id AND order-id to corresponding method params for something like this: http://localhost/rest/customer/custid123/orders/ord9988. Please tell me if this breaks your idea of a REST uri.

Next, we need to create the implementation class as follows in the impl package:


package com.db.btsdkexamples.impl;

import javax.jws.WebService;

import org.codehaus.enunciate.rest.annotations.RESTEndpoint;

import com.db.btsdkexamples.api.MessagingInterface;

@RESTEndpoint
@WebService

public class MessagingImpl implements MessagingInterface {

public void sendMessage(String endpoint, String message) {
System.err.println("Sending message to " + endpoint + " == " + message);
new com.bt.sdk.capabilities.messaging.oneway.MessagingOneWayManager().sendMessage(endpoint, message);
}

}



Now that we have [almost] everything done, we need to enable the BT SDK. To do this requires a simple properties file and a private key/certificate. You can obtain the the key and certificate by using the Certificate Tool at https://web21c.bt.com/registered_applications/new.

Go ahead and just generate one for the Sandbox environment (it's free, but you can only have 5 sandbox certs which are valid for 1 month each, plus you have limited number of messages you can send in a single day).

Save the generated PKCS12/PFX file to your "src" directory. Don't forget your password!

Now, create security.properties in the "src" directory as follows and plug in the value for your password below and the name of your key file.


org.apache.ws.security.crypto.provider=com.bt.security.PKCS12Crypto
org.apache.ws.security.crypto.merlin.keystore.type=pkcs12
org.apache.ws.security.crypto.merlin.keystore.password=yourpass
org.apache.ws.security.crypto.merlin.alias.password=yourpass
org.apache.ws.security.crypto.merlin.file=YourPrivateKey_in_src_folder.pfx

#constants.provider=com.bt.sdk.common.ProductionConstants
constants.provider=com.bt.sdk.samples.SandboxEndpoints


You are literally minutes away from testing!

Now, we just need to create a special enunciate.xml config file that tells enunciate to bundle up your security.properties file and key file into the WAR in the WEB-INF/classes directory.

Create enunciate.xml in the project root:


<?xml version="1.0"?>
<enunciate label="btsdkexamples">
<modules>
<spring-app compileDebugInfo="true">
<copyResources dir="src" pattern="*.properties"/>
<copyResources dir="src" pattern="*.pfx"/>
</spring-app>
</modules>
</enunciate>


Now, you will need your build.xml, so here it is, pretty much identical to my last post:

<project name="btsdkexample" default="package">

<target name="init">
<property name="enunciate.home" value="/home/dbreese/bin/enunciate-1.6" />
<property name="jdk.home" value="/opt/java/" />

<path id="enunciate.classpath">
<fileset dir="${enunciate.home}/lib">
<include name="**/*.jar" />
</fileset>
<fileset dir="${enunciate.home}">
<include name="enunciate-full-*.jar" />
</fileset>
<fileset dir="${jdk.home}/lib">
<include name="tools.jar"/>
</fileset>
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</path>

<taskdef name="enunciate" classname="org.codehaus.enunciate.main.EnunciateTask">
<classpath refid="enunciate.classpath" />
</taskdef>

</target>

<target name="clean">
<delete dir="dist"/>
</target>

<target name="package" depends="clean,init">
<mkdir dir="dist"/>
<enunciate basedir="src" configFile="enunciate.xml">
<include name="**/*.java" />
<classpath refid="enunciate.classpath" />
<export artifactId="spring.war.file" destination="dist/${ant.project.name}.war" />
</enunciate>
</target>
</project>



Run the build, copy the war file to your container (for me it's JBOSS_HOME/server/default/deploy), and test with the following. The format of "endpoint" is "tel:+" + 2 digit country code + tn. (%2B is urlencoding for a plus sign!)


curl -d 'endpoint=tel:%2B17195551212&message=test' http://localhost:8080/btsdkexample/rest/message



Returning more complex data types


In the above example, our method return type was void. What about returning a complex data type? This is also easy using JAXB 2.0 annotations. The only requirement is that the return type must be annotated with @XmlRootElement.

Let's return a simple data type called "MyMessageStatus" which simply contains the telephone nbr, the message, and the message id returned from the BT SDK. (Yeah, I know my naming conventions suck.)


package com.db.btsdkexamples.business;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class MyMessageStatus {
public String endpoint;
public String message;
public String btMessageId;

public MyMessageStatus(String endpoint, String message, String messageId) {
this.endpoint = endpoint;
this.message = message;
this.btMessageId = messageId;
}

public MyMessageStatus() {
// satisfy no-arg requirement
}
}



And modify the interface and impl class to return an object instead of void (only IMPL class method shown here):


public MyMessageStatus sendMessage(String endpoint, String message) {
System.err.println("Sending message to " + endpoint + " == " + message);
Message msg = new com.bt.sdk.capabilities.messaging.oneway.MessagingOneWayManager().sendMessage(endpoint, message);
return new MyMessageStatus(endpoint,message,msg.getMessageId());
}


Run the build, deploy, and test:


$ curl -d 'endpoint=tel:%2B17192137681&message=test' http://localhost:8080/btsdkexample/rest/message

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myMessageStatus>
<endpoint>tel:+17192137681</endpoint>
<message>test</message>
<btMessageId>e385b6e38eac4de9567a3c2e76b51729at</btMessageId>
</myMessageStatus>



Some restrictions I've run across with the return types:
1) It is not possible to have a complex class type as a method parameter; therefore, I had to modify my method signatures to use only Strings and simple data types.

2) enunciate does not [yet] support returning collections, so to return a collection, it appears, you'd need to wrap it with a class.