package core.framework.api.module; import core.framework.api.http.HTTPClient; import core.framework.api.http.HTTPClientBuilder; import core.framework.api.http.HTTPMethod; import core.framework.api.web.Controller; import core.framework.api.web.service.Path; import core.framework.impl.module.ModuleContext; import core.framework.impl.web.BeanValidator; import core.framework.impl.web.ControllerHolder; import core.framework.impl.web.service.HTTPMethodHelper; import core.framework.impl.web.service.WebServiceClient; import core.framework.impl.web.service.WebServiceClientBuilder; import core.framework.impl.web.service.WebServiceControllerBuilder; import core.framework.impl.web.service.WebServiceImplValidator; import core.framework.impl.web.service.WebServiceInterfaceValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; /** * @author neo */ public final class APIConfig { private final Logger logger = LoggerFactory.getLogger(APIConfig.class); private final ModuleContext context; private final State state; public APIConfig(ModuleContext context) { this.context = context; state = context.config.api(); } public <T> void service(Class<T> serviceInterface, T service) { logger.info("create api service, interface={}", serviceInterface.getCanonicalName()); BeanValidator validator = context.httpServer.handler.validator; new WebServiceInterfaceValidator(serviceInterface, validator).validate(); new WebServiceImplValidator<>(serviceInterface, service).validate(); Method[] methods = serviceInterface.getDeclaredMethods(); for (Method method : methods) { HTTPMethod httpMethod = HTTPMethodHelper.httpMethod(method); String path = method.getDeclaredAnnotation(Path.class).value(); Controller controller = new WebServiceControllerBuilder<>(serviceInterface, service, method).build(); try { Class<?>[] parameterTypes = method.getParameterTypes(); Method targetMethod = service.getClass().getMethod(method.getName(), parameterTypes); context.httpServer.handler.route.add(httpMethod, path, new ControllerHolder(controller, targetMethod)); } catch (NoSuchMethodException e) { throw new Error("failed to find impl method", e); } } } public <T> APIClientConfig client(Class<T> serviceInterface, String serviceURL) { logger.info("create api service client, interface={}, serviceURL={}", serviceInterface.getCanonicalName(), serviceURL); BeanValidator validator = context.httpServer.handler.validator; new WebServiceInterfaceValidator(serviceInterface, validator).validate(); HTTPClient httpClient = httpClient(); WebServiceClient webServiceClient = new WebServiceClient(serviceURL, httpClient, validator, context.logManager); T client = createWebServiceClient(serviceInterface, webServiceClient); context.beanFactory.bind(serviceInterface, null, client); return new APIClientConfig(webServiceClient); } private <T> T createWebServiceClient(Class<T> serviceInterface, WebServiceClient webServiceClient) { if (context.isTest()) { return context.mockFactory.create(serviceInterface); } else { return new WebServiceClientBuilder<>(serviceInterface, webServiceClient).build(); } } private HTTPClient httpClient() { if (state.httpClient == null) { HTTPClient httpClient = new HTTPClientBuilder().userAgent("APIClient").build(); context.shutdownHook.add(httpClient::close); state.httpClient = httpClient; } return state.httpClient; } public static class State { HTTPClient httpClient; } }