Saturday, September 27, 2014

Updating EAR with Environment Specific deployment descriptor using ANT Script


  1. EAR contains a web application.
  2. The EAR need to be deployed in three client environments e.g. Development, UAT and Production
  3. The different environments required filters in web.xml. But the URL of filters are different for different environment. 
  4. So, before deployment, the web.xml of Development should be there in Web Application (WAR) and same applies before deployment in UAT and Production.
  1. Write an Ant Script to update the WAR file with respective web.xml and update the EAR with updated WAR File.
Ant Script:

ant -Dtar=apptar.tar -Dxml=PRO movwebx -f build.xml all

ant -f build.xml all


<project  name="UPDATE_EAR" default="dist" basedir=".">
    <property name="upd_ear.dir" value="upd_ear"/>

    <target name="mkchdir">
<echo>CREATING TMP FOLDER</echo>   
        <mkdir dir="upd_ear"/>

    <target name="mov" depends="mkchdir">
        <move file="${tar}" todir="${upd_ear.dir}"/>

    <target name="tarxvf" depends="mov">
<echo>UN TAR ${tar} IN TMP FOLDER</echo> 
        <unjar src="${upd_ear.dir}/${tar}" dest="${upd_ear.dir}"/>

    <target name="earxvf" depends="tarxvf">
<echo>UN JAR appear.ear IN TMP FOLDER</echo> 
        <unjar src="${upd_ear.dir}/appear.ear" dest="${upd_ear.dir}"/>

    <target name="warxvf" depends="earxvf">
<echo>UN JAR appwar.war IN TMP FOLDER</echo> 
        <unwar src="${upd_ear.dir}/appwar.war" dest="${upd_ear.dir}"/>

    <target name="movwebx" depends="warxvf">
<echo>MOVE web_${xml}.xml to web.xml</echo> 
        <move file="${upd_ear.dir}/WEB-INF/web_${xml}.xml"  tofile="${upd_ear.dir}/WEB-INF/web.xml" />

   <target name="updwar" depends="movwebx"> 
  <echo>UPDATE web.xml of ${xml} IN appwar.war</echo> 
<zip destfile="${upd_ear.dir}/appwar.war" update="true">
<fileset dir="${upd_ear.dir}"> 
<include name="WEB-INF/web.xml" /> 

   <target name="updear" depends="updwar"> 
      <echo>UPDATING appear.ear WITH appwar.war</echo>   
 <zip destfile="${upd_ear.dir}/appear.ear" update="true">
<fileset dir="${upd_ear.dir}"> 
<include name="appwar.war" /> 

   <target name="movear" depends="updear">
         <echo>MOVING EAR FILE</echo>   
        <move file="${upd_ear.dir}/appear.ear"  todir="." />

   <target name="movtar" depends="movear">
         <echo>MOVING TAR FILE</echo>   
        <move file="${upd_ear.dir}/${tar}"  todir="." />

    <target name="delchdir" depends="movtar">
        <echo>DELETING TMP FOLDER</echo>   
        <delete dir="${upd_ear.dir}"/>
   <target name="updateear" depends="delchdir"/>


Friday, July 25, 2014

AXIS 2 - Catching Errors

Axis2 - This utility will never throw errors if your log4j is not enabled in the application. This will make you to struggle to find the issue. You will never understand the issue is in Client Code or Server Code. And it will consume your 2-3-4 days to one Week, So, then what is the solution: Enable the log4j of your WebService Server Application.

Step 1 - Create a file.
Step 2 - Create a ServletContextListener
Step 3 - Load the file in PropertyConfigurator, its a log4j class.

Step 1 -

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE
log4j.rootCategory=DEBUG, LOGFILE

# Set the enterprise logger priority to FATAL

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE.layout.ConversionPattern=[%p] %m%n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

Step 2 - Create a ServletContextListener and Step 3

package com.init;

import java.util.Properties;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.PropertyConfigurator;

public class MyClass implements ServletContextListener {

public void contextInitialized(ServletContextEvent e) {
System.out.println("\n\ncontextInitialized(ServletContextEvent e)");

public void contextDestroyed(ServletContextEvent e) {

System.out.println("\n\ncontextDestroyed(ServletContextEvent e)");

private static void init() {
Properties prop = new Properties();
// code added by sanjeev for NON_CLUSTER_CR -START
try {
String logpath = System.getProperty("log4j.configuration");

prop = PropertyLoader.getProperties();

System.out.println("IPHLogger | init | prop="+prop );

if (prop != null) {
                                        //loading in log4j memory
} catch (Exception exception) {
package com.init;

import java.util.Enumeration;
import java.util.Properties;
import java.util.ResourceBundle;

public abstract class PropertyLoader {

private PropertyLoader() {

private static final boolean THROW_ON_LOAD_FAILURE = true;

private static final boolean LOAD_AS_RESOURCE_BUNDLE = true;

private static final String SUFFIX = ".properties";

private static volatile Properties result = null;

// public: ................................................................

* Looks up a resource named 'name' in the classpath. The resource must map
* to a file with .properties extention. The name is assumed to be absolute
* and can use either "/" or "." for package segment separation with an
* optional leading "/" and optional ".properties" suffix. Thus, the
* following names refer to the same resource:

* some.pkg.Resource
* some/pkg/Resource
* some/pkg/
* /some/pkg/Resource
* /some/pkg/
* @param argStrname classpath resource name [may not be null]
* @param argClassloader classloader through which to load the resource [null
* is equivalent to the application loader]
* @return resource converted to java.util.Properties [may be null if the
* resource was not found and THROW_ON_LOAD_FAILURE is false]
* @throws IllegalArgumentException if the resource was not found and
public static Properties loadProperties(String argStrname,
ClassLoader argClassloader) {
if (argStrname == null)
throw new IllegalArgumentException("null input: name");

if (argStrname.startsWith("/"))
argStrname = argStrname.substring(1);

if (argStrname.endsWith(SUFFIX))
argStrname = argStrname.substring(0, argStrname.length()
- SUFFIX.length());

InputStream objInputStream = null;
try {
if (argClassloader == null)
argClassloader = ClassLoader.getSystemClassLoader();

argStrname = argStrname.replace('/', '.');

// throws MissingResourceException on lookup failures:
final ResourceBundle objResourceBundle = ResourceBundle .getBundle(argStrname);

result = new Properties();
for (Enumeration keys = objResourceBundle.getKeys(); keys.hasMoreElements();) {
final String key = (String) keys.nextElement();
final String value = objResourceBundle.getString(key);
result.put(key, value);
} else {
argStrname = argStrname.replace('.', '/');

if (!argStrname.endsWith(SUFFIX))
argStrname = argStrname.concat(SUFFIX);

// returns null on lookup failures:
objInputStream = argClassloader.getResourceAsStream(argStrname);
if (objInputStream != null) {
result = new Properties();
result.load(objInputStream); // can throw IOException
} catch (Exception e) {
result = null;
} finally {
if (objInputStream != null)
try {
} catch (Throwable ignore) {

if (THROW_ON_LOAD_FAILURE && (result == null)) {
throw new IllegalArgumentException("could not load ["
+ argStrname
+ "]"
+ " as "
+ (LOAD_AS_RESOURCE_BUNDLE ? "a resource bundle"
: "a classloader resource"));

return result;

* A convenience overload of loadProperties(String, ClassLoader)
* that uses the current thread's context classloader.
public static Properties loadProperties(final String argStrName) {
return loadProperties(argStrName, Thread.currentThread().getContextClassLoader());

* A method to retrieve the properties value based on the key
* passed as an argument
public static String getValue(String argStrKeyVal) {
return (result == null) ? (null): ((result.containsKey(argStrKeyVal)) ? ((String) result
.get(argStrKeyVal)) : (null));

* A method to retrieve the properties object associated with
* the file.
public static synchronized Properties getProperties() {
return (result == null) ? (null) : result;

} // end of class

Adding listener in web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app >

Sunday, May 18, 2014

AXIS 2 - Client and Password Call Back Handler - For a secured (using Rampart) webservice

Password Call Back Handler - This class is invoked by container when the webservice receives a secured  request.

package crishantha.rampart;




public class PWCBHandler implements CallbackHandler {

public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
System.out.println("handle->(Callback[]:"+ callbacks);
for (int i = 0; i < callbacks.length; i++) {
System.out.println("(Callback["+i+"]:"+ callbacks[i]);
//When the server side need to authenticate the user
WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];


if(pwcb.getIdentifier().equals("apache") /*&& pwcb.getPassword().equals("password")*/) {
//If authentication successful, simply return
pwcb.setPassword("password"); // this value should be same as password supplied in SOAP Envelop.
//See the client program below for password
System.out.println("user authenticated->"+pwcb.getIdentifier());

} else {
throw new UnsupportedCallbackException(callbacks[i], "check failed");

Tag in services.xml ( need to be embed in services.xml for integrating Password Call Back Handler.

Client Program to call secured webservice

package ramp.client;

import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;

public class Client {
public static void main(String[] args)throws Exception {

System.setProperty("", "D:\\apache-tomcat-7.0.53\\bin\\sslkey\\sslkey.jks");
System.setProperty("", "password");

ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("D:\\AXIS2_DUMP\\axis2-1.6.2\\repository", null);

TemperatureConversionServiceStub stub =  new TemperatureConversionServiceStub(ctx, "https://localhost:8443/ram/services/TemperatureConversionService");

ServiceClient sc = stub._getServiceClient();
Options options = sc.getOptions();


TemperatureConversionServiceStub.Celcius2Farenhit celc = new TemperatureConversionServiceStub.Celcius2Farenhit();
TemperatureConversionServiceStub.Celcius2FarenhitResponse cfr = stub.celcius2Farenhit(celc);
float f = cfr.get_return();
System.out.println("5. result->"+f);



SOAP Envelop sent by client program:

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="">
<wsu:Timestamp wsu:Id="TS-1">
<wsse:UsernameToken wsu:Id="UsernameToken-2">
<ns1:celcius2farenhit xmlns:ns1="">

Saturday, May 17, 2014

AXIS 2 - SOAP Webservice - Adding Security layer to webservice using Rampart

Tools and Libraries used 

  1. apache-tomcat-7.0.53
  2. axis2-1.6.2
  3. rampart-1.6.2
  4. jdk 1.6
Exploring ram.war - The war file name is ram.war. The directory structure of the war file is below.

    │   ├───com
    │   │   └───polaris
    │   │       └───iph
    │   │           └───ws
    │   └───crishantha
    │       └───rampart

Below folders contain classes for webservice.
- classes/ 
- classes/crishantha.rampart

Integrating rampart with Axis 2 webservice
WEB-INF/conf - contains axis2.xml
WEB-INF/lib - contains all jars from  Axis2_HOME/lib/ and RAMPART_HOME/lib directory. 

Very important Note 
- The version of Axis2 and Rampart should be same. I faced issues because previously I was using axis2-1.6.2 and rampart-1.3.2. Then I changed the version of rampart to rampart-1.6.2 and it worked. This is very important point.
- The axis2 libs should not be mixed with various versions of other libs of Rampart and other extensions. It creates compatibility issues.

WEB-INF/modules - copy rahas-1.6.2.mar and rampart-1.6.2.mar files from  rampart-1.6.2\modules folder  in  WEB-INF/modules folder.

Declare webservice and engaging Rampart 

Adding Webservice in WAR file  and engaging Rampart with Axis2. Follow this link to see the META-INF/services/TemperatureConversionService/META-INF/services.xml.

Making server ready for HTTPS
Creating SSL Key to make tomcat server HTTPS /SSL Enabled. Execute below command from Tomcat_home\bin folder
keytool -genkey -alias tomcat -keyalg RSA -keystore  c:\sslkey\sslkey.jks

c:\sslkey\sslkey.jks will be created with the key. This key will be used to enable SSL.

Open the server.xml of tomcat from TOMCAT_HOME\conf\server.xml and enable /change/add below lines  around tags.

     <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
      keystorePass="password" />
Note: keystorePass="password", "password" value is entered while creating sslkey.jks using keytool (see few lines above)

Open WEB-INF/conf/axis2.xml and add below lines below tag  <transportReceiver>
<transportReceiver name="https" class="org.apache.axis2.transport.http.AxisServletListener">

<parameter name="port">8443</parameter>
Note : The port in axis2.xml and server.xml should be same, here its kept 8443.

Generating Client Code - Stub to call this service.

Save the WSDL  -TemperatureConversionService.xml
Execute below command

D:\AXIS2_DUMP\axis2-1.6.2\bin\clientcode>..\WSDL2Java.bat -uri D:\2010SANT\27_0_0\WS-POC\RAMPART\WebContent\WEB-INF\wsdl\TemperatureConversionService.xml -p ramp.client -d adb -s

NOTE: Get the jar from, before executing above command of WSDL2Java.bat. Issues will come without this jar.

Follow below link to develop Webservice Client for secured Webservice

AXIS 2 - services.xml - engaging rampart

<service name="TemperatureConversionService" targetNamespace="">

<module ref="rampart" /> <!-- Engaging Rampart -->
This service is to get the running Axis version
<schema schemaNamespace="" />
<parameter name="ServiceClass">crishantha.rampart.TemperatureConversionService
<operation name="celcius2farenhit">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
<operation name="farenhit2celcius">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />

<!-- Rampart specific tags  - start -->
<wsp:Policy wsu:Id="UsernameTokenOverHTTPS"
<sp:HttpsToken RequireClientCertificate="false" />
<sp:Basic256 />
<sp:Lax />
<sp:IncludeTimestamp />
sp:IncludeToken="" />
<ramp:RampartConfig xmlns:ramp="">
<ramp:passwordCallbackClass>crishantha.rampart.PWCBHandler</ramp:passwordCallbackClass> <!-- crishantha.rampart.PWCBHandler is user defined class to handle user name password -->
<!-- Rampart specific tags  - End-->

Thursday, May 1, 2014

SOAP Webservice - JAX-WS


  1. Create a sample SOAP Webservice using JAX-WS
  2. Deploy in Tomcat 7.0
  3. Invoke WSDL
  4. Create Client
  5. Use Client to invoke Webservice

  1. Create a sample SOAP Webservice using JAX-WS
    1. Create a dynamic Web Project in Eclipse
    2. Create Service Endpoint Interface (SEI) HelloWorld 
    3. Create Service Inplementation Bean (SIB), HelloWorldImpl which implement SEI.
    4. Change web.xml, add entries if Servlet giving service to Webservice HelloWorldImpl 
    5. Add sun-jaxws.xml in WEB-INF folder. This file will publish and start the webservice runtime in Tomcat.
  2. Deploy in Tomcat 7.0
    1. Add a new server in Eclipse, pointing to Tomcat 7 installation directory.
    2. Add below jars in WEB-INF/lib folder
      1. gmbal-api-only.jar
      2. ha-api.jar
      3. jaxb-api.jar
      4. jaxb-impl-2.2.6.jar
      5. jaxb-impl.jar
      6. jaxws-rt.jar
      7. management-api.jar
      8. policy.jar
      9. stax-ex.jar
      10. streambuffer.jar
    3. Add the webservice project (created in 1) in server.
    4. Start the server.
  3. Invoke WSDL
    1. http://localhost:8080/SOAP_JAX/hello?wsdl
  4. Create Client
    1. Create a new java project in eclipse.
    2. Go to src directory in doc command prompt.
    3. Invoke command "wsimport -keep -verbose http://localhost:8080/SOAP_JAX/hello?wsdl"
    4. Two classes will be created in src folder. These are stubs to invoke webservice. 
    5. Write the client file using the stubs created in 4 above.
  5. Invoke main method to access webservice. (SEI)


import javax.jws.WebMethod;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
@WebService(name = "HelloWorld", targetNamespace = "http://com.soap.sanjeev/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloWorld {

     * @return
     *     returns java.lang.String
    @WebResult(partName = "return")
    public String getHelloWorldAsString();

} (SIB)


import javax.jws.WebService;

@WebService(endpointInterface = "")
public class HelloWorldImpl implements HelloWorld {
public String getHelloWorldAsString() {
// TODO Auto-generated method stub
return "hello world";

WEB-INF/sun-jaxws.xml  - will publish the webservice and start the webservice runtime

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns=""
<endpoint name="HelloWorld" implementation=""
url-pattern="/hello" />


WEB-INF/web.xml - setup servlet and url for webservice
<?xml version="1.0" encoding="UTF-8"?>


<display-name>Archetype Created Web Application</display-name>

<url-pattern>/hello</url-pattern>  <!-- service the webservice -->



<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><!-- Generated by JAX-WS RI at RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><definitions xmlns:wsu="" xmlns:wsp="" xmlns:wsp1_2="" xmlns:wsam="" xmlns:soap="" xmlns:tns="" xmlns:xsd="" xmlns="" targetNamespace="" name="HelloWorldImplService">
<import namespace="http://com.soap.sanjeev/" location="http://localhost:8080/SOAP_JAX/hello?wsdl=1"></import>
<binding xmlns:ns1="http://com.soap.sanjeev/" name="HelloWorldImplPortBinding" type="ns1:HelloWorld">
<soap:binding transport="" style="rpc"></soap:binding>
<operation name="getHelloWorldAsString">
<soap:operation soapAction=""></soap:operation>
<soap:body use="literal" namespace="http://com.soap.sanjeev/"></soap:body>
<soap:body use="literal" namespace="http://com.soap.sanjeev/"></soap:body>
<service name="HelloWorldImplService">
<port name="HelloWorldImplPort" binding="tns:HelloWorldImplPortBinding">
<soap:address location="http://localhost:8080/SOAP_JAX/hello"></soap:address>

</definitions>   -  Webservice Client 

package com.client.soap.jaxws.sanjeev;



public class HelloClient {
    static HelloWorldImplService service;

    public static void main(String[] args) {
        try {
            HelloClient client = new HelloClient();
        } catch(Exception e) {

    public void doTest(String[] args) {
        try {
   service = new HelloWorldImplService();        
            System.out.println("Retrieving the port from    the following service: " + service);
            HelloWorld port = service.getHelloWorldImplPort();
            System.out.println("Invoking the sayHello operation                 on the port.");

            String name;
            if (args.length > 0) {
                name = args[0];
            } else {
                name = "No Name";

            String response = port.getHelloWorldAsString();
        } catch(Exception e) {