package com.github.dreamhead.moco.parser.model; import com.github.dreamhead.moco.Moco; import com.github.dreamhead.moco.RequestExtractor; import com.github.dreamhead.moco.RequestMatcher; import com.github.dreamhead.moco.extractor.Extractors; import com.github.dreamhead.moco.matcher.AndRequestMatcher; import com.github.dreamhead.moco.parser.RequestMatcherFactory; import com.github.dreamhead.moco.resource.Resource; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Map; import static com.github.dreamhead.moco.Moco.by; import static com.github.dreamhead.moco.Moco.eq; import static com.github.dreamhead.moco.Moco.exist; import static com.github.dreamhead.moco.Moco.json; import static com.github.dreamhead.moco.Moco.not; import static com.google.common.collect.FluentIterable.from; public class DynamicRequestMatcherFactory extends Dynamics implements RequestMatcherFactory { @Override public RequestMatcher createRequestMatcher(final RequestSetting request) { return wrapRequestMatcher(request, createRequestMatchers(request)); } private ImmutableList<RequestMatcher> createRequestMatchers(final RequestSetting request) { return from(getFields(RequestSetting.class)) .filter(isValidField(request)) .transform(fieldToRequestMatcher(request)) .toList(); } private Function<Field, RequestMatcher> fieldToRequestMatcher(final RequestSetting request) { return new Function<Field, RequestMatcher>() { @Override public RequestMatcher apply(final Field field) { try { Object value = field.get(request); return createRequestMatcherFromValue(field.getName(), value); } catch (Exception e) { throw new RuntimeException(e); } } }; } private RequestMatcher createRequestMatcherFromValue(final String name, final Object value) { if ("json".equalsIgnoreCase(name)) { return json(value); } if (Map.class.isInstance(value)) { return createCompositeMatcher(name, castToMap(value)); } if (TextContainer.class.isInstance(value)) { return createSingleTextMatcher(name, TextContainer.class.cast(value)); } throw new IllegalArgumentException("unknown configuration :" + value); } @SuppressWarnings("unchecked") private Map<String, Object> castToMap(final Object value) { return Map.class.cast(value); } private RequestMatcher createSingleMatcher(final String name, final String value) { return by(createResource(name, value)); } private Resource createResource(final String name, final String value) { return invokeTarget(name, value, Resource.class); } private RequestMatcher createSingleTextMatcher(final String name, final TextContainer container) { if (container.isRawText()) { return createSingleMatcher(name, container.getText()); } if (isExistOperator(container)) { return existMatcher(Extractors.extractor(name), container); } return createRequestMatcherWithResource(container.getOperation(), createResource(name, container.getText())); } private boolean isExistOperator(final TextContainer container) { return "exist".equals(container.getOperation()); } private RequestMatcher createRequestMatcherWithResource(final String operation, final Resource resource) { try { Method operationMethod = Moco.class.getMethod(operation, Resource.class); return RequestMatcher.class.cast(operationMethod.invoke(null, resource)); } catch (Exception e) { throw new RuntimeException(e); } } private RequestMatcher createCompositeMatcher(final String name, final Map<String, Object> collection) { ImmutableList<RequestMatcher> matchers = from(collection.entrySet()) .transform(toTargetMatcher(getExtractorMethod(name))) .toList(); return wrapRequestMatcher(null, matchers); } private Function<Map.Entry<String, Object>, RequestMatcher> toTargetMatcher(final Method extractorMethod) { return new Function<Map.Entry<String, Object>, RequestMatcher>() { @Override @SuppressWarnings("unchecked") public RequestMatcher apply(final Map.Entry<String, Object> pair) { RequestExtractor extractor = createRequestExtractor(extractorMethod, pair.getKey()); return createRequestMatcher(extractor, pair.getValue()); } }; } private <T> RequestMatcher createRequestMatcher(final RequestExtractor<T> extractor, final Object value) { if (TextContainer.class.isInstance(value)) { return getRequestMatcher(extractor, TextContainer.class.cast(value)); } throw new IllegalArgumentException("unknown value type: " + value); } private <T> RequestMatcher getRequestMatcher(final RequestExtractor<T> extractor, final TextContainer container) { if (container.isRawText()) { return eq(extractor, container.getText()); } if (isExistOperator(container)) { return existMatcher(extractor, container); } try { Method operatorMethod = Moco.class.getMethod(container.getOperation(), RequestExtractor.class, String.class); Object result = operatorMethod.invoke(null, extractor, container.getText()); return RequestMatcher.class.cast(result); } catch (Exception e) { throw new RuntimeException(e); } } private <T> RequestMatcher existMatcher(final RequestExtractor<T> extractor, final TextContainer container) { String text = container.getText(); if ("true".equalsIgnoreCase(text)) { return exist(extractor); } if ("false".equalsIgnoreCase(text)) { return not(exist(extractor)); } throw new IllegalArgumentException(String.format("Unknown exist parameter: [%s]", text)); } private static RequestMatcher wrapRequestMatcher(final RequestSetting request, final ImmutableList<RequestMatcher> matchers) { switch (matchers.size()) { case 0: throw new IllegalArgumentException("illegal request setting:" + request); case 1: return matchers.get(0); default: return new AndRequestMatcher(matchers); } } }