All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.ljtfreitas.restify.http.contract.metadata.DefaultContractReader Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2016 Tiago de Freitas Lima
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
package com.github.ljtfreitas.restify.http.contract.metadata;

import static com.github.ljtfreitas.restify.util.Preconditions.isTrue;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.github.ljtfreitas.restify.http.contract.Cookie;
import com.github.ljtfreitas.restify.http.contract.Header;
import com.github.ljtfreitas.restify.http.contract.ParameterSerializer;
import com.github.ljtfreitas.restify.http.contract.Path;
import com.github.ljtfreitas.restify.http.contract.Version;
import com.github.ljtfreitas.restify.http.contract.metadata.EndpointMethodParameter.EndpointMethodParameterType;

public class DefaultContractReader implements ContractReader {

	private final ContractExpressionResolver expressionResolver;

	public DefaultContractReader() {
		this(new SimpleContractExpressionResolver());
	}

	public DefaultContractReader(ContractExpressionResolver expressionResolver) {
		this.expressionResolver = expressionResolver;
	}

	@Override
	public EndpointMethods read(EndpointTarget target) {
		return new EndpointMethods(doRead(target));
	}

	private Collection doRead(EndpointTarget target) {
		ContractTypeMetadata javaTypeMetadata = new ContractTypeMetadata(target.type());
		return target.methods().stream()
			.map(javaMethod -> doReadMethod(target, javaTypeMetadata, javaMethod))
				.collect(Collectors.toList());
	}

	private EndpointMethod doReadMethod(EndpointTarget target, ContractTypeMetadata javaTypeMetadata, java.lang.reflect.Method javaMethod) {
		ContractMethodMetadata javaMethodMetadata = new ContractMethodMetadata(javaMethod);

		String endpointPath = endpointPath(target, javaTypeMetadata, javaMethodMetadata);

		String endpointHttpMethod = javaMethodMetadata.httpMethod().value().toUpperCase();

		EndpointMethodParameters parameters = endpointMethodParameters(javaMethod, target);

		EndpointHeaders headers = endpointMethodHeaders(javaTypeMetadata, javaMethodMetadata);

		Type returnType = javaMethodMetadata.returnType(target.type());

		String version = endpointMethodVersion(endpointVersion(javaTypeMetadata, javaMethodMetadata, true));

		return new EndpointMethod(javaMethod, endpointPath, endpointHttpMethod, parameters, headers, returnType, version);
	}

	private String endpointPath(EndpointTarget target, ContractTypeMetadata javaTypeMetadata, ContractMethodMetadata javaMethodMetadata) {
		return new EndpointPathBuilder()
				.append(endpointTarget(target))
				.append(endpointTypePath(javaTypeMetadata))
				.append(endpointVersion(javaTypeMetadata, javaMethodMetadata))
				.append(endpointMethodPath(javaMethodMetadata))
				.build();
	}

	private String endpointTarget(EndpointTarget target) {
		return expressionResolver.resolve(target.endpoint().orElse(""));
	}

	private String endpointTypePath(ContractTypeMetadata javaTypeMetadata) {
		return Arrays.stream(javaTypeMetadata.paths())
				.map(Path::value)
					.map(p -> expressionResolver.resolve(p))
						.collect(Collectors.joining());
	}

	private String endpointVersion(ContractTypeMetadata javaTypeMetadata, ContractMethodMetadata javaMethodMetadata) {
		return endpointVersion(javaTypeMetadata, javaMethodMetadata, false);
	}

	private String endpointVersion(ContractTypeMetadata javaTypeMetadata, ContractMethodMetadata javaMethodMetadata, boolean force) {
		Version version = javaMethodMetadata.version()
			.filter(v -> v.uri() || force)
				.orElseGet(() -> javaTypeMetadata.version()
						.filter(v -> v.uri() || force)
							.orElse(null));

		return Optional.ofNullable(version)
			.map(Version::value)
				.orElse("");
	}

	private String endpointMethodVersion(String version) {
		 return Optional.ofNullable(version)
			.filter(v -> !v.trim().isEmpty())
				.orElse(null);
	}

	private String endpointMethodPath(ContractMethodMetadata javaMethodMetadata) {
		return javaMethodMetadata.path().map(Path::value).orElse("");
	}

	private EndpointMethodParameters endpointMethodParameters(Method javaMethod, EndpointTarget target) {
		EndpointMethodParameters parameters = new EndpointMethodParameters();

		Parameter[] javaMethodParameters = javaMethod.getParameters();

		for (int position = 0; position < javaMethodParameters.length; position ++) {
			Parameter javaMethodParameter = javaMethodParameters[position];

			ContractMethodParameterMetadata javaMethodParameterMetadata = new ContractMethodParameterMetadata(javaMethodParameter, target.type());

			EndpointMethodParameterType type = javaMethodParameterMetadata.path()? EndpointMethodParameterType.PATH :
				javaMethodParameterMetadata.header()? EndpointMethodParameterType.HEADER :
					javaMethodParameterMetadata.body() ? EndpointMethodParameterType.BODY :
						javaMethodParameterMetadata.query() ? EndpointMethodParameterType.QUERY_STRING :
							javaMethodParameterMetadata.cookie() ? EndpointMethodParameterType.COOKIE :
								EndpointMethodParameterType.ENDPOINT_CALLBACK;

			if (type == EndpointMethodParameterType.ENDPOINT_CALLBACK) {
				isTrue(parameters.callbacks(javaMethodParameterMetadata.javaType().classType()).isEmpty(),
						"Only one @CallbackParameter of type [" + javaMethodParameterMetadata.javaType() + "] is allowed.");
			}

			ParameterSerializer serializer = Optional.ofNullable(javaMethodParameterMetadata.serializer())
					.map(s -> serializerOf(javaMethodParameterMetadata)).orElse(null);

			parameters = parameters.put(new EndpointMethodParameter(position, javaMethodParameterMetadata.name(), javaMethodParameterMetadata.javaType(), type, serializer));
		}

		return parameters;
	}

	private ParameterSerializer serializerOf(ContractMethodParameterMetadata javaMethodParameterMetadata) {
		try {
			return javaMethodParameterMetadata.serializer().newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			throw new UnsupportedOperationException("Cannot create new instance of EndpointMethodParameterSerializer type " + javaMethodParameterMetadata.serializer());
		}
	}

	private EndpointHeaders endpointMethodHeaders(ContractTypeMetadata javaTypeMetadata, ContractMethodMetadata javaMethodMetadata) {
		Collection
headersOfType = javaTypeMetadata.headers(); Collection
headersOfMethod = javaMethodMetadata.headers(); Collection headers = Stream.concat(headersOfType.stream(), headersOfMethod.stream()) .map(h -> new EndpointHeader(h.name(), h.value())) .collect(Collectors.toCollection(HashSet::new)); Collection cookiesOfType = javaTypeMetadata.cookies(); Collection cookiesOfMethod = javaMethodMetadata.cookies(); headers.addAll(Stream.concat(cookiesOfType.stream(), cookiesOfMethod.stream()) .map(c -> new EndpointCookie(c.name(), c.value())) .map(EndpointCookie::asHeader) .collect(Collectors.toCollection(HashSet::new))); return new EndpointHeaders(headers); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy