Saturday, December 20, 2014

JNDI Lookup in Spring Boot

I started using spring boot since last year and pleased with it so far. In this article I want to talk about one common issue that you may run into and that is configuring JDNI resource. Well configuring JNDI in spring boot application and running it in external tomcat is a piece of cake. But if you are wondering how to configure JNDI resource so that you could run your app in external tomcat, embedded tomcat and even integration tests against same configuration, then here is how.
External Tomcat
Let’s look at the easier one first and that is configuring your external tomcat.

If you are planning on sharing resources across many applications deployed into same tomcat then you would configure global naming resources in server.xml like below,


<Resource auth="Container" 
 driverClassName="Your DB driver class name" 
 global=" jdbc/DB_Name " 
 maxActive="20" maxIdle="0" maxWait="10000" 
 name="jdbc/DB_Name" 
 username="dbuser"
 password="password" 
 type="javax.sql.DataSource" 
 url="Your connection URL" />


Since this is a global resource you would require defining a resource link in the context.xml like below,


<ResourceLink name=" jdbc/DB_Name "
                global=" jdbc/DB_Name”
                auth="Container"
                type="javax.sql.DataSource" />



At this point if you restart your tomcat this resource should be registered and ready to look up through your application using the name in resource link configuration.

In your application’s application.properties add this line

spring.datasource.jndi-name=java:comp/env/jdbc/DB_Name



Spring boot will take care of looking up and loading the datasource automagically for you. Now you can define a bean JdbcTemplate or NamedJdbcTemplate in your application’s ServletIntializer class like below but again this is optional.


@Bean
JdbcTemplate jdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(
                dataSource);

        return jdbcTemplate;
}

@Bean
NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(
                dataSource);

        return namedParameterJdbcTemplate;
}

Now in your Repository class simply autowire it,


@Autowired
private JdbcTemplate jdbcTemplate;

Technically you are done configuring jndi resource for your application.

 Embedded Tomcat
Now you want to have the same resource configured within the embedded tomcat so that you can run the app with in the embedded server.

In your application’s application.properties add these lines,


connection.url=jdbc://localhost:port/dbname
connection.username=user
connection.password=password
connection.driverClassName=Driver Class Name
connection.jndiName=jdbc/DB_Name


In your ServletIntialzer class you will have to define a bean TomcatEmbeddedServletContainerFactory and instantiate it. First thing to do is to enable the naming service in embedded server which is turned off by default. Second override postProcessContext method to create ContextResource, add it to the catalina context. The resource name will be added to java:comp/env context.


@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
        return new TomcatEmbeddedServletContainerFactory() {

            @Override
            protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
                    Tomcat tomcat) {
                tomcat.enableNaming();
                return super.getTomcatEmbeddedServletContainer(tomcat);
            }

            @Override
            protected void postProcessContext(Context context) {
                ContextResource resource = new ContextResource();
                resource.setName(connectionJndiName);
                resource.setType(DataSource.class.getName());
                resource.setProperty("driverClassName",
                        connectionDriverClassName);
                resource.setProperty("url", connectionURL);
                resource.setProperty("password", connectionPassword);
                resource.setProperty("username", connectionUserName);

                context.getNamingResources().addResource(resource);
            }
        };
}


Now you can define one more bean to create DataSource by looking up the resource that you just registered using the Jndi name. The complete jndi name to look up “java:comp/env/jdbc/DB_Name”


@Bean(destroyMethod = "")
    public DataSource jndiDataSource() throws IllegalArgumentException,
            NamingException {
        JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
        bean.setJndiName(jndiLookupName);
        bean.setProxyInterface(DataSource.class);
        bean.setLookupOnStartup(false);
        bean.afterPropertiesSet();
        return (DataSource) bean.getObject();
    }



Now run your Application class, JdbcTemplate should be autowired in your Repository class and ready to execute queries.

Integration Tests for Repository
I do not believe in writing unit tests for Dao/Repository classes with or without mocking framework. It doesn’t make sense to write these tests just for the sake of writing test cases but what makes sense is to write integration tests. Again writing integration tests with some in memory databases doesn’t make whole lot of sense either as you will run into issues using some in built functionalities of your real database. It could simply be a nightmare if there are differences in functionalities supported in your real database vs in memory database. So I would write my integration tests against real database. As long as they are transactional and wipe out the data at the end.
Here’s how you could do that,
Spring provides a simple implementation of a JNDI naming context builder class SimpleNamingContextBuilder that helps to bind a JDBC DataSource to a JNDI location that can be exposed through initialContext().
Take a look at the class below,


public class JndiDatasourceCreator {
    private static final Logger LOGGER = Logger
     .getLogger(JndiDatasourceCreator.class);
    
    private static final String username = "userName";
    private static final String password = "password";
    private static final String jndiName = "DB_Name";
    private static final String driverClassName="Driver Name";
    private static final String url="jdbc://localhost:port/dbName";
    public static BasicDataSource dataSource;
    
    public static void create() throws Exception {
 try {
     final SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
     dataSource = new BasicDataSource();
     dataSource.setUsername(username);
     dataSource.setPassword(password);
     dataSource.setDriverClassName(driverClassName);
     dataSource.setUrl(url);
     builder.bind("java:comp/env/jdbc/" + jndiName, dataSource);
     builder.activate();
 } catch (NamingException ex) {
     LOGGER.info(ex.getMessage());
 }
    }
}

You could use Apache's Commons DBCP’s BasicDataSource to use a real pool and make sure it is static so that it’s setup one time.
Now you could write test case for your Dao like below,


@Autowired
private UserRepository userRepository;

@Before
public void setUp() throws Exception {
  JndiDatasourceCreator.create();
  insertTestUsers();//private test harness method
}

@Test
public void getUsers() {
  List<User> users = userRepository
  .getUsers();
 assertEquals(users.get(0).getName(), testUsers.get(0).getName());
}


I would recommend doing setup in the parent test class that every test could inherit.

That’s it for now, enjoy coding.





Thursday, April 10, 2014

Mocking Rest API Simplified


              Is your web development in jeopardy due to unavailable services that it would intend to consume but are not available? We are in the era of micro services where it’s common that your web requires making lot of calls to web services. There is a danger of overlapping development life cycles of web service components. Quite naturally this might add pressure on development and would cripple due to the unavailability of services to consume or changes in service without notice. This is where we think of mocking these services. That’s right, let’s mock these services quickly and move on with web development. Now that you have decided to mock, you would start researching with a hope that there must be some frameworks out there already that can do this job. But unfortunately it’s not really the case and soon you would tell yourself, “Let me build one simple framework to do this”.

             There are third party mock tools that are available as hosted services or cloud services as well few tools available that you can host on in premises.
From the development perspective mocking can be achieved either on service side or on web side. If you are using Angular or Ember JS frameworks for the web then you are in luck as they both support mocking framework. But if you plan to mock your services rather then you have few options SOAP UI, Mocky, Mockable, WireMock etc. 
I don’t want to get into comparing these tools in this article, I liked wiremock but some caveats to it and I will get to it in another article. I guess you will have to shift your mindset to go with one of these tools to mock your services. Bottom line you know the idea of mocking, it should not complicate the development process and switching between the mocked and real ones should be trivial. Anyways if you are looking for some simple lightweight framework to achieve this then here is one thought!

First Thing First

             Let’s get to the details of developing a framework within your application to mock services. All you need is the Jackson library to build this framework. You setup, develop and publish your Rest Services as usual but you only mock the responses. Mocking a service is as simple as, reading the mock data from a file and building the response dynamically. You want to mock the data in XML or Json, either way Jackson got you covered.
Mocking is a simple 2 step process,
  • Step 1 is recording, you use your junit test case to compose objects needed to produce the response and record the response into a file. The response could be either in XML or JSON.
  • Step 2 is time to playback, write a Mock repository object to read the response from these files, convert to objects and pass it back to your service.

Ha, first thing is to run the app. 
Now open the rest client of your choice

 Mock It Away!

          Let’s look into details of this simple Rest API to support Users for a company that supports adding, updating, retrieving users.

Simple user object,

public class User implements Serializable {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
    private String phone;
}
UserResponse object in this case simply wraps User object,
public class UserResponse implements Serializable{
    private List<User> users = new ArrayList<User>();
}
Mocking user data should be trivial, create users.xml and place it in src/main/resources directory



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Users>
    <User>
        <id>101</id>
        <firstName>Vin1</firstName>
        <lastName>Shiv1</lastName>
        <email>vin1@email.com</email>
        <phone>123-456-7890</phone>
    </User>
    <User>
        <id>102</id>
        <firstName>Vin2</firstName>
        <lastName>Shiv2</lastName>
        <email>vin2@email.com</email>
        <phone>223-456-7890</phone>
    </User>
    <User>
        <id>103</id>
        <firstName>Vin3</firstName>
        <lastName>Shiv3</lastName>
        <email>vin3@email.com</email>
        <phone>323-456-7890</phone>
    </User>
</Users>
Interested only in JSON, create users.json

{"users":
 [{"id":"101","firstName":"Vin1","lastName":"Shiv1","email":"vin1@email.com","phone":"123-456-7890"},
 {"id":"102","firstName":"Vin2","lastName":"Shiv2","email":"vin2@email.com","phone":"223-456-7890"},
  {"id":"103","firstName":"Vin3","lastName":"Shiv3","email":"vin3@email.com","phone":"323-456-7890"}]
}


This sample includes 2 Mock Repository classes, let’s look at our MockXmlUserRepository.java


@Repository
public class MockXmlUserRepository {

    private static final String USERS_XML_FILE = "users.xml";
    private static final String FILE_DIR = "c:/sandbox/mockService/src/main/resources/mockdata/";
    
    @Cacheable(value = { "usersCache" })
    public UserResponse getUsers() throws Exception {
 UserResponse userResponse = loadUsers();
 return userResponse;
    }

    private UserResponse loadUsers() throws Exception {
 JAXBContext context = JAXBContext.newInstance(UserResponse.class);
 Unmarshaller un = context.createUnmarshaller();
 return (UserResponse) un.unmarshal(new File(FILE_DIR + USERS_XML_FILE));
    }
}


As you see a JAXBContext unmarshalling the XML data from file to Users object. If you look at the MockJsonUserRepository.java


@Repository
public class MockJsonUserRepository {

    private static final String USERS_JSON_FILE = "users.json";
    private static final String FILE_DIR = "c:/sandbox/mockService/src/main/resources/mockdata/";

    @Cacheable(value = { "usersCache" })
    public UserResponse getUsers() throws Exception {
 UserResponse userResponse = loadUsers();
 return userResponse;
    }

    private UserResponse loadUsers() throws Exception {
 return (UserResponse) new com.fasterxml.jackson.databind.ObjectMapper()
  .readValue(new File(FILE_DIR + USERS_JSON_FILE),
   UserResponse.class);
    }
}


We use Jackson’s mapper object to read json and convert to java object.
UserService implementation uses Repository to get those response user objects built earlier,


@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private MockXmlUserRepository mockXmlUserRepository;

    @Autowired
    private MockJsonUserRepository mockJsonUserRepository;
    
    private Cache usersCache = null;

    @SuppressWarnings("unchecked")
    @Override
    public UserResponse getUsers() throws Exception {
 ConcurrentMap<String, User> map = (ConcurrentMap<String, User>) usersCache.getNativeCache();
 UserResponse userResponse = new UserResponse();
 List<User> userList = new ArrayList<User>(map.values());
 userResponse.setUsers(userList);
 return userResponse;
    }

    @Override
    public User getUserById(String id) {
 return usersCache.get(id, User.class);
    }

    @Override
    public void addUser(User user) {
 usersCache.put(user.getId(), user);
    }

    @Override
    public void updateUser(final String id, User user) {
 usersCache.evict(id);
 usersCache.put(id, user);
    }    
}


Two Mock Repository objects were injected into the service. We are using spring simple cache manager to manage these objects once loaded by repository.
All our service methods are simply using this cache to compose the response.
We want to load these mock data response objects at the application startup so we will use bean initializer init method by using @PostConstruct annotation like below,


@PostConstruct
    public void init() throws Exception {
 loadUsersCache();
    }
private Cache loadUsersCache() throws Exception {
 if (usersCache != null)
     return usersCache;
 usersCache = new ConcurrentMapCache("usersCache");
 UserResponse userResponse = mockXmlUserRepository.getUsers();
 if (userResponse != null && userResponse.getUsers() != null) {
     for (User user : userResponse.getUsers())
  usersCache.putIfAbsent(user.getId(), user);
 }
 return usersCache;
    }


Note that loadUsersCache method is using Xml Mock Repository but you could switch to json repository if needed as it’s already auto wired.
Finally the Rest controller to return users by calling the service above,


@RequestMapping(method = RequestMethod.GET, headers = { "Accept=application/json,application/xml" }, produces = {
     "application/json", "application/xml" })
    @ResponseBody
    public Users getUsers(HttpServletRequest request) throws Exception {
 Users users = userService.getUsers();

 return users;
    }


Notice that this service supports both XML and Json response. Download the sample app for complete listing of this controller.
Each service or domain will have its own Mock Repository and could ideally be replaced with real implementation whenever it’s ready.
So at this point your service is mocked and ready to serve the request.
  
You must be thinking, does that mean I need to hand write these xml/json files? What if my objects structure is complicated? Is there a better way? But wait, where is the step 1 that you mentioned earlier?
Here is step one, this is a simple process to produce these mock data files through your Junit. Look at Junit testcase to our Mock Repository classes that not only test the unmarshaller but also marshall’s the data and writes to a file. There is recordUsers and playUsers method that does all this.


    @Test
    public void recordUsers() throws Exception {
 usersToXML(buildUsers());
    }
    
    @Test
    public void playUsers() throws Exception {
 UserResponse users = xmlToUsers();
 assertEquals(3, users.getUsers().size());
    }


buildUsers() is a test harness to compose the data objects.


private UserResponse buildUsers(){
 UserResponse userResponse = new UserResponse();
 userResponse.getUsers().add(buildUser("101", "Vin1", "Shiv1", "vin1@email.com", "123-456-7890"));
 userResponse.getUsers().add(buildUser("102", "Vin2", "Shiv2", "vin2@email.com", "223-456-7890"));
 userResponse.getUsers().add(buildUser("103", "Vin3", "Shiv3", "vin3@email.com", "323-456-7890"));
 return userResponse;
    }


recordUsers() calls usersToXML method that marshall’s the UserResponse object parameter into a xml file under src/main/resources directory.

private void usersToXML(UserResponse userResponse) {
 try {
            JAXBContext context = JAXBContext.newInstance(UserResponse.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            m.marshal(userResponse, new File(FILE_DIR+USERS_XML_FILE));
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }


playUsers() calls xmlToUsers() that does unmarshalling the data from a file.


private UserResponse xmlToUsers() {
        try {
            JAXBContext context = JAXBContext.newInstance(UserResponse.class);
            Unmarshaller un = context.createUnmarshaller();
            UserResponse userResponse = (UserResponse) un.unmarshal(new File(FILE_DIR+USERS_XML_FILE));
            return userResponse;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }


You need to write the test harness to build the test data objects. Once you got the file generated it’s easier to manipulate the data in a file later.

Final Note

There are some pros and cons around this approach and here are some that I can think of.

Advantages

  • You will be able to work through your object structure to compose the Json/Xml response otherwise it’s hard to compose json response in case of complex object structure.
  • Allows you to manipulate the mock data in a generated mock file to mock large set of data easily if needed.
  • Allows you to publish a real service by having you exercise through all the setup, environment and configuration issues.
  •  Allows you to defer implementation details to the later stage by mocking the response.
  • The implementation could be as simple as switching to real repository objects when there are ready.
Disadvantages

  • You will have to go through complete set up, environment and configuration steps as this is almost a real service.
  • You will have to go through deployment process every time requirement changes as you will have to adjust the response data.
  • Please feel free to share your thoughts on this approach or got better ideas to achieve this.
That’s it for now, happy mocking.