Package-level declarations

Types

Link copied to clipboard
class AccessAttributeManifest @InternalWowApi constructor(val name: String, val type: AccessAttributeManifest.Type, val multiple: Boolean = false)

An access attribute of an aggregate (@Access): its name (AccessAttributeName), unique within the aggregate ignoring case, the type of its values, and whether it holds several of them (multiple) or one, which may be absent.

Link copied to clipboard

The rule of an access attribute's name (@Access): lower camel case, a lower-case letter then letters and digits (PATTERN, [a-z][A-Za-z0-9]*), at most MAX_LENGTH characters, such as department or sharedWith, and not one of the built-in attributes' names (BUILT_IN).

Link copied to clipboard

Where an aggregate's id comes from (me.ahoo.wow.api.aggregate.AggregateIdSource).

Link copied to clipboard
class AggregateManifest @InternalWowApi constructor(val name: String, val description: String? = null, val state: StateManifest, val snapshot: SnapshotManifest = SnapshotManifest(), val commands: List<CommandManifest> = emptyList(), val events: List<EventManifest> = emptyList(), val queries: List<QueryManifest> = emptyList(), val schedules: List<String>? = null, val ownership: Ownership = Ownership.OWNER, val retired: List<String> = emptyList(), val idSource: AggregateIdSource = AggregateIdSource.ASSIGNED, val access: List<AccessAttributeManifest> = emptyList())

An aggregate of a context. Its commands are those it decides, those mounted under its routes, and its system commands: the lifecycle commands its model handles and the rebuild of its snapshots, named by their full names in the system namespace (wow.lifecycle.DeleteAggregate, wow.snapshot.Rebuild). Those are the same types for every aggregate, so they are not names within the aggregate and never conflict between aggregates; the body of each is the schema of Manifest.defs keyed by that full name (Manifest.schemaRef of it), so a client types it like a command's. queries are the read models of the aggregate a client queries (QueryManifest).

Link copied to clipboard

The one reader of the peer contracts on a class path: every PeerContracts.RESOURCE, one per api jar (or directory) that carries the contracts of its contexts, each parsed by the caller's JSON library into the plain tree ManifestTree.read reads, so this module stays free of one. The same contract found twice is read once. A node's contract directory and wow-client's command names both read through it.

Link copied to clipboard

The commands of manifests by their schemas, the one rule that names a command class: the command of the schema #/$defs/<binary name> in whichever context decides it is <context>.<aggregate>.<Command>; and their routes by their full type names, the only routes a client sends a command to (routeOf). A mounted command is only an edge's, which no one sends, and is left out. A system command (SystemCommands) is named by its system name on its target (systemCommandTypeOf): an aggregate's lifecycle commands and snapshot rebuild, and a context's schedule job commands, whose target is the context's job aggregate (<context>.schedule). On a conflict the first Manifest's wins. A node's contract directory and wow-client both name commands through it.

Link copied to clipboard
class CommandManifest @InternalWowApi constructor(val name: String, val aliases: List<String> = emptyList(), val schema: String, val creation: Creation = Creation.NONE, val produces: List<String>? = null, val routes: List<RouteManifest> = emptyList(), val mounted: Boolean = false, val transformsTo: List<String>? = null, val description: String? = null, val system: Boolean = false, val idProperty: String? = null, val internal: Boolean = false)

A command the aggregate decides, or one mounted under its routes.

Link copied to clipboard

The REST routes of a command, and the names they reserve.

Link copied to clipboard
class ContextManifest @InternalWowApi constructor(val name: String, val description: String? = null, val aggregates: List<AggregateManifest> = emptyList(), val subscriptions: List<SubscriptionManifest> = emptyList(), val published: List<PublishedManifest> = emptyList(), val errors: List<ErrorManifest> = emptyList(), val commands: List<CommandManifest> = emptyList(), val routes: List<ServiceRouteManifest> = emptyList())

A bounded context. errors optionally documents the domain's rejection codes, the @ErrorCode constants of its module; they are runtime strings, so the list is neither complete nor checked against what the code rejects with, and a wow.* code is not the context's.

Link copied to clipboard

The rule of a bounded context's name: lower-case letters, digits and hyphens, starting with a letter (PATTERN, [a-z][a-z0-9-]*), such as shop or eshop-catalog. A dot is never part of one: it separates the context from the aggregate and the type in every name built from it (context.aggregate.Command, the topics wow.<context>.<aggregate>.state, the host's wow.aggregates.[<context>.<aggregate>] keys), which a dotted context name would make ambiguous.

Link copied to clipboard

The contracts of a service and its peers do not hold together; problems lists each problem.

Link copied to clipboard
enum class Creation : Enum<Creation>

Whether a command creates its aggregate (@CreateAggregate, @AllowCreate).

Link copied to clipboard
class ErrorManifest @InternalWowApi constructor(val code: String, val status: Int, val description: String? = null, val retry: Retry = Retry.NONE, val retryAfter: Int? = null)

An error code a client may receive: its code, the HTTP status it is answered with, what it means, and what a retry may do (retry), after retryAfter seconds, the Retry-After of its problem: one when a retry may get past it, none otherwise. The code is the code of a CommandResult and of a problem+json body, whose type is urn:wow:error:<code> and whose retry member is retry's.

Link copied to clipboard
class EventManifest @InternalWowApi constructor(val name: String, val aliases: List<String> = emptyList(), val revision: Int = 1, val schema: String, val description: String? = null)

An event of the aggregate: its name in the log, its revision and former names, and its description, as for a CommandManifest.

Link copied to clipboard

The framework's error codes and the HTTP status each is answered with: the one table the Manifest's top-level errors (Manifest.errors) and the edge's problem+json answers both read.

Link copied to clipboard

The kinds of me.ahoo.wow.api.result.FunctionKind a Manifest names.

Link copied to clipboard
class FunctionManifest @InternalWowApi constructor(val kind: FunctionKind, val context: String, val processor: String, val name: String)

The function a subscription runs, as CommandResult.function names it.

Link copied to clipboard
class JobManifest @InternalWowApi constructor(val name: String, val cron: String, val zone: String = "UTC", val scope: String = SYSTEM, val misfire: String = COALESCE)

A job of an @OnSchedule handler: its name, its default rule (cron read in zone, missed slots handled as misfire says: coalesce or catch-up) and its scope (system, tenant or sharded), each value spelled as Wow writes its enumerations. The host configures the job under wow.schedules.<name>.*: its rule, and the retries of its subscriptions.

Link copied to clipboard
class Manifest @InternalWowApi constructor(val format: Int = FORMAT, val service: ServiceInfo? = null, val contexts: List<ContextManifest> = emptyList(), val errors: List<ErrorManifest> = emptyList(), val defs: Map<String, Any?> = emptyMap(), val requires: List<String> = emptyList())

The contract of a service: its bounded contexts, their aggregates with the commands and events they speak, and their subscriptions, with the JSON Schema 2020-12 of every payload in defs (written $defs).

Link copied to clipboard

The one assembly of a service's Manifest from its modules' fragments, the build's (mergeManifest) and the node's at startup alike, so the Manifest a service serves is the one its build wrote: the fragments merged (ManifestMerger), naming the service, then a subscription of another context's events by type given the aggregates the peer contracts list them under (PeerSources).

Link copied to clipboard

The fragments of a service contradict each other; conflicts lists every contradiction found.

Link copied to clipboard

The markers of Manifest.requires this reader understands: a marker names a change in what part of a Manifest means, which a reader that does not know it would misread, so ManifestTree.read refuses a Manifest that requires one outside KNOWN. A value that only widens a set, such as a new enum value, needs no marker: readers read it leniently. Format 1 has none yet.

Link copied to clipboard
class ManifestFragment @InternalWowApi constructor(val source: String, val manifest: Manifest)

A fragment and where it was read from, for the messages of ManifestMerger.

Link copied to clipboard

Assembles a service's Manifest from its modules' fragments. The build merges them into the service's manifest.json; the runtime merges the same fragments when it starts. Both refuse a conflict, so a name the runtime resolves is never ambiguous:

Link copied to clipboard

The JSON Schema 2020-12 of the Manifest format (Manifest.FORMAT): every object ManifestTree writes, with its keys, which of them it always writes (required: a reader may rely on them; ManifestTree.read also takes a Manifest that leaves out an empty list), and the values of each enumeration this version writes. Its objects are open, as a reader of a newer writer's Manifest reads the keys it does not know past, and an enumeration's values are those of this writer: a reader reads one it does not know leniently (ManifestTree.read).

Link copied to clipboard

The JSON shape of a Manifest, as a tree of plain values: a JSON object is a Map<String, Any?> (insertion ordered when written), an array a List<Any?>, and a scalar a String, Number, Boolean or null. Any JSON library writes and reads such a tree, so the Manifest's field names are defined here once and wow-manifest needs none.

Link copied to clipboard
enum class Ownership : Enum<Ownership>

Who an aggregate belongs to besides its tenant (me.ahoo.wow.api.aggregate.Ownership).

Link copied to clipboard

The peer contracts of a context: what another service needs to know of a context to send it commands, read its published streams and follow a wait chain through it, carried by the jar of the context's api module, so a service that depends on that api knows the context with no configuration.

Link copied to clipboard

The aggregates a subscription of another context's events reads when its handler takes them by type without naming their aggregate (SubscriptionSource.eventSchemas): those whose events the peer contracts list under the schemas the handler takes, all of one context. Each schema names an event of exactly one aggregate; an event two aggregates list, one no contract lists, or events of several contexts are a problem, which names the candidates.

Link copied to clipboard
class PublishedManifest @InternalWowApi constructor(val aggregate: String, val topic: String, val includeState: Boolean = true)

A stream of state events a context publishes for other contexts: those of its aggregate, on the Kafka topic (defaultTopic unless overridden), each with the aggregate's state after the commit unless includeState is false, for an aggregate whose state is too large (a subscriber of such a stream declares a nullable state).

Link copied to clipboard

The names of the query field constants of an aggregate's state: the compiler's <State>Properties in the domain module and the <Context>Contract generated into its api module from the state schema name each path of the state alike, so the two sets are the same.

Link copied to clipboard
class QueryManifest @InternalWowApi constructor(val model: String, val routes: List<RouteManifest> = emptyList())

A query model of an aggregate: model is QueryRoutes.SNAPSHOT, the aggregate's snapshots, when it keeps them, or QueryRoutes.EVENTS, its event streams; routes are the model's query route and the route of its capability descriptor (QueryRoutes). What a model can do (its operations, fields, limits) is not here: it depends on the query backend the service runs on, which the build does not know, and the descriptor route answers it.

Link copied to clipboard

The routes of an aggregate's query models.

Link copied to clipboard
class RetryManifest @InternalWowApi constructor(val maxAttempts: Int? = null, val initialBackoff: String? = null, val maxBackoff: String? = null, val timeout: String? = null, val recoverable: List<String>? = null, val unrecoverable: List<String>? = null, val multiplier: Double? = null, val systemic: List<String>? = null)

A subscription handler's in-process retry budget as @Retry declares it: each setting null when it is not given. Durations are ISO-8601 (PT2S). recoverable, unrecoverable and systemic are the qualified names of the exception classes the handler classifies itself (@Retry(recoverable, unrecoverable, systemic)).

Link copied to clipboard
class RouteManifest @InternalWowApi constructor(val method: String, val path: String)

An HTTP route: its method and its path, a template whose variables are written literally in braces (/shop/cart/{id}/add-item).

Link copied to clipboard
class RouteParameterManifest @InternalWowApi constructor(val name: String, val location: RouteParameterManifest.Location, val schema: Map<String, Any?>, val required: Boolean = location == Location.PATH)

A parameter of a ServiceRouteManifest: a variable of its path or a query parameter (location), its schema an inline JSON Schema of a scalar ({"type":"string"}, an enum), and whether a call must give it (required; a path variable always is).

Link copied to clipboard
class ServiceInfo @InternalWowApi constructor(val name: String, val version: String? = null)

The service a merged Manifest describes; a fragment has none, and a peer contract names the service that hosts its contexts, by its name alone, when its module declares it.

Link copied to clipboard
class ServiceRouteManifest @InternalWowApi constructor(val name: String, val route: RouteManifest, val parameters: List<RouteParameterManifest> = emptyList(), val request: Map<String, Any?>? = null, val response: Map<String, Any?>? = null, val responseOptional: Boolean = false, val errors: List<String> = emptyList(), val description: String? = null, val deprecated: Boolean = false)

A service route of a context (@ServiceRoute): a route whose handler is the service's own code. Its name is its identity within the context, for compatibility and for its generated client; route is where the edge serves it, below the context; parameters are its path variables and query parameters; request and response are the inline JSON Schemas of its body and its answer, null when it takes none or answers 204 No Content: a reference into $defs ({"$ref": "#/$defs/<key>"}), or an array of one ({"type": "array", "items": {"$ref": ...}}, "uniqueItems": true for a set), a nullable one, the body or an item, written with a null alternative (Manifest.nullableSchema). A null answer is 204 No Content, no body, so an answer's schema is never nullable itself: responseOptional says the route may answer 204 No Content instead of its response (its function returns a nullable value), where a route of no response always answers it (its function returns Unit). errors are the codes it refuses with, entries of the context's error table.

Link copied to clipboard
class SnapshotManifest @InternalWowApi constructor(val enabled: Boolean = true, val stateRevision: Int = 1)

Whether the aggregate keeps snapshots (enabled), and the revision of its state's structure the snapshots are written at (stateRevision): raised, the service rebuilds the stored snapshots in place, and the compatibility gate accepts a state schema change of an aggregate whose state no one else reads (no snapshot query, no published stream with the state).

Link copied to clipboard
class StateManifest @InternalWowApi constructor(val schema: String, val fingerprint: String? = null, val view: String? = null)

The aggregate's state: its schema, and the fingerprint a snapshot written under it carries; the fingerprint is null until the schemas are generated. In a peer contract, view is the binary name of the <State>View the api module generates of it (PeerContracts.viewsOf), which a reader finds the view by: null for a state the contract has no view of, and in a service's own Manifest.

Link copied to clipboard
Link copied to clipboard
class SubscriptionManifest @InternalWowApi constructor(val name: String, val kind: SubscriptionKind, val source: SubscriptionSource, val function: FunctionManifest, val derives: List<String>? = null, val rejected: List<String>? = null, val start: SubscriptionStart? = null, val schedules: List<String>? = null, val retry: RetryManifest? = null, val committed: List<String>? = null, val job: JobManifest? = null, val calls: List<String>? = null)

A subscription: one handler of a processor, named processor.function.

Link copied to clipboard
class SubscriptionSource @InternalWowApi constructor(val context: String? = null, val aggregates: List<String> = emptyList(), val events: List<String> = emptyList(), val nullableState: Boolean = false, val eventSchemas: List<String> = emptyList())

What a subscription reads: the aggregates (by name) of context whose state events it receives, and the event names it is limited to. Empty aggregates or events mean no limit; a null context means the handler's state type is not an aggregate of the module that declares it.

Link copied to clipboard

Where a new subscription, one without a checkpoint, starts reading the log or the stream.

Link copied to clipboard

The framework's system commands as a Manifest lists them, with their routes (CommandRoutes): each named by its full system name, its body the schema of Manifest.defs keyed by that name.

Properties

Link copied to clipboard

The schema keyword naming the JVM class a value is written from, by its binary name: an api module's generator reads it from the contract to reference the class or copy its structure into a state view. It is the service's internals, so the public port's documents leave it out (withoutClassNames); the contract and the internal port keep it.

Functions

Link copied to clipboard
fun ManifestFragment.copyWith(source: String = this.source, manifest: Manifest = this.manifest): ManifestFragment
fun QueryManifest.copyWith(model: String = this.model, routes: List<RouteManifest> = this.routes): QueryManifest
fun RouteManifest.copyWith(method: String = this.method, path: String = this.path): RouteManifest
fun ServiceInfo.copyWith(name: String = this.name, version: String? = this.version): ServiceInfo
fun SnapshotManifest.copyWith(enabled: Boolean = this.enabled, stateRevision: Int = this.stateRevision): SnapshotManifest
fun PublishedManifest.copyWith(aggregate: String = this.aggregate, topic: String = this.topic, includeState: Boolean = this.includeState): PublishedManifest
fun StateManifest.copyWith(schema: String = this.schema, fingerprint: String? = this.fingerprint, view: String? = this.view): StateManifest
fun FunctionManifest.copyWith(kind: FunctionKind = this.kind, context: String = this.context, processor: String = this.processor, name: String = this.name): FunctionManifest
fun RouteParameterManifest.copyWith(name: String = this.name, location: RouteParameterManifest.Location = this.location, schema: Map<String, Any?> = this.schema, required: Boolean = this.required): RouteParameterManifest
fun ErrorManifest.copyWith(code: String = this.code, status: Int = this.status, description: String? = this.description, retry: Retry = this.retry, retryAfter: Int? = this.retryAfter): ErrorManifest
fun EventManifest.copyWith(name: String = this.name, aliases: List<String> = this.aliases, revision: Int = this.revision, schema: String = this.schema, description: String? = this.description): EventManifest
fun JobManifest.copyWith(name: String = this.name, cron: String = this.cron, zone: String = this.zone, scope: String = this.scope, misfire: String = this.misfire): JobManifest
fun SubscriptionSource.copyWith(context: String? = this.context, aggregates: List<String> = this.aggregates, events: List<String> = this.events, nullableState: Boolean = this.nullableState, eventSchemas: List<String> = this.eventSchemas): SubscriptionSource
fun Manifest.copyWith(format: Int = this.format, service: ServiceInfo? = this.service, contexts: List<ContextManifest> = this.contexts, errors: List<ErrorManifest> = this.errors, defs: Map<String, Any?> = this.defs, requires: List<String> = this.requires): Manifest
fun ContextManifest.copyWith(name: String = this.name, description: String? = this.description, aggregates: List<AggregateManifest> = this.aggregates, subscriptions: List<SubscriptionManifest> = this.subscriptions, published: List<PublishedManifest> = this.published, errors: List<ErrorManifest> = this.errors, commands: List<CommandManifest> = this.commands, routes: List<ServiceRouteManifest> = this.routes): ContextManifest
fun RetryManifest.copyWith(maxAttempts: Int? = this.maxAttempts, initialBackoff: String? = this.initialBackoff, maxBackoff: String? = this.maxBackoff, timeout: String? = this.timeout, recoverable: List<String>? = this.recoverable, unrecoverable: List<String>? = this.unrecoverable, multiplier: Double? = this.multiplier, systemic: List<String>? = this.systemic): RetryManifest
fun ServiceRouteManifest.copyWith(name: String = this.name, route: RouteManifest = this.route, parameters: List<RouteParameterManifest> = this.parameters, request: Map<String, Any?>? = this.request, response: Map<String, Any?>? = this.response, responseOptional: Boolean = this.responseOptional, errors: List<String> = this.errors, description: String? = this.description, deprecated: Boolean = this.deprecated): ServiceRouteManifest
fun AggregateManifest.copyWith(name: String = this.name, description: String? = this.description, state: StateManifest = this.state, snapshot: SnapshotManifest = this.snapshot, commands: List<CommandManifest> = this.commands, events: List<EventManifest> = this.events, queries: List<QueryManifest> = this.queries, schedules: List<String>? = this.schedules, ownership: Ownership = this.ownership, retired: List<String> = this.retired, idSource: AggregateIdSource = this.idSource, access: List<AccessAttributeManifest> = this.access): AggregateManifest
fun CommandManifest.copyWith(name: String = this.name, aliases: List<String> = this.aliases, schema: String = this.schema, creation: Creation = this.creation, produces: List<String>? = this.produces, routes: List<RouteManifest> = this.routes, mounted: Boolean = this.mounted, transformsTo: List<String>? = this.transformsTo, description: String? = this.description, system: Boolean = this.system, idProperty: String? = this.idProperty, internal: Boolean = this.internal): CommandManifest
fun SubscriptionManifest.copyWith(name: String = this.name, kind: SubscriptionKind = this.kind, source: SubscriptionSource = this.source, function: FunctionManifest = this.function, derives: List<String>? = this.derives, rejected: List<String>? = this.rejected, start: SubscriptionStart? = this.start, schedules: List<String>? = this.schedules, retry: RetryManifest? = this.retry, committed: List<String>? = this.committed, job: JobManifest? = this.job, calls: List<String>? = this.calls): SubscriptionManifest
Link copied to clipboard

This Manifest without CLASS_KEYWORD in any schema of its $defs: what the public port serves.