Disabling Caching at Runtime if Couchbase Connection Failed

In our application we have number of REST API calls out of which some of them are flagged with @Cacheable to cache the response. Cache is backed by Couchbase and whenever application fails to connect Couchbase node then application goes down.

Which is what we are not expecting, we expect data should be served from the source system whenever connection failed, basically bypassing the cache and as soon as the Couchbase node is up or connection established response should be served from cache.

To achieve the same mechanism, I returned “null” whenever connection fails or there is a Cache miss overriding CouchbaseCacheManager, as follows:


import java.util.Map;
import org.springframework.cache.Cache;
import com.couchbase.client.spring.cache.CacheBuilder;
import com.couchbase.client.spring.cache.CouchbaseCacheManager;

public class CouchbaseCustomCacheManager extends CouchbaseCacheManager {

	public CouchbaseCustomCacheManager(final Map<String, CacheBuilder> initialCaches) {
		super(initialCaches);
	}

	@Override
	public Cache getCache(String name) {
		return new CouchbaseCacheWrapper(super.getCache(name));
	}

	protected static class CouchbaseCacheWrapper implements Cache {

		private final Cache delegate;

		public CouchbaseCacheWrapper(Cache couchbaseCache) {
			this.delegate = couchbaseCache;
		}

		@Override
		public String getName() {
			try {
				return delegate.getName();
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public Object getNativeCache() {
			try {
				return delegate.getNativeCache();
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public ValueWrapper get(Object key) {
			try {
				return delegate.get(key);
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public <T> T get(Object key, Class<T> type) {
			try {
				return delegate.get(key, type);
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public void put(Object key, Object value) {
			try {
				delegate.put(key, value);
			} catch (Exception e) {
				try {
					handleErrors(e);
				} catch (Exception e1) {
				}
			}
		}

		@Override
		public ValueWrapper putIfAbsent(Object key, Object value) {
			try {
				return delegate.putIfAbsent(key, value);
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public void evict(Object key) {
			try {
				delegate.evict(key);
			} catch (Exception e) {
				try {
					handleErrors(e);
				} catch (Exception e1) {
				}
			}
		}

		@Override
		public void clear() {
			try {
				delegate.clear();
			} catch (Exception e) {
				try {
					handleErrors(e);
				} catch (Exception e1) {
				}
			}
		}

		protected <T> T handleErrors(Exception e) throws Exception {
			if (e instanceof Exception) {
				return null;
			} else {
				throw e;
			}
		}
	}
}

And used it as CacheManager, as follows:

@Bean
public CacheManager cacheManager() {
	final Map<String, CacheBuilder> cache = new HashMap<>();
	for (final String appCache : "127.0.0.1,127.0.0.2,127.0.0.3".split(",")) {
			cache.put(appCache, CacheBuilder.newInstance(CouchbaseCluster
					.create().openBucket("default", "")));
	}
	return new CouchbaseCustomCacheManager(cache);
}

Complete source is available on github.

Mocking Spring Security Context for Unit Testing

Today, while writing unit test case for one of the Java method which looks like below:

public ApplicationUser getApplicationUser() {
	ApplicationUser applicationUser = (ApplicationUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
	return applicationUser;
}

I want to mock Spring Security Context to get the Principal, to achieve the same I mocked each level of method calls as follows:

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import com.arpit.security.user.ApplicationUser;

public class BaseTest {

	@Before
	public void setupMock() {
		MockitoAnnotations.initMocks(this);
	}

	@Test
	public void mockApplicationUser() {
		ApplicationUser applicationUser = mock(ApplicationUser.class);
		Authentication authentication = mock(Authentication.class);
		SecurityContext securityContext = mock(SecurityContext.class);
		when(securityContext.getAuthentication()).thenReturn(authentication);
		SecurityContextHolder.setContext(securityContext);
		when(SecurityContextHolder.getContext().getAuthentication().getPrincipal()).thenReturn(applicationUser);
	}

}

Fixing com.couchbase.client.java.error.TranscodingException: Could not encode document with ID cache:EMPLOYEE_:1 – Couchbase

If you are using couchbase spring cache then you might get following exception:


Error occured: Details com.couchbase.client.java.error.TranscodingException: Could not encode document with ID cache:EMPLOYEE_:1

This exception is raised by couchbase client when document is not able to serialized, possible use case is when you are caching the resource which contain nested objects and does not implement Serializable, for example:

Employee.java


public class Employee {

   private int id;
   private String name;
   private Address address;
}

Address.java


 public class Address {
   private String city;
   private String country;
}

If you are facing the same problem as me then you can fix it implementing Serializable in all the classes, as follows:

Employee.java

import java.io.Serializable;

public class Employee implements Serializable {

  private static final long serialVersionUID = 1L;
  private int id;
  private String name;
  private Address address;
}

Address.java

import java.io.Serializable;

public class Address implements Serializable {

  private static final long serialVersionUID = 1L;
  private String city;
  private String country;

}

Fixing com.couchbase.client.java.error.DocumentDoesNotExistException – Couchbase

If you are using couchbase spring cache then you might get following exception:


12:16:58,338 ERROR [com.arpit.common.util.Resource] (http-/127.0.0.1:8080-6) Error occured: Details com.couchbase.client.java.error.DocumentDoesNotExistException

This exception is raised by couchbase client when document does not exist in cache and a replace operation is used, possible use case is when you are caching the resource which return null (which was happening for me), for example:

@Override
@Cacheable(value = "EMPLOYEE_", key = "#id")
public Employee getEmployee(int id) {
	return null;
}

If you are facing the same problem as me then you can fix it using the unless attribute of @Cacheable which is available as of Spring 3.2, as follows:

@Override
@Cacheable(value = "EMPLOYEE_", key = "#id", unless = "#result == null")
public Employee getEmployee(int id) {
	return null;
}

Setting TTL for @Cacheable – Spring

Today I was asked to set the expiry time of cache for some of the keys our application is using, so I quickly started looking for all of the options provided by Spring @Cacheable notation to set up the expiry time or time to live. Since Spring does not provide any configurable option to achieve it, I build one implementation leveraging @Scheduled annotation with a fixed delay, as follows:


@CacheEvict(allEntries = true, cacheNames = { "EMPLOYEE_", "MANAGER_" })
@Scheduled(fixedDelay = 30000)
public void cacheEvict() {
}

Now the problem is I want cache names as well as the fixed delay time period should be populated from environmental values instead of hard coded values. To achieve the same I declared variables(populated from properties file) at class level and populated the values of the key in the annotation which made IDE to complain that values must be constant, as follows:

“The value for annotation attribute CacheEvict.cacheNames must be a constant expression”

Then I started looking for other options to get the values for the keys from environment and came across fixedDelayString element of @Scheduled notation which helped me to achieve my goal, as follows:


@Scheduled(fixedDelayString = "${couchbase.cache.flush.fixed.delay}")
public void cacheEvict() {
}

Looking for the similar element for @CacheEvict annotation as well, which is unfortunately not available given me a hint after reading the the comment on a bug SPR-10778 which says:

“The cache abstraction supports the CacheResolver abstraction now and it can be specified globally, per class and/or on a specific operation. The CacheResolver give you the ability to compute the caches to use in code so you have all the flexibility that you want.”

As bug says to make use of CacheResolver to dynamically populate the cache names, I used AbstractCacheResolver implementation of it to get the names of cache from environment, as follows:


@Value("#{'${couchbase.cache.flush}'}")
private String couchbaseCacheFlush;

@Bean(name = "customCacheResolver")
	public CacheResolver cacheResolver() {
		CacheResolver cacheResolver = new AbstractCacheResolver(cacheManager()) {
			@Override
			protected Collection<String> getCacheNames(
					CacheOperationInvocationContext<?> context) {
				return Arrays.asList(couchbaseCacheFlush.split(","));
			}
		};
		return cacheResolver;
	}

Modifying the cacheEvict() to use custom cache resolver instead of cache names completed my task for the day, as follows:


@CacheEvict(allEntries = true, cacheResolver = "customCacheResolver")
@Scheduled(fixedDelayString = "${couchbase.cache.flush.fixed.delay}")
public void cacheEvict() {
}

Complete source is available on github.

Expected Exception Rule and Mocking Static Methods – JUnit

Today I was asked to consume a RESTful service so I started implementing it following Robert Cecil Martin’s rules for TDD and came across a new way (atleast for me) of testing the expected exception along with the error message so thought of sharing the way I implemented it as part of this post.

To start with let’s write a @Test and specify rule that our code will throw a specific exception for our example it’s EmployeeServiceException which we will verify it using ExpectedException which will provide us more precise information about the exception expected to be thrown with the ability to verify error message, as follows:


@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStaticMethod.class)
public class EmployeeServiceImplTest {

	@InjectMocks
	private EmployeeServiceImpl employeeServiceImpl;

	@Rule
	public ExpectedException expectedException = ExpectedException.none();

	@Before
	public void setupMock() {
		MockitoAnnotations.initMocks(this);
	}

	@Test
	public void addEmployeeForNull() throws EmployeeServiceException {
		expectedException.expect(EmployeeServiceException.class);
		expectedException.expectMessage("Invalid Request");
		employeeServiceImpl.addEmployee(null);
	}

}

Now we will create an implementing class for our @Test which will throw EmployeeServiceException whenever the request is null, for me it’s EmployeeServiceImpl as follows:

EmployeeServiceImpl.java


public class EmployeeServiceImpl implements IEmployeeService {

	@Override
	public String addEmployee(final Request request)
			throws EmployeeServiceException {
		if (request == null) {
			throw new EmployeeServiceException("Invalid Request");
		}
		return null;
	}
}

Next we will write a @Test where we will mock static method which accepts input parameters with return type using PowerMockito.mockStatic(), verify it using PowerMockito.verifyStatic() and finally do an Assert to record test pass or failure status, as follows:


@Test
	public void addEmployee() throws EmployeeServiceException {
		PowerMockito.mockStatic(ClassWithStaticMethod.class);
		PowerMockito.when(ClassWithStaticMethod.getDetails(anyString()))
				.thenAnswer(new Answer<String>() {
					@Override
					public String answer(InvocationOnMock invocation)
							throws Throwable {
						Object[] args = invocation.getArguments();
						return (String) args[0];
					}
				});
		final String response = employeeServiceImpl.addEmployee(new Request(
				"Arpit"));
		PowerMockito.verifyStatic();
		assertThat(response, is("Arpit"));
	}

Now we will provide the implementation for our @Test inside EmployeeServiceImpl itself. To do that, lets modify the EmployeeServiceImpl to have static method call as part of else statement of addEmployee, as follows:


public class EmployeeServiceImpl implements IEmployeeService {

	@Override
	public String addEmployee(final Request request)
			throws EmployeeServiceException {
		if (request == null) {
			throw new EmployeeServiceException("Invalid Request");
		} else {
			return ClassWithStaticMethod.getDetails(request.getName());
		}
	}
}

Where getDetails is a static method inside ClassWithStaticMethod:


public class ClassWithStaticMethod {

	public static String getDetails(String name) {
		return name;
	}
}


 
Complete source code is hosted on github.

Deploying RESTful Service on Cloudfoundry

In this post, we will deploy RESTful service on Cloudfoundry using Pivotal Cloud Foundry (PCF) Dev. As creating a restful web service is not a part of this post, I already created employee-service which have a static backend and available for clone from GitHub.

Before deploying it on Cloudfoundry, let’s have a brief about it.

Cloudfoundry

Cloud Foundry is an open source cloud platform as a service (PaaS) on which developers can build, deploy, run and scale applications on public and private cloud models. It is VMware originally created by VMware and now it is part of Pivotal Software.

Now let’s set up lightweight PCF on our local workstation using PCF Dev, following below steps:

Step 1: Download and install cf-cli-installer_6.22.2_osx.pkg  in a directory, for me it’s /Users/ArpitAggarwal/cloudfoundry

$ cd /Users/ArpitAggarwal/cloudfoundry/ 
$ sudo installer -pkg ./cf-cli-installer_6.22.2_osx.pkg -target /

Step 2: Test if Cloudfoundry CLI installed successfully:

$ cf help

Step 3: Next we will download and install PCF Dev in the same directory we created earlier, as follows:

$ cd /Users/ArpitAggarwal/cloudfoundry/
$ unzip pcfdev-v0.22.0+PCF1.8.2-osx.zip
$ ./pcfdev-v0.22.0+PCF1.8.2-osx

Start 4: Start PCF Dev:

$ cd /Users/ArpitAggarwal/cloudfoundry/
$ cf dev start

Above command starts a single virtual machine on our workstation running PCF.

Step 5: Clone employee-service from GitHub in a directory, for me it’s /Users/ArpitAggarwal/

$ cd /Users/ArpitAggarwal/
$ git clone https://github.com/arpitaggarwal/empoyee-service.git

Step 6: Update the employee-service with manifest.yml:

$ cd /Users/ArpitAggarwal/employee-service
$ touch manifest.yml

manifest.yml created above is used by PCF for deployment to local workstation or on public cloud.

Step 7: Copy the below content in manifest.yml:

---
applications:
- name: empoyee-service
  memory: 1G
  random-route: true
  path: build/libs/empoyee-service-0.0.1.war
  buildpack: https://github.com/arpitaggarwal/java-buildpack.git

name attribute specified above is the name of an application.
path attribute is the directory location of an application.
buildpack attribute points to the java-buildpack, which is used by PCF for running JVM-based applications.

More about manifest.yml you can explore here.

Step 8: Next, we will build the application and push it to Cloudfoundry local workstation after login, as follows:

$ cd /Users/ArpitAggarwal/empoyee-service
$ empoyee-service git:(master) ./gradlew clean build
$ empoyee-service git:(master) ✗ cf login -a api.local.pcfdev.io --skip-ssl-validation
API endpoint: api.local.pcfdev.io

Email> user
Password> pass

$ cf push

cf push command specified above push an app or syncs changes to an existing app to the URL http://empoyee-service.local.pcfdev.io

Is application successfully deployed on Cloudfoundry?

Let’s verify it viewing the recent deployment logs where we can look server start up status, as follows:

$ cd /Users/ArpitAggarwal/empoyee-service
$ cf logs empoyee-service --recent

We can also verify application deployment executing GET and POST request against it, as follows:

GET Request to get all employees:

curl -i -H "Accept: application/json" -H "Content-Type: application/json" http://empoyee-service.local.pcfdev.io/empoyee/get

POST Request to create an employee:

curl -H "Content-Type: application/json" -X POST -d '{"name": "Arpit Aggarwal","email":"aggarwalarpit.89@gmail.com"}' http://empoyee-service.local.pcfdev.io/employee/create

The complete source code is hosted on github.