Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.

No matter how good official documentation is, sometimes it simply isn't enough to cover certain cases when multiple technologies overlap, and sometimes small mistakes creep in too. So some time ago while I was working on a WS-AtomicTransaction enabled webservice, I ran into issues that were to do with WebLogic dependencies and compilation. At the time I got past the issues with what were essentially hacks, where I used deeply nested dependencies in Maven, but now I wanted to revisit this approach and to see what was required to build a WS-AT enabled webservice from scratch by using only documented approaches.

This post builds heavily on the article I wrote a couple of years ago where I show an example JAX-WS webservice built with the Oracle WebLogic Maven Plugin. It also depends on another post from earlier this year where I wrote about setting up a WebLogic development server. So check those out if something is not clear here.

The basic requirement is that you have a WebLogic 12.2.1.3 development server set up. In my case since I use a Mac, the path to the ORACLE_HOME for this server is /Applications/devtools/wls_12.2.1.3. Adjust it to suit your needs and your setup.

So the WS-AT topic is rather large for one post, but there are no tricks or magic to writing the Java code for a WS-AT participant service i.e. a service that joins a distributed transaction that is initiated by another (coordinating) service. All you need to do is simply add the weblogic.wsee.wstx.wsat.Transactional annotation to the service class or individual web methods and then have the correct dependencies to compile it. Lets look at the Java side first. In fact, this is mostly lifted verbatim from the official documentation.
 Java
package net.igorkromin;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.BindingType;
import weblogic.wsee.wstx.wsat.Transactional;
@WebService(
name="WsAtExamplePortType",
portName="WsAtExamplePort",
serviceName="WsAtExampleService",
targetNamespace="http://igorkromin.net/wsat/participant"
)
@SOAPBinding(
style=SOAPBinding.Style.DOCUMENT,
use=SOAPBinding.Use.LITERAL,
parameterStyle=SOAPBinding.ParameterStyle.WRAPPED
)
@BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public class WsAtExampleImpl {
public WsAtExampleImpl() {
super();
}
@WebMethod()
@Transactional(
version=Transactional.Version.WSAT12,
value=Transactional.TransactionFlowType.MANDATORY
)
public void doOp()
{
/*
Your Code Here - All transactional resources with which the code
interacts are enlisted with the imported transaction.
*/
}
}




That's almost too simple! Of course I don't show any code that you'd usually have here like looking up a DataSource and doing something useful with JDBC or other transactional stores...that's up to you. The main point to take away from this is anything in the @Transactioal annotated method above that uses resources that can participate in a transaction i.e. data sources, database connections, etc, will be automatically part of the global/atomic transaction.

So what happens when we try to build this service using the POM file from my earlier post? Well, as expected it will fail with several missing class file errors...cannot find symbol. That's expected because we didn't define any dependencies to tell Maven where to find classes in the weblogic.wsee.wstx.wsat package. This is where the official documentation on building WS-AT enabled services falls short, but there is more documentation that talks about setting up Maven in the first place. Overlapping, but distinct technologies - splitting up documentation like this makes sense, but it can be a challenge to piece it all together sometimes.

Unfortunately this is also where a typo creeps in...and it had me stumbled for a while until I went digging around the .m2 directory. In the official documentation, the WebLogic Maven Plugin version is specified as 12.2.1-0-0, which is fine if you're on the base release of WebLogic 12.2.1, but remember the prerequisite mentioned earlier? We're using WebLogic 12.2.1.3, so the version string should be 12.2.1-3-0. One character difference, and yes the documentation is for the WebLogic 12.2.1.3 release! Of course if you were on a different dot point release, that '3' would change to whatever the dot point version is.

After that debacle was solved, my final POM file looked like this...
 pom.xml
<?xml version="1.0" encoding="UTF-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<groupId>net.igorkromin</groupId>
<artifactId>WsAtExample</artifactId>
<version>1.0</version>
<properties>
<!-- Exact version of WLS -->
<wls.version>12.2.1-3-0</wls.version>
</properties>
<build>
<plugins>
<!-- War Packager Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<filtering>true</filtering>
<targetPath>WEB-INF</targetPath>
<includes>
<include>web.xml</include>
<include>weblogic.xml</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<!-- Oracle WebLogic Maven Plugin -->
<plugin>
<groupId>com.oracle.weblogic</groupId>
<artifactId>weblogic-maven-plugin</artifactId>
<version>${wls.version}</version>
<executions>
<execution>
<id>wsgen</id>
<phase>process-classes</phase>
<goals>
<goal>wsgen</goal>
</goals>
<configuration>
<keep>false</keep>
<protocol>Xsoap1.2</protocol>
<sei>net.igorkromin.WsAtExampleImpl</sei>
<genWsdl>false</genWsdl>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- WLS Server Dependency -->
<dependencies>
<dependency>
<groupId>com.oracle.weblogic</groupId>
<artifactId>weblogic-server-pom</artifactId>
<version>${wls.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- Disable central repo updates to avoid constantly
downloading dependencies -->
<repositories>
<repository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<updatePolicy>never</updatePolicy>
</snapshots>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<updatePolicy>never</updatePolicy>
</snapshots>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
</pluginRepositories>
</project>



It may look complicated, but it is mostly the same as the POM file from my earlier JAX-WS service example, with a few additions. First I define the WebLogic version string as a property and make sure that I use it in both the plugin and dependency sections (this saves me typing it multiple times if I want to change versions later). Second I add a dependency on weblogic-server-pom, again exactly as per documentation, this gives us access to all the WebLogic class files. Last - I make sure that the central repository is not checked every time by disabling updates because this wastes a huge amount of time due to the number of transient dependencies we've just introduced (it's well over a thousand).

And with that, the webservice can finally be built by running 'mvn clean package'...unless you didn't install all the WebLogic jars into your local Maven repository that is! ...so lets have a quick look at how that's done.

These steps are also documented in the official documentation, the only difference here is a correction for the exact WebLogic version number used. Adjust the path for ORACLE_HOME to suit your installation.
 Terminal Commands
export ORACLE_HOME=/Applications/devtools/wls_12.2.1.3
cd $ORACLE_HOME
cd oracle_common/plugins/maven/com/oracle/maven/oracle-maven-sync/12.2.1
mvn install:install-file -DpomFile=oracle-maven-sync-12.2.1.pom -Dfile=oracle-maven-sync-12.2.1.jar
mvn com.oracle.maven:oracle-maven-sync:push -DoracleHome=$ORACLE_HOME
mvn archetype:crawl -Dcatalog=$HOME/.m2/archetype-catalog.xml
mvn help:describe -DgroupId=com.oracle.weblogic -DartifactId=weblogic-maven-plugin -Dversion=12.2.1-3-0


The above commands took around 10 minutes to complete on my Mac, so it's not a quick process. By the end of it, all of the Oracle Maven WebLogic plugin and WebLogic dependencies will be loaded into your local Maven repository however.

Now, we're finally done with this example. The next article will cover how this service can be called from another service while being enrolled into the same atomic/global transaction. You can read that here - Invoke a WS-AtomicTransaction participant service with a JAXWS proxy in WebLogic.

-i

Skip down to comments...
Hope you found this post useful...

...so please read on! I love writing articles that provide beneficial information, tips and examples to my readers. All information on my blog is provided free of charge and I encourage you to share it as you wish. There is a small favour I ask in return however - engage in comments below, provide feedback, and if you see mistakes let me know.

If you want to show additional support and help me pay for web hosting and domain name registration, donations, no matter how small, are always welcome!

Use of any information contained in this blog post/article is subject to this disclaimer.
 
comments powered by Disqus
Other posts you may like...