What this is about
CRMS runs in two ways, just like CIAS:
- embedded (
local): CRMS runs in the same process as a CDMS application. The application calls the ports as Java methods. - as a service of its own (
remote): CRMS runs as a program of its own. Other applications call it over HTTP, withcrms-client.
In terms of the subject area, CRMS behaves the same in both cases: the same ports, the same answers, the same error keys.
The two operating modes
| local | remote | |
|---|---|---|
| Property | codamai.crms.placement=local | codamai.crms.placement=remote |
| On the classpath | starter, the embedded CRMS (brings template management, renderer and evidence along), the chosen format modules, the CRMS HTTP interface and, as long as final documents are stored, the CRMS S3 storage | starter and crms-client, nothing else of CRMS |
| Call | method call in the same process | HTTP to the CRMS service |
| Database | the database of the CDMS application | the service's own database |
| Scheduled passes | run in the application: anchoring and retention | run in the CRMS service, not in the application |
| Editing templates | through /crms/** of the application | directly through the routes of the CRMS service |
The CRMS HTTP interface belongs to the embedded mode. An application that embeds CRMS serves /crms/** with it, and other applications can use it as a CRMS service. An application with remote must not have this interface. Otherwise it would pass the service on through routes of its own, behind its own security.
CIAS knows the same two shapes, see CIAS embedded (a single unit).
What is checked at start
The starter checks the property against the classpath before any other part of CRMS is created. If something does not match, the application does not start, and the message says which jar is missing or which one is too many.
| CRMS renderer and crms-client together? | codamai.crms.placement | Classpath | Start |
|---|---|---|---|
| yes | – | – | fails: embed or call, never both |
| no | missing or empty | – | fails: the property is required |
| no | neither local nor remote | – | fails |
| no | local | embedded CRMS missing | fails |
| no | remote | crms-client missing | fails |
| no | remote | CRMS HTTP interface present | fails |
| no | local | embedded CRMS present | CRMS embedded |
| no | remote | crms-client present | CRMS over HTTP |
The property has no default. Otherwise a project scaffold that forgot it would silently run with the wrong mode.
In a native image, the classpath is already fixed at build time, while the property is only read at start. This is on purpose: a native image has a fixed classpath but runs in different environments. The environment variable for it is CODAMAI_CRMS_PLACEMENT.
The hub decides
A project in the hub has at most one CRMS module. Where you put this module, that is, into which runtime (the program that runs later), decides the operating mode of every CDMS application of the project. There is no field where you enter local or remote.
| Does the project have a CRMS module? | Does the CDMS application authenticate through CIAS? | Where is the CRMS module? | The CDMS application |
|---|---|---|---|
| no | – | – | without CRMS |
| yes | no | not in its own runtime | without CRMS |
| yes | no | in its own runtime | build refused: CRMS needs CIAS |
| yes | yes | in no runtime | build refused: the CRMS module must be placed in a runtime |
| yes | yes | in its own runtime | local: CRMS embedded |
| yes | yes | in another runtime | remote: client of the CRMS there |
“In another runtime” means either a CRMS service of its own or another CDMS application of the project that embeds CRMS. If the CRMS module is in a runtime without a CDMS application, it becomes a CRMS service of its own.
The build then puts the matching dependencies into the POM. With local, only the format modules of the formats the CRMS module chose go in. With remote, no format module goes in, because the rendering happens in the service.
A call over HTTP
With remote one rule applies: the call carries the person, not the service. crms-client forwards the access token of the request the application is answering right now. It never sends a service token of its own. This way every revision, every approval and every final document names the person who caused it.
-
1User→Clientclicks "Create report"
-
2Client→CDMSrequest with token:
Authorization: Bearer … -
3CDMSbuilds the payload and calls
ReportRenderPort.render(…) -
4CDMSis a request with a token running right now?
-
5CDMSno token, for example in a background job →
crms-authentication-required, nothing is sent -
6CDMS→CRMS
crms-clientsendsPOST /crms/renderwith the same token -
7CRMS→Keycloakexchanges the token for its own, with the roles CRMS knows for this person
-
8CRMSrenders as when embedded
-
9CRMS→CDMSanswers with the document
-
10CDMS→Clientpasses the result onResult: The same
RenderedDocumentor the sameCrmsExceptionas when embedded
crms-client translates the answer back into the same objects and errors the embedded mode returns. If the service cannot be reached, the time runs out, or an answer comes back that is not from CRMS, the result is crms-unavailable, never half a result. The address of the service is in CODAMAI_CRMS_CLIENT_URL. More in The client.