The Blog of Jeff Layton / jeffl8n
programming
Building Axis2 Java Classes From WSDLs Using Ant Foreach
Oct 23rd
I’ve had a few requests to get an example of the build script I referenced in my post, Ant Foreach Properties, so here it is.
In our ant build.xml file we have a task called buildAllWsdls which gets all of the WSDL files from the web service URL, then feeds each of them into Axis2 to convert them to Java classes.
Here are the basic steps of what this build does:
- Finds each property which ends with “Service” and concatenates them into a comma delimited string (ex. ATestService, BTestService, CTestService…)
<propertyselector property="services.list" delimiter="," match="(\w)*Service" />
- Loop through each of those Service properties using the foreach task and get the WSDL file from the WSDL end point URL.
<foreach list="${services.list}" inheritall="true" target="-getSingleWsdl" delimiter="," param="prettyName" /> - Translate the namespace to package properties file into a comma delimited list (as required by Axis 2).
<loadfile srcfile="${conf.dir}/NStoPkg.properties" property="ns2p.all"> <filterchain> <striplinecomments> <comment value="//" /> </striplinecomments> <prefixlines prefix="," /> <striplinebreaks /> <tokenfilter> <trim /> <ignoreblank /> </tokenfilter> </filterchain> </loadfile> - Run each WSDL in the download directory through the Axis2 Java class creation Ant task.
<foreach target="-createStubs" param="file" inheritall="true"> <path> <fileset dir="${wsdldir}" /> </path> </foreach> <target name="-createStubs"> <basename property="wsdl" file="${file}" /> <echo message="Generating client code for service: ${wsdl}" /> <java fork="true" classname="org.apache.axis2.wsdl.WSDL2Java" failonerror="true"> <arg line="-ns2p ${ns2p.all} -s -u -uri ${wsdldir}/${wsdl} -o ${stubsdir} --noBuildXML" /> <classpath refid="cp.axis" /> </java> </target>
If you don’t mind your web services being in a Java package that corresponds with the web service namespace, you can skip step 3 and leave out the -ns2p command line argument in the java ant task in step 4.
Here is the full example Ant build.xml file for doing this:
<project name="Axis2WSDLBuild" default="buildAllWsdls" basedir=".">
<tstamp>
<format property="TODAY" pattern="MM/dd/yyyy HH:mm:ss"/>
</tstamp>
<property name="ws-domain" value="http://services.test.com:8080" />
<property name="webservices.dir" value="${app.dir}/axisStubsProject" />
<property name="wsdldir" value="${webservices.dir}/wsdls" />
<property name="stubsdir" value="${webservices.dir}" />
<!-- patternsets -->
<patternset id="jar.files">
<include name="**/*.jar"/>
</patternset>
<path id="cp.axis">
<fileset dir="${lib.dir}/axis">
<patternset refid="jar.files"/>
</fileset>
</path>
<path id="cp.antcontrib">
<fileset dir="${lib.dir}/antcontrib">
<patternset refid="jar.files"/>
</fileset>
</path>
<!-- Allow usage of ant-contrib defined tasks -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath refid="cp.antcontrib"/>
</taskdef>
<!-- =================================================================== -->
<!-- Project initialization -->
<!-- =================================================================== -->
<target name="init">
<property name="version" value="build ${TODAY}"/>
<property file="${conf.dir}/soa-addresses.properties"/>
<filter token="version" value="${version}"/>
<filter token="today" value="${TODAY}"/>
</target>
<!--=======================================================-->
<!-- TARGET [buildAllWsdls] -->
<!-- Target which gets and creates the web service stubs necessary for client invocation. -->
<!--=======================================================-->
<target name="buildAllWsdls" depends="init">
<antcall target="wsdlGet" />
<antcall target="buildWsdls" />
</target>
<!--=======================================================-->
<!-- TARGET [buildWsdls] -->
<!-- Target which creates the web service stubs necessary for client invocation. -->
<!--=======================================================-->
<target name="buildWsdls">
<!-- create the download directory -->
<mkdir dir="${stubsdir}" />
<!--
Translate the namespace to package properties file (as typically used in
an Axis 1 implementation) into a comma delimited list (as required by
Axis 2).
-->
<loadfile srcfile="${conf.dir}/NStoPkg.properties" property="ns2p.all">
<filterchain>
<striplinecomments>
<comment value="//" />
</striplinecomments>
<prefixlines prefix="," />
<striplinebreaks />
<tokenfilter>
<trim />
<ignoreblank />
</tokenfilter>
</filterchain>
</loadfile>
<!-- run client generation for each WSDL in the download directory -->
<foreach target="-createStubs" param="file" inheritall="true">
<path>
<fileset dir="${wsdldir}" />
</path>
</foreach>
</target>
<!--=======================================================-->
<!-- TARGET [wsdlGet] -->
<!-- Target retrieving all the WSDL files necessary for generating client code. -->
<!--=======================================================-->
<target name="wsdlGet">
<!-- create the download directory -->
<mkdir dir="${wsdldir}" />
<!-- find the properties related to WSDL locations -->
<propertyselector property="services.list" delimiter="," match="(\w)*Service" />
<!-- for each property found, retrieve the WSDL -->
<foreach list="${services.list}" inheritall="true" target="-getSingleWsdl" delimiter="," param="prettyName" />
</target>
<!--=======================================================-->
<!-- TARGET [-getSingleWsdl] -->
<!-- Hidden Target to retrieve a single WSDL. -->
<!--=======================================================-->
<target name="-getSingleWsdl">
<!-- get the property value -->
<propertycopy property="fullPath" from="${prettyName}" />
<!-- download the WSDL file -->
<get src="${ws-domain}/${fullPath}?wsdl" dest="${wsdldir}/${prettyName}.wsdl" verbose="true" usetimestamp="true" />
</target>
<!--=======================================================-->
<!-- TARGET [-createStubs] -->
<!-- Hidden target to run WSDL2Java on an input file. -->
<!--=======================================================-->
<target name="-createStubs">
<!-- strip the full path from the file -->
<basename property="wsdl" file="${file}" />
<echo message="Generating client code for service: ${wsdl}" />
<java fork="true" classname="org.apache.axis2.wsdl.WSDL2Java" failonerror="true">
<arg line="-ns2p ${ns2p.all} -s -u -uri ${wsdldir}/${wsdl} -o ${stubsdir} --noBuildXML" />
<classpath refid="cp.axis" />
</java>
</target>
</project>
the soa-addresses.properties file, which contains the different web service URLs:
ATestService=services/ATestService BTestService=services/BTestService CTestService=services/CTestService DTestService=services/DTestService ETestService=services/ETestService
and the NStoPkg.properties file which converts the default web service namespace based off the WSDL URL to a specified java package:
http://typens.test.com/common=com.test.axis.common.types http://servicens.test.com/common/ATestService=com.test.axis.common.services.atestservice http://servicens.test.com/common/BTestService=com.test.axis.common.services.btestservice http://servicens.test.com/common/CTestService=com.test.axis.common.services.ctestservice http://servicens.test.com/common/DTestService=com.test.axis.common.services.dtestservice http://servicens.test.com/common/ETestService=com.test.axis.common.services.etestservice
Ant Foreach Properties
Mar 13th
Update 10/23/2009: An example of this build has been posted.
I’ve been working with Apache Ant a bit at work the past couple weeks. We’ve been setting up a Hudson continuous integration server to automate some of our builds and deployments. We’re also hoping to setup more automated tests using tools like Selenium, HTTPUnit, JUnit, etc., but those are going to be gradually added with the coming releases.
I’ve worked with Ant a lot before, but hadn’t really used the Ant-Contrib Tasks until modifying this build script. The foreach task is useful for running a list of things through a certain ant target. We have a properties file that has the webservice name and the associated WSDL URL. We feed that list to an Ant target through the foreach task (for each URL, go get the WSDL file/definition), then we generate Axis2 stubs from each WSDL file. To automate the generation/retrieving of these WSDL files I was moving the base URL (ex: http://services.test.com/) to the environment property file, since this is different in each environment (Test, QA, Production), but the relative URL (ex: /services/…) stays the same. So to summarize, the webservices properties file now has ExampleService=/services/ExampleService and the environment properties file has SERVICES-DOMAIN=http://services.test.com (SERVICES-DOMAIN is assigned to the ws-domain after the environment properties file is loaded in the ant build file).
Here’s where I ran into a little issue that I wanted to share so no one else has to spend a half hour debugging it. Well, also so I can find the answer here the next time I run into it. The property for the base URL wasn’t evaluating when I was running the WSDL list through the foreach call to get/download the WSDL file. It kept erroring saying ${ws-domain}/services/ExampleService?wsdl couldn’t be found. I spent a few minutes putting echo’s in the ant script to see where it was failing until I saw ${ws-domain} was set up until the ant target that gets the WSDL file. It was then I saw this foreach task attribute:
Attribute Description
inheritall Iftrue, pass all properties to the called target. Defaults tofalse.
Now I’m not sure why you wouldn’t want properties passed, but I’m sure there is some good reason why this is false by default. Maybe. So of course, adding this attribute set as true to the foreach ant task made everything work without a hitch.
Project Euler Primes
Jan 17th
I first checked out Project Euler a couple years ago when one of my friends mentioned it to me. If you haven’t heard of it before it is a series of challenging mathematical/computer programming problems that will require more than just mathematical insights to solve.
I took a couple classes in college for basic C++ programming, but we never got too deep. It was mostly principles of programming, etc. and, since it was a class aimed at Electrical Engineers first programming class and not Computer Science majors, we spent a bit of time on structures of programs and other general concepts that are core to most programming languages. I was (and still am) interested in strengthening my C++ knowledge, so I decided to try the Project Euler problems in C++.
So far I haven’t completed many (13 out of 228), but haven’t spent too much time on it, even though I started a couple years ago… The questions range in difficulty from Problem #1 Find the sum of all the multiples of 3 or 5 below 1000. to Problem #198 How many ambiguous numbers x = p/q, 0
x
1/100, are there whose denominator q does not exceed 108? The higher number problem # doesn’t necessarily mean it is more difficult, but difficulty is measured by how many people have solved the problem. You can see a trend of how people may start doing some of the problems, but quickly the numbers dwindle. For example, over 48,000 people have completed problem #1, but less than 20,000 people have completed more than 10 and less than 2,000 people have completed more than 25 problems. Once you’ve solved a problem, you can look at other ways people have solved it in other languages or even by hand. However, you can’t see any hints or other posts about a problem on the site until you’ve typed in the correct answer for that problem.
Today I spent a little bit of time optimizing some of the old algorithms I had used for previous problems. (Several algorithms can be re-used between problems and the less time it takes for them to run, the less time you have to wait to see if your answer is correct…) I started with optimizing my function to check if a number is a prime number.
There are basic things you can do to make figuring out if a number is prime or not. For example, it’s very easy and quick to find the remainder of a number when it is divided by 2 or 3. Since this is a lot of the cases for non-prime numbers, it’s best to check these cases first before checking if a number is divisible by any other number. A couple other quick (and perhaps obvious) things to do is to not check every single number from 1 … n where n is the number you are trying to check is prime or not… We know that anything even is divisble by 2 , so instead of checking if the number is divisible by 2, 4, 6, 8… start by checking if it’s divisible by 5 (since we’ve already checked 2 and 3) and check every odd number from there (5,7,9,11…). This cuts your computations in half. Also, we know that we only have to check up to the square root of the number (16/2 = 8, so there’s no point in checking if there is a remainder with 16/8). This cuts the computations in at least half again. After adding this optimizations, my code went from a minute or two to run down to a few seconds.
If you enjoy programming, math, or especially both, I would recommend checking out some of the problems on the site. It is a great way to keep your math skills from getting too rusty and a great way to learn how to do some math programming in a new language. If nothing else, you’ll get your mind thinking of different ways to solve problems.
