Tuesday 12 July 2016

Loading jars from Lib folder for standalone Jar execution


Loading Jars While Booting of application from separate external folder 

I have faced an issue with dynamic jars loading to start the service without giving any classpath in MANIFEST file inside jar file.

I have spent lot much time on this to get on to the solution, but no luck. I found some info on stackoverflow pertaining to this. I wanna share that with you today with slight modifications make use as simple jar file.

Here is the simple class I wrote and also created a simple jar file for direct usage.

Here is the Reference for source code url.

You can also download direct jar file from above URL under "dist"  directory.


Sample Class::


package com.rnd.java.bootup;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

import org.apache.commons.io.FileUtils;

public class Bootup 
{
 public void run(String[] args) throws Exception 
 {
  
  List jars  =  (List) FileUtils.listFiles(new File(args[1]), null, true);
  URL urls[] =  FileUtils.toURLs(jars.toArray(new File[jars.size()]));
  
  for (int i = 0; i < urls.length; i++) 
  {
   loadMe(urls[i]);
   System.out.println(urls[i]);
  }
  
  Object[] arguments = new Object[]{args};
  Class classToLoad = Class.forName(args[0]);
  Method method = classToLoad.getMethod("main",String[].class);
  Object result = method.invoke (null,arguments);
  System.out.println(result);
 }
 
 
 private void loadMe(URL url) {
  try {
      
      URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
      Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
      method.setAccessible(true);
      method.invoke(classLoader, url);
  } catch (Exception ex) {
      ex.printStackTrace();
  }

 }
 
 
 /**
  * How to use ?
  * java -jar bootup.jar com.company.application.mainclass lib main 
  * 
  * 
  * @param args
  */
 public static void main(String[] args) 
 {
  if(args.length==0)
  {
   StringBuilder help = new StringBuilder();
   help.append("Usage !!! \n java -jar bootup.jar fullyQualifiedClassName libFolderName method2Call ");
   System.out.println(help.toString());
   throw new IllegalArgumentException("Wrong number of arguments!!!!");
  }else if(args.length==1)
  {
   args = new String[]{args[0],"lib","main"};
  }else if(args.length==2)
  {
   args = new String[]{args[0],args[1],"main"};
  }
  try{
   new Bootup().run(args);
  
  }catch(Exception e)
  {
   e.printStackTrace();
  }
 }

}



Tuesday 5 July 2016

Mocking Http Server in Java for Integration Testing

If you want to create a mock Http server for integration testing to mock external URLS/Servers. Here is the solution for java.

I have gone through the all options like WireMock, nanoHttpd,Mock-Server,LightWeightServer…etc but not full fill my requirements and not easy to use for my use case.

I created my own solution for this problem and of course inspired from other blogs to get into this .

First use  Dependencies:

testCompile group: 'org.mortbay.jetty', name: 'jetty', version: '7.0.0.pre5'
compile 'commons-io:commons-io:2.5'

Mortbay Jetty will do simple and nice job here.

If you’re working with webserver clients you will certainly have noticed the difficulty in integration-testing your webserver clients. Building webserver clients can already be quite a complex task, but providing a mock-up webservice backend delivering useful test responses is quite often just to much work, if not impossible, since many web server backends are very complex constructs. Furthermore, setting up a backend for each integration test consumes valuable build time.
As an alternative, one may simply replace the backend with a mock HTTP server that does one thing: deliver the expected webserver response – i.e. XML data – when called by the client. All you need to set this up is a HTTP server and a pre-recorded service response (quite often this comes with WS client specifications). If you don’t have this data, you can record it, for example using a proxy server in between your WS client and a real WS backend, or a tool such as wireshark.

The recorded XML response thus represents your assumptions against which you test the client. This makes your tests fast, lightweight and a lot better to understand.

Server Code Here

package com.java.testing.httpclient;

import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.apache.commons.io.IOUtils.write;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.http.entity.ContentType;
import org.junit.Ignore;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;

import com.touchpeak.restclient.util.NullUtil;

/**
 * Used for Mocking Http Server
 * 
 * @author Kumar
 *
 */
@Ignore
public class MockHttpTestServer {

 private int HTTP_PORT = 55556;
 private Server _server;
 private String _responseBody;
 private String _requestBody;
 private String _mockResponseData;
 private Integer _mockResponseStatus;
 private String _mockResponseContentType;
 private String _requestPath;
 private String _requestMethod;
 private Map requestedQueryParams = new HashMap<>();

 public MockHttpTestServer() {
 }

 public MockHttpTestServer(int port) {
  HTTP_PORT = port;
 }

 public MockHttpTestServer(String mockData) {
  setMockResponseData(mockData);
 }

 public void start() throws Exception {
  configureServer();
  startServer();
 }

 private void startServer() throws Exception {
  _server.start();
 }

 protected void configureServer() {
  _server = new Server(HTTP_PORT);
  _server.setHandler(getMockHandler());
 }

 /**
  * Creates an {@link AbstractHandler handler} returning an arbitrary String
  * as a response.
  * 
  * @return never null.
  */
 public Handler getMockHandler() {
  Handler handler = new AbstractHandler() {

   public void handle(String target, HttpServletRequest request,
     HttpServletResponse response, int dispatch)
     throws IOException, ServletException {

    cleanInMemory();
    Request baseRequest = request instanceof Request ? (Request) request
      : HttpConnection.getCurrentConnection().getRequest();
    setRequestMethod(baseRequest.getMethod());
    setRequestPath(baseRequest.getUri().getPath());
    setResponseBody(getMockResponseData());
    setRequestBody(IOUtils.toString(baseRequest.getInputStream(),
      "UTF-8"));
    response.setStatus(getMockResponseStatus());
    response.setContentType(getMockResponseContentType() != null ? getMockResponseContentType()
      : "text/plain");
    write(getResponseBody(), response.getOutputStream(), "UTF-8");
    baseRequest.setHandled(true);
   }
  };
  return handler;
 }

 protected void cleanInMemory() {

  setRequestBody("");
  setRequestPath("");

 }

 public void stop() throws Exception {
  _server.stop();
 }

 public void setResponseBody(String responseBody) {
  _responseBody = responseBody;
 }

 public String getResponseBody() {
  return _responseBody;
 }

 public void setRequestBody(String requestBody) {
  _requestBody = requestBody;
 }

 public String getRequestBody() {
  return _requestBody;
 }

 public static void main(String[] args) {
  MockHttpTestServer server = new MockHttpTestServer();
  try {
   server.start();
  } catch (Exception e) {
   throw new RuntimeException(e);
  }
 }

 public void setMockResponseData(String mockResponseData) {
  _mockResponseData = mockResponseData;
 }

 public String getMockResponseData() {
  return _mockResponseData;
 }

 protected Server getServer() {
  return _server;
 }

 public Map getRequestedQueryParams() {
  return requestedQueryParams;
 }

 public String getRequestPath() {
  return _requestPath;
 }

 public String getMockResponseContentType() {
  return _mockResponseContentType;
 }

 public void setMockResponseContentType(String _mockResponseContentType) {
  this._mockResponseContentType = _mockResponseContentType;
 }

 public Integer getMockResponseStatus() {
  return NullUtil.isNullOrEmpty(_mockResponseStatus) ? SC_OK
    : _mockResponseStatus;
 }

 public void setMockResponseStatus(Integer _mockResponseStatus) {
  this._mockResponseStatus = _mockResponseStatus;
 }

 public void setRequestPath(String _requestPath) {
  this._requestPath = _requestPath;
 }

 public String getRequestMethod() {
  return _requestMethod;
 }

 public void setRequestMethod(String _requestMethod) {
  this._requestMethod = _requestMethod;
 }
}

Client Code Here
package com.java.testing.httpclient;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.touchpeak.restclient.test.MockHttpTestServer;

public class HttpClientTests {

 
 private static final Logger logger = LoggerFactory
   .getLogger(HttpClientTests.class);
 
 private MockHttpTestServer server;

 private String HOST = "127.0.0.1";
 private int PORT =56342;
 private String TEST_BASE_URI = "http://"+HOST+":"+PORT;
 
 @Before
 public  void init() 
 {
  server = new MockHttpTestServer(PORT);
  try {
   server.start();
  } catch (Exception e) {
   logger.error(" While starting Mock Http Server ",e);
  }
 }
 
 
 @After
 public void close() 
 {
  try {
   server.stop();
  } catch (Exception e) {
   logger.error(" While stopping Mock Http Server ",e);
  }
 }

 
 @Test
 public void test_Server_Call() 
 {
  String mockResponse = "Mock Response you expect from server";
  String mockRequestBody ="RequestBody Sent to server from client"; 
  server.setMockResponseData(mockResponse);
  
  //Server will return above expected responses to client call.
  String actualResponse = " write client code here to call server and get the response from server call";
  
  assertEquals("GET", server.getRequestMethod());//Check HTTP METHOD here
  assertEquals("/order/3?area=LONDON", server.getRequestPath());// Check Request URI
  assertEquals(mockRequestBody, server.getRequestBody());//Check RequestBody received by Server
  assertEquals(mockResponse, actualResponse);//check Response from server
  
  
 }

}
Tips: 1. you can also add Listeners to Server class to get control back on client side while executing.