{{announcement.body}}
{{announcement.title}}

Generating a JAX-WS Client JAR From WSDL URL Using PowerShell

DZone 's Guide to

Generating a JAX-WS Client JAR From WSDL URL Using PowerShell

Don't underestimate the power of PowerShell.

· Java Zone ·
Free Resource

PowerShell

Don't underestimate the power of PowerShell.

Sometimes, I like to get to the point directly rather than read an entire article. So if you are short on time, you may want to skip to the final step where you just have to copy the code, save it as a PowerShell script file, and run it with PowerShell.

However, if you are in the mood to do a little reading, then let's begin.

You may also like: [DZone Refcard] Windows PowerShell

1) Removing Unnecessary Files and Folders for a Clean Start

We will be dealing with WSDL, XSD, Jar, and XML files as well as some folders. To prevent any mistakes, let's first get rid of all the files with these extensions and the folders we will be working with.

Get-ChildItem returns the child items in the path specified. To get all the child items in subfolders, we use the Recurse parameter. The returned items can then be deleted with the Remove-Item command.

Get-ChildItem -Path "./*.wsdl" -Recurse | Remove-Item -force -recurse
Get-ChildItem -Path "./*.xsd" -Recurse | Remove-Item -force -recurse
Get-ChildItem -Path "./*.jar" -Recurse | Remove-Item -force -recurse

Remove-Item -LiteralPath "./files" -Force -Recurse -ErrorAction SilentlyContinue


2) Creating Necessary Folders

We need our target and META-INF  folders under the files folder. We can then create them with a new-item command.

new-item -Name "./files" -ItemType directory
new-item -Name "./files/target" -ItemType directory
new-item -Name "./files/META-INF" -ItemType directory


3) Creating Necessary Files

We will be using JAXB for generating Java classes from XML. Let's now create a jaxWs catalog and jaxbBindings files with their content embedded in the script.

$jaxWsCatalog = '<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"><system systemId="http://localhost/wsdl/service.wsdl"uri="service.wsdl"/></catalog>'
$jaxbBindings = '<?xml version="1.0" encoding="UTF-8"?><jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:version="2.1"><jaxb:globalBindings><xjc:serializable uid="1"/></jaxb:globalBindings></jaxb:bindings>'

$jaxWsCatalog | Set-Content "files/jax-ws-catalog.xml"
$jaxbBindings | Set-Content "files/Jaxb-bindings.xml"


4) Requesting the WSDL URL From the User and Retrieving Wsdl Content

All of the files and folders are ready. We now need to ask the user for the WSDL URL. In PowerShell, you can get an input from the user with  Read-Host. Once we get the URL, we can get the content of the wsdl with the Invoke-WebRequestcommand.

$wsdlUrl = Read-Host 'Please enter wsdl url'
$WsdlOriginal = (Invoke-WebRequest $wsdlUrl).Content


5) Checking for XSD Existence

The WSDL content may contain all xsd file information. We will check its existence by checking if the content contains schemaLocation or not using the IndexOf command.

$startIndex = [int]$WsdlOriginal.IndexOf("schemaLocation")+16

if( $startIndex -ge 16)


If XSD does not exist (the index is less then 16), we must skip to step 8. If it exists, then we have to retrieve the xsd file and modify the WSDL content retrieved in step 4.

6) Retrieving the XSD Content and Writing it to a File

By using the OutFile parameter, we can write the content retrieved with Invoke-WebRequest to a file with a name that we will give. In our example, it is  service.xsd:

Invoke-WebRequest -OutFile service.xsd $xsdUrl


7) Modifying WSDL Content

We retrieved the XSD file defined in the WSDL content. We need to change the reference of the XSD file from our URL to the local file. The start index of the string to be replaced was found in step 5. The end index is the position of the first quote symbol after the start index. This index can be found with:

$endIndex = [int]$WsdlOriginal.IndexOf('"',$startIndex)


The string between the start and end index must be replaced with the name of the XSD file ( service.xsd). This can ben achieved with the join command.

$WsdlModified = -join($WsdlOriginal.Substring(0,$startIndex),"service.xsd",$WsdlOriginal.Substring($endIndex))


The second modification we need to make is to replace the IP of the service-port-address-location with localhost

$startIndex = [int]$WsdlModified.IndexOf('address location="http://')+25
$endIndex = [int]$WsdlModified.IndexOf(':',$startIndex)
$WsdlModified = -join($WsdlModified.Substring(0,$startIndex),"localhost",$WsdlModified.Substring($endIndex))


8) Writing WSDL content to a File

Our WSDL content ( $WsdlOriginal if we skipped steps 6 and 7,  $WsdlModified otherwise) is ready. Let's now write it to a file with the Set-Content command.

$WsdlModified | Set-Content "service.wsdl"


9) Retrieving a Package Name From the User

Let's get the full package name of the classes to be generated from the user.

 $packageName = Read-Host 'Please enter package name'


10) Copying the Necessary Files

The files we generated in earlier steps must be in the folders we created in step 2. Let's copy the files to the folders:

copy service.wsdl files\
copy *.xsd files\
cd files
copy service.wsdl META-INF\
copy *.xsd META-INF\
copy jax-ws-catalog.xml META-INF\


11) Generating the Client

The preparation is complete. Let's create our client into the target folder with the package name $packageName using the Jaxb-bindings.xml file and XautoNameResolution parameter to prevent a problem with the class name already in use.

wsimport -d target -keep -p $packageName -b Jaxb-bindings.xml -B-XautoNameResolution -wsdllocation http://localhost/wsdl/service.wsdl -catalog jax-ws-catalog.xml service.wsdl


12) Removing Java Files

Our client has been generated. We have got the Java files and the class files. To decrease the size of the final JAR, let's get rid of the Java files. You may skip this step if you want to keep the Java files.

$packageName = [string]$packageName -replace "\.", "/"
Get-ChildItem -Path $packageName *.java | foreach { Remove-Item -Path $_.FullName }


13) Creating a JAR File and Moving it to the Root Folder

Now, let's create the JAR file and move it to the root folder.

jar cvf service.jar .
cd ..
cd ..
Move-Item files/target/service.jar ./


14) Final Code

If we combine all the steps above and add some controls and comments, we will get the result below. Once you save the following code in the PowerShell script file and run it, all you have to do to generate a JAX-WS client JAR and enter a valid WSDL URL and enter the package name for the generated classes.

#Removal of unnecessary files and folders for a clean start
Get-ChildItem -Path "./*.wsdl" -Recurse | Remove-Item -force -recurse
Get-ChildItem -Path "./*.xsd" -Recurse | Remove-Item -force -recurse
Get-ChildItem -Path "./*.jar" -Recurse | Remove-Item -force -recurse

Remove-Item -LiteralPath "./files" -Force -Recurse -ErrorAction SilentlyContinue

#Creation of necessary folders
new-item -Name "./files" -ItemType directory
new-item -Name "./files/target" -ItemType directory
new-item -Name "./files/META-INF" -ItemType directory

#Creation of necessary files
$jaxWsCatalog = '<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"><system systemId="http://localhost/wsdl/service.wsdl"uri="service.wsdl"/></catalog>'
$jaxbBindings = '<?xml version="1.0" encoding="UTF-8"?><jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:version="2.1"><jaxb:globalBindings><xjc:serializable uid="1"/></jaxb:globalBindings></jaxb:bindings>'

$jaxWsCatalog | Set-Content "files/jax-ws-catalog.xml"
$jaxbBindings | Set-Content "files/Jaxb-bindings.xml"

Write-Output ''
Write-Output 'Deleted unnecessary files/folders'
Write-Output 'Created necessary files/folders'
Write-Output ''

#Request wsdl url from user and retrieve wsdl content
$wsdlUrl = Read-Host 'Please enter wsdl url'
$WsdlOriginal = (Invoke-WebRequest $wsdlUrl).Content

Try
{ 
#Check if the wsdl contains xsd file definition by looking for schemaLocation tag name
$startIndex = [int]$WsdlOriginal.IndexOf("schemaLocation")+16

#if xsd exists 
if( $startIndex -ge 16)
{
$endIndex = [int]$WsdlOriginal.IndexOf('"',$startIndex)

Try{
#retrieve the xsd url from wsdl
$xsdUrl = [string]$WsdlOriginal.Substring($startIndex,$endIndex-$startIndex)

#if the xsd url is not a full path url, append the prefix of the wsdl url to the begining of xsd url
if( ([int]$xsdUrl.IndexOf("http")) -lt 0 )
{
$xsdUrl = -join($wsdlUrl.Substring(0,($wsdlUrl.LastIndexOf('/')+1)),$xsdUrl) 
}

#retrieve the xsd file from the xsd url and then write its content to service.xsd file
Invoke-WebRequest -OutFile service.xsd $xsdUrl
}Catch
{
#if something goes wrong, ask the user for the valid xsd url and then retriev and write its content to service.xsd file
$xsdUrl = Read-Host 'Please enter valid xsd url'
Invoke-WebRequest -OutFile service.xsd $xsdUrl
}

#replace the xsd schemaLocation value with the file name of the xsd
$WsdlModified = -join($WsdlOriginal.Substring(0,$startIndex),"service.xsd",$WsdlOriginal.Substring($endIndex))

#replace the ip of the service-port-address-location with localhost
$startIndex = [int]$WsdlModified.IndexOf('address location="http://')+25

if( $startIndex -ge 0 )
{
$endIndex = [int]$WsdlModified.IndexOf(':',$startIndex)
$WsdlModified = -join($WsdlModified.Substring(0,$startIndex),"localhost",$WsdlModified.Substring($endIndex))
}else
{
Write-Output 'ATTENTION! service port address ip could not be replaced with localhost. Change must be made manually!'
}

#write the modified wsdl to service.wsdl file
$WsdlModified | Set-Content "service.wsdl"
}else
{
#There is no xsd. For this reason no need to make changes with wsdl so write it to service.wsdl as it is.
$WsdlOriginal | Set-Content "service.wsdl"
}

Write-Output 'Check input files and make necessary changes if needed'
pause

#ask user for package name
$packageName = Read-Host 'Please enter package name'

#copy necessary files to folders 
copy service.wsdl files\
copy *.xsd files\
cd files
copy service.wsdl META-INF\
copy *.xsd META-INF\
copy jax-ws-catalog.xml META-INF\

#generate client
wsimport -d target -keep -p $packageName -b Jaxb-bindings.xml -B-XautoNameResolution -wsdllocation http://localhost/wsdl/service.wsdl -catalog jax-ws-catalog.xml service.wsdl

#remove .java files to minimize the size of the client jar
cd target
$packageName = [string]$packageName -replace "\.", "/"
Get-ChildItem -Path $packageName *.java | foreach { Remove-Item -Path $_.FullName }

#create the jar file and move it to the same folder with the powershell script file
jar cvf service.jar .
cd ..
cd ..
Move-Item files/target/service.jar ./

pause

}Catch
{
Write-Output "An error occured. Open the powershell script file and check each step"
}


That's it! Happy coding!

Further Reading

My First PowerShell: A Simple Story With Dramatic Flair

[DZone Refcard] Windows PowerShell

Topics:
jax-ws ,wsdl ,powershell ,client ,jar ,generate ,url

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}