package org.minnal.jaxrs.test;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import org.apache.commons.beanutils.PropertyUtils;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.internal.PropertiesDelegate;
import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ContainerResponse;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spi.ContainerResponseWriter;
import org.minnal.autopojo.AutoPojoFactory;
import org.minnal.autopojo.Configuration;
import org.minnal.autopojo.GenerationStrategy;
import org.minnal.autopojo.util.PropertyUtil;
import org.minnal.jaxrs.test.exception.MinnalJaxrsTestException;
import org.minnal.jaxrs.test.provider.JacksonProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams;
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class BaseResourceTest {
private static final Logger logger = LoggerFactory.getLogger(BaseResourceTest.class);
private static final int MAX_DEPTH = 20;
private static final int BUFFER_CAPACITY = 10240000;
private static AutoPojoFactory factory;
private JacksonProvider provider = new JacksonProvider();
private static ApplicationHandler handler;
static {
Set<Class<? extends Annotation>> excludeAnnotations = new HashSet<Class<? extends Annotation>>();
excludeAnnotations.add(JsonIgnore.class);
excludeAnnotations.add(JsonBackReference.class);
try {
excludeAnnotations.add((Class) ClassUtil.findClass("javax.persistence.GeneratedValue"));
} catch (ClassNotFoundException e) {
logger.trace("javax.persistence.GeneratedValue class not found. Ignoring it", e);
}
Configuration configuration = new Configuration();
configuration.setExcludeAnnotations(excludeAnnotations);
GenerationStrategy strategy = new GenerationStrategy(configuration);
strategy.register(Object.class, BiDirectionalObjectResolver.class);
strategy.register(Collection.class, BiDirectionalCollectionResolver.class);
factory = new AutoPojoFactory(strategy);
}
@BeforeSuite
public void beforeSuite() {
}
@BeforeMethod
public void beforeMethod() {
setup();
}
@AfterMethod
public void afterMethod() {
destroy();
}
@AfterSuite
public void afterSuite() {
}
public JacksonProvider getProvider() {
return provider;
}
public void setProvider(JacksonProvider provider) {
this.provider = provider;
}
/**
* init method
*
* @param resourceConfig
*/
protected void init(ResourceConfig resourceConfig) {
handler = createApplicationHandler(resourceConfig);
}
protected void setup() {
}
protected void destroy() {
}
public ContainerRequest request(String uri, String method, ByteBuffer content) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ByteStreams.copy(new ByteArrayInputStream(content.array()), bos);
return request(uri, method, bos.toString(Charsets.UTF_8.name()), MediaType.APPLICATION_JSON_TYPE);
} catch (Exception e) {
throw new MinnalJaxrsTestException(e);
}
}
public ContainerRequest request(String uri, String method) {
return request(uri, method, "", MediaType.APPLICATION_JSON_TYPE);
}
public ContainerRequest request(String uri, String method, String content) {
return request(uri, method, content, MediaType.APPLICATION_JSON_TYPE);
}
public ContainerRequest request(String uri, String method, String content, MediaType contentType) {
return request(uri, method, content, contentType, Maps.<String, String>newHashMap());
}
public ContainerRequest request(String uri, String method, String content, MediaType contentType, Map<String, String> headers) {
return createContainerRequest(URI.create(""), URI.create(uri), method, content, headers,
null, new MapPropertiesDelegate());
}
public <T> T createDomain(Class<T> clazz, Class<?>... genericTypes) {
return factory.populate(clazz, MAX_DEPTH, genericTypes);
}
public <T> T createDomain(Class<T> clazz, int maxDepth, Class<?>... genericTypes) {
return factory.populate(clazz, maxDepth, genericTypes);
}
public <T> boolean compare(T model1, T model2, int depth) {
if (model1 == null || model2 == null) {
return false;
}
for (PropertyDescriptor descriptor : PropertyUtils.getPropertyDescriptors(model1)) {
if (PropertyUtil.isSimpleProperty(descriptor.getPropertyType())) {
try {
Object property1 = PropertyUtils.getProperty(model1, descriptor.getName());
Object property2 = PropertyUtils.getProperty(model2, descriptor.getName());
if (property1 != null && property2 != null && !property1.equals(property2)) {
return false;
}
} catch (Exception e) {
logger.info(e.getMessage(), e);
}
}
}
return true;
}
public ByteBuffer serialize(Object value) {
return provider.serialize(value, javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
}
public <T> T deserialize(ByteBuffer byteBuf, Class<T> type) {
return (T) provider.deserialize(byteBuf, type, javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
}
public <T> T deserializeCollection(ByteBuffer byteBuf, Class<T> type, Class elementType) {
return (T) provider.deserializeCollection(byteBuf, type, elementType, javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
}
public ContainerResponse call(ContainerRequest containerRequest) {
ByteBuffer byteBuf = ByteBuffer.allocate(BUFFER_CAPACITY);
ContainerResponse response;
try {
response = handler.apply(containerRequest, new ByteBufferOutputStream(byteBuf)).get();
} catch (Exception e) {
logger.debug("Failed while handling the request - " + containerRequest, e);
response = new ContainerResponse(containerRequest, Response.serverError().build());
}
ContainerResponseWriter responseWriter = containerRequest.getResponseWriter();
OutputStream os = responseWriter.writeResponseStatusAndHeaders(response.getLength(), response);
response.setEntityStream(os);
return response;
}
private ApplicationHandler createApplicationHandler(ResourceConfig resourceConfig) {
return new ApplicationHandler(resourceConfig);
}
private ContainerRequest createContainerRequest(URI baseUri, URI requestUri, String method, String content, Map<String, String> headers,
SecurityContext securityContext, PropertiesDelegate propertiesDelegate) {
URI uri = URI.create(baseUri.getPath() + "/");
ContainerRequest containerRequest = new ContainerRequest(uri, requestUri, method, securityContext, propertiesDelegate);
containerRequest.setEntityStream(new ByteArrayInputStream(content.getBytes()));
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
containerRequest.getHeaders().add(headerEntry.getKey(), headerEntry.getValue());
}
return containerRequest;
}
/**
* Gets byte buffer from container response
*
* @param response
* @return
*/
protected ByteBuffer getContent(ContainerResponse response) {
return ((ByteBufferOutputStream) response.getEntityStream()).getBuffer();
}
}