Getting JAX-WS client work on Weblogic 9.2 with ant - java

I've recently had lots of issues trying to deploy a JAX-WS web servcie client on Weblogic 9.2. It turns out there is no straightforward guide on how to achieve this, so I decided to put together this short wiki entry hoping it might be useful for others.
Firstly, Weblogic 9.2 does not support web servcies using JAX-WS in general. It comes with old versions of XML-related java libraries that are incompatible with the latest JAX-WS (similar issues occur with Axis2, only Axis1 seems to be working flawlessly with Weblogic 9.x but that's a very old and unsupported library).
So, in order to get it working, some hacking is required. This is how I did it (note that we're using ant in our legacy corporate project, you probably should be using maven which should eliminate 50% of those steps below):
1.Download the most recent JAX-WS distribution from https://jax-ws.dev.java.net/ (The exact version I got was JAXWS2.2-20091203.zip)
2.Place the JAX-WS jars with the dependencies in a separate folder like lib/webservices.
3.Create a patternset in ant to reference those jars:
<?xml version="1.0"?>
<patternset id="jaxws.classpath">
<include name="webservices/jsr173_api.jar" />
<include name="webservices/jsr181-api.jar" />
<include name="webservices/jaxb-api.jar" />
<include name="webservices/jaxb-impl.jar" />
<include name="webservices/jaxb-xjc.jar" />
<include name="webservices/jaxws-tools.jar" />
<include name="webservices/jaxws-rt.jar" />
<include name="webservices/jaxws-api.jar" />
<include name="webservices/policy.jar" />
<include name="webservices/woodstox.jar" />
<include name="webservices/streambuffer.jar" />
<include name="webservices/stax-ex.jar" />
<include name="webservices/saaj-api.jar" />
<include name="webservices/saaj-impl.jar" />
<include name="webservices/gmbal-api-only.jar" />
</patternset>
4.Include the patternset in your WAR-related goal. This could look something like:
<?xml version="1.0"?>
<copy todir="${wardir.lib}" includeEmptyDirs="false" flatten="true">
<fileset dir="${libs}">
<!--lots of libs here, related to your project -->
<patternset refid="jaxws.classpath"/>
</fileset>
</copy>
(not the flatten="true" parameter - it's important as Weblogic 9.x is by default not smart enough to access jars located in a different lcoation than WEB-INF/lib inside your WAR file)
5.In case of clashes, Weblogic uses its own jars by default. We want it to use the JAX-WS jars from our application instead. This is achieved by preparing a weblogic-application.xml file and placing it in META-INF folder of the deplotyed EAR file. It should look like this:
<?xml version="1.0"?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<prefer-application-packages>
<package-name>javax.jws.*</package-name>
<package-name>javax.xml.bind.*</package-name>
<package-name>javax.xml.crypto.*</package-name>
<package-name>javax.xml.registry.*</package-name>
<package-name>javax.xml.rpc.*</package-name>
<package-name>javax.xml.soap.*</package-name>
<package-name>javax.xml.stream.*</package-name>
<package-name>javax.xml.ws.*</package-name>
<package-name>com.sun.xml.api.streaming.*</package-name>
</prefer-application-packages>
</weblogic-application>
6.Remember to place that weblogic-application.xml file in your EAR! The ant goal for that may look similar to:
<?xml version="1.0"?>
<target name="build-ear" depends="war, manifest">
<delete dir="${dist}"/>
<mkdir dir="${dist}"/>
<jar destfile="${warfile}" basedir="${wardir}"/>
<ear destfile="${earfile}" appxml="resources/${app.name}/application.xml">
<fileset dir="${dist}" includes="${app.name}.war"/>
<metainf dir="resources/META-INF"/>
</ear>
</target>
7.Also you need to tell weblogic to prefer your WEB-INF classes to those in distribution. You do that by placing the following lines in your WEB-INF/weblogic.xml file:
<?xml version="1.0"?>
<container-descriptor>
<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>
8.And that's it for the weblogic-related configuration. Now only set up your JAX-WS goal. The one below is going to simply generate the web service stubs and classes based on a locally deployed WSDL file and place them in a folder in your app:
<?xml version="1.0"?>
<target name="generate-jaxws-client">
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
<classpath path="classpath.main"/>
</taskdef>
<wsimport
destdir="${src}"
package="acme.somewhere.in.your.package.tree.webservices."
keep="true"
wsdl="http://localhost:8088/mockWebService?WSDL">
</wsimport>
</target>
Remember about the keep="true" parameter. Without it, wsimport generates the classes and... deletes them, believe it or not!
For mocking a web service I suggest using SOAPUI, an open source project. Very easy to deploy, crucial for web servcies intergation testing.
9.We're almost there. The final thing is to write a Java class for testing the web service, try to run it as a standalone app first (or as part of your unit tests)
10.And then try to run the same code from withing Weblogic. It should work. It worked for me. After some 3 days of frustration.
And yes, I know I should've put 9 and 10 under a single bullet-point, but the title "10 steps to deploy a JAX-WS web service under Web logic 9.2 using ant" sounds just so much better.
Please, edit this post and improve it if you find something missing!

This is not really a question but a guide so I'm answering it myself just to mark it as done.

Another way of dealing with web services on Weblogic 9.2 is using Apache CXF. This particularly well integrates with Spring as each web service is exposed as a bean and the actual classes don't even need to know that they are web services, it's all configuration driven.
A great guide about setting up Apache CXF on Weblogic can be found here: http://wheelersoftware.com/articles/spring-cxf-web-services.html
This works on Weblogic 9.2 as well and if you need to expose web services, not just connect to existing ones, this is by far better approach than using plain JAXWS (which is used by CXF anyway).

Related

Ivy OutOfMemoryError during ivy:publish

I am having an issue with Ivy uploading large(ish) artifacts to our in-house artifact server (Artifactory 3.9.2). When we upload a 400MB file, we run out of Java heap space and it fails (thus failing our CI build). We keep nudging the upper limit up, but we're anticipating some significantly larger artifacts (~1GB in size) that is going to break our steady bumping in size.
We are using Ant 1.10, Ivy 2.4, OpenJSK 1.8.0.141, on a CentOS7 environment.
The issue has been documented with Ivy as IVY-1197 but it has not been fixed in a trunk build, so I want to put the described workaround:
The workaround is to always use ivy with commons-httpclient, commons-codec and commons-logging when the use case will involve uploading large files to sites requiring authentication
I want to add the commons-httpclient, commons-codec, and commons-logging to the Ivy classpath so that Ivy uses these during upload of the artifacts. Unfortunately, I am struggling to make this work. To be completely honest, I am a newcomer to the Java world, with classpaths being a foreign concept; I'm a C++ developer who has volunteered to fix this legacy part of our system.
We invoke our Ivy tasks through Ant. We pull in an ivysettings.xml file, whose relevant structure looks something like:
<ivysettings>
<classpath file="${build-utils.basedir}/ivy.lib/commons-httpclient-3.1.jar"/>
<classpath file="${build-utils.basedir}/ivy.lib/commons-codec-1.10.jar"/>
<classpath file="${build-utils.basedir}/ivy.lib/commons-logging-1.2.jar"/>
</ivysettings>
The ivysettings.xml is pulled in through a build-utils.xml file that is shared among our components:
<project name="build-utils" xmlns:ivy="antlib:org.apache.ivy.ant">
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant">
<classpath>
<fileset dir="${build-utils.basedir}/ant.lib">
<include name="ivy*.jar"/>
</fileset>
</classpath>
</taskdef>
<ivy:settings file="${build-utils.basedir}/ivysettings.xml"/>
<target name="convert-POM-to-Ivy" > <!-- description="Convert a POM file to an Ivy file"; additionally verifies that we've pulled in Ivy correctly -->
<ivy:convertpom pomFile="pom.xml" ivyFile="ivyFileOut.xml" />
</target>
</project>
We also have an ivy.xml for each of our components that is pretty straightforward:
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
<info organisation = "${groupId}"
module = "${artifactId}"
revision = "${version}}"/>
<configurations>
<include file="ivy-configurations.xml"/>
</configurations>
<!-- Some giant artifact -->
<artifact conf="${conf.el7}" type="tar.bz2" e:classifier="${conf.el7}"/>
<artifact type="pom"/>
<dependencies />
</ivy-module>
If I run the ant echoproperties target and grep for 'class.path' I get the following:
[echoproperties]
java.class.path=/usr/share/java/ant.jar\:/usr/share/java/ant-launcher.jar\:/usr/share/java/jaxp_parser_impl.jar\:/usr/share/java/xml-commons-apis.jar\:/usr/lib/jvm/java/lib/tools.jar\:/usr/share/ant/lib/ant-bootstrap.jar\:/usr/share/ant/lib/ant-launcher.jar\:/usr/share/ant/lib/ant.jar
[echoproperties]
java.class.path.ivy.instance=/usr/share/java/ant.jar\:/usr/share/java/ant-launcher.jar\:/usr/share/java/jaxp_parser_impl.jar\:/usr/share/java/xml-commons-apis.jar\:/usr/lib/jvm/java/lib/tools.jar\:/usr/share/ant/lib/ant-bootstrap.jar\:/usr/share/ant/lib/ant-launcher.jar\:/usr/share/ant/lib/ant.jar
With this setup, I still have issues with the upload, and I'm not sure if I can verify that I'm using the commons-httpclient.
Could someone provide some tips on how to get a jar into the Ivy classpath? Am I doing this wrong and I need to have it in the Ant classpath? If so, can someone point me in the right direction?

JRebel do not detect web resource changes over multiple webapp folders

I have a modular web project and thus I am allowing modules to be a war archive including webapp folder. Using the following rebel.xml works fine on detecting class changes over all modules. But for some reason jrebel does not move when a html or js is changed.
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com"
xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
<classpath>
<!-- appserver -->
<dir name="/home/xx/data/appserver/target/classes/main"/>
<dir name="/home/xx/data/appserver/target/resources/main"/>
<!-- module -->
<dir name="/home/xx/data/as.module.core/target/classes/main"/>
<dir name="/home/xx/data/as.module.core/target/resources/main"/>
<dir name="/home/xx/data/as.module.mqlcore/target/classes/main"/>
<dir name="/home/xx/data/as.module.mqlcore/target/resources/main"/>
</classpath>
<!-- web>
<link target="/">
<dir name="/home/xx/data/appserver/src/main/webapp"/>
<dir name="/home/xx/data/as.module.core/src/main/webapp"/>
<dir name="/home/xx/data/as.module.mqlcore/src/main/webapp"/>
</link>
</web -->
<web>
<link target="/">
<dirset dir="/home/xx/data">
<include name="**/src/main/webapp"/>
</dirset>
</link>
</web>
</application>
EDIT:
Interesting fact is. When I use the commented part of web configuration all three webapp folders are in the log and will be monitored for changes. But the application server can not find all of the webapp files. When I use the second <web> configuration all files are seen by the application server but are not observed by jrebel. I think it is not possible to have multiple directories linked to "/"
Each of the modules eg .war or .jar files need to have their own rebel.xml files. Otherwise all of them will reload same resources and when having different classloaders all kind of weird things can happen.
It is possible to check which instance of the file JRebel actually uses by searching "found resource" from jrebel.log. It should be written something like this
sun.misc.Launcher$AppClassLoader#184be29 found resource: 'cfg/log4j.xml' from 'file:/C:/Projects/testproject/Trunk/edm/target/cfg/log4j.xml'.
It is also seen which of the file changed by loking up lines with Event like this:
[IntelliJFSNotify] Event 'CHANGE' on: 'C:/Projects/testproject/Trunk/edm/target/cfg/log4j.xml'
Usually found resource and changed file paths do not match if the file is not reloaded. If they do match then it is recommended to send absolute path of the file and jrebel.log to support#zeroturnaround.com for investigation.
Ok, the answer is: indeed it is not possible to configure more than one directory under the <web><link target="/"></link></web> configuration. I have now a folder ./target/all-webapp where I smylink (cp -sR) all files via gradle task ... not nice but works ... and thank god jrebel is following symlinks!

Apple .app (build with Ant's JarBundler) won't run

I build my app with the following build.xml
When I click on release/MyApp.app, it won't run!!!
But when I do
java -jar release/MyApp.app/Contents/Resources/Java/helloworld.jar
the executable (a Windows) does come up, meaning the helloworld.jar is built correctly.
But for some reason, the app doesn't know to load it.
<?xml version="1.0" encoding="UTF-8"?>
<project name="App Builder" default="build_app" basedir=".">
<taskdef name="jarbundler"
classname="net.sourceforge.jarbundler.JarBundler" />
<target name="build_app">
<jarbundler dir="release"
name="MyApp"
mainclass="com.test"
jar="helloworld.jar" />
</target>
</project>
Does anyone know what is wrong here?
Thanks
+1 to trashgod. When testing this (from your previous question), my app wouldn't start. It was because the Stub was using Java 6 instead of Java 7 ... go figure. Once I compiled my files down to Java 6, it worked fine.
Also, make sure that you are including all the dependent Jar files...
I used this as my target...
<target name="default">
<delete dir="package" failonerror="false"/>
<mkdir dir="package"/>
<jarbundler dir="package"
name="Cars"
mainclass="testanimation10.TestAnimation10">
<jarfileset dir="dist">
<include name="**/*.jar" />
<!--<exclude name="**/CVS" />-->
</jarfileset>
</jarbundler>
Updated
I downloaded Java Application Bundler from java.net, which seems to be the replacement for Apple's bundler and following the basic instructions from here and was able to build a bundle that was capable of running binaries compiled under Java 7

Beanshell in Ant yielding, "Unable to create javax script engine for beanshell"

Greeting, I'm trying to put some Beanshell script in my Ant build.xml file. I've followed the Ant manual as well as I can but I keep getting "Unable to create javax script engine for beanshell" when I run Ant. Here is the test target I wrote mostly from examples in the Ant manual:
<target name="test-target">
<script language="beanshell" setbeans="true">
<classpath>
<fileset dir="c:\TEMP" includes="*.jar" />
</classpath>
System.out.println("Hello world");
</script>
</target>
My beanshell "bsh-2.0b4.jar" file is on the script task's classpath the way the manual recommended. Hope I have the right file. I'm working in c:\TEMP right now.
I've been googling and trying for a while now. Any ideas would be greatly appreciated. Thanks.
First, you need jsr-engines.zip from here:
https://scripting.dev.java.net/servlets/ProjectDocumentList
Inside, you'll find jsr223/beanshell/build/bsh-engine.jar. Some searching implied that you need to download bsh-2.05b.jar. I found it here:
http://beanshell.org/bsh-2.0b5.jar
The more easily findable bsh-2.0b4.jar also seemed to work, but it printed a message that implied it was experimental.
Currently (2012) you need only 1 jar to fire the script task for BeanShell:
bsh-2.0b5.jar
Previously I also thought of the following, as mentioned by Ant Manual, Library Dependencies chapter:
bsf-2.4.0.jar
commons-logging-api-1.1.jar
But it looks like bsf is not needed for bsh, at least in my environment.
Once the jar is given to ant, the script task runs smoothly. There are 2 possible scenarios for getting the jars and making them available to ant.
Manual download way
Download the jars above. I provided the links from maven repository. Once you have all the jars downloaded, make them available to ant. There are
at least 3 ways to do it:
Put it in java library path
Put it in ant library directory
Give the correct classpath to script task.
I find the last method the best, because it is most easily ported between
different systems. The ant file for the script task could look as follows:
<project default="t1" >
<property name="bsh.path"
location="/mnt/q/jarek/lang/java/ant/stackoverflow/bsh-2.0b5.jar" />
<target name="t1">
<script language="beanshell" classpath="${bsh.path}">
javax.swing.JOptionPane.showMessageDialog(null, "Hello, Script!");
</script>
</target>
</project>
Automatic download method, employing Ivy
The manual method is not perfect when you want to distribute your build script. Then you would like a way to make sure the jars are present in the destination system. For distributing builds there's no better tool than ivy. Ivy will download the jars and put them in classpath for you. The problem is that there appears another dependency, which is ivy itself. But providing ivy.jar is quite easy and that is the last dependency we need to supply explicitly.
One may ask why to provide ivy.jar, while we could simply download bsh.jar in the same way. The answer is flexibility. When you have the ivy.jar, you get any jar you wish with a single step being adding it to the ivy.xml file. And there is an agreed universal location for the ivy.jar file, while for other file we would have to think of a suitable directory.
Below comes the full example that downloads ivy and then all the necessary dependencies. Ivy download script is based on Installation chapter of Ivy reference.
Then a simple ivy.xml file is needed, which is given after the sample build.xml.
Original auto-download ivy script has a disadvantage of always checking the ivy url, even if ivy.jar is already in the expected location. This may be overriden by specifying -Doffline=true. I prefer to add another target to the build file and to do the http check only if we don't already have the ivy.jar. This is the way the script here works. To observe what ivy actually downloaded, set IVY_HOME environment variable to a directory of your choice. It will be created and filled with ivy stuff.
build.xml:
<project default="t1"
xmlns:ivy="antlib:org.apache.ivy.ant" >
<property name="ivy.install.version" value="2.2.0" />
<property environment="env" />
<condition property="ivy.home" value="${env.IVY_HOME}">
<isset property="env.IVY_HOME" />
</condition>
<property name="ivy.home" value="${user.home}/.ant" />
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
<target name="check-ivy">
<condition property="ivy.present">
<available file="${ivy.jar.file}" type="file" />
</condition>
</target>
<target name="download-ivy" unless="ivy.present">
<mkdir dir="${ivy.jar.dir}"/>
<!-- download Ivy from web site so that it can be used even without any special installation -->
<get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
</target>
<target name="init-ivy" depends="check-ivy, download-ivy">
<!-- try to load ivy here from ivy home, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>
<target name="ivy-libs" depends="init-ivy" >
<ivy:cachepath pathid="path.from.ivy" log="download-only" />
</target>
<target name="t1" depends="ivy-libs" >
<script language="beanshell" classpathref="path.from.ivy">
javax.swing.JOptionPane.showMessageDialog(null, "Hello, Script!");
</script>
</target>
</project>
ivy.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="example.com" module="testing-script-task" />
<dependencies>
<dependency org="org.beanshell" name="bsh" rev="2.0b5" />
<!-- <dependency org="bsf" name="bsf" rev="2.4.0" /> -->
</dependencies>
</ivy-module>
The Ant plug-in "org.apache.ant_1.7.0.v200803061910" have all the jar files needed
Don't use beanshell language. Use javascript instead, as it runs on jdk6 without any additional jars. Rebse told me that.
Javascript is also allowed to use java classes, for example java.lang.System.out.println()

Why do Jars get Excluded from Enunciate's Deployment?

I'm using Enunciate to build a prototype REST api and need to include a jar containing custom code as a library.
My Ant Script looks like this:
<!--include all jars-->
<path id="en.classpath">
<fileset dir="${lib}">
<include name="**/*.jar" />
</fileset>
</path>
<!--define the task-->
<taskdef name="enunciate" classname="org.codehaus.enunciate.main.EnunciateTask">
<classpath refid="en.classpath" />
</taskdef>
<mkdir dir="${dist}" />
<enunciate dir="${src}" configFile="${basedir}/enunciate.xml">
<include name="**/*.java" />
<classpath refid="en.classpath"/>
<export artifactId="spring.war.file" destination="${dist}/${war.name}" />
</enunciate>
The problem is that my custom jar is being excluded from the WAR file. It is necessary to compile the enunciate annotated classes so the jar is obviously on the classpath at compile time but enunciate is failing to include it in the distribution. I have also noticed that several of the jars needed by enunciate are not being included in the WAR file.
Why are they being excluded and how do I fix it?
I never used enunciate, but as a quick hack you can add the jars to the war:
<jar jarfile="${dist}/${war.name}" update="true">
<fileset dir="${lib}">
<include name="**/*.jar" />
</fileset>
</jar>
Note: you probably want to add the jars to the WEB-INF/lib directory, instead of the root directory.
I'm guessing that enunciate does the mininum to interfere with your own build process, since you know best what to put within your jar file.
As it turns out one of the jars we're attempting to include has a dependency listed in it's Manifest file of a jar that Enunciate depends on (freemarker). Enunciate automatically excludes freemarker and at first glance it seems as though it automatically excludes anything that depends on freemarker as well. If we remove freemarker from the list of dependent jars in our code's manifest file it works just fine.
However; I've spoken with the main developer of Enunciate (Ryan Heaten) and he assures me this isn't what's happening. Including his response below:
Really?!
Wow. Interesting. I can't explain
it; Enunciate doesn't look at what's
in the Manifest in order to determine
what to include in the war, so I'm
kind of stumped here. It could also
be some weird Ant behavior (not
including that jar in the
"en.classpath" reference for some
reason).
~Ryan
In enunciate.xml I tell it not to copy any libs itself:
<webapp doLibCopy="false">
Then in the ant build file at the end of the enunciate task I update the war (you can do this to update the included/excluded jars whether or not you have Enunciate copy the jars for you in the step above):
<war destfile="build-output/{mywar}" update="true">
<lib dir="WebContent/WEB-INF/lib">
<include name="**/*.jar" />
</lib>
<lib dir="build-output">
<include name="some_other.jar" />
</lib>
</war>

Categories