Showing posts with label Axis2. Show all posts
Showing posts with label Axis2. Show all posts

Saturday, January 11, 2014

Test your Axis2 service without deploy in server

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.

/**
 * 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. :)