August 30, 2007

Using XFire (Apache CXF) All The Way

I thought I'd write a little bit about how to use XFire, which is now Apache CXF, "all the way". Because I think it's good to have this information in another place so people can find it easily by searching, even though a the existing framework documentation is very good. Some people may be just implementing web services by writing XML senders and receivers over HTTP. Which technically meets the definition of a web service, but does so in a way that requires everyone to do a lot of extra work.

If you really use a web services framework, like XFire or the stuff you get when you buy Rational Application Developer, to its full capabilities, then you don't even have to know that HTTP or XML is happening. In fact, you don't need a separate server or HTTP communication at all, since the underlying transmission protocol is hidden from you and might actually just be communication within the same JVM. Publication of the WSDL ensures everyone else can use your service even if they're not using the same framework you are. Of course, WSDLs don't contain meaning, so you still need documentation of your APIs. :)

Anway, for the real meat, you should check out the online documentation. But here's the skinny for making an XFire project in MyEclipse.

Server Setup

  1. Select your existing web project in the navigator and choose MyEclipse->Add Web Service Capabilities.... Alternatively, create your new project from scratch as a Web Service Project.

    Doing this adds the XFireServlet to the web.xml. This servlet is used to execute all of your defined web services. This should also add some XFire libraries to your project, and IIRC prompts you to choose which libraries you want to include. You need the core XFire libraries, of course, but you also need to pick a bean-binding library. I used JAXB because I found it did what I wanted. A configuration file services.xml will be created; I would suggest creating this file at src/META-INF/xfire/services.xml because that's where it will end up anyway (i.e. webapps/war/WEB-INF/classes/META-INF/xfire/services.xml).


  2. Create an interface. This interface will be the API that you implement on the server, and the API that clients call on the client. Here's a sample interface that I'm going to turn into a web service.

    public interface PersonService {
      public PersonMetaData getMetaData(int personId);
      public PersonMetaData[] getMetaData(int[] personId);
    }
    

  3. Create an implementation of the interface to go with the interface. The naming convention I've seen is to stick Impl on the end of the interface name.

    public class PersonServiceImpl implements PersonService {
      public PersonMetaData getMetaData(int personId) {
        return new PersonMetaData(personId);
      }
    
    

    public PersonMetaData[] getMetaData(int[] personId) {
    PersonMetaData[] metaData = new PersonMetaData[personId.length];
    for (int i = 0; i < personId.length; i++)
    metaData[i] = new PersonMetaData(personId[i]);
    return metaData;
    }
    }



  4. Now you need to define the web service and map the interface PersonService onto the implementation PersonServiceImpl. This is done by editing the services.xml that was created earlier. This is what my services.xml would look like for this PersonService web service.

    <beans xmlns="http://xfire.codehaus.org/config/1.0">
      <service>
        <name>PersonService</name>
        <serviceClass>com.netflix.PersonService</serviceClass>
        <implementationClass>com.netflix.PersonServiceImpl</implementationClass>
        <style>wrapped</style>
        <use>literal</use>
        <scope>application</scope>
      </service>
    </beans>
    

  5. At this point, you're good to go. Deploy your web project using MyEclipse and start up Tomcat. If everything's good, you should see a bunch of XFire-related initialization messages printed out on the console. Assuming no exceptions are thrown during startup, your web service is up and running and your server-side is done.

    To get to the WSDL which you can use for automatically generating the client-side code, access your web application via the URL http://hostname:port/war/services/. Your deployed web services will be listed, along with a WSDL link. Clicking that link will give you the WSDL that you can give to someone else or use yourself.


Client Setup

  1. Using MyEclipse, you can generate the client-side code from the WSDL. I recommend creating a new Java project that will act as your client project, as the automatic code generation will create and overwrite existing files if it thinks it needs to. Plus, it lets you see exactly how someone else would put together a client if all you gave them was the WSDL.

    To generate the code, use File->New->Other... and select MyEclipse->Web Services->Web Service Client. You'll have to either provide the URL (http:// only because MyEclipse's XFire plug-in does not support SSL) to the WSDL or the file on disk. All the client-side classes will be created in the client project in the same packages as on the server, and then you can use them.


  2. Assuming the client code generated is from the WSDL of the server interface described above, here's how you would use it.

    public static void main(String args[]) {
      PersonServiceClient client = PersonServiceClient();
      PersonServicePortType service = client.getPersonServiceHttpPort("http://remote:port/war/services/PersonService");
      PersonMetaData mmd = service.getMetaData(12345678);
      ArrayOfInt personIds = ObjectFactory.createArrayOfInt();
      personIds.getInt() = new int[] {12345678, 23456789, 34567890};
      ArrayOfPersonMetaData aommd = service.getMetaData(personIds);
    }
    

    Note that the parameters and return types might be JAXB objects like ArrayOfPersonMetaData or ArrayOfInt. So the API is not exactly the same as you might expect. However it might be the case that if you build the client code in the same project and source folder as the server code, your client code uses the original class definitions. I'm not entirely sure since I haven't tried that, but I believe it may work. Either that or it'll overwrite your existing class definitions. :p

    Also, I'm not entirely sure about how you'd go about assigning the personIds.getInt(). I'm just guessing from memory, but it should look something like that.


Posted by josuah at August 30, 2007 10:03 PM UTC+00:00

Trackback Pings

TrackBack URL for this entry:
http://www.wesman.net/cgi-bin/mt/mt-tb.cgi/1267

Comments

Post a comment

July 2013
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Search