Wednesday, December 24, 2008

JNDI lookup on Tomcat and JBoss using Spring

Unfortunately Java EE specs does not specify any standard way of JNDI naming conventions, hence most of the application servers have their own way of JNDI naming. On specifying a Datasource's JNDI name as 'jdbc/myDatasource', Tomcat (6) binds that as 'java:/comp/env/jdbc/myDatasource' while JBoss (5) binds as 'java:/jdbc/myDatasource'. So if one wants to deploy the application on multiple application servers then at least JNDI names has to be changed. I was wondering if Spring Framework has a solution for this, so tried to do lookup using <jee:jndi-lookup ...> as shown below-

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDatasource" resource-ref="true"/>
it works well with Tomcat but fails on JBoss. Reason, the JNDI prefix is hard coded in Spring to 'java:comp/env/'.
package org.springframework.jndi;

public abstract class JndiLocatorSupport extends JndiAccessor {

    /** JNDI prefix used in a J2EE container */
    public static final String CONTAINER_PREFIX = "java:comp/env/";
    . . .
}
So it is obvious that it will fail on JBoss. To overcome this limitation, I came up with following solution-
public final class ServiceLocator {

    private static final Map<String, Object> services = new ConcurrentHashMap<String, Object>();

    private static ServiceLocator instance;

    private static Context context;

    static {
        try {
            Context initContext = new InitialContext();
            if (ServerDetector.isJBoss()) {
                context = (Context) initContext.lookup("java:");
            } else if (ServerDetector.isTomcat()) {
                context = (Context) initContext.lookup("java:/comp/env");
            } else {
                context = initContext;
                // or add more 'else if' blocks according to servers to be supported
            }
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public DataSource getDataSource(String name) throws Exception {
        if (name == null || name.length() <= 0)
            throw new IllegalArgumentException("name");

        if (services.containsKey(name))
            return (DataSource) services.get(name);

        DataSource ds = (DataSource) context.lookup(name);

        services.put(name, ds);
        return ds;
    }
}

Here ServerDetector is a good utility class I found in Liferay code base. Now ServiceLocator takes care of application server specific JNDI prefixes and avoids hassles of changing configuration or code to deploy it on a specific server. In case of Spring instead of using <jee:jndi-lookup ...> one can do the lookup using above-mentioned ServiceLocator as shown below-
    <bean id="serviceLocator" class="com.vinodsingh.ServiceLocator" factory-method="getInstance" />

    <bean id="dataSource" factory-bean="serviceLocator" factory-method="getDataSource">
        <constructor-arg value="jdbc/myDatasource" />
    </bean>
Now entire code (including configuration files) becomes truly portable, at least for JNDI lookups :-)

Saturday, December 20, 2008

Let Spring load service class for JAX-WS

During deployment JAX-WS RI by default creates an instance (singleton) of web service implementation class and uses that to serve requests. At times we may want to customize the instantiation of the web service implementation class e.g. let Spring configure and load the object.

JAX-WS Commons has an extension for Spring integration, which delegates total configuration to Spring and makes RI specific files (sun-jaxws.xml) redundant. Currently I am happy with the way JAX-WS RI exposes web services and do not want everything to move to Spring or something else. I was just looking for a way to load the service implementation class by my code instead of RI doing so. JAX-WS RI has a poorly documented (or may be I am not able find it easily) feature called InstanceResolver, which lets developers to customize the way service implementation class is loaded. The code snippets below demostrate how to so-

public class MyResolver extends InstanceResolver<Object> {

    private final Object serviceImpl;

    /**
     * @param clazz
     */
    public MyResolver(Class<?> clazz) {
        serviceImpl= . . . load the class here or get it from Spring or somewhere else . . .;
    }

    /**
     * @see com.sun.xml.ws.api.server.InstanceResolver#resolve(com.sun.xml.ws.api.message.Packet)
     */
    @Override
    public Object resolve(Packet request) {
        return serviceImpl;
    }

}

// Now create an Annotation, which has @InstanceResolverAnnotation with MyResolver.class
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InstanceResolverAnnotation(MyResolver.class)
public @interface MyWs {
}

// Now annotate the service class with above-mentioned annotation
@WebService(endpointInterface = "com.vinodsingh.Address")
@MyWs
public class AddressImpl implements Address {
    . . .
}

During deployment (WSServletContextListener) JAX-WS RI iterates through all annotations on the service class and sees if there is any annotation annotated with @InstanceResolverAnnotation. On finding one it will delegate the task of creating instance of the service class to the user defined InstanceResolver. With this I am able to load service classes using Spring.

Sunday, December 07, 2008

Locally packaged WSDL

As discussed in my earlier post Consuming web services with Spring, web service client initialization might fail due to non-availability of the running web service. We can overcome this limiting factor by packaging the WSDL with client and using that for creating the instance of client stub and during service method invocation use the live URL of the service. Have a look at Packaging dynamic resources with Maven to know more about packaging. The following code snippet shows how to use locally packaged WSDL and live service URL-

// during instantiation use the locally packaged WSDL
WebServiceClient ann = AddressService.class.getAnnotation(WebServiceClient.class);  
URL wsdlURL = this.getClass().getResource("/wsdl/AddressService.wsdl");

AddressService serviceObj = new AddressService(wsdlURL, new QName(ann.targetNamespace(), ann.name()));
Address service = serviceObj.getAddressPort();
BindingProvider bp = ((BindingProvider) service);
Map<String, Object> context = bp.getRequestContext();

// set the live URL of the service, which will be used during service method invocations
context.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "LIVE URL OF THE WEB SERVICE");

Sunday, November 30, 2008

Environment specific property with Spring

In an application there are lots of properties which vary from one environment to another e.g. database used in development will be different from the one used in production, leading to different connection properties (url, user names and password). Applications using Spring Framework usually fallback on PropertyPlaceholderConfigurer for inserting such values from an external properties file.

I would like to have everything at one place instead of externalizing properties into separate file for each environment. Fortunately Spring Framework provides extension points to create user defined XML elements and classes to instantiate beans using those elements. To have environment specific properties in single configuration file along with other bean definitions, I decided to create a custom element named <property>. Next I will try to explain how it works.

Here is the schema for <property> element, which is used to define different property for each environment-
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://vinodsingh.com/schema/spring"
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   targetNamespace="http://vinodsingh.com/schema/spring">

    <xsd:element name="property">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string" use="required" />
            <xsd:attribute name="class" type="xsd:string" use="optional" default="java.lang.String" />
            <xsd:attribute name="value" type="xsd:string" use="required" />
            <xsd:attribute name="region" use="optional" default="all">
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                        <xsd:enumeration value="dev" />
                        <xsd:enumeration value="test" />
                        <xsd:enumeration value="integ" />
                        <xsd:enumeration value="stage" />
                        <xsd:enumeration value="uat" />
                        <xsd:enumeration value="prod" />
                        <xsd:enumeration value="all" />
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:attribute>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>
Now create a bean definition parser to parse the <property> element-
public class PropertyDefinitionParser extends AbstractSingleBeanDefinitionParser {

    /** Region where bean will be available. */
    private String beanRegion = null;

    private static String sysRegion = System.getProperty("region");

    static {
        if (sysRegion == null || sysRegion.length() <= 0)
            sysRegion = "all";
    }

    @Override
    protected Class<?> getBeanClass(Element element) {
        Class<?> clazz = null;
        String className = element.getAttribute("class");
        if (className != null && className.length() > 0) {
            try {
                clazz = Class.forName(className);
            } catch (Exception e) {
                log.error("Failed to load class: " + className, e);
                throw new RuntimeException(e);
            }
        }

        return clazz;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        beanRegion = element.getAttribute("region");

        bean.addConstructorArgValue(element.getAttribute("value"));
    }

    @Override
    protected void registerBeanDefinition(BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
        if (beanRegion.equals(sysRegion) || "all".equals(beanRegion))
            super.registerBeanDefinition(definition, registry);
    }
}
Based on the above-mentioned schema the resulting bean definitions will looks like-
<property id="jdbc.url" value="jdbc:hsqldb:hsql://dev:9002" region="dev" />
<property id="jdbc.url" value="jdbc:hsqldb:hsql://production:9002" region="prod" />

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="driverClassName"/>
    <property name="url" ref="jdbc.url"/>
    <property name="username" value="username"/>
    <property name="password" value="password"/>
</bean>
Here jdbc.url property is defined twice with different region value. In bean definition for dataSource the jdbc.url is used as bean reference. The PropertyDefinitionParser will register only one definition of jdbc.url,which belongs to the current runtime region. The region will be passed as a system property to JVM.

Saturday, November 29, 2008

Packaging dynamic resources with Maven

Maven is an excellent project management tool which makes difficult things easy. With doing so many things it also bundles resource files if we tell it the path to resources as shown below-
<?xml version="1.0" encoding="UTF-8"?>
<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">
    . . .
    <properties>
        <resource.dir>${code.base.dir}/${project.artifactId}/src/main/resources</resource.dir>
    </properties>
    . . .
    <build>
        . . .
    <resources>
            <resource>
                <directory>${resource.dir}</directory>
            </resource>
        </resources>
        . . .
    </build>
</project>
Above configuration works well for the resources, which are already present along with source code. There are cases when these resources are generated during build process like WSDL for a web service project. Though usually it is not required but in certain use cases it may be required to bundle such dynamically generated resources. As I mentioned in my earlier post about issues being faced in consuming web services in an array of applications based on SOA Architecture. In this particular scenario bundling WSDL will be really helpful, I will discuss more about it in coming posts.

To include generated WSDLs we can decalre their directory as resource directory and invoke the wsgen and wsimport tasks to generate the artificats-
    <properties>
        <wsdl.dir>${target.dir}/jaxws/wsgen/wsdl</wsdl.dir>
        <resource.dir>${wsdl.dir}/..</resource.dir>
        <keep.src>false</keep.src>
        <verbose>true</verbose>
    </properties>
    . . .
    <build>
        <plugins>
             <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                <version>${jaxws-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>My Service</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>wsgen</goal>
                        </goals>
                        <configuration>
                            <sei>pkg.MyServiceImpl</sei>
                            <destDir></destDir>
                            <genWsdl>true</genWsdl>
                            <keep>${keep.src}</keep>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                <version>${jaxws-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>My Service</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>wsimport</goal>
                        </goals>
                        <configuration>
                            <wsdlDirectory>${wsdl.dir}</wsdlDirectory>
                            <wsdlFiles>
                                <wsdlFile>MyService.wsdl</wsdlFile>
                            </wsdlFiles>
                            <packageName>pkg.wsclient</packageName>
                            <target>2.0</target>
                            <keep>${keep.src}</keep>
                            <verbose>${verbose}</verbose>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
In the above example <phase>generate-sources</phase> declaration is very important. If phase is defined as compile then WSDL files won't be included in the jar as by that time Maven has already decided what to be included and from where. Similar tricks can be used to include other kind of dynamically generated content as well.

Sunday, November 23, 2008

Consuming web services with Spring

Consuming web services with Spring framework is amazingly easy. It avoids the need of creating client side stubs during compile time and does the same at run time. A typical web service client can be configured as shown below-

<bean id="myWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
    <property name="serviceInterface" value="pkg.MyService"/>
    <property name="wsdlDocumentUrl" value="http://localhost:8080/testws/myService?wsdl"/>
    <property name="namespaceUri" value="http://com.pkg/"/>
    <property name="serviceName" value="MyService"/>
    <property name="portName" value="MyServicePort"/>
</bean>
Where serviceInterface is the business interface that clients will use for invoking service methods. wsdlDocumentUrl is the URL for the published WSDL file. Spring will download WSDL from the given URL and generate the client side stubs when it creates the bean usually during application start up. namespaceUri corresponds to the targetNamespace in the .wsdl file. serviceName corresponds to the service name in the .wsdl file. portName corresponds to the port name in the .wsdl file.

Now accessing web service pretty easy, just get the bean from Spring context and use that to invoke methods-
MyService myService = springContext.getBean("myWebService");
myService.someMethod(. . .);
One downside of this approach is that the web service must be up running when consumer application is being deployed. To avoid this problem one can use lazy-init="true" to lazily initialize the beans when they are first requested but all this quickly becomes unmanageable when we have an array of SOA based applications. In such a scenario one have to strictly follow the order of application deployment else deployment might fail.

Tuesday, October 07, 2008

Using dynamic proxies for cache implementation

The act of storing a copy of data (which is usually expensive to fetch or compute) from the original source, near (ideally, though not necessary) the users is called caching. Once the data is stored in the cache, future use can be made by accessing the cached copy rather than re-fetching or re-computing the original data, so that the average access time is shorter, leading to performance gains. There are various cache implementations in java e.g. EHCache, Memcached etc.

Usually we interleave cache lookup calls for objects in our business logic as shown in following example-

public Employee getEmployee(long id) {
// See if it is available in cache
Employee employee = MyCache.get(Long.toString(id));
if (employee != null)
return employee;

// Construct new objects and put in cache
employee = new Employee(id, "Vinod", "Singh");
MyCache.put(Long.toString(id), employee);
return employee;
}
Where we first look in cache for the object and return the same if available. If not found then create the new one and put that in cache before returning to client. This kind of implementation looks superfluous and adds to clutter in the code. In my opinion business classes should concentrate on the relevant logic only and developers should not be bothered about caching. The caching logic should be moved out of business logic and kept at one centralized place and intercept the calls to business logic and take up the task of looking for objects in cache or putting newly created objects in cache. This will provide great flexibility to enable/disable and/or change the caching implementation at will with almost no changes in code. In rest of the post I will try to explain how with the help of dynamic proxies we can separate out the caching code from business logic.

Usually the returned object of some method is the thing what we keep in cache. So let us create an annotation, which can be used on any method to indicate that the returned object needs to be cached.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cacheable {
}
The Cacheable annotation will be applied as shown in following example-

public interface HrmItf {

@Cacheable
Employee getEmployee(long id);
}
Now create a proxy, which will look for the object in cache or put it in cache whenever a method with @Cacheable annotation is called.

public class CacheProxy implements InvocationHandler {

private Object obj;

public static T newInstance(Class cls, Object obj) {
return cls.cast(Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new CacheProxy(obj)));
}

private CacheProxy(Object obj) {
this.obj = obj;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// If method is not annotated, don't look in cache
Cacheable cacheable = method.getAnnotation(Cacheable.class);
if (cacheable == null)
return method.invoke(obj, args);

// try to get from cache
String key = args[0].toString();
Object value = MyCache.get(key);
if (value != null)
return value;

// Invoke the actual method and put the result in cache
value = method.invoke(obj, args);
MyCache.put(key, value);
return value;
}
}
When we get a handle to our business interface, actually we will be get a proxy encapsulating the implementation. Here is how we do that-

public void proxyCacheTest() {
HrmItf hrm = CacheProxy.newInstance(HrmItf.class, new HrmImpl());
hrm.getEmployee(1);
}
Now business layer is concerned only about the task it is supposed to do. It looks much cleaner now without any noise.

public Employee getEmployee(long id) {
return new Employee(id, "Vinod", "Singh");
}
If we want to use the in-process caching solution like EHCache or the distributed one like Memcached or want to disable the cache at all, it is the one place CacheProxy.java where we have to make changes.

Friday, September 26, 2008

Proxy setting on Linux

If your Linux box is behind a proxy server then to access the internet, proxy configuration will be required. The 'http_proxy' and 'ftp_proxy' environment variables hold the information about proxy server. Just execute the following commands-

$export http_proxy=http://<proxy-server-ip>:<port>
$export ftp_proxy=http://<proxy-server-ip>:<port>


Now wget, yum, apt-get etc. can use these variables to access http/s and ftp URLs out of office LAN. If proxy server needs authentication credentials then pass them as shown below-

$export http_proxy=http://<user>:<password>@<proxy-server-ip>:<port>
$export ftp_proxy=http://<user>:<password>@<proxy-server-ip>:<port>


To avoid executing these commands every time you login or reboot the machine then add them in ~/.bashrc file.

Thursday, September 25, 2008

Using JAX-WS Handlers

The JAX-WS provides a good facility to do pre/post processing on SOAP messages using SOAPHandler. The handlers are useful for auditing, logging and potentialy some more functionality. In this entry I will try to explain a typical usage of handlers for logging the SOAP messages. Every handler class needs to implement javax.xml.ws.handler.soap.SOAPHandler interface as shown below-
public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {

    @Override
    public Set<QName> getHeaders() {
        return null;
    }

    @Override
    public void close(MessageContext context) {
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        logToSystemOut(context);
        return true;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        logToSystemOut(context);
        return true;
    }

    private void logToSystemOut(SOAPMessageContext smc) {
        Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        if (outboundProperty.booleanValue()) {
            System.out.println("\nOutgoing message:");
        } else {
            System.out.println("\nIncoming message:");
        }

        SOAPMessage message = smc.getMessage();
        try {
            message.writeTo(System.out);
        } catch (Exception e) {
            System.out.println("Exception in handler: " + e);
        }
    }

}
Now create a handler confiuration file say 'handlers.xml' as shown below and put it in 'WEB-INF' directory of your application.

<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
   <handler-chain>
      <handler>
         <handler-class>my.server.pkg.LoggingHandler</handler-class>
      </handler>
   </handler-chain>
</handler-chains>
Using @HandlerChain annotation we can instruct the JAX-WS runtime to apply the handlers configured in the above-mentioned configuration on a web service endpoint-
@WebService(endpointInterface = "my.server.pkg.IMyService")
@HandlerChain(file = "handlers.xml")
public class MyServiceImpl implements IMyService {
Now all incoming and outgoing SOAP messages will be logged to standard output stream. Source code for this example is available here.
For developing and deploying web services see my earlier posts-
http://blog.vinodsingh.com/2008/09/building-jax-ws-web-service.html
http://blog.vinodsingh.com/2008/09/jax-ws-web-service-and-jboss.html

Friday, September 19, 2008

JAX-WS web service and JBoss

Yesterday I wrote an entry about building JAX-WS web service. So thought about testing them on latest versions of JBoss. I chose 4.2.3 and 5.0.0 CR2 (released yesterday), both with Java 6.

JBoss 4.2.3
The deployment of web service failed with following error-

Error configuring application listener of class com.sun.xml.ws.transport.http.servlet.WSServletContextListener
java.lang.ClassNotFoundException: com.sun.xml.ws.transport.http.servlet.WSServletContextListener


which looks quite natural as JBoss has its own implementation of JAX-WS, so it does not have the RI classes. After bundling RI jars with application deployment was error free. I created a small standalone program to invoke the web service, which succeeded without any errors.

What about if web service consumer is also a web application? To test this scenario I created a small web application to consume the above-mentioned service and deployed on JBoss. On invoking web service the following exception was thrown-

org.jboss.ws.metadata.wsdl.WSDLException: Invalid default namespace: null

I thought that by bundling JAX-WS jars with the application, I can overcome this error. But faced another exception-
com.sun.xml.ws.client.WSServiceDelegate cannot be cast to javax.xml.ws.spi.ServiceDelegate21

Now I started scratching my head :-/ When in difficulty the developer community takes help of Google, but here Google did not gave clues. After investigating the JBoss directory structure and their contents I discovered an endorsed directory at ‘jboss-4.2.3.GA\lib\endorsed’ location. Then I deleted all jars (related to JAXB, JAXWS and JAAS) from there except the following ones-
  • Serializer.jar
  • Xalan.jar
  • xercesImpl.jar
and copied JAX-WS RI jars here. Now everything worked even no need to bundle the JAX-WS jars with the applications.

JBoss 5 RC2
Making the web service work on this version of the JBoss also required same steps as with 4.2.3 and service was consumed by a standalone application without any hiccups. Then tried to consume the service using same web application as used for 4.2.3 and with JBoss 5 also it failed with similar error on trying to invoke a service method-

org.jboss.ws.metadata.wsdl.WSDLException: Invalid default namespace: null

On bundling JAX-WS RI jars with the consumer application everything worked fine, so no more ClassCastException or using the endorsed directory mechanism. This is a good improvement over previous versions of JBoss.

Wednesday, September 17, 2008

Building JAX-WS web service

Last year I wrote a small step by step guide to build JAX-RPC web services. Now JAX-RPC has been replaced by new standard JAX-WS, so I thought it is good time to write an entry for JAX-WS as well. Building web services with JAX-WS is pretty straight forward though it might look cumbersome to a newbie. In this entry I am going explain the basic steps for building a Java first web service, which I developed and tested with JAX-WS 2.1.4, Java 6 update 6 and Tomcat 6.0.16.

Step #1 - Write an interface

@WebService(targetNamespace = "http://vinodsingh.com", name = "MyService")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL)
public interface MyService {

    String sayHello(@WebParam(name = "name") String name);
}

Step #2 - Implement the interface
@WebService(endpointInterface = "pkg.MyService")
public class MyServiceImpl implements MyService {

    @Override
    public String sayHello(String name) {
        return "Hello " + name + "!";
    }
}

Step #3 - Configure web.xml

The JAX-WS context listener and servlet are required to be configured in deployment descriptor (web.xml). The WSServletContextListener initializes and configures the web service endpoint and WSServlet serves the service requests using implementing class.
<listener>
    <listener-class>
        com.sun.xml.ws.transport.http.servlet.WSServletContextListener
    </listener-class>
</listener>
<servlet>
    <servlet-name>jaxws</servlet-name>
    <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>jaxws</servlet-name>
    <url-pattern>/myService</url-pattern>
</servlet-mapping>

Step #4 - sun-jaxws.xml

The JAX-WS RI uses information available in this file while initializing and configuring a web service endpoint. This file should be present in WEB-INF directory.
<endpoints
    xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime'
    version='2.0'>
    <endpoint
        name='myService'
        implementation='pkg.MyServiceImpl'
        url-pattern='/myService' />
</endpoints>

Step #5 - Build and deploy

Here is an Ant script to prepare the server side stuff-
<!-- Define classpath. -->
<path id="jaxws.classpath">
    <pathelement location="${java.home}/../lib/tools.jar" />
    <fileset dir="${jaxws.lib.dir}">
        <include name="*.jar" />
    </fileset>
</path>

<!-- Declare ant tasks required to generate service and client. -->
<taskdef name="apt" classname="com.sun.tools.ws.ant.Apt" classpathref="jaxws.classpath" />
<taskdef name="wsgen" classname="com.sun.tools.ws.ant.WsGen" classpathref="jaxws.classpath" />
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport" classpathref="jaxws.classpath" />

<!-- Run the 'apt' tool on annotated code to generate server side stuff. -->
<target name="buildService">
    <apt fork="true" destdir="${classes.dir}" 
         sourcepath="${src.main.dir}" 
         sourcedestdir="${gensrc.dir}" 
         debug="${debug}" verbose="${verbose}" classpathref="jaxws.classpath">
        <source dir="${src.main.dir}">
            <include name="**/MyServiceImpl.java" />
        </source>
    </apt>

    <jar destfile="${build.home}/server.jar" basedir="${classes.dir}" compress="true" />
</target>

Now package all this in a WAR file and deploy on the server. The web service can be accessed at http://localhost:8080/testws/myService (URL may change according to the server configuration).

Update Feb 13, 2009: With latest versions of Java 6 and JAX-WS, apt task is optional. See this comment below.

Step #6 - Generate client

And this script will generate client side stubs. Here first we are generating WSDL and then using that to generate client side stubs. Though we can avoid the WSDL generation and use the live URL by deploying the web service on a server but usually that is not feasible in a project where build process is automated.
<!-- Generate the client, for that first WSDL needs to be generated. -->
<target name="genClient" depends="buildServer">
    <wsgen sei="pkg.MyServiceImpl" 
        resourcedestdir="${gen.wsdl.dir}" 
        sourcedestdir="${gensrc.dir}/client" 
        destdir="${classes.dir}/client" 
        genwsdl="true" verbose="${verbose}" keep="true">
        <classpath>
            <pathelement location="${classes.dir}/server" />
        </classpath>
    </wsgen>

    <wsimport destdir="${classes.dir}/client" 
        sourcedestdir="${gensrc.dir}/client" 
        package="pkg" debug="${debug}" 
        wsdl="${gen.wsdl.dir}\MyServiceImplService.wsdl" 
        xendorsed="true" keep="true" />

    <jar jarfile="${build.home}/ws-client.jar" basedir="${classes.dir}/client" compress="true" />
</target>

Step #7 - Invoke the service

Here is the sample code to invoke the web service, which we just built and deployed.
// Get a handle to web service client interface
WebServiceClient ann = MyServiceImplService.class.getAnnotation(WebServiceClient.class);
MyServiceImplService service = new MyServiceImplService(new URL(
    "http://localhost:8080/testws/myService"), 
    new QName(ann.targetNamespace(), ann.name()));
MyService myService = service.getMyServiceImplPort();

// Invoke methods
String hello = myService.sayHello("Vinod");
System.out.println(hello);

Thats it. We are done. Source code of this example is available here.

Update Apr 12, 2010 - A new post JAX-WS Web service with Maven shows usage of Maven as build script for building JAX-WS web services.

Friday, September 05, 2008

AnyType object over webservice and Hibernate

Recently I came across a requirement of moving objects over the network using web services (JAX-WS 2.1). The application was CRUD in nature and Hibernate was used as data tier on the server. In case of web service usually we have WSDL, which clearly defines the kind of objects it expects in request and response. So we can have add/modify/delete/retrieve methods for each type of entity in the WSDL. This approach seems to be doable when we have very few entities. But in our case we were having too many entities and the WSDL was going to be very huge and repetitive in nature. Then what is the way out!!!

I created a base class say BaseEntity.java, which is just a place holder having no variables or methods. Each entity was made to extend BaseEntity.java. The methods in web service interface were having signature like-

@XmlSeeAlso( { MyActualEntity.class })
public interface DataService {

   public void add(BaseEntity object);
}
In the implementing class of the web service interface, Hibernate can determine the actual class name handles that properly to insert the data in correct table. So all seems to be set on the server side, what about client side?

After generating client side stubs when I tried to add an instance of MyActualEntity.java, JAXB complaint that it does not know anything about MyActualEntity. JAXB was absolutely right, it knows only about those data types, which are mentioned in WSDL and MyActualEntity was not part of the WSDL. Then how shall I tell the JAXB about the real entities :-/

We can add the complexType definitions for all entities in the WSDL, but lazy resisted that ;-)
After doing some research I found @XmlSeeAlso annotation., which can be applied on the web service interface. When wsgen task encounters the @XmlSeeAlso annotation, it will include those classes in the WSDL. Now JAXB knows about MyActualEntity and sends that across the wire.

Seems to be a good trick :-)

Tuesday, July 29, 2008

SVN with Apache + LDAP

We have been using CVS at work for long, though personally I am a big fan of SVN. Lately we thought to catch up with the SVN buzz and I was asked to have a Proof Of Concept before we officially move to SVN. Installation of SVN with Apache was pretty straightforward. Though LDAP integration was also simpler but at times it failed without any obvious reasons. Here are the steps for the entire process on Windows XP-

1. Install Apache 2.2.
2. Install SVN 1.5 by unzipping the distribution.
3. Add SVN\bin folder to PATH.
4. Copy mod_dav_svn.so to modules directory of Apache.
5. Add following line in Apache conf file-
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so

# Following are required for LDAP authentication
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule ldap_module modules/mod_ldap.so

6. Download [svnindex.css and svnindex.xsl] from http://svn.collab.net/repos/svn/trunk/tools/xslt/
and put them in 'htdocs' folder of Apache. This will do nice listing of SVN contents.

7. Add the repository location in http conf file, this will have LDAP auth as well

#Location of repository
<Location>
DAV svn

SVNParentPath C:\svn
SVNListParentPath on
SVNIndexXSLT "/svnindex.xsl"

AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative off
AuthName "My SVN Setup"
AuthLDAPURL ldap://host:3268/dc=X,dc=Y?sAMAccountName?sub?(objectClass=user) NONE
AuthLDAPBindDN myUserID
AuthLDAPBindPassword myPassword
Require valid-user
</Location>

7. Run 'httpd' command from Apache

VOILA! YOU ARE DONE

I gave it a try on Fedora 4 as well, which comes with Apache 2.2 and SVN 1.4 pre-installed. Only thing that was missing was there 'mod_dav_svn'. Getting that to with YUM is pretty simple, just do-
yum install mod_dav_svn

Here we were using Active Directory as our LDAP server. Initially I used the port 389 in the AUthLDAPURL shown above and it worked fine for first 2 weeks but after that it failed without any obvious reasons with this error message in Apache log files-
[ldap_search_ext_s() for user failed][Operations Error]

It made it to work for brief periods by re-starting the Apache. Re-starting is not an option in production. After googling for some time I found suggestions to use port 3268 instead of 389. More than 2 weeks has been passed since I switched to port 3268 and it is working fine till date :-)

My next step will be to convert some CVS repositories to SVN. Will update soon about the results of this conversion.

Saturday, May 31, 2008

Webservice endpoint

The Java JAX-RPC implementation used to create simple to use web service clients, where developer can easily change the web service endpoint as shown below-

MyWsImpl stub = new MyWsImplService_Impl().getXXX();
((Stub) stub)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://myHost/myWs/myWs");

See this entry for details about building JAX-RPC web services.

The JAX-WS has changed the way it generates the clients. As a general practice people keep the WSDL along with their code and create the client side stubs at the build time. The JAX-WS hard codes the WSDL path in the client stub. See the one such generated code below-
package cache;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceClient;

@WebServiceClient(name = "MyServiceImplService", targetNamespace = "http://c.b.a/", wsdlLocation = "file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl")
public class MyServiceImplService extends Service {

private final static URL MYSERVICEIMPLSERVICE_WSDL_LOCATION;
private final static Logger logger = Logger
.getLogger(MyServiceImplService.class.getName());

static {
URL url = null;
try {
URL baseUrl;
baseUrl = MyServiceImplService.class.getResource(".");
url = new URL(baseUrl,
"file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
MYSERVICEIMPLSERVICE_WSDL_LOCATION = url;
}

public MyServiceImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}

public MyServiceImplService() {
super(MYSERVICEIMPLSERVICE_WSDL_LOCATION, new QName("http://c.b.a/",
"MyServiceImplService"));
}
}
If one tries to create an instance of client using the default constructor then it looks for the WSDL file at the location hard coded in the class and might fail with FileNotFoundException. The workaround for this problem is to call the another consturcutor, passing the endpoint URL and QName. Creating this QName is quite annoying and also that may change in future changes to WSDL. Then what is the easy wayout?

If you look closely at the web service client, it has an annotation @WebServiceClient, which has all the information to create the QName dynamically.
WebServiceClient ann = MyServiceImplService.class
.getAnnotation(WebServiceClient.class);
MyServiceImplService service = new MyServiceImplService(
new URL("ENDPOINT URL OF MY SERVICE"),
new QName(ann.targetNamespace(), ann.name()));

Now it looks pretty simple, is not it?

Wednesday, May 28, 2008

Proxy authentication in Java

The usual corporate networks provide internet access via proxy servers and at times they require authentication as well. May applications do open the connections to servers which are external to the corporate intranet. So one has to do proxy authentication programmatically. Fortunately Java provides a transparent mechanism to do proxy authentications.

Create a simple class like below-

import java.net.Authenticator;

class ProxyAuthenticator extends Authenticator {

private String user, password;

public ProxyAuthenticator(String user, String password) {
this.user = user;
this.password = password;
}

protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password.toCharArray());
}
}
and put these lines of code before your code opens an URLConnection-
Authenticator.setDefault(new ProxyAuthenticator("user", "password"));
System.setProperty("http.proxyHost", "proxy host");
System.setProperty("http.proxyPort", "port");

Now all calls will successfully pass through the proxy authentication.

Monday, May 05, 2008

@Stateless + @WebService +Weblogic 10 = :-(

On my last project we have to expose some stateless session beans as web service as well. The deployment platform was Weblogic 10 MP1. For the initial few weeks everything (development, deployment and testing) went fine and then all of a sudden Weblogic refused to deploy couple of EJBs without any error messages. The general observation is, if a class has both @Stateless and @WebService on a single java class and number of code lines grow beyond some limit (our classes have around 350 lines) then Weblogic has issues with them. If we reduced the code by commenting out some code or removing some methods then deployment went well.

This is not the only issue with Weblogic, one more equally weird observation is that @EJB annotations does not work when a class has both @Stateless and @WebService.

Monday, April 07, 2008

Primitives vs Objects

At times we come across a situation when we need to decide whether to use primitive types or wrapper objects for numeric values in Java. The wrapper classes come in handy when we need to pass on the null values, which can't be achieved with primitive types as they are always initialized to their respective default values.

The general concept is that primitive types are far more efficient then using wrapper classes in terms of memory usage and time taken for creating the data types. For one of my project I need to decide which one to use, so I thought about measuring the cost difference between these two options. I wrote a simple class which creates n number of objects of a class either having primitives or wrapper classes. The code is given below-

import java.util.ArrayList;
import java.util.List;

public class ObjectVsPrimitive {

List<WrapperNumbers> wrappers;
List<PrimitiveNumbers> primitives;

public void testWrapper(int count) {
wrappers = new ArrayList<WrapperNumbers>();
for (int i = 0; i <= count; i++)
wrappers.add(new WrapperNumbers());
}

public void testPrimitive(int count) {
primitives = new ArrayList<PrimitiveNumbers>();
for (int i = 0; i <= count; i++)
primitives.add(new PrimitiveNumbers());
}

public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Usage: java ObjectVsPrimitive 'P' (or 'O') <some number>");
System.exit(-1);
}

int count = 0;

try {
count = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number.");
System.exit(-1);
}

ObjectVsPrimitive test = new ObjectVsPrimitive();
StopWatch watch = new StopWatch();

if (args[0].equalsIgnoreCase("p"))
test.testPrimitive(count);
else
test.testWrapper(count);

watch.stop();
double freeMem = Runtime.getRuntime().freeMemory() / 1024 / 1024;
double totalMem = Runtime.getRuntime().totalMemory() / 1024 / 1024;
System.out.println("Time taken: " + watch.time() + " seconds");
System.out.println("Total Memory: " + totalMem + "MB, Free Memory: " + freeMem + " MB"
+ ", Used Memory: " + (totalMem - freeMem) + "MB");
}

/**
* A class having primitives for holding numeric values.
*/
@SuppressWarnings("unused")
public class PrimitiveNumbers {
private short SHORT = 10;
private int INT = 10;
private long LONG = 10l;
private double DOUBLE = 10.0d;
private float FLOAT = 10.0f;
}

/**
* A class having wrapper classes for holding numeric values.
*/
@SuppressWarnings("unused")
public class WrapperNumbers {
private Short SHORT = new Short((short) 10);
private Integer INT = new Integer(10);
private Long LONG = new Long(10l);
private Float FLOAT = new Float(10.0f);
private Double DOUBLE = new Double(10.0d);
}

/**
* Simple class to measure time.
*/
static class StopWatch {
private long start;
private long stop;

public StopWatch() {
start();
}

/** Starts timer */
public final void start() {
this.start = System.currentTimeMillis();
this.stop = 0;
}

/** Stops timer */
public void stop() {
this.stop = System.currentTimeMillis();
}

/** Returns time taken in seconds */
public double time() {
return (stop - start) / 1000.0;
}
}
}
A test run for creating 1 million objects of the class having primitives consumed 52MB of RAM while class having wrappers consumed a whooping 111MB, which is more then twice over the primitives.

Memory (MB)

Creation of 1 million objects of the class having primitives took 0.77 seconds while class having wrappers took 2.64 seconds, which is around 3.5 times over the primitives.

Time (seconds)

If one looks at the comparative results and calculates it in percentage terms then obviously choice will be primitives. If we think deeply then using wrappers may make sense, if there is a requirement. Think does your application will ever need 1 million objects in memory at the same time or do you need to create 1 million objects within couple of seconds only? If this is not the case then use the wrappers without worrying much about the performance cost.