Hi All,
This is a topic that I tried out during last two days and finally I was able to find a proper mechanism to do it. During these days I'm under a training and I assigned some exercise to complete. So the one exercise is to study the Axis2 and write service and client. I wrote a service and generate the .aar by maven plugin axis2-aar-maven-plugin and deploy it in a WSO2 application server. It support to deploy the .aar file.
Add following dependencies to pom.xml
Add axis2-aar-maven-plugin under <plugins></plugins>
So the next step is to create a client to test the service. This also can done with axis2-wsdl2code-maven-plugin easily. This will generate call back handler and service stub.
Using service stub directly is not a good practice. Therefore I wrote a wrapper class to call the stub methods. This makes directly call the service method and get the result.
Then I wrote a test class to test the web service through client. But to do all these, the prerequisite is the service must be up and running. :) The problem is each and every time when I build the project service must be available otherwise test cases fails. :( I can skip the test case and build the project but it's not the proper way to do it.
So what I want is find out is the way to dynamically create the axis2 service. Axis2 has rich set of features. I found that it's possible to programmatically create and deploy the service by providing the service class.
Note that I have to do some changes in generated stub (OrderServiceStub) to execute test due to namespace issue with programmatically deploy service. You can write a client inside the test method and test the service method. :)
You don't need to use mockup framework for testing. You can easily test your web services as they real time deploy in the server. :)
/**
* Order model class
*/
public class Order {
private Integer orderNumber;
private String customerName;
private Date orderDate;
public Integer getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(Integer orderNumber) {
this.orderNumber = orderNumber;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
}
/**
* OrderService used to handle order process
*/
public interface OrderService {
/**
* Add order to process
*
* @param order {@link org.wso2.axis.model.Order} object which contains order details
* @return message to the user
*/
String addOrder(Order order);
/**
* Get order details by order number
*
* @param orderNumber order number to get order details
* @return {@link org.wso2.axis.model.Order} object which contains order details
*/
Order getOrderByOrderNumber(Integer orderNumber);
/**
* Get all oder details
*
* @return List of {@link org.wso2.axis.model.Order} objects which contains order details
*/
List<Order> getAllOderDetails();
}
/**
* Implementation of {@link org.wso2.axis.service.OrderService}
*/
public class OrderServiceImpl implements OrderService {
private static List<Order> orderList = new ArrayList<Order>();
/**
* Add order to process
*
* @param order {@link org.wso2.axis.model.Order} object which contains order details
* @return message to the user
*/
@Override
public String addOrder(Order order) {
String message = null;
if(OrderValidator.validateOrder(order)){
orderList.add(order);
message = "Order added successfully. ["+order.getOrderNumber()+", "+order.getOrderDate()+", "+order.getCustomerName()+"]";
} else {
message = "Order not added. Please check your data.";
}
return message;
}
/**
* Get order details by order number
*
* @param orderNumber order number to get order details
* @return {@link org.wso2.axis.model.Order} object which contains order details
*/
@Override
public Order getOrderByOrderNumber(Integer orderNumber) {
Order orderFound = null;
if(orderNumber != null){
for (Order order : orderList) {
if(order.getOrderNumber().equals(orderNumber)){
orderFound = order;
}
}
}
return orderFound;
}
/**
* Get all oder details
*
* @return List of {@link org.wso2.axis.model.Order} objects which contains order details
*/
@Override
public List<Order> getAllOderDetails() {
return orderList;
}
}
/**
* Validate order object
*/
public class OrderValidator {
public static boolean validateOrder(Order order) {
boolean validate = false;
if (order != null) {
if (order.getOrderNumber() != null && order.getCustomerName() != null &&
order.getOrderDate() != null) {
validate = true;
}
}
return validate;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<service name="OrderService" targetNamespace="http://service.axis.wso2.org">
<schema schemaNamespace="http://service.axis.wso2.org"/>
<description>Order web service</description>
<!--compulsory parameter-->
<parameter name="ServiceClass" locked="false">org.wso2.axis.service.impl.OrderServiceImpl</parameter>
<!--common message receivers-->
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
<!--addOder operation-->
<operation name="addOrder" namespace="http://service.axis.wso2.org">
<actionMapping>urn:addOrder</actionMapping>
</operation>
<!--getOrderByOrderNumber operation-->
<operation name="getOrderByOrderNumber" namespace="http://service.axis.wso2.org">
<actionMapping>urn:getOrderByOrderNumber</actionMapping>
</operation>
<!--getAllOderDetails operation-->
<operation name="getAllOderDetails" namespace="http://service.axis.wso2.org">
<actionMapping>urn:getAllOderDetails</actionMapping>
</operation>
</service>
Add following dependencies to pom.xml
<dependency>
<groupId>training.exercise</groupId>
<artifactId>exercise-utils</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-adb</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-local</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-xmlbeans</artifactId>
<version>1.6.1</version>
</dependency>
Add axis2-aar-maven-plugin under <plugins></plugins>
<!--Axis Archive generate plugin-->
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-aar-maven-plugin</artifactId>
<version>${axis2.version}</version>
<configuration>
<aarName>OrderService</aarName>
<servicesXmlFile>${basedir}/src/main/resources/META-INF/services.xml</servicesXmlFile>
<includeDependencies>false</includeDependencies>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>aar</goal>
</goals>
</execution>
</executions>
</plugin>
So the next step is to create a client to test the service. This also can done with axis2-wsdl2code-maven-plugin easily. This will generate call back handler and service stub.
<!--Axis client generate plugin-->
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-wsdl2code-maven-plugin</artifactId>
<version>${axis2.version}</version>
<executions>
<execution>
<goals>
<goal>wsdl2code</goal>
</goals>
<configuration>
<wsdlFile>${basedir}/src/main/resources/wsdl/OrderService.wsdl</wsdlFile>
<databindingName>adb</databindingName>
<packageName>org.wso2.axis.stub</packageName>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<flattenFiles>true</flattenFiles>
</configuration>
</execution>
</executions>
</plugin>
/**
* OrderServiceCallbackHandler Callback class, Users can extend this class and
* implement
* their own receiveResult and receiveError methods.
*/
public abstract class OrderServiceCallbackHandler {
/*
* OrderServiceStub java implementation
*/
public class OrderServiceStub extends org.apache.axis2.client.Stub {
Using service stub directly is not a good practice. Therefore I wrote a wrapper class to call the stub methods. This makes directly call the service method and get the result.
/**
* Wrapper class to call the {@see org.wso2.axis.stub.OrderServiceStub}
*/
public class OrderServiceClient {
private static final Logger logger = LoggerFactory.getLogger(OrderServiceClient.class);
private String endPoint;
public OrderServiceClient(String endPoint) {
this.endPoint = endPoint;
}
/**
* call the addOrder web service method
*
* @param order {@see Order} object which contains data
* @return result message
*/
public String addOrder(Order order){
String result = null;
try {
//instantiate OrderServiceStub
OrderServiceStub orderServiceStub = getOrderServiceStub();
//instantiate AddOrder
OrderServiceStub.AddOrder addOrder = new OrderServiceStub.AddOrder();
//instantiate Order
OrderServiceStub.Order order1 = new OrderServiceStub.Order();
//Marshalling data
order1.setCustomerName(order.getCustomerName());
order1.setOrderDate(order.getOrderDate());
order1.setOrderNumber(order.getOrderNumber());
addOrder.setOrder(order1);
//call addOrder
OrderServiceStub.AddOrderResponse addOrderResponse = orderServiceStub.addOrder(addOrder);
result = addOrderResponse.get_return();
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
logger.error("Exception occurred in Service End Point", axisFault);
} catch (RemoteException e) {
e.printStackTrace();
logger.error("Exception occurred in calling service", e);
}
return result;
}
/**
* call the getOrderByOrderNumber web service method
*
* @param orderNumber order number of given order
* @return {@see Order} object which contains data
*/
public Order getOrderByOrderNumber(Integer orderNumber){
Order order = new Order();
try {
//instantiate OrderServiceStub
OrderServiceStub orderServiceStub = getOrderServiceStub();
//instantiate GetOrderByOrderNumber
OrderServiceStub.GetOrderByOrderNumber getOrderByOrderNumber = new OrderServiceStub.GetOrderByOrderNumber();
//set order number
getOrderByOrderNumber.setOrderNumber(orderNumber);
//call getOrderByOrderNumber
OrderServiceStub.GetOrderByOrderNumberResponse orderByOrderNumber =
orderServiceStub.getOrderByOrderNumber(getOrderByOrderNumber);
OrderServiceStub.Order order1 = orderByOrderNumber.get_return();
//Unmarshalling order
order.setOrderNumber(order1.getOrderNumber());
order.setOrderDate(order1.getOrderDate());
order.setCustomerName(order1.getCustomerName());
} catch (AxisFault axisFault) {
logger.error("Exception occurred in Service End Point", axisFault);
} catch (RemoteException e) {
logger.error("Exception occurred in calling service", e);
}
return order;
}
/**
* call the getAllOrderDetails web service method
*
* @return
*/
public List<Order> getAllOderDetails() {
List<Order> orderList = new ArrayList<Order>();
try {
//instantiate OrderServiceStub
OrderServiceStub orderServiceStub = getOrderServiceStub();
//instantiate GetAllOrderDetails
OrderServiceStub.GetAllOderDetails getAllOderDetails = new OrderServiceStub.GetAllOderDetails();
//call getAllOrderDetails
OrderServiceStub.GetAllOderDetailsResponse allOderDetails =
orderServiceStub.getAllOderDetails(getAllOderDetails);
//unmarshalling order
OrderServiceStub.Order[] orders = allOderDetails.get_return();
for (OrderServiceStub.Order order : orders) {
Order order1 = new Order();
order1.setOrderNumber(order.getOrderNumber());
order1.setOrderDate(order.getOrderDate());
order1.setCustomerName(order.getCustomerName());
orderList.add(order1);
}
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
logger.error("Exception occurred in Service End Point", axisFault);
} catch (RemoteException e) {
e.printStackTrace();
logger.error("Exception occurred in calling service", e);
}
return orderList;
}
/**
* OrderServiceStub factory method
*
* @return {@see OrderServiceStub} object
* @throws AxisFault
*/
private OrderServiceStub getOrderServiceStub() throws AxisFault {
return new OrderServiceStub(endPoint);
}
}
Then I wrote a test class to test the web service through client. But to do all these, the prerequisite is the service must be up and running. :) The problem is each and every time when I build the project service must be available otherwise test cases fails. :( I can skip the test case and build the project but it's not the proper way to do it.
/**
* Test class for OrderServiceClient
*
*/
public class OrderServiceClientTest {
public static final String ORDER_SERVICE_END_POINT="http://as.wso2.org:9763/services/OrderService?wsdl";
@Test
public void testAddOrder() {
OrderServiceClient orderServiceClient = getOrderServiceClient();
Order order = createOrder(1, new Date(), "Indika Sampath");
String result = orderServiceClient.addOrder(order);
Assert.assertNotNull(result);
System.out.println(result);
}
/**
* OrderServiceClient factory method
*
* @return
*/
private OrderServiceClient getOrderServiceClient() {
return new OrderServiceClient(ORDER_SERVICE_END_POINT);
}
/**
* Order factory method
*
* @param orderNumber
* @param orderDate
* @param customerName
* @return
*/
private Order createOrder(Integer orderNumber, Date orderDate, String customerName) {
Order order = new Order();
order.setOrderNumber(orderNumber);
order.setOrderDate(orderDate);
order.setCustomerName(customerName);
return order;
}
}
So what I want is find out is the way to dynamically create the axis2 service. Axis2 has rich set of features. I found that it's possible to programmatically create and deploy the service by providing the service class.
/**
* Test class for OrderServiceClient
*
*/
public class OrderServiceClientTest implements ServiceObjectSupplier {
private OrderService orderService = new OrderServiceImpl();
private static int port = RemoteUtil.findFreePort();
private AxisServer server = new AxisServer();
@BeforeClass(alwaysRun = true)
public void setUp() throws Exception {
setupAxisServer(OrderService.class.getName(), OrderServiceClientTest.class.getName());
}
@AfterClass
public void tearDown() throws Exception {
server.stop();
}
@Test
public void testAddOrder() {
OrderServiceClient orderServiceClient = getOrderServiceClient();
Order order = createOrder(1, new Date(), "Indika Sampath");
String result = orderServiceClient.addOrder(order);
Assert.assertNotNull(result);
System.out.println(result);
}
/**
* OrderServiceClient factory method
*
* @return
*/
private OrderServiceClient getOrderServiceClient() {
return new OrderServiceClient("http://localhost:" + port +
"/axis2/services/OrderService");
}
/**
* Order factory method
*
* @param orderNumber
* @param orderDate
* @param customerName
* @return
*/
private Order createOrder(Integer orderNumber, Date orderDate, String customerName) {
Order order = new Order();
order.setOrderNumber(orderNumber);
order.setOrderDate(orderDate);
order.setCustomerName(customerName);
return order;
}
/**
* Setup and start Axis-Server.
*
* @param serviceClassName
* @throws org.apache.axis2.AxisFault
*/
private void setupAxisServer(String serviceClassName, String serviceObjectSupplierClassName)
throws AxisFault,
IllegalAccessException,
InstantiationException {
// Setup the custom port
Map<String, TransportInDescription> transports =
server.getConfigurationContext()
.getAxisConfiguration()
.getTransportsIn();
for (Map.Entry<String, TransportInDescription> objectEntry : transports.entrySet()) {
TransportInDescription desc = objectEntry.getValue();
Parameter param = desc.getParameter("port");
param.setValue(Integer.toString(port));
}
server.getConfigurationContext().getAxisConfiguration()
.addParameter(Constants.SERVICE_OBJECT_SUPPLIER, serviceObjectSupplierClassName);
//deploy OrderService
server.deployService(serviceClassName);
}
/**
* Callback-Method to retrieve the Service
*
* @param theService
* @return Object
*/
public Object getServiceObject(AxisService theService) {
String service = theService.getName();
if (service.equals("OrderService")) {
return orderService;
}
return null;
}
}
Note that I have to do some changes in generated stub (OrderServiceStub) to execute test due to namespace issue with programmatically deploy service. You can write a client inside the test method and test the service method. :)
@Test
public void testGetOrderByOrderNumber() throws AxisFault {
RPCServiceClient serviceClient = getRpcServiceClient();
QName operationName = new QName("http://service.axis.wso2.org", "addOrder");
Order order = createOrder(1, new Date(), "Indika Sampath");
Object[] operationArguments = new Object[] { order };
Class[] returnTypes = new Class[] { String.class };
Object[] response =
serviceClient.invokeBlocking(operationName, operationArguments,
returnTypes);
String result = (String) response[0];
Assert.assertNotNull(result);
System.out.println(result);
/*OrderServiceClient orderServiceClient = getOrderServiceClient();
Order order = createOrder(1, new Date(), "Indika Sampath");
String result = orderServiceClient.addOrder(order);
Assert.assertNotNull(result);
System.out.println(result);*/
}
/**
* Axis2 Client stuff
*
* @return
* @throws org.apache.axis2.AxisFault
*/
private RPCServiceClient getRpcServiceClient() throws AxisFault {
RPCServiceClient serviceClient = new RPCServiceClient();
Options options = serviceClient.getOptions();
EndpointReference targetEPR =
new EndpointReference("http://localhost:" + port +
"/axis2/services/OrderService");
options.setTo(targetEPR);
return serviceClient;
}
You don't need to use mockup framework for testing. You can easily test your web services as they real time deploy in the server. :)
No comments:
Post a Comment