CodamAIDocs
Topicdone

The client for a separate service

crms-client talks to a separate CRMS service over HTTP: the same ports as embedded, the person's token is passed on, timeouts and errors come back as the same exceptions.

Variants
ReportRenderPort and CapabilitiesPort (render, renderTo, validate, capabilities)DocumentArchivePort (read, revisions, verify, setLegalHold, releaseLegalHold, erase)token present, no token, own CallerToken beanerror answer, 401/403 of the security chain, service unreachable, timeout

What this is about

When CRMS runs as a separate service, the application needs a way to reach it. That is crms-client. It offers the same ports as the embedded CRMS. A port is a Java interface through which your application calls CRMS. Behind the port there is no renderer here, but an HTTP call to the service.

When the client applies

The operating mode is set in codamai.crms.placement (CODAMAI_CRMS_PLACEMENT). The hub derives it from the runtime the CRMS module is placed in.

placementIn the buildThe start fails if
localthe embedded CRMS and the format modulesthe embedded CRMS is missing
remotecrms-clientcrms-client is missing, or the CRMS renderer or the CRMS HTTP interface are present

More in Embedded or standalone.

What the client offers

Port and methodRoute on the service
ReportRenderPort.renderPOST /crms/render
ReportRenderPort.renderToPOST /crms/render, the response flows straight into your OutputStream as it arrives
ReportRenderPort.validatePOST /crms/render/validate
CapabilitiesPort.capabilitiesGET /crms/capabilities
DocumentArchivePort.readGET /crms/documents/{revision}
DocumentArchivePort.revisionsGET /crms/documents?template=…&scope=…&reference=…
DocumentArchivePort.verifyPOST /crms/documents/{revision}/verify
DocumentArchivePort.setLegalHold / releaseLegalHoldPOST /crms/documents/{revision}/legal-hold / …/release
DocumentArchivePort.erasePOST /crms/documents/{revision}/erase

Editing templates is not a port. A template editor calls the service’s template routes directly, see The endpoints.

The person’s token, not a service token

On every call, crms-client sends along the token of the person whose request the application is answering right now. Unchanged. The CRMS service then exchanges it for one for its own client. This way every revision and every document names the person who caused it, and not “the service”.

sequenceDiagram
    participant B as User
    participant A as Application
    participant C as CRMS service
    participant I as CIAS in the service
    B->>A: Request with bearer token
    A->>C: POST /crms/render, the same bearer token
    C->>I: Check and exchange the token
    I-->>C: Person, tenant, roles of the CRMS client
    C-->>A: Document or error answer
    A-->>B: Response
Where the token comes from

When: the normal case, the application is answering an HTTP request right now

The client takes the token from the header Authorization: Bearer … of this request.

Result: the call is made on behalf of this person

When: a background job, a timer, a thread of its own

There is no person, so there is no token. The client sends nothing.

Result: CrmsException with crms-authentication-required

When: the application provides its own bean of type CallerToken

The client asks this bean for the token instead of the running request.

Result: the call is made with the token the bean returns

How the exchange works in the service is described in Token exchange. Which roles the service then sees, in The roles.

Settings

PropertyVariableDefaultMeaning
codamai.crms.client.urlCODAMAI_CRMS_CLIENT_URLnone, requiredhttp or https address of the service. The routes sit below it: https://crms.example.com becomes https://crms.example.com/crms/render
codamai.crms.client.connect-timeoutCODAMAI_CRMS_CLIENT_CONNECT_TIMEOUTPT5Show long the client waits for a connection
codamai.crms.client.timeoutCODAMAI_CRMS_CLIENT_TIMEOUTPT2Mhow long one whole call may take

The values are ISO-8601 durations: PT5S means five seconds, PT2M two minutes. If the address is missing or is not an http or https address, the application does not start. Neither does it with a duration of zero or less.

The default of timeout is longer than the service’s render timeout (default PT30S). This way a slow document comes back as the service’s render-timeout, instead of the client giving up first.

How responses come back

StatusError answer with messageKey?What your code gets
2xx–the object, as embedded: RenderedDocument, Capabilities, ArchivedDocument …
erroryes, payload-rejectedPayloadRejectedException with the same violations
erroryesCrmsException with the same key and the same parameters
401nocrms-authentication-required
403nocrms-access-denied
othernocrms-unavailable

A 401 or 403 without an error answer comes from the service’s security chain, before CRMS saw the request. crms-unavailable means: the service could not be reached, did not answer in time, or the response did not come from CRMS, such as a proxy’s page or a missing route. A successful response that lacks something is also crms-unavailable. The client never returns half an object.

Values on the way

  • Data travels as JSON carries it. Dates and times as ISO-8601 text, decimals with their decimal places: 12.50 stays 12.50. Otherwise a template would print something different than when embedded.
  • What JSON cannot carry is already refused by the client, as payload-rejected with the same rule as the embedded check (value-type-unsupported, key-invalid).
  • With attachments, the body is compressed. If a render request has pictures as attachments, the client sends it with Content-Encoding: gzip. Base64 makes pictures a third larger, gzip takes back almost all of it.
  • No redirects. If the address answers with a redirect, the client does not follow it. The result is then crms-unavailable.

Pitfalls

Next

Search