public static class MatsInitiator.MatsInitiateWrapper extends java.lang.Object implements MatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>, MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate
, which simply implements MatsInitiate, takes a MatsInitiate instance and
forwards all calls to that. Use this if you need to wrap the MatsInitiate, where most of the methods are
pass-through to the target, as any changes to the MatsInitiate interface then won't break your wrapper.Constructor and Description |
---|
MatsInitiateWrapper()
No-args constructor, which implies that you either need to invoke
#setWrappee(MatsInitiate) before
publishing the instance (making it available for other threads), or override unwrap() to provide the
desired MatsInitiator.MatsInitiate instance. |
MatsInitiateWrapper(MatsInitiator.MatsInitiate targetMatsInitiate)
Standard constructor, taking the wrapped
MatsInitiator.MatsInitiate instance. |
Modifier and Type | Method and Description |
---|---|
MatsInitiator.MatsInitiate |
addBytes(java.lang.String key,
byte[] payload)
Adds a binary payload to the outgoing request message, e.g.
|
MatsInitiator.MatsInitiate |
addString(java.lang.String key,
java.lang.String payload)
Adds a String payload to the outgoing request message, e.g.
|
MatsInitiator.MatsInitiate |
from(java.lang.String initiatorId)
Sets the originating/initiating "synthetic endpoint Id" - only used for statistics/tracing/debugging.
|
<T> java.util.Optional<T> |
getAttribute(java.lang.Class<T> type,
java.lang.String... name)
Provides a way to get hold of (optional) attributes/objects from the Mats implementation, either specific to
the Mats implementation in use, or configured into this instance of the Mats implementation.
|
MatsInitiator.MatsInitiate |
interactive()
Prioritize this Mats flow! Hint to the underlying implementation that a human is actually waiting for
the result of a request, and that the flow therefore should be prioritized.
|
MatsInitiator.MatsInitiate |
keepTrace(MatsInitiator.KeepTrace keepTrace)
Hint to the underlying implementation to which level of call and state history the underlying protocol should
retain.
|
MatsInitiator.MatsInitiate |
logMeasurement(java.lang.String metricId,
java.lang.String metricDescription,
java.lang.String baseUnit,
double measure,
java.lang.String... labelKeyValue)
Adds a measurement of a described variable, in a base unit, for this Initiation - be sure to understand
that the three String parameters are constants for each measurement. To exemplify, you may measure
five different things in an Initiation, i.e.
|
MatsInitiator.MatsInitiate |
logTimingMeasurement(java.lang.String metricId,
java.lang.String metricDescription,
long nanos,
java.lang.String... labelKeyValue)
Same as
addMeasurement(..) , but
specifically for timings - Read that JavaDoc!
Note: It is illegal to use the same 'metricId' for more than one measurement for a given Initiation, and this
also goes between timing measurements and measurements . |
MatsInitiator.MatsInitiate |
noAudit()
Marks this Mats flow as not relevant for auditing.
|
MatsInitiator.MatsInitiate |
nonPersistent()
Enable unreliable, but fast, messaging! Hint to the underlying implementation that it does not matter
that much if this message is lost.
|
MatsInitiator.MatsInitiate |
nonPersistent(long timeToLiveMillis)
Same as
MatsInitiator.MatsInitiate.nonPersistent() , but you can set a time-to-live too. |
MatsInitiator.MessageReference |
publish(java.lang.Object messageDto)
Sends a message to a
SubscriptionTerminator , employing the publish/subscribe pattern instead of message queues (topic in JMS
terms). |
MatsInitiator.MessageReference |
publish(java.lang.Object messageDto,
java.lang.Object initialTargetSto)
Variation of the
MatsInitiator.MatsInitiate.publish(Object) method, where the incoming state is sent along. |
MatsInitiator.MatsInitiate |
replyTo(java.lang.String endpointId,
java.lang.Object replySto)
Specified which MATS Endpoint the reply of the invoked Endpoint should go to.
|
MatsInitiator.MatsInitiate |
replyToSubscription(java.lang.String endpointId,
java.lang.Object replySto)
A "pub-sub" variant of
replyTo , where the reply will go to the specified
endpointId which must be a
SubscriptionTerminator . |
MatsInitiator.MessageReference |
request(java.lang.Object requestDto)
The standard request initiation method: All of from, to and replyTo must be set.
|
MatsInitiator.MessageReference |
request(java.lang.Object requestDto,
java.lang.Object initialTargetSto)
Variation of the request initiation method, where the incoming state is sent along.
|
MatsInitiator.MessageReference |
send(java.lang.Object messageDto)
Sends a message to an endpoint, without expecting any reply ("fire-and-forget").
|
MatsInitiator.MessageReference |
send(java.lang.Object messageDto,
java.lang.Object initialTargetSto)
Variation of the
MatsInitiator.MatsInitiate.send(Object) method, where the incoming state is sent along. |
MatsInitiator.MatsInitiate |
setTraceProperty(java.lang.String propertyName,
java.lang.Object propertyValue)
Adds a property that will "stick" with the call flow from this call on out.
|
void |
setWrappee(MatsInitiator.MatsInitiate targetMatsInitiate)
Sets the wrapped
MatsInitiator.MatsInitiate , e.g. |
MatsInitiator.MatsInitiate |
to(java.lang.String endpointId)
Sets which MATS Endpoint this message should go.
|
java.lang.String |
toString() |
MatsInitiator.MatsInitiate |
traceId(java.lang.CharSequence traceId)
Sets (or appends with a joining "|" in case of
initiation
within a stage ) the supplied Trace Id, which is solely used for logging and debugging purposes. |
<R,S,I> void |
unstash(byte[] stash,
java.lang.Class<R> replyClass,
java.lang.Class<S> stateClass,
java.lang.Class<I> incomingClass,
MatsEndpoint.ProcessLambda<R,S,I> lambda)
Unstashes a Mats Flow that have been previously
stashed . |
MatsInitiator.MatsInitiate |
unwrap() |
MatsInitiator.MatsInitiate |
unwrapFully() |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
unwrapTo
public MatsInitiateWrapper(MatsInitiator.MatsInitiate targetMatsInitiate)
MatsInitiator.MatsInitiate
instance.targetMatsInitiate
- the MatsFactory
instance which unwrap()
will return (and hence all forwarded
methods will use).public MatsInitiateWrapper()
#setWrappee(MatsInitiate)
before
publishing the instance (making it available for other threads), or override unwrap()
to provide the
desired MatsInitiator.MatsInitiate
instance. In these cases, make sure to honor memory visibility semantics - i.e.
establish a happens-before edge between the setting of the instance and any other threads getting it.public void setWrappee(MatsInitiator.MatsInitiate targetMatsInitiate)
MatsInitiator.MatsInitiate
, e.g. in case you instantiated it with the no-args constructor. Do
note that the field holding the wrapped instance is not volatile nor synchronized. This means that if you
want to set it after it has been published to other threads, you will have to override both this method and
unwrap()
to provide for needed memory visibility semantics, i.e. establish a happens-before edge
between the setting of the instance and any other threads getting it. A volatile
field would
work nice.setWrappee
in interface MatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
targetMatsInitiate
- the MatsInitiator.MatsInitiate
which is returned by unwrap()
, unless that is overridden.public MatsInitiator.MatsInitiate unwrap()
unwrap
in interface MatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
MatsInitiator.MatsInitiate
. All forwarding methods invokes this method to get the wrapped
MatsInitiator.MatsInitiate
, thus if you want to get creative wrt. how and when the MatsInitiate is decided,
you can override this method.public MatsInitiator.MatsInitiate unwrapFully()
unwrapFully
in interface MatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
unwrapFully
in interface MatsInitiator.MatsInitiate
MatsFactory.MatsWrapper.unwrap()
is itself a
MatsWrapper
, it will recurse down by invoking this method
(unwrapFully()
) again on the returned target.public MatsInitiator.MatsInitiate traceId(java.lang.CharSequence traceId)
MatsInitiator.MatsInitiate
initiation
within a stage
) the supplied Trace Id, which is solely used for logging and debugging purposes. It
should be unique, at least to a degree where it is very unlikely that you will have two identical
traceIds within a couple of years ("guaranteed globally unique through all time" is not relevant).
Since this is very important when doing distributed and asynchronous architectures, it is mandatory.
The traceId follows a Mats processing from the initiation until it is finished, usually in a Terminator.
It should be a world-unique Id, preferably set all the way back when some actual person performed some event.
E.g. in a "new order" situation, the Id would best be set when the user clicked the "place order" button on
the web page - or maybe even derived from the event when he first initiated the shopping cart - or maybe even
when he started the session. The point is that when using e.g. Kibana or Splunk to track events that led to
some outcome, a robust, versatile and information-rich track/trace Id makes wonders.
It is strongly recommended to use small, dense, information rich Trace Ids. Sticking in an UUID
as Trace Id certainly fulfils the uniqueness-requirement, but it is a crappy solution, as it by itself does
not give any hint of source, cause, relevant entities, or goal. (It isn't even dense for the uniqueness an
UUID gives, which also is way above the required uniqueness unless you handle billions of such messages per
minute. A random alphanum (A-Z,a-z,0-9) string of much smaller length would give plenty enough
uniqueness). The following would be a much better Trace Id than a random UUID, which follows some scheme
that could be system wide: "Web.placeOrder[cid:43512][cart:xa4ru5285fej]qz7apy9". From this example TraceId
we could infer that it originated at the Web system, it regards Placing an order for
Customer Id 43512, it regards the Shopping Cart Id xa4ru5285fej, and it contains some
uniqueness ('qz7apy9') generated at the initiating, so that even if the customer managed to click three times
on the "place order" button for the same cart, you would still be able to separate the resulting three
different Mats call flows.
You should consider storing the traceId as a column in any inserted rows in any databases that was affected
by this call flow, e.g. in the row for a placed order, you'd have the traceId as a column. This both to be
able to tie this db row back to the logging system, but also if new Mats flows are initiated based on this
row, you can include the order TraceId in the new TraceId (with either "|" or "+" as separator).
For situations where one Mats Flow "forks" new Mats flows, make new TraceIds for the "sub flows" by tying
together the existing TraceId and a new Sub TraceId with a "|". In the order/shipping example, the user would
first have placed an order, resulting in an entry in an order database table - where the traceId was stored
along. Then, when some batch process Mats Flow initiated the filling process, you would pick up the order's
traceId and append that to the sub Mats Flow. Sub Flow Mats TraceId = "{Filling Batch Id}|{Existing Order
TraceId}". If you took this all the way, you could in your logging system follow the "total flow" from the
initial click on the web page, through the order book, order processing, shipment, and all the way to the
delivered and signed package on the person's door - even if the entirety of the order fulfillment consists of
multiple "stop and go" sub-flows (the stops being where the process stays for a while as an entry in a
database, here "order", then possibly "filling", "shipping" and finally "delivery", or whatever your multiple
processes' flows consists of).
The "+" character should be used to indicate that an "initiated from the outside" TraceId is concatenated by
multiple parts, which so far has been used to pick up an X-Request-ID header from a HTTP-request, and
prepending this to the TraceId for a resulting Mats-flow, i.e. Mats TraceId="{X-Request-ID}+{Flow TraceID}".
(Check out MatsFactory.FactoryConfig.setInitiateTraceIdModifier(Function)
for a way to automate this.)
The difference between "|" and "+" is meant to be that "|" indicates that there is a Mats Flow TraceId on
both sides of the "|", while the "+" is used when a "from the outside"-initiated TraceId is built up by
multiple pieces, e.g. X-Request-Id, or Batch Run Number, on the left side. Remember, this is all meant for
human consumption, in particular when debugging. Do what you feel is meaningful - the Mats system doesn't
care!
(For the default implementation "JMS Mats", the Trace Id is set on the MDC
of the SLF4J logging
system, using the key "traceId". Since this implementation logs a few lines per handled message, in addition
to any log lines you emit yourself, you will, by collecting the log lines in a common log system (e.g. the
ELK stack), be able to very easily follow the processing trace through all the services the call flow
passes.)traceId
in interface MatsInitiator.MatsInitiate
traceId
- the traceId that will follow the mats trace from initiation (first call) to termination (last
call, where the flow ends). Although the type is CharSequence
, the implementation
will immediately do toString()
on the instance to fix the value.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate keepTrace(MatsInitiator.KeepTrace keepTrace)
MatsInitiator.MatsInitiate
MatsInitiator.KeepTrace.COMPACT
, keeps a trail of all the stages
the flow has been through, but drops state and DTOs that aren't relevant for the current message. You might
want to use MatsInitiator.KeepTrace.FULL
while developing new functionality, while once a certain call flow
stabilizes, without much errors or DLQs, you should consider initializing it with MatsInitiator.KeepTrace.COMPACT
or even MatsInitiator.KeepTrace.MINIMAL
(the latter also dropping the "trail", thus only keeping information
strictly relevant for the current message).
This functionality is solely for debugging, the Mats endpoints works identically with any setting,
thus it is a tradeoff between performance (size of messages) and debuggability. The resulting kept trace
would typically be visible in a "toString()" of the MatsEndpoint.ProcessContext
- or in an external (e.g.
Brokerside) debugging/tracing system.keepTrace
in interface MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate nonPersistent()
MatsInitiator.MatsInitiate
nonPersistent
in interface MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate nonPersistent(long timeToLiveMillis)
MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate.nonPersistent()
, but you can set a time-to-live too. If the message gets this old and have
not yet been delivered to the receiving Mats endpoint, it will be deleted and never delivered.
This functionality often makes sense for messages that are both interactive
and
non-persistent
: Such messages shall only be "getters" free of any side effects (i.e.
no state is changed by the entire message flow), and where a human is actively waiting for the reply. If
there is a situation where such messages aren't consumed due to the receiving service having problems, it
does not make sense to use processing resources to handle a massive stack of these messages when the
consumption is restored an hour later, as e.g. the synchronously waiting HTTP call that was waiting for the
reply has timed out, and the waiting human is probably long gone anyway.
Notice on use: This should NOT be employed for message flows where any stage might change any
state, i.e. message flows with side effects (Think "PUT", "POST" and "DELETE"-style messages) - which also
should NOT employ non-persistent
messaging. The rationale is that such
messages should never just cease to exists, for any reason - they should have both guaranteed delivery and
execution. You should also never use this to handle any business logic, e.g. some kind of order time-out
where an order is only valid until 21:00, or something like this. This both because of the "Note on
implementation" below, and that the entire facility of "time to live" is optional both for Mats and for
the underlying message queue system.
Notice on implementation: If the message is a part of a multi-message flow, which most Mats
initiations pretty much invariably is (a request consists of a request-message and a reply-message), this TTL
will be set afresh on every new message in the flow, possibly with the amount of time taken in the processing
of the stage deducted. However, the time that the message waited in queue will not be deducted. The
effective TTL of the flow might therefore be a multiple of what is set here. An example: The TTL of an
initiation is set to 5000 ms. The request message stays 4 seconds in queue, before being received and
processed, where the processing took 100 ms. The reply-message will thus have its TTL set to 4900 ms: 5000 ms
TTL - 100 ms for processing. The reply message stays 4 seconds in queue before being received. The total
"time in flight" has now been 8.1 seconds, and there was still 900 ms left of the reply-message's TTL. The
rationale for not deducting queue-time on the subsequent message is that there is no easy way to get the
"queue time" which does not involve taking the difference between two timestamps, but in a multi-server
architecture there is a clear possibility of clock skews between different services, even for instances of
the same service. You could then deduce a too high queue time, deducting a too high value from the
reply-message's TTL, and effectively time out the full message flow too early. However, for the intended use
case - to hinder build-up of messages that will nevertheless be valueless when the answer is received since
the interactively waiting human is long gone - this is no big problem.nonPersistent
in interface MatsInitiator.MatsInitiate
timeToLiveMillis
- the number of milliseconds before this message is timed out and thus will never be delivered - 0
means "live forever", and this is the default.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate interactive()
MatsInitiator.MatsInitiate
concurrency
or the number of nodes that is running the
problematic endpoint or stage; increase the speed and/or throughput of external systems like the database; or
somehow just code the whole thing to be faster!
It will often make sense to set both this flag, and the MatsInitiator.MatsInitiate.nonPersistent()
, at the same time. E.g. when
you need to show the account balance for a customer: It both needs to skip past any bulk/batch queue of such
requests (since a human is literally waiting for the result), but it is also a "pure GET"-style request, not
altering state whatsoever, so it can also be set to non-persistent.interactive
in interface MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate noAudit()
MatsInitiator.MatsInitiate
noAudit
in interface MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate from(java.lang.String initiatorId)
MatsInitiator.MatsInitiate
ProcessContext#initiate(InitiateLambda)
, the 'from' property is already set to the stageId of the
currently processing Stage, but it can be overridden if desired. It is important that you do not make
this into a dynamic string, i.e. do not add some Id to it (such Ids should go into the traceId).
It it is smart to decide on a common prefix for all Mats Endpoints and InitiatorIds for a particular service.
E.g. "OrderService" or "InventoryService" or something like this.
A good value that would be of use when debugging a call trace is something following a structure like
"OrderService.REST.place_order_from_user"
, this example trying to convey that it is from the
OrderSystem, coming in over its REST endpoint "place_order_from_user". Note that there are no e.g. userId
there.
NOTE: This is only used for tracing/debugging (in particular, it is not related to the
replyTo
functionality), but should be set to something that will give
insights when you try to make sense of call flows. Think of a introspection system showing a histogram of
where messages are initiated, so that you can see that 45% of the messages are coming from the OrderSystem's
REST endpoints, and 15% of all initiations are its "place_order_from_user". This also implies that it
shall not be a dynamic value, i.e. do not put something that will vary between each call, that is, do NOT add
the user's Id or something like that. Such dynamic elements is what the MatsInitiator.MatsInitiate.traceId(CharSequence)
is
for.from
in interface MatsInitiator.MatsInitiate
initiatorId
- the originating/initiating "synthetic endpoint Id" - only used for tracing/debugging.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate to(java.lang.String endpointId)
MatsInitiator.MatsInitiate
to
in interface MatsInitiator.MatsInitiate
endpointId
- to which MATS Endpoint this message should go.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate replyTo(java.lang.String endpointId, java.lang.Object replySto)
MatsInitiator.MatsInitiate
replyTo
in interface MatsInitiator.MatsInitiate
endpointId
- which MATS Endpoint the reply of the invoked Endpoint should go to.replySto
- the object that should be provided as STO to the service which get the reply.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate replyToSubscription(java.lang.String endpointId, java.lang.Object replySto)
MatsInitiator.MatsInitiate
replyTo
, where the reply will go to the specified
endpointId which must be a
SubscriptionTerminator
.replyToSubscription
in interface MatsInitiator.MatsInitiate
endpointId
- which MATS Endpoint the reply of the invoked Endpoint should go to.replySto
- the object that should be provided as STO to the service which get the reply.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate setTraceProperty(java.lang.String propertyName, java.lang.Object propertyValue)
MatsInitiator.MatsInitiate
MatsEndpoint.ProcessContext.setTraceProperty(String, Object)
.setTraceProperty
in interface MatsInitiator.MatsInitiate
propertyName
- the name of the propertypropertyValue
- the value of the property, which will be serialized using the active MATS serializer.MatsEndpoint.ProcessContext.setTraceProperty(String, Object)
,
MatsEndpoint.DetachedProcessContext.getTraceProperty(String, Class)
public MatsInitiator.MatsInitiate logMeasurement(java.lang.String metricId, java.lang.String metricDescription, java.lang.String baseUnit, double measure, java.lang.String... labelKeyValue)
MatsInitiator.MatsInitiate
timing
measurements
.
Inclusion as metric by plugin 'mats-intercept-micrometer': A new meter will be created (and cached),
of type DistributionSummary
, with the 'name' set to
"mats.exec.ops.measure.{metricId}.{baseUnit}"
("measure"->"time" for timings), and
'description' to description. (Tags/labels already added on the meter by the plugin include 'appName',
'initiatorId', 'initiatingAppName', 'stageId' (for stages), and 'initiatorName' (for inits)). Read about
parameter 'labelKeyValue' below.
Inclusion as log line by plugin 'mats-intercept-logging': A log line will be output by each added
measurement, where the MDC for that log line will have an entry with key
"mats.ops.measure.{metricId}.{baseUnit}"
. Read about parameter 'labelKeyValue' below.
It generally makes most sense if the same metrics are added for each processing of a particular Initiation,
i.e. if the "number of items" are 0, then that should also be recorded along with the "total amount for order
in dollar" as 0, not just elided. Otherwise, your metrics will be skewed.
You should use a dot-notation for the metricId if you want to add multiple meters with a
hierarchical/subdivision layout.
The vararg 'labelKeyValue' is an optional element where the String-array consist of one or several alternate
key, value pairs. Do not employ this feature unless you know what the effects are, and you actually need
it! This will be added as labels/tags to the metric, and added to the SLF4J MDC for the measurement log
line with the key being "mats.ops.measure.{metricId}.{labelKey}"
("measure"->"time" for
timings). The keys should be constants as explained for the other parameters, while the value can change, but
only between a given set of values (think enum
) - using e.g. the 'customerId' as value doesn't
make sense and will blow up your metric cardinality. Notice that if you do employ e.g. two labels, each
having one of three values, you'll effectively create 9 different meters, where your measurement will
go to one of them.
NOTICE: If you want to do a timing, then instead use
MatsInitiator.MatsInitiate.logTimingMeasurement(String, String, long, String...)
logMeasurement
in interface MatsInitiator.MatsInitiate
metricId
- constant, short, possibly dot-separated if hierarchical, id for this particular metric, e.g.
"items" or "amount", or "db.query.orders".metricDescription
- constant, textual description for this metric, e.g. "Number of items in customer order", "Total
amount of customer order"baseUnit
- the unit for this measurement, e.g. "quantity" (for a count measure), "dollar" (for an amount), or
"bytes" (for a document size).measure
- value of the measurementlabelKeyValue
- a String-vararg array consisting of alternate key,value pairs which will becomes labels or tags or
entries for the metrics and log lines. Read the JavaDoc above; the keys shall be "static" for a
specific measure, while the values can change between a specific small set values.MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate logTimingMeasurement(java.lang.String metricId, java.lang.String metricDescription, long nanos, java.lang.String... labelKeyValue)
MatsInitiator.MatsInitiate
addMeasurement(..)
, but
specifically for timings - Read that JavaDoc!
Note: It is illegal to use the same 'metricId' for more than one measurement for a given Initiation, and this
also goes between timing measurements and measurements
.
For the metrics-plugin 'mats-intercept-micrometer' plugin, the 'baseUnit' argument is deduced to whatever is
appropriate for the receiving metrics system, e.g. for Prometheus it is "seconds", even though you always
record the measurement in nanoseconds using this method.
For the logging-plugin 'mats-intercept-logging' plugin, the timing in the log line will be in milliseconds
(with fractions), even though you always record the measurement in nanoseconds using this method.logTimingMeasurement
in interface MatsInitiator.MatsInitiate
metricId
- constant, short, possibly dot-separated if hierarchical, id for this particular metric, e.g.
"db.query.orders" or "calcprofit".metricDescription
- constant, textual description for this metric, e.g. "Time taken to execute order query", "Time
taken to calculate profit or loss".nanos
- time taken in nanosecondslabelKeyValue
- a String-vararg array consisting of alternate key,value pairs which will becomes labels or tags or
entries for the metrics and log lines. Read the JavaDoc at
addMeasurement(..)
MatsInitiator.MatsInitiate
for chaining.public MatsInitiator.MatsInitiate addBytes(java.lang.String key, byte[] payload)
MatsInitiator.MatsInitiate
addBytes
in interface MatsInitiator.MatsInitiate
key
- the key on which to store the byte array payload. The receiver will have to use this key to get
the payload out again, so either it will be a specific key that the sender and receiver agree
upon, or you could generate a random key, and reference this key as a field in the Request DTO.payload
- the byte array.MatsInitiator.MatsInitiate
for chaining.MatsInitiator.MatsInitiate.addString(String, String)
public MatsInitiator.MatsInitiate addString(java.lang.String key, java.lang.String payload)
MatsInitiator.MatsInitiate
addBytes(..)
method (and will then have to decompress it on the receiving
side).addString
in interface MatsInitiator.MatsInitiate
key
- the key on which to store the String payload. The receiver will have to use this key to get the
payload out again, so either it will be a specific key that the sender and receiver agree upon, or
you could generate a random key, and reference this key as a field in the Request DTO.payload
- the string.MatsInitiator.MatsInitiate
for chaining.MatsInitiator.MatsInitiate.addBytes(String, byte[])
public MatsInitiator.MessageReference request(java.lang.Object requestDto)
MatsInitiator.MatsInitiate
request
in interface MatsInitiator.MatsInitiate
requestDto
- the object which the endpoint will get as its incoming DTO (Data Transfer Object).public MatsInitiator.MessageReference request(java.lang.Object requestDto, java.lang.Object initialTargetSto)
MatsInitiator.MatsInitiate
request
in interface MatsInitiator.MatsInitiate
requestDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).initialTargetSto
- the object which the target endpoint will get as its STO (State Transfer Object).public MatsInitiator.MessageReference send(java.lang.Object messageDto)
MatsInitiator.MatsInitiate
request(..)
and send(..)
is only that replyTo is
not set for send, otherwise the mechanism is exactly the same.send
in interface MatsInitiator.MatsInitiate
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).public MatsInitiator.MessageReference send(java.lang.Object messageDto, java.lang.Object initialTargetSto)
MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate.send(Object)
method, where the incoming state is sent along.
This only makes sense if the same code base "owns" both the initiation code and the endpoint to which this
message is sent. It is mostly here for completeness, since it is possible to send state along with
the message, but if employed between different services, it violates the premise that MATS is built on: State
is private to the stages of a multi-stage endpoint, and the Request and Reply DTOs are the public interface.send
in interface MatsInitiator.MatsInitiate
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).initialTargetSto
- the object which the target endpoint will get as its STO (State Transfer Object).public MatsInitiator.MessageReference publish(java.lang.Object messageDto)
MatsInitiator.MatsInitiate
SubscriptionTerminator
, employing the publish/subscribe pattern instead of message queues (topic in JMS
terms). This means that all of the live servers that are listening to this endpointId will receive the
message, and if there are no live servers, then no one will receive it.
The concurrency of a SubscriptionTerminator is always 1, as it only makes sense for there being only one
receiver per server - otherwise it would just mean that all of the active listeners on one server would get
the message, per semantics of the pub/sub.
It is only possible to publish to SubscriptionTerminators as employing publish/subscribe for multi-stage
services makes no sense.publish
in interface MatsInitiator.MatsInitiate
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).public MatsInitiator.MessageReference publish(java.lang.Object messageDto, java.lang.Object initialTargetSto)
MatsInitiator.MatsInitiate
MatsInitiator.MatsInitiate.publish(Object)
method, where the incoming state is sent along.
This only makes sense if the same code base "owns" both the initiation code and the endpoint to which this
message is sent. The possibility to send state along with the request makes most sense with the publish
method: A SubscriptionTerminator is often paired with a Terminator, where the Terminator receives the
message, typically a reply from a requested service, along with the state that was sent in the initiation.
The terminator does any "needs to be guaranteed to be performed" state changes to e.g. database, and then
passes the incoming message - along with the same state it received - on to a SubscriptionTerminator.
The SubscriptionTerminator performs any updates of any connected GUI clients, or for any other local states,
e.g. invalidation of caches, on all live servers listening to that endpoint, the point being that if
no servers are live at that moment, no one will process that message - but at the same time, there is
obviously no GUI clients connected, nor are there are local state in form of caches that needs to be
invalidated.publish
in interface MatsInitiator.MatsInitiate
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).initialTargetSto
- the object which the target endpoint will get as its STO (State Transfer Object).public <R,S,I> void unstash(byte[] stash, java.lang.Class<R> replyClass, java.lang.Class<S> stateClass, java.lang.Class<I> incomingClass, MatsEndpoint.ProcessLambda<R,S,I> lambda)
MatsInitiator.MatsInitiate
stashed
. To be able to
deserialize the stashed bytes to instances provided to the supplied MatsEndpoint.ProcessLambda
, you need to
provide the classes of the original stage's Reply, State and Incoming objects.unstash
in interface MatsInitiator.MatsInitiate
R
- type of the ReplyClassS
- type of the StateClassI
- type of the IncomingClassstash
- the stashed bytes which now should be unstashedreplyClass
- the class which the original stage originally would reply with.stateClass
- the class which used for state in the original stage (endpoint) - or Void.TYPE
(i.e.
void.class
) if none.incomingClass
- the class which the original stage gets as incoming DTO.lambda
- the stage lambda which should now be executed instead of the original stage lambda where stash was
invoked.public <T> java.util.Optional<T> getAttribute(java.lang.Class<T> type, java.lang.String... name)
MatsInitiator.MatsInitiate
MatsEndpoint.ProcessContext.getAttribute(Class, String...)
. There is also a ThreadLocal-accessible
version at MatsFactory.ContextLocal.getAttribute(Class, String...)
.
Mandatory: If the Mats implementation has a transactional SQL Connection, it shall be available by
'context.getAttribute(Connection.class)'
.getAttribute
in interface MatsInitiator.MatsInitiate
T
- The type of the attribute.type
- The expected type of the attributename
- The (optional) (hierarchical) name(s) of the attribute.MatsEndpoint.ProcessContext.getAttribute(Class, String...)
,
MatsFactory.ContextLocal.getAttribute(Class, String...)
public java.lang.String toString()
toString
in class java.lang.Object