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

com.dexmatech.styx.modules.grizzly.ApiGateway Maven / Gradle / Ivy

package com.dexmatech.styx.modules.grizzly;

import com.dexmatech.styx.core.ApiPipeline;
import com.dexmatech.styx.core.http.HttpResponse;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.http.server.Response;
import org.glassfish.grizzly.http.util.HttpStatus;
import org.glassfish.grizzly.threadpool.GrizzlyExecutorService;
import org.glassfish.grizzly.threadpool.ThreadPoolConfig;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;

/**
 * Created by aortiz on 12/08/16.
 */
@Slf4j
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ApiGateway {

	public static final int DEFAULT_PORT = 8080;
	public static final Supplier DEFAULT_EXECUTOR_SERVICE_SUPPLIER = () ->
			GrizzlyExecutorService.createInstance(
					ThreadPoolConfig.defaultConfig()
							.copy()
							.setCorePoolSize(5)
							.setMaxPoolSize(5)
			);

	@Getter
	private final HttpServer httpServer;
	@Getter
	private final ExecutorService executorService;
	@Getter
	private final ApiPipeline pipeline;

	public static Builder runningOverGrizzly() {
		return new Builder();
	}

	public static class Builder {
		private Optional httpServer = Optional.empty();//HttpServer.createSimpleServer();
		private Optional complexAppExecutorService = Optional.empty();
		private int port = DEFAULT_PORT;
		private ApiPipeline pipeline;

		public Builder providingHttpServer(HttpServer httpServer) {
			this.httpServer = Optional.ofNullable(httpServer);
			return this;
		}

		public Builder withExecutorService(ExecutorService complexAppExecutorService) {
			this.complexAppExecutorService = Optional.ofNullable(complexAppExecutorService);
			return this;
		}

		public Builder withDefaultServerRunningOnPort(int port) {
			this.port = port;
			return this;
		}

		public Builder withPipeline(ApiPipeline pipeline) {
			this.pipeline = pipeline;
			return this;
		}

		public ApiGateway build() {
			Objects.requireNonNull(pipeline, "Api pipeline can not be empty");
			log.info("[API Gateway on Grizzly] was successfully created");
			return new ApiGateway(
					httpServer.orElse(HttpServer.createSimpleServer(".", port)),
					complexAppExecutorService.orElseGet(DEFAULT_EXECUTOR_SERVICE_SUPPLIER),
					pipeline

			);
		}
	}

	public void start(){
		this.run(false);
	}

	public void startAndKeepRunning(){
		this.run(true);
	}

	private ApiGateway run(boolean keepRunning) {
		httpServer.getServerConfiguration().addHttpHandler(new HttpHandler() {

			@Override
			public void service(final Request request, final Response response) throws Exception {

				response.suspend(); // Instruct Grizzly to not flush response, once we exit the service(...) method
				log.debug("[Grizzly adapter] Handling request and dispatching to pipeline '{}'",request.getRequest());
				executorService.execute(() -> {
					try {
						//						log.info(request.toString());
						CompletableFuture applyHttpReplyProtocol = pipeline.reply(RequestResponseMappers.asPipelineRequest(request));
						applyHttpReplyProtocol
								.thenAccept(httpResponse -> {
									try {
										RequestResponseMappers.mapResponseFields(httpResponse, response);
										response.resume();
									} catch (Throwable e) {
										handleError(response, e);
									}
								});
					} catch (Throwable e) {
						handleError(response, e);
					}

				});
			}
		}, "/*");
		try {
			httpServer.start();
			if(keepRunning) {
				Thread.currentThread().join();
			}
		} catch (Exception e) {
			log.error("Grizzly server not loaded", e);
		}
		return this;
	}


	public void shutdown(){
		httpServer.shutdownNow();
	}

	private void handleError(Response response, Throwable e) {
		log.error("REQUEST NOT ATTENDED", e);
		response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
		response.resume();  // Finishing HTTP request processing and flushing the response to the client
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy