Archive for February, 2010

How do we collaborate through software: Take 2

Thursday, February 25th, 2010

It is official. I have been invited to speak at Ignite Dallas.

In my prior recording of the talk, I neglected to mention the names of some folks who have been influential in collaborative application design. This new recording remedies that oversight.

I also modified the second half of the talk to tell the partial ordering story a little better. It still needs the slides in order to really get it, but fortunately those are coming along.

Give it a listen. Hope to see you next Wednesday!

How do we collaborate through software?

Saturday, February 20th, 2010

I am preparing for the upcoming Ignite Dallas event. 5 minutes, 20 slides that auto advance every 15 seconds. The final speaker list has not yet been determined, but I’m hopeful that I’ll have a chance to present.

I will be talking about the current thinking in collaborative applications.

  • The CAP Theorem
  • Eventual Consistency
  • Event Sourcing
  • Partial Ordering

The challenge is to condense all of this learning into 5 minutes, make it accessible, and make it entertaining. You can help.

Please take five minutes (actually 4:45) to listen to my rough draft. Leave comments on what I can improve, what I didn’t make clear, and anything I could leave out.

Then order your tickets to the event and see some really great performances. Or submit one of your own.

Java/WCF Interop

Monday, February 8th, 2010

As of today (February 2010), the story of Java/WCF interoperability is fair. That wasn’t always the case. In the past, I’ve struggled to get Java and .NET to play nice. Today, I was able to make a .NET WCF client talk to a Java CXF web service with just a little coaxing. Here’s how I did it.

Contract first
The first step to successful interoperability is to define the contract. Somehow you need to generate the WSDL, and you need to tightly control what it looks like. Use tools to help you, but keep a close eye on what those tools do.

I started with a WCF service contract. This is a .NET interface that uses the [ServiceContract] and [OperationContract] attributes. Put this interface and all of the data types it uses into a class library project. Here’s an example:

[ServiceContract(Namespace = "http://correspondence.updatecontrols.com")]
public interface ISynchronizationService
{
    [OperationContract]
    FactTree Get(FactTree pivotTree, long pivotId, long timestamp);

    [OperationContract]
    void Post(FactTree messageBody);
}

The FactTree data type used by this interface is decorated with the [DataContract] and [DataMember] attributes.

[DataContract(Namespace = "http://correspondence.updatecontrols.com")]
public class FactTree
{
    [DataMember]
    public long DatabaseId { get; set; }

    [DataMember]
    public List<Fact> Facts { get; set; }

    [DataMember]
    public List<FactRole> Roles { get; set; }

    [DataMember]
    public List<FactType> Types { get; set; }
}

Create a WCF service

Even though we want to end up with a Java web service, an intermediate step is to implement this service in WCF.

  1. Create a new project in Visual Studio using the template Visual C#: Web: WCF Service Application.
  2. Add a reference to the class library that defines the interface.
  3. Change the name of the generated service from Service1 to something meaningful.
  4. Delete the generated IService1 interface.
  5. Use your own interface instead.
  6. Add a [ServiceBehavior] attribute to set the Namespace.

At this point, the service looks something like this:

// NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in Web.config and in the associated .svc file.
[ServiceBehavior(Namespace = "http://correspondence.updatecontrols.com")]
public class SynchronizationService : ISynchronizationService
{
    public FactTree Get(FactTree pivotTree, long pivotId, long timestamp)
    {
        throw new NotImplementedException();
    }

    public void Post(FactTree messageBody)
    {
        throw new NotImplementedException();
    }
}

Like the comment says, we need to edit the svc file and the web.config. Right-click the svc file in the project tree and select “View Markup”. Change the Service attribute to the fully qualified name of the service class.

<%@ ServiceHost Language="C#" Debug="true"
  Service="UpdateControls.Correspondence.WebService.SynchronizationService"
  CodeBehind="SynchronizationService.svc.cs" %>

The web.config change is slightly more complicated. There’s a lot of junk in web.config that you don’t need to worry about. The section you want is all the way at the bottom. Look for the <service> tag. It has two attributes: name and behaviorConfiguration. Also look for the <endpoint> tag right below it. It has three attributes: address, binding, and contract.

  1. Change the service name to the fully qualified name of your service class.
  2. Change the endpoint binding from wsHttpBinding to basicHttpBinding.
  3. Change the endpoint contract from IService1 to the fully qualified name of your interface.

Here’s a trick to getting the fully qualified names. Delete the text between the quotes of the attributes. Open the Class View by hitting Ctrl+Shift+C in Visual Studio. Expand the tree to find your service class and interface. Drag them onto the web.config file between the quotes.

You can also change the name of the service behavior, but that’s not necessary for this intermediate step.

Examine the WSDL

These steps ensure that we have nice clean WSDL to work from. Take a look at it by running your WCF service application. A directory listing will open in the browser. Click on the svc file. If you get a yellow screen, please double-check your steps.

Click on the link to see the WSDL you’ve created. Different browsers react differently to raw XML. IE and Firefox will show it to you, but Chrome will give you a blank screen. You’ll have to view source to see the WSDL in Chrome.

On this first page, you’ll see all of the input and output messages, and the operations, and the service itself. Double-check that the service uses binding="i0:BasicHttpBinding_...".

Hack the url to look at more detailed information. Change the query string to “?wsdl=wsdl0” to see the declaration for the binding. It uses “http://schemas.xmlsoap.org/soap/http” with the “document” style.

Hack the url again with “?xsd=xsd0” to see the data types. You should recognize these data types as the ones you wrote in C#. Notice that it turns all of your List<T>s into ArrayOfTs. When we import these into Java, they will become classes containing List<T>.

Create the Java contract project

Create a Java project in your favorite IDE (mine is Eclipse). Open a command prompt and go to the source directory of that project (probably ends in “src”). Download Apache CXF and unzip it to your hard drive (mine is in “c:\apache-cxf-2.2.6”).

Go back to the first WSDL page, the one with the “?wsdl” query string. This is the URL that we are going to generate Java files from. Copy this URL and use it at the command line:

\apache-cxf-2.2.6\bin\wsdl2java.bat http://localhost:3642/SynchronizationService.svc?wsdl

CXF will generate a bunch of class files. Most will be in a package derived from your namespace. One will be in “com.microsoft.schemas._2003._10.serialization”. If you find one in org.tempuri package, you forgot a Namespace setting in one of your attributes. These class files are decorated with enough annotations to make them compatible with the WCF service.

Create the Java service project

Although you could put your service implementation and contract in the same project, I prefer to keep them separate. You can use the contract project to write a different service implementation, or even to write a client.

Create a new Dynamic Web Project. Add to the new project a reference to the contact project. You will also need to add this reference to the Java EE Module Dependencies in the project properties. Otherwise it won’t copy the contract jar file to the service lib directory, resulting in a NoClassDefFoundError at runtime. Then add a class that implements the service contract. Copy the @WebService annotation from the interface to the class. The service looks something like this:

@WebService(targetNamespace = "http://correspondence.updatecontrols.com", name = "ISynchronizationService")
public class SynchronizationService implements ISynchronizationService {

    @Override
    public FactTree get(FactTree pivotTree, Long pivotId, Long timestamp) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void post(FactTree messageBody) {
        // TODO Auto-generated method stub

    }

}

The service project needs the CXF jar files. Copy them from the CXF install folder (C:\apache-cxf-2.2.6\lib) into the project’s library folder (WebContent\WEB-INF\lib). This is the minimal set that you will need:

  • jaxb-api-2.1.jar
  • jaxb-impl-2.1.12.jar
  • wsdl4j-1.6.2.jar
  • XmlSchema-1.4.5.jar
  • cxf-2.2.6.jar

Now we need to publish this web service as a servlet. The quickest way to do that is to derive a class from CXFNonSpringServlet. Right-click the project and select "New: Servlet”. Change the servlet base class to “org.apache.cxf.transport.servlet.CXFNonSpringServlet”. Uncheck the boxes to implement doGet and doPost. The base class handles those for you. Once the class is created, override the loadBus method.

package com.updatecontrols.correspondence.service;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.xml.ws.Endpoint;

import org.apache.cxf.transport.servlet.CXFNonSpringServlet;

public class SynchronizationServlet extends CXFNonSpringServlet {
    @Override
    public void loadBus(ServletConfig servletConfig) throws ServletException {
        super.loadBus(servletConfig);        

        Endpoint.publish("/SynchronizationService", new SynchronizationService());
    }
}

Open the web.xml file. You will notice that a servlet mapping was created for you. This mapping is set up to handle URLs that directly address the servlet, but the CXF servlet adds the service name to the URL. Add a “/*” to the end of the URL pattern to direct all such addresses to the servlet.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>correspondence_sync_service</display-name>
    <servlet>
        <description>
        </description>
        <display-name>SynchronizationServlet</display-name>
        <servlet-name>SynchronizationServlet</servlet-name>
        <servlet-class>
        com.updatecontrols.correspondence.service.SynchronizationServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SynchronizationServlet</servlet-name>
        <url-pattern>/SynchronizationServlet/*</url-pattern>
    </servlet-mapping>
</web-app>

Run the project in Tomcat to make sure the servlet is published correctly. Point a browser at the servlet (in my case http://localhost:8080/correspondence_sync_service/SynchronizationServlet) and you should see a listing of available SOAP services. Append the service name to the URL (http://localhost:8080/correspondence_sync_service/SynchronizationServlet/SynchronizationService) and you will get a 500 error. If you get a 404, you haven’t modified the web.xml file correctly.

Create a WCF client

The last step is the easiest. Since we started by creating a WCF service contract, we can ask WCF to create a client proxy. I documented this technique in .NET to .NET web services without WSDL. It turns out that this trick works equally well for .NET to Java web services.

Add an endpoint to the app.config of your client. The URL should be the servlet name followed by the service name. For example:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="SynchronizationServiceSoapBinding" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:8080/correspondence_sync_service/SynchronizationServlet/SynchronizationService"
          binding="basicHttpBinding" bindingConfiguration="SynchronizationServiceSoapBinding"
          contract="UpdateControls.Correspondence.WebService.Contract.ISynchronizationService" name="SynchronizationService" />
    </client>
  </system.serviceModel>
</configuration>

And with that you have a .NET WCF client communicating with a Java CXF server. I expect that similar strategies could be used to go the other direction, although I haven’t tried yet.