Skip to content

Instantly share code, notes, and snippets.

@mp911de
Last active December 20, 2015 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mp911de/6086572 to your computer and use it in GitHub Desktop.
Save mp911de/6086572 to your computer and use it in GitHub Desktop.
Suite for WebService Delegators
public interface ChoiceValuesService {
ChoiceValues getChoiceValues(String choiceValuesId, boolean useCache) throws ChoiceValuesNotFoundException;
}
@WebService(name = "ChoiceValuesWebService",
targetNamespace = WSConstants.Q_NAME_NAMESPACE_URI)
public interface ChoiceValuesWebService {
@WebMethod(operationName = "getChoiceValues")
ChoiceValues getChoiceValues(@WebParam(name = "choiceValuesId") String choiceValuesId, @WebParam(name = "useCache") boolean useCache)
throws ChoiceValuesNotFoundFault, TechnicalFault;
}
/**
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a>
* @since 25.07.13 12:31
*/
public class ChoiceValuesWebServiceClient implements ChoiceValuesService {
@Inject
private ChoiceValuesWebService choiceValuesWebService;
@Override
public ChoiceValues getChoiceValues(String choiceValuesId, boolean useCache) throws ChoiceValuesNotFoundException {
try {
return choiceValuesWebService.getChoiceValues(choiceValuesId, useCache);
} catch (ChoiceValuesNotFoundFault e) {
throw new ChoiceValuesNotFoundException(e.getMessage()); // NOPMD
} catch (TechnicalFault e) {
throw new TechnicalException(e);
}
}
import java.util.List;
import javax.ejb.EJB;
import javax.jws.WebService;
import org.apache.log4j.Logger;
/**
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a>
* @since 24.07.13 10:41
*/
@WebService(name = "ChoiceValuesWebService",
serviceName = "ChoiceValuesWebService",
portName = "ChoiceValuesWebServicePort",
targetNamespace = WSConstants.Q_NAME_NAMESPACE_URI,
endpointInterface = "de.paluch.delegate.ws.ChoiceValuesWebService")
public class ChoiceValuesWebServiceImpl implements ChoiceValuesWebService {
private Logger log = Logger.getLogger(getClass());
@EJB
private ChoiceValuesService choiceValuesService;
@Override
public ChoiceValues getChoiceValues(String choiceValuesId, boolean useCache) throws ChoiceValuesNotFoundFault, TechnicalFault {
try {
return choiceValuesService.getChoiceValues(choiceValuesId, useCache);
} catch (ChoiceValuesNotFoundException e) {
throw new ChoiceValuesNotFoundFault(e);
} catch (RuntimeException e) {
logError(log, e, choiceValuesId, useCache);
throw new TechnicalFault(EJBExceptionUtil.unwrap(e));
}
}
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import javax.jws.WebService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.Mockito;
import org.mockito.internal.util.reflection.Fields;
import org.mockito.internal.util.reflection.InstanceField;
/**
* This Test performs full-branch testing on supplied delegates. All calls with all exceptions are tested. The test also checks whether
* faults are converted properly into exceptions and vice versa.
*
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a>
* @since 25.07.13 12:44
*/
@RunWith(Parameterized.class)
public class WebserviceDelegatorsTest {
public static final String EXCEPTION_SUFFIX = "Exception";
public static final String FAULT_SUFFIX = "Fault";
@Parameterized.Parameters(name = "{1}.{4}")
public static java.util.Collection<Object[]> data() {
// WebService Impl to Facade-Class Mapping
Map<Class<?>, Class<?>> classes = new HashMap<>();
// SOAP Services
classes.put(ChoiceValuesWebServiceImpl.class, ChoiceValuesService.class);
classes.put(ConfigurationWebServiceImpl.class, ConfigurationService.class);
classes.put(DocumentWebServiceImpl.class, DocumentService.class);
classes.put(DossierWebServiceImpl.class, DossierService.class);
classes.put(MailWebServiceImpl.class, MailService.class);
classes.put(RenditionWebServiceImpl.class, RenditionService.class);
classes.put(SecurityPrincipalWebServiceImpl.class, SecurityPrincipalService.class);
classes.put(SupplierWebServiceImpl.class, SupplierService.class);
classes.put(WorkflowWebServiceImpl.class, WorkflowService.class);
// SOAP Clients
classes.put(ChoiceValuesWebServiceClient.class, ChoiceValuesWebService.class);
classes.put(ConfigurationWebServiceClient.class, ConfigurationWebService.class);
classes.put(DocumentWebServiceClient.class, DocumentWebService.class);
classes.put(DossierWebServiceClient.class, DossierWebService.class);
classes.put(MailWebServiceClient.class, MailWebService.class);
classes.put(RenditionWebServiceClient.class, RenditionWebService.class);
classes.put(SecurityPrincipalWebServiceClient.class, SecurityPrincipalWebService.class);
classes.put(SupplierWebServiceClient.class, SupplierWebService.class);
classes.put(WorkflowWebServiceClient.class, WorkflowWebService.class);
return map(classes);
}
private static List<Object[]> map(Map<Class<?>, Class<?>> classes) {
List<Object[]> result = new ArrayList<>();
for (Map.Entry<Class<?>, Class<?>> entry : classes.entrySet()) {
for (Method method : entry.getKey().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
}
result.add(new Object[] {
entry.getKey(), entry.getKey().getSimpleName(), entry.getValue(), method, method.getName()
});
}
}
return result;
}
private Class<?> wrapperClass;
private Class<?> delegateInterfaceClass;
private Object wrapperInstance;
private Object delegateMock;
private Method method;
private Class expectedTechnicalExceptionClass;
private boolean wrappingOfRuntimeExceptions = true;
/**
*
* @param wrapperClass
* @param simpleClassName
* just for Test-Name
* @param delegateInterfaceClass
* @param method
* @param methodName
* just for Test-Name
* @throws Exception
*/
public WebserviceDelegatorsTest(Class<?> wrapperClass, String simpleClassName, Class<?> delegateInterfaceClass, Method method,
String methodName) throws Exception {
this.wrapperClass = wrapperClass;
this.delegateInterfaceClass = delegateInterfaceClass;
this.method = method;
delegateMock = Mockito.mock(delegateInterfaceClass, delegateInterfaceClass.getSimpleName());
wrapperInstance = wrapperClass.newInstance();
tryInjection(delegateInterfaceClass);
if (wrapperClass.getAnnotation(WebService.class) != null) {
expectedTechnicalExceptionClass = TechnicalFault.class;
} else {
expectedTechnicalExceptionClass = TechnicalException.class;
wrappingOfRuntimeExceptions = false;
}
}
private void tryInjection(Class<?> delegateInterfaceClass) {
boolean injected = false;
for (InstanceField field : Fields.allDeclaredFieldsOf(wrapperInstance).instanceFields()) {
if (field.jdkField().getType().equals(delegateInterfaceClass)) {
field.set(delegateMock);
injected = true;
}
}
if (!injected) {
throw new IllegalStateException("Could not inject mock of type " + delegateInterfaceClass + " . Perhaps wrong type?");
}
}
@Before
public void before() throws Exception {
Mockito.reset(delegateMock);
}
/**
* Test the Happy Path.
*
* @throws Exception
*/
@Test
public void testSimpleDelegation() throws Exception {
Object[] parameters = createParameters(method.getParameterTypes());
Method deletgateMethod = delegateInterfaceClass.getMethod(method.getName(), method.getParameterTypes());
Object expectedMethodResult = null;
boolean hasReturn = hasReturn(deletgateMethod);
// Setup Return-Value
if (hasReturn) {
expectedMethodResult = createValue(deletgateMethod.getReturnType());
Object stubbingResult = deletgateMethod.invoke(delegateMock, parameters);
when(stubbingResult).thenReturn(expectedMethodResult);
}
Object result = method.invoke(wrapperInstance, parameters);
// Verify that delegated method was also invoked on the mock.
deletgateMethod.invoke(verify(delegateMock), parameters);
if (hasReturn) {
assertEquals("Expected return object is wrong, " + getClassAndMethodName(), expectedMethodResult, result);
}
}
/**
* Test the declared Exceptions from the delegate. Every exception has to be thrown.
*
* @throws Exception
*/
@Test
public void testExceptions() throws Exception {
Object[] parameters = createParameters(method.getParameterTypes());
Method deletgateMethod = delegateInterfaceClass.getMethod(method.getName(), method.getParameterTypes());
for (Class exceptionType : deletgateMethod.getExceptionTypes()) {
Mockito.reset(delegateMock);
Object stubbingResult = deletgateMethod.invoke(delegateMock, parameters);
when(stubbingResult).thenThrow(exceptionType);
try {
Object result = method.invoke(wrapperInstance, parameters);
fail("Missing Exception on calling " + getClassAndMethodName() + ", tried to throw " + exceptionType);
} catch (InvocationTargetException e) {
if (isExceptionAlsoContainedInWrapper(exceptionType)) {
String simpleName = getTranscodedExceptionName(exceptionType);
assertEquals("Wrong Exception on calling " + getClassAndMethodName(), simpleName, e.getTargetException().getClass()
.getSimpleName());
} else {
assertEquals("Wrong Exception on calling " + getClassAndMethodName(), expectedTechnicalExceptionClass, e
.getTargetException().getClass());
}
}
}
}
/**
* Test behavior of Runtime-Exceptions. Sometimes they have to be wrapped.
*
* @throws Exception
*/
@Test
public void testRuntimeException() throws Exception {
Object[] parameters = createParameters(method.getParameterTypes());
Method deletgateMethod = delegateInterfaceClass.getMethod(method.getName(), method.getParameterTypes());
Object stubbingResult = deletgateMethod.invoke(delegateMock, parameters);
when(stubbingResult).thenThrow(new NullPointerException());
try {
method.invoke(wrapperInstance, parameters);
fail("Missing Exception on calling " + getClassAndMethodName() + ", tried to throw " + NullPointerException.class);
} catch (InvocationTargetException e) {
if (wrappingOfRuntimeExceptions) {
assertEquals("Wrong Exception on calling " + getClassAndMethodName(), expectedTechnicalExceptionClass, e
.getTargetException().getClass());
} else {
assertEquals("Wrong Exception on calling " + getClassAndMethodName(), NullPointerException.class, e.getTargetException()
.getClass());
}
}
}
private String getTranscodedExceptionName(Class exceptionType) {
String simpleName = null;
if (exceptionType.getSimpleName().contains(EXCEPTION_SUFFIX)) {
simpleName = exceptionType.getSimpleName().replaceAll(EXCEPTION_SUFFIX, FAULT_SUFFIX);
}
if (exceptionType.getSimpleName().contains(FAULT_SUFFIX)) {
simpleName = exceptionType.getSimpleName().replaceAll(FAULT_SUFFIX, EXCEPTION_SUFFIX);
}
return simpleName;
}
private boolean isExceptionAlsoContainedInWrapper(Class exceptionType) {
String wrapperExceptionName = getTranscodedExceptionName(exceptionType);
for (Class wrapperExceptionType : method.getExceptionTypes()) {
if (wrapperExceptionType.getSimpleName().equals(wrapperExceptionName)) {
return true;
}
}
return false;
}
private boolean hasReturn(Method deletgateMethod) {
boolean hasReturn = false;
if (deletgateMethod.getReturnType() != null && !deletgateMethod.getReturnType().equals(Void.class)
&& !deletgateMethod.getReturnType().equals(Void.TYPE)) {
hasReturn = true;
}
return hasReturn;
}
private String getClassAndMethodName() {
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
}
private Object[] createParameters(Class[] parameterTypes) throws IllegalAccessException {
Object result[] = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
Class parameterType = parameterTypes[i];
result[i] = createValue(parameterType);
}
return result;
}
private Object createValue(Class parameterType) throws IllegalAccessException {
if (parameterType == String.class) {
return "Test-String " + System.currentTimeMillis();
}
if (parameterType == Integer.class || parameterType == Integer.TYPE) {
return Integer.valueOf((int) System.currentTimeMillis());
}
if (parameterType == Long.class || parameterType == Long.TYPE) {
return Long.valueOf(System.currentTimeMillis());
}
if (parameterType == Double.class || parameterType == Double.TYPE) {
return Double.valueOf(System.currentTimeMillis());
}
if (parameterType == Boolean.class || parameterType == Boolean.TYPE) {
return Boolean.valueOf(System.currentTimeMillis() % 2 == 0);
}
if (parameterType.isEnum()) {
Field[] fields = parameterType.getFields();
return fields[0].get(null);
}
if (parameterType.getPackage() == null) {
if (parameterType.isArray()) {
Object array = Array.newInstance(parameterType.getComponentType(), 1);
Object value = createValue(parameterType.getComponentType());
Array.set(array, 0, value);
return array;
}
throw new UnsupportedOperationException("Package is null: " + parameterType);
}
// Create stubs for our packages.
if (parameterType.getPackage().getName().startsWith("de.paluch.delegate")) {
return Mockito.mock(parameterType);
}
if (parameterType.getName().startsWith("java.util.List")) {
return Mockito.mock(parameterType);
}
if (parameterType.getName().startsWith("java.util.Map")) {
return Mockito.mock(parameterType);
}
if (parameterType.getName().startsWith("java.util.Locale")) {
return new Locale("de", "DE");
}
throw new UnsupportedOperationException("Parameter-Type" + parameterType
+ " not yet supported. Would you be so kind and implement it?");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment