FTN6: FutoIn Executor Concept
Copyright: 2014 FutoIn Project (http://futoin.org)
Authors: Andrey Galkin
This specification IS NOT mandatory. It is just a reference model.
Any implementation IS ALLOWED to provide own architecture with
drawback of breaking easy migration from one to another.
There must be a generic object type, which can represent both
request and response message data and/or communication channels.
There must be a wrapper, which holds current request-response info
and potentially a set of standard utilities.
There must be a generic request Executor, which knows all registered
interfaces and their implementations.
Executor implementation is not limited in internal behavior, but should
have standardized interface even for helper tools, like FutoIn interface
compilers and/or converters.
Executor is responsible for (actions are done in AsyncSteps):
- converting request from transport-level representation to internal message format
- gathering basic request-response info
- checking interface constraints
- checking message security (HMAC) or authenticating user by credentials
- passing control to implementation of specific interfaces with required major version
- catching exceptions or normal result
- converting response to transport-level representation
- maintaining persistent communication channel, if needed
Client || Executor Implementation
. || [Register] .
. || | .
|----- Request ----->| .
| || [Unpack] .
| || [Info] .
| || [Constraints] .
| || [Security] .
| || |---- Invoke -------->|
| || |<-- Except/Result ---|
| || [Pack] .
|<---- Response -----| .
. || | .
. || | .
Executor should be tighly integrated with MasterService implementation, if supported.
General FutoIn message verification should be based on HMAC checking.
Executor should also integrate with AuthService as consumer, if real human users expected to use the service.
Note: Executor is allowed to pass control to implementation only if requested major version of
interfaces exactly matches implemented version and minor version is greater than or equal
to requested minor version.
All actions are implemented through AsyncSteps interface (FTN12: Async API).
For backward compatibility with pre-FutoIn code and/or complex logic, it is possible to make blocking
implementation. Such implementations run in dedicated worker threads/processes and receive only RequestInfo
All true asynchronous implementations must implement special FutoIn AsyncImplementation interface to
clearly distinguish more advanced one.
void AsyncMethod( AsyncSteps as, RequestInfo reqinfo );
Result BlockingMethod( RequestInfo reqinfo );
Note: if BlockingMethod or AsyncMethod returns result then its fields are added to already existing
result fields in reqinfo object.
1.1. FutoIn interfaces
Interfaces must get converted according to language/platform-specific
convention into native interfaces, which can depend only on
standard runtime and native language/platform-specific interfaces
of Executor and related objects.
2. Native Executor interface requirements
Language/platform should support runtime introspection and
exceptions. For other cases, platform/language-specific workarounds
2.1. FutoIn interface
- Each FutoIn interfaces is represented as simple native
interface type with only abstract methods for each
FutoIn interface function
- Each abstract method must return no value and take exactly one
Request Info object as argument for blocking implementation. Or
AsyncSteps and RequestInfo objects as arguments for asynchronous
- Implementation method can assume that all request parameters defined
in spec can be accessed from request data
- Access to unexpected request and/or response parameters
should raise InternalError
- Throw of unexpected error should raise InternalError
- Each implementation method should have public access
- There must be no public method which is not part of the
specific FutoIn interface definition
- All native interfaces should inherit from single
native interface with no public abstract methods
2.2. Request Info
- SL_ANONYMOUS = "Anonymous"
- SL_INFO = "Info"
- SL_SAFEOPS = "SafeOps"
- SL_PRIVLEGED_OPS = "PrivilegedOps"
- SL_EXCEPTIONAL_OPS = "ExceptionalOps"
- INFO_X509_CN - validated x509 certificate CN field
- INFO_PUBKEY - public key, if present
- INFO_CLIENT_ADDR - SourceAddress object of request external to current system
(e.g. without trusted reverse proxies, gateways, etc.)
- INFO_USER_AGENT - User Agent, coming from HTTP headers or other source
- INFO_COOKIES - array of strings
- INFO_SECURE_CHANNEL - boolean - is request coming through secure channel?
- INFO_REQUEST_TIME_FLOAT - platform-specific timestamp of request processing start
- INFO_SECURITY_LEVEL - one of pre-defined security levels of current processing
- INFO_USER_INFO - user information object
- INFO_RAW_REQUEST - raw request object
- INFO_RAW_RESPONSE - raw response object
- INFO_DERIVED_KEY - derived key object
- INFO_HAVE_RAW_UPLOAD - boolean - have raw upload (e.g. can open rawInput())
- params() - return reference to request parameter map
- result() - return reference to response parameter map
- info() - return reference to info parameter map, keys (defined as const with INFO_ prefix):
- Note: info() is not merged to AsyncSteps only for minor security reasons
- rawInput() - return raw input stream or null, if FutoIn request comes in that stream
- rawOutput() - return raw output stream (no result variables are expected)
- context() - get reference to Executor
- ignoreInvokerAbort( [bool=true] ) - [un]mark request as ready to be canceled on
Invoker abort (disconnect)
- Language-specic get accessor for info properties
2.3. User info
- localID() - get user ID as seen by trusted AuthService (string)
- globalID() - get globally unique user ID (string)
- details( AsyncSteps as, array user_field_identifiers )
- Request more detailed user information gets available
- Note: executor implementation should cache it at least in scope of current request processing
2.4. Source Address
- host() - numeric, no name lookup
- type() - IPv4, IPv6
- asString() "Type:Host:Port"
2.5. Derived Key
- encrypt( AsyncSteps as, data ) - return Base64 data
- decrypt( AsyncSteps as, data ) - decrypt Base64 data
2.6. General Async Step interface
See FTN12 Async API
2.7. Async completion interface
There is little use of extended AsyncSteps to provide additional API.
Instead, by convention, "reqinfo" AsyncSteps state field must point to
associated RequestInfo instance.
- ccm() - get reference to Invoker CCM, if any
- register( AsyncSteps as, ifacever, impl ) - add interface implementation
- ifacever must be represented as FutoIn interface identifier and version, separated by colon ":"
- impl is object derived from native interface or associative name for lazy loading
- process( AsyncSteps as ) - do full cycle of request processing, including all security checks
- as->reqinfo must point to instance of RequestInfo
- checkAccess( AsyncSteps as, acd ) - shortcut to check access through #acl interface
- as->reqinfo must point to instance of RequestInfo
- initFromCache( AsyncSteps as )
- load initialization from cache
- cacheInit( AsyncSteps as )
- store initialization to cache
2.9. Interface Implementation
No public members
3. Language/Platform-specific notes
3.1. native JVM (Java, Groovy, etc.)
=END OF SPEC=