![JAR search and dependency download from the Maven repository](/logo.png)
net.officefloor.web.WebArchitectEmployer Maven / Gradle / Ivy
Show all versions of officeweb Show documentation
/*
* 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.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import net.officefloor.compile.impl.util.CompileUtil;
import net.officefloor.compile.managedfunction.ManagedFunctionObjectType;
import net.officefloor.compile.managedfunction.ManagedFunctionType;
import net.officefloor.compile.properties.Property;
import net.officefloor.compile.spi.office.ManagedFunctionAugmentorContext;
import net.officefloor.compile.spi.office.OfficeArchitect;
import net.officefloor.compile.spi.office.OfficeFlowSinkNode;
import net.officefloor.compile.spi.office.OfficeFlowSourceNode;
import net.officefloor.compile.spi.office.OfficeManagedObject;
import net.officefloor.compile.spi.office.OfficeManagedObjectSource;
import net.officefloor.compile.spi.office.OfficeSection;
import net.officefloor.compile.spi.office.OfficeSectionInput;
import net.officefloor.compile.spi.office.source.OfficeSourceContext;
import net.officefloor.frame.internal.structure.ManagedObjectScope;
import net.officefloor.server.http.HttpMethod;
import net.officefloor.server.http.HttpRequest;
import net.officefloor.web.HttpRouteSectionSource.Interception;
import net.officefloor.web.HttpRouteSectionSource.Redirect;
import net.officefloor.web.HttpRouteSectionSource.RouteInput;
import net.officefloor.web.accept.AcceptNegotiatorBuilderImpl;
import net.officefloor.web.build.AcceptNegotiatorBuilder;
import net.officefloor.web.build.HttpArgumentParser;
import net.officefloor.web.build.HttpInput;
import net.officefloor.web.build.HttpObjectParserFactory;
import net.officefloor.web.build.HttpObjectParserServiceFactory;
import net.officefloor.web.build.HttpObjectResponderFactory;
import net.officefloor.web.build.HttpObjectResponderServiceFactory;
import net.officefloor.web.build.HttpUrlContinuation;
import net.officefloor.web.build.HttpValueLocation;
import net.officefloor.web.build.WebArchitect;
import net.officefloor.web.response.ObjectResponseManagedObjectSource;
import net.officefloor.web.session.HttpSessionManagedObjectSource;
import net.officefloor.web.session.object.HttpSessionObjectManagedObjectSource;
import net.officefloor.web.state.HttpApplicationObjectManagedObjectSource;
import net.officefloor.web.state.HttpApplicationStateManagedObjectSource;
import net.officefloor.web.state.HttpArgumentManagedObjectSource;
import net.officefloor.web.state.HttpObjectManagedObjectSource;
import net.officefloor.web.state.HttpRequestObjectManagedObjectSource;
import net.officefloor.web.state.HttpRequestStateManagedObjectSource;
import net.officefloor.web.tokenise.FormHttpArgumentParser;
/**
* {@link WebArchitect} implementation.
*
* @author Daniel Sagenschneider
*/
public class WebArchitectEmployer implements WebArchitect {
/**
* Name of {@link Property} specifying the context path.
*/
public static final String PROPERTY_CONTEXT_PATH = "context.path";
/**
* Employs a {@link WebArchitect}.
*
* @param officeArchitect
* {@link OfficeArchitect}.
* @param officeSourceContext
* {@link OfficeSourceContext} used to source {@link Property} values
* to configure the {@link WebArchitect}.
* @return {@link WebArchitect}.
*/
public static WebArchitect employWebArchitect(OfficeArchitect officeArchitect,
OfficeSourceContext officeSourceContext) {
// Obtain the context path
String contextPath = officeSourceContext.getProperty(PROPERTY_CONTEXT_PATH, null);
// Employ the web architect
return employWebArchitect(contextPath, officeArchitect, officeSourceContext);
}
/**
* Employs a {@link WebArchitect}.
*
* @param contextPath
* Context path for the web application. May be null
for
* no context path.
* @param officeArchitect
* {@link OfficeArchitect}.
* @param officeSourceContext
* {@link OfficeSourceContext} used to source {@link Property} values
* to configure the {@link WebArchitect}.
* @return {@link WebArchitect}.
*/
public static WebArchitect employWebArchitect(String contextPath, OfficeArchitect officeArchitect,
OfficeSourceContext officeSourceContext) {
return new WebArchitectEmployer(contextPath, officeArchitect, officeSourceContext);
}
/**
* Context path. May be null
for no context path.
*/
private final String contextPath;
/**
* {@link OfficeArchitect}.
*/
private final OfficeArchitect officeArchitect;
/**
* {@link OfficeSourceContext}.
*/
private final OfficeSourceContext officeSourceContext;
/**
* {@link HttpRouteSectionSource}.
*/
private final HttpRouteSectionSource routing;
/**
* Routing {@link OfficeSection}.
*/
private final OfficeSection routingSection;
/**
* Registry of HTTP arguments to its {@link OfficeManagedObject}.
*/
private final Map httpArguments = new HashMap<>();
/**
* Singleton {@link List} provided to the {@link HttpObjectManagedObjectSource}
* for the registered {@link HttpObjectParserFactory} instances.
*/
private final List singletonObjectParserList = new LinkedList<>();
/**
* Registry of {@link HttpObject} {@link Annotation} alias to accepted
* content-type
values. Note: the keys indicate the aliases, as
* accepted content-type
values are optional.
*/
private final Map, String[]> httpObjectAliases = new HashMap<>();
/**
* Registry of HTTP objects by their {@link Class}.
*/
private final Map, OfficeManagedObject> httpObjects = new HashMap<>();
/**
* Registry of HTTP Application Object to its {@link OfficeManagedObject}.
*/
private final Map httpApplicationObjects = new HashMap<>();
/**
* Registry of HTTP Session Object to its {@link OfficeManagedObject}.
*/
private final Map httpSessionObjects = new HashMap<>();
/**
* Registry of HTTP Request Object to its {@link OfficeManagedObject}.
*/
private final Map httpRequestObjects = new HashMap<>();
/**
* {@link HttpObjectResponderFactory} instances.
*/
private final List objectResponderFactories = new LinkedList<>();
/**
* {@link HttpInputImpl} instances.
*/
private final List inputs = new LinkedList<>();
/**
* {@link Interceptor} instances.
*/
private final List interceptors = new LinkedList<>();
/**
* {@link ChainedServicer} instances.
*/
private final List chainedServicers = new LinkedList<>();
/**
* Instantiate.
*
* @param contextPath
* Context path for the web application. May be null
for
* no context path.
* @param officeArchitect
* {@link OfficeArchitect}.
* @param officeSourceContext
* {@link OfficeSourceContext}.
*/
private WebArchitectEmployer(String contextPath, OfficeArchitect officeArchitect,
OfficeSourceContext officeSourceContext) {
this.contextPath = contextPath;
this.officeArchitect = officeArchitect;
this.officeSourceContext = officeSourceContext;
this.routing = new HttpRouteSectionSource(this.contextPath);
this.routingSection = this.officeArchitect.addOfficeSection(HANDLER_SECTION_NAME, this.routing, null);
// Obtain the registered HTTP object parser factories
Iterable objectParserFactories = this.officeSourceContext
.loadOptionalServices(HttpObjectParserServiceFactory.class);
for (HttpObjectParserFactory objectParserFactory : objectParserFactories) {
this.singletonObjectParserList.add(objectParserFactory);
}
// Obtain the HTTP object responder factories
Iterable objectResponderFactories = this.officeSourceContext
.loadOptionalServices(HttpObjectResponderServiceFactory.class);
for (HttpObjectResponderFactory objectResponderFactory : objectResponderFactories) {
this.objectResponderFactories.add(objectResponderFactory);
}
}
/**
* Obtains the bind name for the {@link OfficeManagedObject}.
*
* @param objectClass
* {@link Class} of the {@link Object}.
* @param bindName
* Optional bind name. May be null
.
* @return Bind name for the {@link OfficeManagedObject};
*/
private static String getBindName(Class> objectClass, String bindName) {
return (CompileUtil.isBlank(bindName) ? objectClass.getName() : bindName);
}
/*
* ======================== WebArchitect =========================
*/
@Override
public OfficeManagedObject addHttpArgument(String parameterName, HttpValueLocation location) {
// Obtain the bind name
String bindName = "HTTP_" + (location == null ? "ANY" : location.name()) + "_" + parameterName;
OfficeManagedObject object = this.httpArguments.get(bindName);
if (object != null) {
return object; // return the already register object
}
// Not registered, so register
OfficeManagedObjectSource mos = this.officeArchitect.addOfficeManagedObjectSource(bindName,
new HttpArgumentManagedObjectSource(parameterName, location));
object = mos.addOfficeManagedObject(bindName, ManagedObjectScope.PROCESS);
this.httpArguments.put(bindName, object);
// Return the object
return object;
}
@Override
public OfficeManagedObject addHttpApplicationObject(Class> objectClass, String bindName) {
// Determine if already registered
bindName = getBindName(objectClass, bindName);
OfficeManagedObject object = this.httpApplicationObjects.get(bindName);
if (object != null) {
return object; // return the already registered object
}
// Not registered, so register
OfficeManagedObjectSource mos = this.officeArchitect.addOfficeManagedObjectSource(bindName,
HttpApplicationObjectManagedObjectSource.class.getName());
mos.addProperty(HttpApplicationObjectManagedObjectSource.PROPERTY_CLASS_NAME, objectClass.getName());
if ((bindName != null) && (bindName.trim().length() > 0)) {
mos.addProperty(HttpApplicationObjectManagedObjectSource.PROPERTY_BIND_NAME, bindName);
}
object = mos.addOfficeManagedObject(bindName, ManagedObjectScope.PROCESS);
this.httpApplicationObjects.put(bindName, object);
// Return the object
return object;
}
@Override
public OfficeManagedObject addHttpApplicationObject(Class> objectClass) {
return this.addHttpApplicationObject(objectClass, null);
}
@Override
public OfficeManagedObject addHttpSessionObject(Class> objectClass, String bindName) {
// Determine if already registered
bindName = getBindName(objectClass, bindName);
OfficeManagedObject object = this.httpSessionObjects.get(bindName);
if (object != null) {
return object; // return the already registered object
}
// Not registered, so register
OfficeManagedObjectSource mos = this.officeArchitect.addOfficeManagedObjectSource(bindName,
HttpSessionObjectManagedObjectSource.class.getName());
mos.addProperty(HttpSessionObjectManagedObjectSource.PROPERTY_CLASS_NAME, objectClass.getName());
if ((bindName != null) && (bindName.trim().length() > 0)) {
mos.addProperty(HttpSessionObjectManagedObjectSource.PROPERTY_BIND_NAME, bindName);
}
object = mos.addOfficeManagedObject(bindName, ManagedObjectScope.PROCESS);
this.httpSessionObjects.put(bindName, object);
// Return the object
return object;
}
@Override
public OfficeManagedObject addHttpSessionObject(Class> objectClass) {
return this.addHttpSessionObject(objectClass, null);
}
@Override
public OfficeManagedObject addHttpRequestObject(Class> objectClass, boolean isLoadParameters, String bindName) {
// Determine if already registered
bindName = getBindName(objectClass, bindName);
OfficeManagedObject object = this.httpRequestObjects.get(bindName);
if (object == null) {
// Not registered, so register
OfficeManagedObjectSource mos = this.officeArchitect.addOfficeManagedObjectSource(bindName,
HttpRequestObjectManagedObjectSource.class.getName());
mos.addProperty(HttpRequestObjectManagedObjectSource.PROPERTY_CLASS_NAME, objectClass.getName());
if ((bindName != null) && (bindName.trim().length() > 0)) {
mos.addProperty(HttpRequestObjectManagedObjectSource.PROPERTY_BIND_NAME, bindName);
}
object = mos.addOfficeManagedObject(bindName, ManagedObjectScope.PROCESS);
this.httpRequestObjects.put(bindName, object);
// Determine if load HTTP parameters
if (isLoadParameters) {
// Add the property to load parameters
mos.addProperty(HttpRequestObjectManagedObjectSource.PROPERTY_IS_LOAD_HTTP_PARAMETERS,
String.valueOf(true));
}
}
// Return the object
return object;
}
@Override
public OfficeManagedObject addHttpRequestObject(Class> objectClass, boolean isLoadParameters) {
return this.addHttpRequestObject(objectClass, isLoadParameters, null);
}
@Override
public void addHttpObjectParser(HttpObjectParserFactory objectParserFactory) {
this.singletonObjectParserList.add(objectParserFactory);
}
@Override
public void addHttpObjectAnnotationAlias(Class> httpObjectAnnotationAliasClass, String... acceptedContentTypes) {
this.httpObjectAliases.put(httpObjectAnnotationAliasClass, acceptedContentTypes);
}
@Override
public OfficeManagedObject addHttpObject(Class> objectClass, String... acceptedContentTypes) {
// Determine if already registered
OfficeManagedObject object = this.httpObjects.get(objectClass);
if (object == null) {
// Not registered, so register
OfficeManagedObjectSource mos = this.officeArchitect.addOfficeManagedObjectSource(objectClass.getName(),
new HttpObjectManagedObjectSource<>(objectClass, acceptedContentTypes,
this.singletonObjectParserList));
object = mos.addOfficeManagedObject(objectClass.getName(), ManagedObjectScope.PROCESS);
this.httpObjects.put(objectClass, object);
}
// Return the object
return object;
}
@Override
public void addHttpObjectResponder(HttpObjectResponderFactory objectResponderFactory) {
this.objectResponderFactories.add(objectResponderFactory);
}
@Override
public boolean isPathParameters(String path) {
return this.routing.isPathParameters(path);
}
@Override
public HttpUrlContinuation getHttpInput(boolean isSecure, String applicationPath) {
HttpUrlContinuationImpl continuation = new HttpUrlContinuationImpl(isSecure, applicationPath);
this.inputs.add(continuation);
return continuation;
}
@Override
public HttpInput getHttpInput(boolean isSecure, String httpMethodName, String applicationPath) {
HttpMethod httpMethod = HttpMethod.getHttpMethod(httpMethodName);
HttpInputImpl input = new HttpInputImpl(isSecure, httpMethod, applicationPath);
this.inputs.add(input);
return input;
}
@Override
public void reroute(OfficeFlowSourceNode flowSourceNode) {
this.officeArchitect.link(flowSourceNode, this.routingSection.getOfficeSectionInput(HANDLER_INPUT_NAME));
}
@Override
public void intercept(OfficeFlowSinkNode flowSinkNode, OfficeFlowSourceNode flowSourceNode) {
this.interceptors.add(new Interceptor(flowSinkNode, flowSourceNode));
}
@Override
public void chainServicer(OfficeFlowSinkNode flowSinkNode, OfficeFlowSourceNode notHandledOutput) {
this.chainedServicers.add(new ChainedServicer(flowSinkNode, notHandledOutput));
}
@Override
public AcceptNegotiatorBuilder createAcceptNegotiator() {
return new AcceptNegotiatorBuilderImpl<>();
}
@Override
public void informOfficeArchitect() {
// Auto wire the objects
this.officeArchitect.enableAutoWireObjects();
// Configure HTTP Session (allowing 10 seconds to retrieve session)
OfficeManagedObjectSource httpSessionMos = this.officeArchitect.addOfficeManagedObjectSource("HTTP_SESSION",
HttpSessionManagedObjectSource.class.getName());
httpSessionMos.setTimeout(10 * 1000); // TODO make configurable
httpSessionMos.addOfficeManagedObject("HTTP_SESSION", ManagedObjectScope.PROCESS);
// Load the argument parsers
HttpArgumentParser[] argumentParsers = new HttpArgumentParser[] { new FormHttpArgumentParser() };
// Configure the HTTP Application and Request State
this.officeArchitect
.addOfficeManagedObjectSource("HTTP_APPLICATION_STATE",
new HttpApplicationStateManagedObjectSource(this.contextPath))
.addOfficeManagedObject("HTTP_APPLICATION_STATE", ManagedObjectScope.PROCESS);
this.officeArchitect
.addOfficeManagedObjectSource("HTTP_REQUEST_STATE",
new HttpRequestStateManagedObjectSource(argumentParsers))
.addOfficeManagedObject("HTTP_REQUEST_STATE", ManagedObjectScope.PROCESS);
// Configure the object responder (if configured factories)
if (this.objectResponderFactories.size() > 0) {
ObjectResponseManagedObjectSource objectResponseMos = new ObjectResponseManagedObjectSource(
this.objectResponderFactories);
this.officeArchitect.addOfficeManagedObjectSource("OBJECT_RESPONSE", objectResponseMos)
.addOfficeManagedObject("OBJECT_RESPONSE", ManagedObjectScope.PROCESS);
this.routing.setHttpEscalationHandler(objectResponseMos);
}
// Determine if intercept
if (this.interceptors.size() > 0) {
// Obtain the interception
Interception interception = routing.getInterception();
// Obtain the section output
OfficeFlowSourceNode interceptionOutput = this.routingSection
.getOfficeSectionOutput(interception.getOutputName());
for (Interceptor interceptor : this.interceptors) {
// Link in interception
this.officeArchitect.link(interceptionOutput, interceptor.flowSinkNode);
// Set up for next iteration
interceptionOutput = interceptor.flowSourceNode;
}
// Link interception back to routing
OfficeSectionInput routingInput = this.routingSection.getOfficeSectionInput(interception.getInputName());
this.officeArchitect.link(interceptionOutput, routingInput);
}
// Load in-line configured dependencies
final Set> httpParameters = new HashSet<>();
this.officeArchitect.addManagedFunctionAugmentor((context) -> {
ManagedFunctionType, ?> functionType = context.getManagedFunctionType();
for (ManagedFunctionObjectType> functionParameterType : functionType.getObjectTypes()) {
Class> objectType = functionParameterType.getObjectType();
// Determine if in-line configuration of dependency
for (Object annotation : functionParameterType.getAnnotations()) {
// Application object
if (annotation instanceof HttpApplicationStateful) {
HttpApplicationStateful stateful = (HttpApplicationStateful) annotation;
this.addHttpApplicationObject(objectType, stateful.bind());
}
// Session object
if (annotation instanceof HttpSessionStateful) {
HttpSessionStateful stateful = (HttpSessionStateful) annotation;
this.addHttpSessionObject(objectType, stateful.bind());
}
// HTTP parameters
if (annotation instanceof HttpParameters) {
// Load as HTTP parameters (only once)
if (!httpParameters.contains(objectType)) {
this.addHttpRequestObject(objectType, true);
httpParameters.add(objectType);
}
}
// HTTP object
if (annotation instanceof HttpObject) {
HttpObject httpObject = (HttpObject) annotation;
String[] acceptedContentTypes = httpObject.acceptedContentTypes();
this.addHttpObject(objectType, acceptedContentTypes);
}
// Determine if HTTP object alias annotation
String[] acceptedContentTypes = WebArchitectEmployer.this.httpObjectAliases
.get(annotation instanceof Annotation ? ((Annotation) annotation).annotationType()
: annotation.getClass());
if (acceptedContentTypes != null) {
this.addHttpObject(objectType, acceptedContentTypes);
}
// Load HTTP arguments
WebArchitectEmployer.this.loadInlineHttpArgument(annotation, HttpPathParameter.class,
HttpValueLocation.PATH, objectType, context, (parameter) -> parameter.value(),
(parameter) -> new HttpPathParameter.HttpPathParameterNameFactory()
.getQualifierName(parameter));
WebArchitectEmployer.this.loadInlineHttpArgument(annotation, HttpQueryParameter.class,
HttpValueLocation.QUERY, objectType, context, (parameter) -> parameter.value(),
(parameter) -> new HttpQueryParameter.HttpQueryParameterNameFactory()
.getQualifierName(parameter));
WebArchitectEmployer.this.loadInlineHttpArgument(annotation, HttpHeaderParameter.class,
HttpValueLocation.HEADER, objectType, context, (parameter) -> parameter.value(),
(parameter) -> new HttpHeaderParameter.HttpHeaderParameterNameFactory()
.getQualifierName(parameter));
WebArchitectEmployer.this.loadInlineHttpArgument(annotation, HttpCookieParameter.class,
HttpValueLocation.COOKIE, objectType, context, (parameter) -> parameter.value(),
(parameter) -> new HttpCookieParameter.HttpCookieParameterNameFactory()
.getQualifierName(parameter));
WebArchitectEmployer.this.loadInlineHttpArgument(annotation, HttpContentParameter.class,
HttpValueLocation.ENTITY, objectType, context, (parameter) -> parameter.value(),
(parameter) -> new HttpContentParameter.HttpContentParameterNameFactory()
.getQualifierName(parameter));
}
}
});
// Chain in the servicer instances
OfficeFlowSourceNode chainOutput = this.routingSection
.getOfficeSectionOutput(HttpRouteSectionSource.UNHANDLED_OUTPUT_NAME);
NEXT_CHAINED_SERVICER: for (ChainedServicer servicer : this.chainedServicers) {
// Do nothing if no output (all handled by previous servicer)
if (chainOutput == null) {
continue NEXT_CHAINED_SERVICER;
}
// Link output to to input
this.officeArchitect.link(chainOutput, servicer.flowSinkNode);
// Set up for next chain
chainOutput = servicer.notHandledOutput;
}
// Configure not handled
if (chainOutput != null) {
this.officeArchitect.link(chainOutput,
this.routingSection.getOfficeSectionInput(HttpRouteSectionSource.NOT_FOUND_INPUT_NAME));
}
}
/**
* Loads the in-line HTTP argument.
*
* @param annotation
* {@link Annotation}.
* @param annotationType
* Type of {@link Annotation}.
* @param valueLocation
* {@link HttpValueLocation}.
* @param objectType
* Parameter object type.
* @param context
* {@link ManagedFunctionAugmentorContext}.
* @param getParameterName
* {@link Function} to obtain the parameter name.
* @param getQualifierName
* {@link Function} to obtain the type qualification name.
*/
private void loadInlineHttpArgument(Object annotation, Class
annotationType,
HttpValueLocation valueLocation, Class> objectType, ManagedFunctionAugmentorContext context,
Function
getParameterName, Function
getQualifierName) {
// Ensure appropriate annotation
if (!(annotation instanceof Annotation)) {
return;
}
if (((Annotation) annotation).annotationType() != annotationType) {
return;
}
// Obtain the parameter
@SuppressWarnings("unchecked")
P parameterAnnotation = (P) annotation;
// Ensure parameter object is a String
if (objectType != String.class) {
this.officeArchitect.addIssue("Parameter must be " + String.class.getName() + " but was "
+ objectType.getName() + " for function " + context.getManagedFunctionName());
}
// Add the HTTP argument
String parameterName = getParameterName.apply(parameterAnnotation);
String typeQualifier = getQualifierName.apply(parameterAnnotation);
this.addHttpArgument(parameterName, valueLocation).addTypeQualification(typeQualifier, String.class.getName());
}
/**
* {@link HttpInput} implementation.
*/
private class HttpInputImpl implements HttpInput {
/**
* Indicates if secure.
*/
protected final boolean isSecure;
/**
* {@link HttpMethod}.
*/
private final HttpMethod httpMethod;
/**
* Application path.
*/
protected final String applicationPath;
/**
* {@link RouteInput}
*/
protected final RouteInput routeInput;
/**
* {@link OfficeFlowSourceNode} to configure handling of this {@link HttpInput}.
*/
private final OfficeFlowSourceNode input;
/**
* Instantiate.
*
* @param isSecure
* Indicates if secure.
* @param httpMethod
* {@link HttpMethod}.
* @param applicationPath
* Application path.
*/
private HttpInputImpl(boolean isSecure, HttpMethod httpMethod, String applicationPath) {
this.isSecure = isSecure;
this.httpMethod = httpMethod;
this.applicationPath = applicationPath;
this.routeInput = WebArchitectEmployer.this.routing.addRoute(isSecure, this.httpMethod,
this.applicationPath);
this.input = WebArchitectEmployer.this.routingSection
.getOfficeSectionOutput(this.routeInput.getOutputName());
}
/*
* ================== HttpInput ====================
*/
@Override
public HttpInputPath getPath() {
return this.routeInput.getHttpInputPath();
}
@Override
public OfficeFlowSourceNode getInput() {
return this.input;
}
}
/**
* {@link HttpUrlContinuation} implementation.
*/
private class HttpUrlContinuationImpl extends HttpInputImpl implements HttpUrlContinuation {
/**
* Mapping of parameter type to {@link OfficeFlowSinkNode} for redirects.
*/
private final Map redirects = new HashMap<>();
/**
* Instantiate.
*
* @param isSecure
* Indicates if secure.
* @param applicationPath
* Application path.
*/
private HttpUrlContinuationImpl(boolean isSecure, String applicationPath) {
super(isSecure, HttpMethod.GET, applicationPath);
}
/*
* =============== HttpUrlContinuation =============
*/
@Override
public OfficeFlowSinkNode getRedirect(String parameterTypeName) {
// Obtain the parameter type class
Class> parameterType = CompileUtil.isBlank(parameterTypeName) ? Object.class
: WebArchitectEmployer.this.officeSourceContext.loadClass(parameterTypeName);
// Determine if already cached
OfficeFlowSinkNode flowSinkNode = this.redirects.get(parameterTypeName);
if (flowSinkNode != null) {
return flowSinkNode;
}
// Not cached, so create
try {
// Create the redirect
Redirect redirect = WebArchitectEmployer.this.routing.addRedirect(this.isSecure, this.routeInput,
parameterType);
// Obtain and cache the flow sink node for the redirect
flowSinkNode = WebArchitectEmployer.this.routingSection.getOfficeSectionInput(redirect.getInputName());
this.redirects.put(parameterTypeName, flowSinkNode);
// Return the section input for redirect
return flowSinkNode;
} catch (Exception ex) {
throw WebArchitectEmployer.this.officeArchitect.addIssue("Failed to create redirect to "
+ this.applicationPath + (parameterTypeName == null ? " with null value type"
: " with values type " + parameterTypeName),
ex);
}
}
}
/**
* Intercepts the {@link HttpRequest} before web application functionality.
*/
private static class Interceptor {
/**
* {@link OfficeFlowSinkNode}.
*/
public final OfficeFlowSinkNode flowSinkNode;
/**
* {@link OfficeFlowSourceNode}.
*/
public final OfficeFlowSourceNode flowSourceNode;
/**
* Initiate.
*
* @param flowSinkNode
* {@link OfficeFlowSinkNode}.
* @param flowSourceNode
* {@link OfficeFlowSourceNode}.
*/
private Interceptor(OfficeFlowSinkNode flowSinkNode, OfficeFlowSourceNode flowSourceNode) {
this.flowSinkNode = flowSinkNode;
this.flowSourceNode = flowSourceNode;
}
}
/**
* Chained servicer.
*/
private static class ChainedServicer {
/**
* {@link OfficeFlowSinkNode}.
*/
public final OfficeFlowSinkNode flowSinkNode;
/**
* {@link OfficeFlowSourceNode}. May be null
.
*/
public final OfficeFlowSourceNode notHandledOutput;
/**
* Initiate.
*
* @param flowSinkNode
* {@link OfficeFlowSinkNode}.
* @param notHandledOutput
* {@link OfficeFlowSourceNode}. May be null
.
*/
private ChainedServicer(OfficeFlowSinkNode flowSinkNode, OfficeFlowSourceNode notHandledOutput) {
this.flowSinkNode = flowSinkNode;
this.notHandledOutput = notHandledOutput;
}
}
}