Thursday, October 24, 2013

Changing Classloader policy in RAD for Websphere Applications

Changing Classloader policy in RAD for Websphere Applications

Sometimes the need arises to make sure the jars in your application get used over class definitions that may be part of the server runtime.  This is true when using Axis2 as your web service engine in Websphere.
To do this follow these instructions below:
In IBM’s RAD, go to your EAR project and open the application.xml file.   Be sure to do this in a JEE like perspective so that you get to use RAD’s special Application Deployment Descriptor UI.
 

At the bottom of the “Application Deployment Descriptor” UI, go to the Deployment tab. And change the “Classloader Mode” to Parent_Last.  I usually do this for both the EAR and the WAR.



This is all you have to do for local testing and development.  Now if you publish to the local WAS test environment, your application should first look for class definitions from the jars in your WEB-INF/lib before looking at the server runtime…(you  may need to restart the server)

Maven build changes.
When you follow the directions above to change the classloader policy, it will create some extra files under the META-INF folder under the ear project.... to get Maven to package these files with your app you have to add a resources section to your ear pom.
<modelVersion>4.0.0</modelVersion>
<artifactId>mobius-ear</artifactId>
<name>Mobius EAR</name>
<packaging>ear</packaging>
<build>
<resources>
<resource>
<directory>META-INF</directory>
<targetPath> ../${project.artifactId}-${project.version}/META-INF</targetPath>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<modules>
<webModule>
<groupId>${project.groupId}</groupId>
<artifactId>mobius-ws</artifactId>
<bundleFileName>mobius-ws.war</bundleFileName>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>  
Isn’t there another way…
You can also change the classloader policy via the Websphere Admin console, but depending your Enterprise environments, you as a developer may not have access to Admin Console… so following the steps above, will automatically change the class loader policy when you application is deployed without requiring changing the classloader policy through the admin console.

Tuesday, July 23, 2013

JAX-WS Retrieving HTTP Headers


Here's a quick blog on how to retrieve HTTP Headers from a JAX-WS service.  In this example, I'm exposing a web service(I'm providing the service).  I created a JAX-WS handler following these directions


In the handleMessage() method, use the SOAPMessageContext to get the http headers by using the "get" method and passing the  javax.xml.ws.handler.MessageContext's HTTP_REQUEST_HEADERS property.


This will return a Map<String, List<String>>.  Where the key is the http header name and the List<String> is the value... I'm not sure why it's a list, but I just retrieved the first value and got what I expected.

Here's the code:



For the following message(raw view from SOAP UI):

I got the following output in my console:


Hope this helps!  Let me know if you have questions or suggestions!



Tuesday, March 19, 2013

Using Axis2 as JAX-WS Web Service Provider using RAD/Eclipse with Maven



This blog is a little rough... it's more like a journal entry or log of steps I went through trying to use Axis2 to provide a JAX-WS web service.  I actually used IBM's RAD (Rational Application Developer) which is IBM's flavor of Eclipse to do generate the JAX-WS code; however, I then used Axis2 as the web service engine when deploying to Websphere Application Server 6.1.

But hopefully this will be useful to someone, even if they aren't deploying to WAS, but just want an example of how to package Axis2 with their web app or want to see how to use Maven to create the servicejars.    As you'll see, I started with Axis2 1.5 and ran into issues and went back to 1.4 to get things working, but later I updated to 1.6 (when it came out) and things went fine.  So, I'd start with the latest version of Axis2 if possible.

Here's the blow by blow of the steps invovled:


  1. Create an Web Project and Ear
  2. Copy Axis2 jars and such from Axis2 war to web project




  1. Also copy the axis2_web folder into your Webcontent or webapp folder


  1. Change deployment descriptor




  1. Tried publishing to server but got this:

[1/8/10 16:32:15:224 EST] 0000001d SystemErr     R com.ibm.ws.metadata.annotations.AnnotationException: Annotation processing failed for class:  com/ibm/icu/impl/data/LocaleElements_zh__PINYIN.class
[1/8/10 16:32:15:224 EST] 0000001d SystemErr     R at com.ibm.ws.metadata.annotations.AnnotationConfigReader.getAnnotationData(AnnotationConfigReader.java:461)



  1. Remove icu4j-2.6.1.jar from WEB-INF/lib.


  1. Re-publish/Re-start the server and your Axis2 install should be ready to go.


  1. You can verify your Axis2 installation, but running the index.jsp under the WebContent/axis2-web folder.



  1. Then from the Axis2 Welcome page go to the “Validate” link, which will take you to the Axis2 Happiness Page.  Everything should be happy.



  1. Then create a generic project for the WSDL and Schema.


  1. Create a Dynamic Web Project to hold the generated service code.  It has to be a web project only because of the IBM wizard.  We will actually jar it up later and package it under the other web project.  (We actually don’t want this project associated with the EAR, but the wizard will make it associated anyway… So, we will have to undo this..






  1. Now run the Web Service wizard…Right click on the WSDL (from the package Explorer or Project Explorer) and go to Web Services->



  1. Change the Web Service Runtime to JAX-WS.  And select your newly created web project as the Service Project.



  1. On the next screen, I left the defaults:




  1. Click finish.  I got an error because it tried to deploy to my server which does not have the Web Services feature pack.  This is fine because I will be using Axis2 as my JAX-WS runtime and not Websphere’s implementation which comes with the feature pack.




  1. This generated the classes based on the schema and created a service class for us called “StandardizePlaceImpl”.





  1. Modified the StandardizePlaceImpl to return a response based on the input.
  2. Remove the project with the generated code from the EAR’s application XML:



  1. Create a folder in the WEB-INF folder of your Axis2 web project to hold the JAX-WS web service.




  1. JAR up your code and put the WSDL and the schema in the META-INF  folder in the jar.  Used the following pom file to jar up the code and this attempt does not include the WSDL’s and schemas.

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nw.gis</groupId>
<name>gis web service</name>
<artifactId>gis-ws</artifactId>
<version>1.0</version>
<packaging>jar</packaging>

<properties>
<sourceComplianceLevel>1.5</sourceComplianceLevel>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>


<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<source>${sourceComplianceLevel}</source>
<target>${sourceComplianceLevel}</target>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jaxws_2.1_spec</artifactId>
<version>1.0</version>
</dependency>
</dependencies>


</project>



  1. Now move the created jar into the servicejars folders under the axis2 folder.



  1. Now refresh the web project and then re-publish and restart the server.

[1/12/10 9:49:25:353 EST] 00000021 ServiceDeploy I org.apache.axis2.deployment.ServiceDeployer deploy Deploying Web service: version-1.5.1.aar - file:/C:/WorkSpaces/RAD7/Axis2_JAXWS/gis-axis-jaxws-ws/WebContent/WEB-INF/services/version-1.5.1.aar
[1/12/10 9:49:25:353 EST] 00000021 JAXWSDeployer I org.apache.axis2.jaxws.framework.JAXWSDeployer deploy Deploying artifact : gis-ws-1.0.jar
[1/12/10 9:49:25:462 EST] 00000021 JAXWSDeployer I org.apache.axis2.jaxws.framework.JAXWSDeployer deployClasses Deploying JAXWS annotated class com.nationwide.gis.service.standardizeplace_1.StandardizePlaceImpl as a service - StandardizePlace.StandardizePlace
[1/12/10 9:49:25:571 EST] 00000021 ServletWrappe I   SRVE0242I: [gis-axis-jaxws-ear] [/gis-axis-jaxws-ws] [AxisServlet]: Initialization successful.



  1. Go back the Axis2 index.jsp and then click Services.



  1. When I click on the service name, which usually shows you the WSDL, I get this error:


<error>
  <description>Unable to generate WSDL 1.1 for this service</description>
  <reason>If you wish Axis2 to automatically generate the WSDL 1.1, then please set useOriginalwsdl as false in your services.xml</reason>
  javax.xml.ws.WebServiceException: Error occurred generating WSDL file for Web service implementation class {com.nationwide.gis.service.standardizeplace_1.StandardizePlaceImpl}: {java.lang.Exception: Error occurred while attempting to read generated schema file {java.lang.RuntimeException: java.net.URISyntaxException: Illegal character in path at index 16: file:/C:/Program Files/IBM/SDP70/runtimes/base_v61/profiles/Axis2JaxWS/temp/NW917514Node10/server1/gis-axis-jaxws-ear/gis-axis-jaxws-ws.war/_axis2com.nationwide.gis.service.standardizeplace_1.StandardizePlaceImpl/StandardizePlace_schema3.xsd}} at org.apache.axis2.jaxws.description.builder.JAXWSRIWSDLGenerator.generateWsdl(JAXWSRIWSDLGenerator.java:187) at org.apache.axis2.jaxws.description.builder.JAXWSRIWSDLGenerator.initialize(JAXWSRIWSDLGenerator.java:371) at org.apache.axis2.jaxws.description.builder.JAXWSRIWSDLGenerator.getWSDL(JAXWSRIWSDLGenerator.java:364) at org.apache.axis2.description.AxisService.printWSDL(AxisService.java:1314) at org.apache.axis2.transport.http.ListingAgent.processListService(ListingAgent.java:270) at org.apache.axis2.transport.http.AxisServlet.doGet(AxisServlet.java:249) at javax.servlet.http.HttpServlet.service(HttpServlet.java:743) at javax.servlet.http.HttpServlet.service(HttpServlet.java:856) at



  1. When I use SOAP UI and point it to a local copy of the WSDL and invoke the service I get this:
1/12/10 11:05:25:080 EST] 00000020 FactoryRegist E org.apache.axis2.jaxws.registry.FactoryRegistry <clinit> null
                                java.lang.ExceptionInInitializerError
at java.lang.J9VMInternals.initialize(J9VMInternals.java:214)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:258)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:139)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:117)
Caused by: java.lang.ClassCastException: org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl incompatible with javax.xml.datatype.DatatypeFactory
at javax.xml.datatype.DatatypeFactory.newInstance(Unknown Source)
at com.sun.xml.bind.DatatypeConverterImpl.<clinit>(DatatypeConverterImpl.java:783)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:192)
... 47 more


  1. Noticed that the class it was complaining about was in the xercesImpl-2.8.1.jar which comes with Axis2 1.4, but my Axis2 1.5 version came with an older version of xercesImpl-2.6.2.jar.  So, I replaced my xerces jar with the newer version.  I believe it was using an implementation from IBM and not from the Axis2 jars since there was no implmentation in the Axis libs.


  1. After this change it worked fine for the first request submitted, but then I got an error on any more requests that I submitted:


[1/12/10 13:53:21:080 EST] 0000001d AxisEngine    E org.apache.axis2.engine.AxisEngine receive javax.xml.bind.UnmarshalException
- with linked exception:
[javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.nationwide.com/schemas/iaa7_1/customerrelationmanagement/GIS/placeInformationManagement_1", local:"standardizePlace"). Expected elements are (none)]
                                org.apache.axis2.AxisFault: javax.xml.bind.UnmarshalException
- with linked exception:
[javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.nationwide.com/schemas/iaa7_1/customerrelationmanagement/GIS/placeInformationManagement_1", local:"standardizePlace"). Expected elements are (none)]
at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430)
at org.apache.axis2.jaxws.server.JAXWSMessageReceiver.receive(JAXWSMessageReceiver.java:218)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:173)
...
Caused by: javax.xml.ws.WebServiceException: javax.xml.bind.UnmarshalException
- with linked exception:
[javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.nationwide.com/schemas/iaa7_1/customerrelationmanagement/GIS/placeInformationManagement_1", local:"standardizePlace"). Expected elements are (none)]
at org.apache.axis2.jaxws.ExceptionFactory.createWebServiceException(ExceptionFactor
... 25 more


  1. Let’s see if we can turn on any logging using Log4J.  So, I added a commons-logging.properties file to the classpath with the following lines:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
priority=999


  1. Then I added a log4j.properties file, and turned on debug level logging on the root logger.


  1. Re-ran the test… Got this for the second request which errored out… (note second request is same as first):

[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: This classloader will be used to construct the JAXBContext
com.ibm.ws.classloader.CompoundClassLoader@34043404
  Local ClassPath: C:\WorkSpaces\RAD7\Axis2_JAXWS\gis-axis-jaxws-ws\WebContent\WEB-INF\classes;C:\WorkSpaces\RAD7\Axis2_JAXWS\gis-axis-jaxws-ws\WebContent\WEB-INF\lib\activation-1.1.jar;C:\WorkSpaces\RAD7\Axis2_JAXWS\gis-axis-jaxws-ws\WebContent\WEB-INF\lib\antlr-2.7.7.jar;C:\WorkSpaces\RAD7\Axis2_JAXWS\gis-axis-jaxws-ws\WebContent\WEB-...
<removed cause it was really long>
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: checking package :com.nationwide.schemas.iaa7_1.customerrelationmanagement.gis.placeinformationmanagement_1
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: Exception thrown from AccessController: java.security.PrivilegedActionException: java.lang.ClassNotFoundException: com.nationwide.schemas.iaa7_1.customerrelationmanagement.gis.placeinformationmanagement_1.ObjectFactory
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: ObjectFactory Class Not Found java.lang.ClassNotFoundException: com.nationwide.schemas.iaa7_1.customerrelationmanagement.gis.placeinformationmanagement_1.ObjectFactory
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: Exception thrown from AccessController: java.security.PrivilegedActionException: java.lang.ClassNotFoundException: com.nationwide.schemas.iaa7_1.customerrelationmanagement.gis.placeinformationmanagement_1.package-info
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: package-info Class Not Found java.lang.ClassNotFoundException: com.nationwide.schemas.iaa7_1.customerrelationmanagement.gis.placeinformationmanagement_1.package-info
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: Package com.nationwide.schemas.iaa7_1.customerrelationmanagement.gis.placeinformationmanagement_1 does not contain an ObjectFactory or package-info class.  Searching for JAXB classes
[1/12/10 15:10:25:795 EST] 00000020 SystemOut     O [01/12/2010 15:10:25,795]JAXBUtils DEBUG: getClassesFromJarFile failed to get Classes


  1. Replaced all Axis2 1.5 jars and folders under WEB-INF with Axis2 1.4 versions and the service works… I have issues getting Axis2 to display the WSDL, but invoking the service works just fine.


  1. I get the following error when trying to click on the Service name to see the WSDL…

[2/15/10 12:07:08:217 EST] 00000020 SystemOut     O [02/15/2010 12:07:08,217]JAXWSRIWSDLGenerator ERROR: Error occurred generating WSDL file for Web service implementation class {com.nationwide.gis.service.standardizeplace_1.StandardizePlaceImpl}: {java.lang.reflect.InvocationTargetException}
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:615)
at org.apache.axis2.jaxws.description.builder.JAXWSRIWSDLGenerator.generateWsdl(JAXWSRIWSDLGenerator.java:173)
at org.apache.axis2.jaxws.description.builder.JAXWSRIWSDLGenerator.initialize(JAXWSRIWSDLGenerator.java:371)
at org.apache.axis2.jaxws.description.builder.JAXWSRIWSDLGenerator.getWSDL(JAXWSRIWSDLGenerator.java:364)
at org.apache.axis2.description.AxisService.printWSDL(AxisService.java:1322)
at ...
Caused by: java.lang.ExceptionInInitializerError
at java.lang.J9VMInternals.initialize(J9VMInternals.java:214)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:219)
at ...
... 33 more
Caused by: java.lang.ClassCastException: org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl incompatible with javax.xml.datatype.DatatypeFactory
at javax.xml.datatype.DatatypeFactory.newInstance(Unknown Source)
at com.sun.xml.bind.DatatypeConverterImpl.<clinit>(DatatypeConverterImpl.java:740)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:192)



UPDATE: 03/23/2012:

Did some more testing with this approach again, and found that I could follow most of this document and get a web service working with RAD 8 and Axis2 1.6.0.

I generated the code in RAD using the WSDL and JAX-WS.  Then created a Dynamic Web Project that I then copied the Axis2 stuff into… all but the libs.  We should be using maven to populate the libs (or m2Eclipse plugin).  I had Axis2 1.6.0 added to our internal enterprise repo last year and found that for most JAX-WS services you just need to add the following dependencies:

<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-kernel</artifactId>
<version>${axis2Version}</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.neethi</groupId>
<artifactId>neethi</artifactId>
</exclusion>

</exclusions>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
<version>${axis2Version}</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-local</artifactId>
<version>${axis2Version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-adb</artifactId>
<version>${axis2Version}</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-jaxws</artifactId>
<version>${axis2Version}</version>
</dependency>
<dependency>
<groupId>org.apache.neethi</groupId>
<artifactId>neethi</artifactId>
<version>2.0.5</version>
</dependency>


This should pull in the jars necessary to use JAX-WS with Axis2.

Also, I used the following plugin configuration in the WAR pom to pull in the generated code into the WEB-INF/servicejars folder.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
  <!-- this is relative to the pom.xml directory -->
      <directory>../spell-check-ws-gen/target</directory>
      <targetPath>WEB-INF/servicejars</targetPath>
      <includes>
    <include>spell-check-ws-gen*</include>
  </includes>
    </resource>
</webResources>
</configuration>
</plugin>


The “spell-check-ws-gen” project is where I had the generated JAX-WS code.  This plug-in configuration was in the Dynamic Web Project that I created and copied the Axis2 stuff into (stuff = web.xml, axis2-web, servicejars folder, modules, etc… but not the lib)

As long as my spell-check-ws-gen project was one of the modules referred to by the build project’s pom, then it would get built and then when the war project got built this plugin would run and pull that jar into the servicejars folder where Axis2 expects it.

At first I put the JAX-WS generated code jar only in the servicejars folder, but then I would get this error:

AxisEngine    E org.apache.axis2.engine.AxisEngine receive org.apache.axis2.jaxws.wrapper.impl.JAXBWrapperException: java.lang.IllegalArgumentException: argument type mismatch
                                org.apache.axis2.AxisFault: org.apache.axis2.jaxws.wrapper.impl.JAXBWrapperException: java.lang.IllegalArgumentException: argument type mismatch


I found that if I added the jar with the generated JAX-WS code(that is the spell-check-ws-gen in my case) also to the WEB-INF/lib, then this error would go away.

So, this jar would be in two places… in the WEB-INF/lib folder and in the WEB-INF/servicejars folder.  Then the service would work fine.

The Axis2 services page was not be able to produce a wsdl for the service, but I didn’t care.