Archive

Archive for the ‘JAXB’ Category

JAX-WS Using WebLogic 10.3

October 9th, 2010 1 comment

The Java API for XML Web Services or JAX-WS provides a simple, easy to understand architecture for developing and deploying web services. In this post I will be creating a simple Task List CRUD application that showcases the JAX WS technology. I will be using Eclipse IDE for development and WebLogic 10.3.0 for deployment. Weblogic 10.3.0 supports Java EE 5 specification and implements JSR109. Therefore it does not require any additional jars or configuration such as jax-ws.xml file for running web services.

Here are the requirements for the Task List application:

  • The application should allow new tasks to be created
  • Tasks can be updated, queried and deleted
  • Tasks can be associated with a one or more tags

To keep this blog post manageable, I will not be storing the tasks in to a persistent store such as a database. I am also not going to worry about concerns such as authentication and security. We will start the implementation with the domain model which consists of Task and Tag objects. The figure below gives the UML representation of the domain model.

One To Many Relationship B/N Task and Tag

And here is the associated Java code for the two classes:

	package com.inflinx.blog.taskservice.domain;
	
	import java.util.ArrayList;
	import java.util.List;
	
	public class Task {
		
		private String id;
		private String name;
		private String notes;
		private List<Tag> tags = new ArrayList<Tag>();
	
		public String getId() {
			return id;
		}
		public void setId(String id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getNotes() {
			return notes;
		}
		public void setNotes(String notes) {
			this.notes = notes;
		}
		public List<Tag> getTags() {
			return tags;
		}
		public void setTags(List<Tag> tags) {
			this.tags = tags;
		}
	}
	package com.inflinx.blog.taskservice.domain;
	
	public class Tag {
		private String id;
		private String name;
	
		public String getId() {
			return id;
		}
		public void setId(String id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
	}

The next step is to create a Web Service class that would service the client’s requests for creating new tasks or updating, removing and querying existing tasks. Here I am taking a Java to WSDL approach where we start with the Java code and let the tools generate WSDL and related schemas at runtime. Web Service classes in JAX WS are simple pojos and use annotations for providing meta data to the container. Here is the starting point of our web service class:

	package com.inflinx.blog.taskservice.service;
	
	import javax.jws.WebService;
	
	@WebService(serviceName="service", targetNamespace="ns.blog.inflinx.com")
	public class TaskManager {
		
		
	}

The @WebService annotation, part of the javax.jws package, indicates that we are building a JAX WS based web service. The targetNamespace attribute assigns a name space to the service defined. If the targetNameSpace is not used, then the reverse package name will be used. The serviceName defines the URL of the deployed service. In this case, the URL to access the service would be: http://locahost:7001/taskservice/service?wsdl The associated XSD can be found at: http://localhost:7001/taskservice/service?xsd=1. If we would like to expose the service under a different URL, say http://localhost:7001/taskservice/api/service we just need to change the serviceName to “api/service”.

Since we will not be using a database to persist tasks, I have added two Maps to hold submitted task and tag data. These maps are initialized with dummy data in the web service constructor as shown in the code below.


	public class TaskManager {
		
		private static Map<String, Task> TASK_DATA = new HashMap<String, Task>();
		private static Map<String, Tag> TAG_DATA = new HashMap<String, Tag>();
		
		public TaskManager() {
			
			TAG_DATA.put("1", new Tag("1", "Web Service"));
			TAG_DATA.put("2", new Tag("2", "Flex"));
			TAG_DATA.put("3", new Tag("3", "Spring"));
			
			Task task = new Task("1", "Write Blog on JAX WS", "This will be part 1");
			List<Tag> tagList = new ArrayList<Tag>();
			tagList.add(TAG_DATA.get("1"));
			task.setTags(tagList);
			TASK_DATA.put("1", task);
			
			Task task2 = new Task("2", "Write Blog on Flex", "This will be a future post");
			List<Tag> tagList2 = new ArrayList<Tag>();
			tagList2.add(TAG_DATA.get("2"));
			task2.setTags(tagList2);
			TASK_DATA.put("2", task2);
		}
	}	

The next step is to add operations to the web service. Here is a simple delete operation with JAX WS annotations.

@WebMethod
public void delete(@WebParam(name="taskId") String taskId) {
	TASK_DATA.remove(taskId);		
}

The @WebMethod annotation is used to indicate a web service operation. The @WebParam is used to provide additional information about the parameters for the generated service. If a name is not specified, then the parameters in the Schema will be named as arg0, arg1 etc. Currently JAX WS does not provide a way to mark a parameter as required. It is not required to annotate web service operations with @WebMethod annotation. However, if you choose to annotate one, then you should annotate all the operations that needs to be exposed as part of the service.

Before we move further, we need to indicate how Java Task objects should be marshalled to XML. In order to do this, we will be using the Java Architecture for XML Binding or JAXB. JAXB provides a convenient model for marshalling Java objects into XML and unmarshalling XML back into Java Objects. The JAXB API constitutes a set of annotations that
enable mapping between Java classes and their XML representations. The table below lists the commonly used JAXB annotations along with their descriptions:

XmlRootElement This annotation indicates a class to be used as a root element in the generated XML document. If the name attribute is not specified then JAXB would automatically use the class name with first letter lowercased as the root element name.
XmlType This annotation can be used to provide additional information for generating the XML schema. For example the propOrder attribute can be used to indicate the order of the child elements in the marshalled document
XmlAccessorType This annotation can be used to control the data that gets serialized. For example, XmlAccessType.FIELD indicates that all non static, non transient fields of a class to be marshalled.
XmlElement This annotation is used to map a JavaBean property to an XML element.
XmlAttribute This annotation is used to map a JavaBean property to an XML attribute.
XmlElementWrapper This annotation can be used to create a wrapper around generated XML for a particular element.

Here are the modified Task and Tag Java classes that uses the above JAXB annotations.

	package com.inflinx.blog.taskservice.domain;
	
	import java.util.ArrayList;
	import java.util.List;
	
	import javax.xml.bind.annotation.XmlAccessType;
	import javax.xml.bind.annotation.XmlAccessorType;
	import javax.xml.bind.annotation.XmlElement;
	import javax.xml.bind.annotation.XmlElementWrapper;
	import javax.xml.bind.annotation.XmlRootElement;
	import javax.xml.bind.annotation.XmlType;

	@XmlAccessorType(XmlAccessType.FIELD)
	@XmlType(name="", propOrder={"id", "name", "notes", "tags"})
	@XmlRootElement(name = "task")
	public class Task {
		
		@XmlElement(required=true)
		private String id;
		
		@XmlElement(required=true)
		private String name;
		
		@XmlElement(required=false)
		private String notes;
		
		@XmlElementWrapper(name="tags", required=false)
		@XmlElement(required=false, name="tag")
		private List<Tag> tags = new ArrayList<Tag>();
		
		// Getters and Setters
		
	}
	package com.inflinx.blog.taskservice.domain;
	
	import javax.xml.bind.annotation.XmlAccessType;
	import javax.xml.bind.annotation.XmlAccessorType;
	import javax.xml.bind.annotation.XmlElement;
	import javax.xml.bind.annotation.XmlRootElement;
	import javax.xml.bind.annotation.XmlType;
	
	@XmlAccessorType(XmlAccessType.FIELD)
	@XmlType(name="", propOrder={"id", "name"})
	@XmlRootElement(name = "tag")
	public class Tag {
		
		@XmlElement(required=true)	
		private String id;
		
		@XmlElement(required=true)
		private String name;
		
		// Getters and setters
	}
	

Finally, here is the rest of the web service implementation.

		@WebMethod	
		public Task findTask(@WebParam(name="taskId") String id) {
					return TASK_DATA.get(id);
		}
		
		@WebMethod
		public @WebResult(name="task") Task[] findAll() {
				return TASK_DATA.values().toArray(new Task[0]);
		}	
		
		@WebMethod
		public void create(@WebParam(name="task") Task task) {
			TASK_DATA.put(task.getId(), task);
		}
			
		@WebMethod
		public void update(@WebParam(name="task") Task task) {
			TASK_DATA.put(task.getId(), task);
		}
			
		@WebMethod
		public void delete(@WebParam(name="taskId") String taskId) {
			TASK_DATA.remove(taskId);
		}

That is all it takes to create a JAX WS web service. Once the web service is deployed to the WebLogic server, you can test it using tools like SoapUI.

Categories: JAX WS, JAXB Tags: ,