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

net.officefloor.web.HttpRouteSectionSource Maven / Gradle / Ivy

/*
 * OfficeFloor - http://www.officefloor.net
 * Copyright (C) 2005-2018 Daniel Sagenschneider
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */
package net.officefloor.web;

import java.util.LinkedList;
import java.util.List;

import net.officefloor.compile.spi.managedfunction.source.FunctionNamespaceBuilder;
import net.officefloor.compile.spi.managedfunction.source.ManagedFunctionSource;
import net.officefloor.compile.spi.managedfunction.source.ManagedFunctionSourceContext;
import net.officefloor.compile.spi.managedfunction.source.ManagedFunctionTypeBuilder;
import net.officefloor.compile.spi.managedfunction.source.impl.AbstractManagedFunctionSource;
import net.officefloor.compile.spi.section.FunctionFlow;
import net.officefloor.compile.spi.section.SectionDesigner;
import net.officefloor.compile.spi.section.SectionFunction;
import net.officefloor.compile.spi.section.SectionFunctionNamespace;
import net.officefloor.compile.spi.section.SectionInput;
import net.officefloor.compile.spi.section.SectionObject;
import net.officefloor.compile.spi.section.SectionOutput;
import net.officefloor.compile.spi.section.source.SectionSource;
import net.officefloor.compile.spi.section.source.SectionSourceContext;
import net.officefloor.compile.spi.section.source.impl.AbstractSectionSource;
import net.officefloor.frame.api.build.Indexed;
import net.officefloor.frame.api.build.None;
import net.officefloor.frame.api.function.ManagedFunction;
import net.officefloor.frame.api.source.PrivateSource;
import net.officefloor.frame.internal.structure.Flow;
import net.officefloor.server.http.HttpEscalationHandler;
import net.officefloor.server.http.HttpMethod;
import net.officefloor.server.http.HttpRequest;
import net.officefloor.server.http.HttpRequestCookie;
import net.officefloor.server.http.ServerHttpConnection;
import net.officefloor.web.HttpHandleRedirectFunction.HttpHandleRedirectDependencies;
import net.officefloor.web.HttpRedirectFunction.HttpRedirectDependencies;
import net.officefloor.web.HttpRouteFunction.HttpRouteDependencies;
import net.officefloor.web.InitialiseHttpRequestStateFunction.InitialiseHttpRequestStateDependencies;
import net.officefloor.web.NotHandledFunction.NotHandledDependencies;
import net.officefloor.web.build.HttpPathFactory;
import net.officefloor.web.build.WebArchitect;
import net.officefloor.web.escalation.NotFoundHttpException;
import net.officefloor.web.route.WebRouter;
import net.officefloor.web.route.WebRouterBuilder;
import net.officefloor.web.route.WebServicer;
import net.officefloor.web.session.HttpSession;
import net.officefloor.web.state.HttpArgument;
import net.officefloor.web.state.HttpRequestState;

/**
 * {@link SectionSource} to handle HTTP routing.
 * 
 * @author Daniel Sagenschneider
 */
@PrivateSource
public class HttpRouteSectionSource extends AbstractSectionSource {

	/**
	 * Name of {@link SectionOutput} for unhandled {@link HttpRequest}.
	 */
	public static final String UNHANDLED_OUTPUT_NAME = "UNHANDLED";

	/**
	 * Name of {@link SectionInput} for not found resource.
	 */
	public static final String NOT_FOUND_INPUT_NAME = "NOT_FOUND";

	/**
	 * Name of the route {@link ManagedFunction}.
	 */
	private static final String ROUTE_FUNCTION_NAME = "route";

	/**
	 * Name of the handle redirect {@link ManagedFunction}.
	 */
	private static final String HANDLE_REDIRECT_FUNCTION_NAME = "redirect";

	/**
	 * Name of {@link FunctionFlow} to handle redirect.
	 */
	private static final String HANDLE_REDIRECT_FLOW = "REDIRECT";

	/**
	 * Name of the initialise {@link HttpRequestState} {@link ManagedFunction}.
	 */
	private static final String INITIALISE_REQUEST_STATE_FUNCTION_NAME = "initialise";

	/**
	 * Obtains the interception details.
	 */
	public static class Interception {

		/**
		 * {@link SectionOutput} name to link the interception.
		 */
		private final String outputName;

		/**
		 * {@link SectionInput} name to link the routing.
		 */
		private final String inputName;

		/**
		 * Instantiate.
		 * 
		 * @param outputName {@link SectionOutput} name to link the interception.
		 * @param inputName  {@link SectionInput} name to link the routing.
		 */
		private Interception(String outputName, String inputName) {
			this.outputName = outputName;
			this.inputName = inputName;
		}

		/**
		 * Obtains the {@link SectionOutput} name to link the interception.
		 * 
		 * @return {@link SectionOutput} name to link the interception.
		 */
		public String getOutputName() {
			return this.outputName;
		}

		/**
		 * Obtains the {@link SectionInput} name to link the routing.
		 * 
		 * @return {@link SectionInput} name to link the routing.
		 */
		public String getInputName() {
			return this.inputName;
		}
	}

	/**
	 * Route input information.
	 */
	public static class RouteInput {

		/**
		 * {@link Flow} index of the route.
		 */
		private final int flowIndex;

		/**
		 * {@link HttpMethod} for the route.
		 */
		private final HttpMethod method;

		/**
		 * Path for the route.
		 */
		private final String path;

		/**
		 * {@link HttpInputPath}.
		 */
		private final HttpInputPath inputPath;

		/**
		 * Instantiate.
		 * 
		 * @param flowIndex {@link Flow} index of the route.
		 * @param method    {@link HttpMethod} for the route.
		 * @param path      Path for the route.
		 * @param inputPath {@link HttpInputPath}.
		 */
		private RouteInput(int flowIndex, HttpMethod method, String path, HttpInputPath inputPath) {
			this.flowIndex = flowIndex;
			this.method = method;
			this.path = path;
			this.inputPath = inputPath;
		}

		/**
		 * Obtains the {@link SectionOutput} name for this route.
		 * 
		 * @return {@link SectionOutput} name for this route.
		 */
		public String getOutputName() {
			return this.flowIndex + "_" + method.getName() + "_" + this.path;
		}

		/**
		 * Obtains the {@link HttpInputPath} for this route.
		 * 
		 * @return {@link HttpInputPath} for this route.
		 */
		public HttpInputPath getHttpInputPath() {
			return this.inputPath;
		}
	}

	/**
	 * Redirect.
	 */
	public static class Redirect {

		/**
		 * Indicates if redirect to a secure port.
		 */
		private final boolean isSecure;

		/**
		 * {@link HttpPathFactory}.
		 */
		private final HttpPathFactory httpPathFactory;

		/**
		 * Name of the {@link SectionInput} to handle the redirect.
		 */
		private final String inputName;

		/**
		 * Instantiate.
		 * 
		 * @param isSecure        Indicates if redirect to a secure port.
		 * @param httpPathFactory {@link HttpPathFactory} for this redirect.
		 * @param inputName       Name of the {@link SectionInput} to handle the
		 *                        redirect.
		 * @param parameterType   Type of parameter passed to the
		 *                        {@link ManagedFunction} to retrieve the values to
		 *                        construct the path.
		 */
		private Redirect(boolean isSecure, HttpPathFactory httpPathFactory, String inputName) {
			this.isSecure = isSecure;
			this.httpPathFactory = httpPathFactory;
			this.inputName = inputName;
		}

		/**
		 * Obtains the name of the {@link SectionInput} to handle the redirect.
		 * 
		 * @return Name of the {@link SectionInput} to handle the redirect.
		 */
		public String getInputName() {
			return this.inputName;
		}
	}

	/**
	 * {@link WebRouterBuilder}.
	 */
	private final WebRouterBuilder builder;

	/**
	 * {@link HttpEscalationHandler}. May be null.
	 */
	private HttpEscalationHandler escalationHandler = null;

	/**
	 * Optional {@link Interception}.
	 */
	private Interception interception = null;

	/**
	 * {@link RouteInput} instances.
	 */
	private final List routes = new LinkedList<>();

	/**
	 * {@link Redirect} instances.
	 */
	private final List redirects = new LinkedList<>();

	/**
	 * Instantiate.
	 * 
	 * @param contextPath Context path. May be null.
	 */
	public HttpRouteSectionSource(String contextPath) {
		this.builder = new WebRouterBuilder(contextPath);
	}

	/**
	 * Specifies the {@link HttpEscalationHandler}
	 * 
	 * @param escalationHandler {@link HttpEscalationHandler}. May be
	 *                          null.
	 */
	public void setHttpEscalationHandler(HttpEscalationHandler escalationHandler) {
		this.escalationHandler = escalationHandler;
	}

	/**
	 * Obtains the {@link Interception}.
	 * 
	 * @return {@link Interception}.
	 */
	public Interception getInterception() {
		if (this.interception == null) {
			this.interception = new Interception("INTERCEPTION_OUT", "INTERCEPTION_IN");
		}
		return this.interception;
	}

	/**
	 * Indicates if the path contains parameters.
	 * 
	 * @param path Path.
	 * @return true should the path contain parameters.
	 */
	public boolean isPathParameters(String path) {
		return WebRouterBuilder.isPathParameters(path);
	}

	/**
	 * Adds a route.
	 * 
	 * @param isSecure Indicates if a secure connection is required for the route.
	 * @param method   {@link HttpMethod}.
	 * @param path     Route path.
	 * @return {@link RouteInput} for the route.
	 */
	public RouteInput addRoute(boolean isSecure, HttpMethod method, String path) {

		// Obtain the flow index for the route
		int flowIndex = this.routes.size();

		// Add the route
		HttpInputPath inputPath = this.builder.addRoute(method, path, new WebRouteHandlerImpl(isSecure, flowIndex));

		// Track route information for configuration
		RouteInput input = new RouteInput(flowIndex, method, path, inputPath);
		this.routes.add(input);

		// Return the route input
		return input;
	}

	/**
	 * Adds a {@link Redirect}.
	 * 
	 * @param isSecure      Indicates to redirect to a secure port.
	 * @param routeInput    {@link RouteInput} to redirect to.
	 * @param parameterType Type of parameter passed to the redirect
	 *                      {@link ManagedFunction} to source values for
	 *                      constructing the path. May be null.
	 * @return {@link Redirect}.
	 * @throws Exception If fails to add the redirect.
	 */
	public Redirect addRedirect(boolean isSecure, RouteInput routeInput, Class parameterType) throws Exception {

		// Obtain the redirect index (to keep name unique)
		int redirectIndex = this.redirects.size();

		// Create the HTTP path factory (defaulting type to object)
		parameterType = (parameterType == null) ? Object.class : parameterType;
		HttpPathFactory httpPathFactory = routeInput.inputPath.createHttpPathFactory(parameterType);

		// Create the redirect input name
		String inputName = "REDIRECT_" + redirectIndex + (isSecure ? "_SECURE_" : "_") + routeInput.path
				+ (parameterType == null ? "" : "_" + parameterType.getName());

		// Create and register the redirect
		Redirect redirect = new Redirect(isSecure, httpPathFactory, inputName);
		this.redirects.add(redirect);

		// Return the redirect
		return redirect;
	}

	/*
	 * ==================== SectionSource ========================
	 */

	@Override
	protected void loadSpecification(SpecificationContext context) {
	}

	@Override
	public void sourceSection(SectionDesigner designer, SectionSourceContext context) throws Exception {

		// All routes added via office, so now build web router
		WebRouter webRouter = this.builder.build();
		int nonHandledFlowIndex = this.routes.size();
		HttpRouter httpRouter = new HttpRouter(webRouter, nonHandledFlowIndex);

		// Add the routing function
		SectionFunctionNamespace routeNamespace = designer.addSectionFunctionNamespace("ROUTE",
				new HttpRouteManagedFunctionSource(httpRouter));
		SectionFunction route = routeNamespace.addSectionFunction(WebArchitect.HANDLER_INPUT_NAME, ROUTE_FUNCTION_NAME);

		// Add the handle redirect function
		SectionFunctionNamespace handleRedirectNamespace = designer.addSectionFunctionNamespace("REDIRECT",
				new HttpHandleRedirectFunctionSource(httpRouter));
		SectionFunction handleRedirect = handleRedirectNamespace.addSectionFunction(HANDLE_REDIRECT_FUNCTION_NAME,
				HANDLE_REDIRECT_FUNCTION_NAME);

		// Link redirect flow to handle redirect
		designer.link(route.getFunctionFlow(HANDLE_REDIRECT_FLOW), handleRedirect, false);

		// Determine if interception
		SectionInput handleHttpInput = designer.addSectionInput(WebArchitect.HANDLER_INPUT_NAME, null);
		if (this.interception == null) {
			// No interception, make routing function handle HTTP input
			designer.link(handleHttpInput, route);

		} else {
			// Have interception, so provide hooks to intercept
			SectionFunctionNamespace interceptNamespace = designer.addSectionFunctionNamespace(
					InterceptManagedFunctionSource.FUNCTION_NAME, new InterceptManagedFunctionSource());
			SectionFunction intercept = interceptNamespace.addSectionFunction(
					InterceptManagedFunctionSource.FUNCTION_NAME, InterceptManagedFunctionSource.FUNCTION_NAME);
			designer.link(handleHttpInput, intercept);

			// Trigger interception
			SectionOutput interceptOutput = designer.addSectionOutput(this.interception.outputName, null, false);
			designer.link(intercept, interceptOutput);

			// After interception, let routing service
			SectionInput routeInput = designer.addSectionInput(this.interception.inputName, null);
			designer.link(routeInput, route);
		}

		// Obtain the connection, request state, session and application state
		SectionObject serverHttpConnection = designer.addSectionObject(ServerHttpConnection.class.getSimpleName(),
				ServerHttpConnection.class.getName());
		SectionObject requestState = designer.addSectionObject(HttpRequestState.class.getSimpleName(),
				HttpRequestState.class.getName());
		SectionObject session = designer.addSectionObject(HttpSession.class.getSimpleName(),
				HttpSession.class.getName());

		// Link the routing to section outputs
		for (RouteInput routeConfig : this.routes) {

			// Obtain the route flow
			String outputName = routeConfig.getOutputName();
			SectionOutput output = designer.addSectionOutput(outputName, null, false);

			// Obtain the handle redirect flow (never initialises)
			FunctionFlow handleRedirectFlow = handleRedirect.getFunctionFlow(outputName);
			designer.link(handleRedirectFlow, output, false);

			// Determine if path parameters
			FunctionFlow routeFlow = route.getFunctionFlow(outputName);
			if (!routeConfig.inputPath.isPathParameters()) {
				// No path parameters, so link directly
				designer.link(routeFlow, output, false);

			} else {
				// Path parameters, so must load to request state
				SectionFunctionNamespace initialiseNamespace = designer.addSectionFunctionNamespace(outputName,
						new InitialiseHttpRequestStateManagedFunctionSource());
				SectionFunction initialise = initialiseNamespace.addSectionFunction(outputName,
						INITIALISE_REQUEST_STATE_FUNCTION_NAME);
				designer.link(routeFlow, initialise, false);

				// Configure HTTP path arguments parameter
				initialise.getFunctionObject(InitialiseHttpRequestStateDependencies.PATH_ARGUMENTS.name())
						.flagAsParameter();

				// Configure dependency on request state
				designer.link(
						initialise.getFunctionObject(InitialiseHttpRequestStateDependencies.HTTP_REQUEST_STATE.name()),
						requestState);

				// Link initialise to output
				designer.link(initialise, output);
			}
		}

		// Link non-handled to output
		SectionOutput unhandled = designer.addSectionOutput(UNHANDLED_OUTPUT_NAME, null, false);
		designer.link(route.getFunctionFlow(UNHANDLED_OUTPUT_NAME), unhandled, false);
		designer.link(handleRedirect.getFunctionFlow(UNHANDLED_OUTPUT_NAME), unhandled, false);

		// Configure the not found input
		SectionInput notHandledInput = designer.addSectionInput(NOT_FOUND_INPUT_NAME, null);
		SectionFunctionNamespace notHandledNamespace = designer.addSectionFunctionNamespace("NOT_HANDLED",
				new NotHandledManagedFunctionSource());
		SectionFunction notHandled = notHandledNamespace.addSectionFunction(NOT_FOUND_INPUT_NAME, NOT_FOUND_INPUT_NAME);
		designer.link(notHandledInput, notHandled);

		// Escalate not found to office
		SectionOutput notFoundEscalation = designer.addSectionOutput(NotFoundHttpException.class.getSimpleName(),
				NotFoundHttpException.class.getName(), true);
		designer.link(notHandled.getFunctionEscalation(NotFoundHttpException.class.getName()), notFoundEscalation,
				true);

		// Configure routing dependencies
		designer.link(route.getFunctionObject(HttpRouteDependencies.SERVER_HTTP_CONNECTION.name()),
				serverHttpConnection);

		// Configure handle redirect dependencies
		handleRedirect.getFunctionObject(HttpHandleRedirectDependencies.COOKIE.name()).flagAsParameter();
		designer.link(handleRedirect.getFunctionObject(HttpHandleRedirectDependencies.SERVER_HTTP_CONNECTION.name()),
				serverHttpConnection);
		designer.link(handleRedirect.getFunctionObject(HttpHandleRedirectDependencies.REQUEST_STATE.name()),
				requestState);
		designer.link(handleRedirect.getFunctionObject(HttpHandleRedirectDependencies.SESSION.name()), session);

		// Configure not handled dependencies
		designer.link(notHandled.getFunctionObject(NotHandledDependencies.SERVER_HTTP_CONNECTION.name()),
				serverHttpConnection);
		notHandled.getFunctionObject(NotHandledDependencies.WEB_SERVICER.name()).flagAsParameter();

		// Configure the redirects
		for (Redirect redirect : this.redirects) {

			// Obtain the function name
			String functionName = redirect.inputName;

			// Add the function to send the redirect
			SectionFunctionNamespace redirectNamespace = designer.addSectionFunctionNamespace(functionName,
					new RedirectManagedFunctionSource(redirect));
			SectionFunction redirection = redirectNamespace.addSectionFunction(functionName, functionName);

			// Link input to the function
			SectionInput redirectInput = designer.addSectionInput(functionName, null);
			designer.link(redirectInput, redirection);

			// Configure dependency on server HTTP connection
			redirection.getFunctionObject(HttpRedirectDependencies.PATH_VALUES.name()).flagAsParameter();
			designer.link(redirection.getFunctionObject(HttpRedirectDependencies.SERVER_HTTP_CONNECTION.name()),
					serverHttpConnection);
			designer.link(redirection.getFunctionObject(HttpRedirectDependencies.REQUEST_STATE.name()), requestState);
			designer.link(redirection.getFunctionObject(HttpRedirectDependencies.SESSION_STATE.name()), session);
		}
	}

	/**
	 * {@link ManagedFunctionSource} for the {@link InterceptFunction}.
	 */
	@PrivateSource
	private static class InterceptManagedFunctionSource extends AbstractManagedFunctionSource {

		/**
		 * Name of the {@link ManagedFunction}.
		 */
		private static final String FUNCTION_NAME = "INTERCEPT";

		/*
		 * ============ ManagedFunctionSource ==============
		 */

		@Override
		protected void loadSpecification(SpecificationContext context) {
		}

		@Override
		public void sourceManagedFunctions(FunctionNamespaceBuilder functionNamespaceTypeBuilder,
				ManagedFunctionSourceContext context) throws Exception {

			// Add the intercept function
			functionNamespaceTypeBuilder.addManagedFunctionType(FUNCTION_NAME, new InterceptFunction(), None.class,
					None.class);
		}
	}

	/**
	 * {@link ManagedFunctionSource} for the {@link HttpRouteFunction}.
	 */
	@PrivateSource
	private class HttpRouteManagedFunctionSource extends AbstractManagedFunctionSource {

		/**
		 * {@link HttpRouter}.
		 */
		private final HttpRouter router;

		/**
		 * Instantiate.
		 * 
		 * @param router {@link HttpRouter}.
		 */
		private HttpRouteManagedFunctionSource(HttpRouter router) {
			this.router = router;
		}

		/*
		 * ============ ManagedFunctionSource ==============
		 */

		@Override
		protected void loadSpecification(SpecificationContext context) {
		}

		@Override
		public void sourceManagedFunctions(FunctionNamespaceBuilder functionNamespaceTypeBuilder,
				ManagedFunctionSourceContext context) throws Exception {

			// Obtain the routes
			List routes = HttpRouteSectionSource.this.routes;

			// Obtain the handle redirect flow (size is non-handled flow)
			int handleRedirectFlowIndex = routes.size() + 1;

			// Build the function
			ManagedFunctionTypeBuilder builder = functionNamespaceTypeBuilder
					.addManagedFunctionType(ROUTE_FUNCTION_NAME,
							new HttpRouteFunction(HttpRouteSectionSource.this.escalationHandler,
									handleRedirectFlowIndex, this.router),
							HttpRouteDependencies.class, Indexed.class);

			// Configure the flows for the routes
			this.router.configureRoutes(routes, builder);

			// Add handle redirect flow
			builder.addFlow().setLabel(HANDLE_REDIRECT_FLOW);

			// Configure dependency on server HTTP connection
			builder.addObject(ServerHttpConnection.class).setKey(HttpRouteDependencies.SERVER_HTTP_CONNECTION);
		}
	}

	/**
	 * {@link ManagedFunctionSource} for the {@link HttpHandleRedirectFunction}.
	 */
	@PrivateSource
	private class HttpHandleRedirectFunctionSource extends AbstractManagedFunctionSource {

		/**
		 * {@link HttpRouter}.
		 */
		private final HttpRouter router;

		/**
		 * Instantiate.
		 * 
		 * @param router {@link HttpRouter}.
		 */
		private HttpHandleRedirectFunctionSource(HttpRouter router) {
			this.router = router;
		}

		/*
		 * ============ ManagedFunctionSource ==============
		 */

		@Override
		protected void loadSpecification(SpecificationContext context) {
		}

		@Override
		public void sourceManagedFunctions(FunctionNamespaceBuilder functionNamespaceTypeBuilder,
				ManagedFunctionSourceContext context) throws Exception {

			// Obtain the routes
			List routes = HttpRouteSectionSource.this.routes;

			// Build the function
			ManagedFunctionTypeBuilder builder = functionNamespaceTypeBuilder
					.addManagedFunctionType(HANDLE_REDIRECT_FUNCTION_NAME, new HttpHandleRedirectFunction(this.router),
							HttpHandleRedirectDependencies.class, Indexed.class);

			// Configure the flows for the routes
			this.router.configureRoutes(routes, builder);

			// Configure dependency on server HTTP connection
			builder.addObject(HttpRequestCookie.class).setKey(HttpHandleRedirectDependencies.COOKIE);
			builder.addObject(ServerHttpConnection.class).setKey(HttpHandleRedirectDependencies.SERVER_HTTP_CONNECTION);
			builder.addObject(HttpRequestState.class).setKey(HttpHandleRedirectDependencies.REQUEST_STATE);
			builder.addObject(HttpSession.class).setKey(HttpHandleRedirectDependencies.SESSION);
		}
	}

	/**
	 * {@link ManagedFunctionSource} for the
	 * {@link InitialiseHttpRequestStateFunction}.
	 */
	@PrivateSource
	private class InitialiseHttpRequestStateManagedFunctionSource extends AbstractManagedFunctionSource {

		/*
		 * ============ ManagedFunctionSource ==============
		 */

		@Override
		protected void loadSpecification(SpecificationContext context) {
		}

		@Override
		public void sourceManagedFunctions(FunctionNamespaceBuilder functionNamespaceTypeBuilder,
				ManagedFunctionSourceContext context) throws Exception {

			// Add the initialise HTTP request state function
			ManagedFunctionTypeBuilder builder = functionNamespaceTypeBuilder
					.addManagedFunctionType(INITIALISE_REQUEST_STATE_FUNCTION_NAME,
							new InitialiseHttpRequestStateFunction(), InitialiseHttpRequestStateDependencies.class,
							None.class);

			// Configure dependency on the request state and path arguments
			builder.addObject(HttpArgument.class).setKey(InitialiseHttpRequestStateDependencies.PATH_ARGUMENTS);
			builder.addObject(HttpRequestState.class).setKey(InitialiseHttpRequestStateDependencies.HTTP_REQUEST_STATE);
		}
	}

	/**
	 * {@link ManagedFunctionSource} for the {@link HttpRedirectFunction}.
	 */
	@PrivateSource
	private class RedirectManagedFunctionSource extends AbstractManagedFunctionSource {

		/**
		 * {@link Redirect}.
		 */
		private final Redirect redirect;

		/**
		 * Instantiate.
		 * 
		 * @param redirect {@link Redirect}.
		 */
		private RedirectManagedFunctionSource(Redirect redirect) {
			this.redirect = redirect;
		}

		/*
		 * ============ ManagedFunctionSource ==============
		 */

		@Override
		protected void loadSpecification(SpecificationContext context) {
		}

		@Override
		public void sourceManagedFunctions(FunctionNamespaceBuilder functionNamespaceTypeBuilder,
				ManagedFunctionSourceContext context) throws Exception {

			// Create the function and obtain it's name
			final String functionName = this.redirect.inputName;
			HttpRedirectFunction function = new HttpRedirectFunction<>(this.redirect.isSecure,
					this.redirect.httpPathFactory);

			// Add the redirect function
			ManagedFunctionTypeBuilder builder = functionNamespaceTypeBuilder
					.addManagedFunctionType(functionName, function, HttpRedirectDependencies.class, None.class);

			// Configure dependencies
			builder.addObject(this.redirect.httpPathFactory.getValuesType())
					.setKey(HttpRedirectDependencies.PATH_VALUES);
			builder.addObject(ServerHttpConnection.class).setKey(HttpRedirectDependencies.SERVER_HTTP_CONNECTION);
			builder.addObject(HttpRequestState.class).setKey(HttpRedirectDependencies.REQUEST_STATE);
			builder.addObject(HttpSession.class).setKey(HttpRedirectDependencies.SESSION_STATE);
		}
	}

	/**
	 * {@link ManagedFunctionSource} for the {@link NotHandledFunction}.
	 */
	@PrivateSource
	private class NotHandledManagedFunctionSource extends AbstractManagedFunctionSource {

		/*
		 * ============ ManagedFunctionSource ==============
		 */

		@Override
		protected void loadSpecification(SpecificationContext context) {
		}

		@Override
		public void sourceManagedFunctions(FunctionNamespaceBuilder functionNamespaceTypeBuilder,
				ManagedFunctionSourceContext context) throws Exception {

			// Add the not handled function
			ManagedFunctionTypeBuilder builder = functionNamespaceTypeBuilder
					.addManagedFunctionType(NOT_FOUND_INPUT_NAME, new NotHandledFunction(),
							NotHandledDependencies.class, None.class);

			// Configure dependencies
			builder.addObject(ServerHttpConnection.class).setKey(NotHandledDependencies.SERVER_HTTP_CONNECTION);
			builder.addObject(WebServicer.class).setKey(NotHandledDependencies.WEB_SERVICER);

			// Configure not found escalation
			builder.addEscalation(NotFoundHttpException.class);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy