Copyright (C) 2019-2022 The Open Library Foundation
This software is distributed under the terms of the Apache License, Version 2.0. See the file "LICENSE" for more information.
The purpose of this edge API is to bridge the gap between self service circulation and patron services stations and FOLIO by allowing these systems to issue requests and receive responses in Standard Interchange Protocol v2 (SIP2). These requests will be serviced by FOLIO APIs and the responses will be based on FOLIO results for all supported (TBD) SIP2 commands.
- edge-sip2
The edge-sip2 module can be launched via edge-sip2-fat.jar as follows:
$ java -jar edge-sip2-fat.jar -conf sip2.confThe -conf option can either specify the filename of the configuration or inline JSON. Here is a sample sip2.conf file:
{
"port": 6443,
"okapiUrl": "https://folio-testing-okapi.dev.folio.org",
"haProxy": false,
"tenantConfigRetrieverOptions": {
"scanPeriod": 300000,
"stores": [{
"type": "file",
"format": "json",
"config": {
"path": "sip2-tenants.conf"
},
"optional": false
}]
}
}For inline JSON, the format is:
-conf '{"port":1234,"okapiUrl":"https://folio-snapshot-okapi.dev.folio.org".....}'
On Windows, inline JSON configuration is in double quotes and the inner double quotes should be escaped, for example:
-conf "{\"port\":1234,\"okapiUrl\":\"https://folio-snapshot-okapi.dev.folio.org\"....}"
One option is to mount the configuration files to the Docker container and provide
command line arguments to point it to the right path (e.g. -conf /path/to/config).
| Config option | Type | Description |
|---|---|---|
port |
int | The port the module will use to bind, typically 1024 <= port <= 65,535; must not be 8081 that is used for health check. |
okapiUrl |
string | The URL of the Okapi server used by FOLIO. |
haProxy |
boolean | Defines if HA proxy support is enabled. See: Using HA PROXY protocol. |
tenantConfigRetrieverOptions |
JSON object | Location for tenant configuration. |
scanPeriod |
int | Frequency in msec that sip2 will check for and reload tenant configuration changes. |
stores |
JSON array | Defines the properties for the tenant configuration stores. Multiple sources of tenant configuration can be loaded and combined together. |
type |
string | The store type. Several supported types include: file, http, github, s3. See: vertx config |
format |
string | Sip2 expects configuration to be in json format. |
config |
string | Store type-specific properties. |
path |
string | Path name of the tenant configuration file for file type stores. |
optional |
boolean | If a failure is caught while loading the tenant configuration from an optional store, the failure is logged, but the processing does not fail. Instead, the tenant configuration will be empty. |
netServerOptions |
JSON object | Configuration options for the server. These are Vertx options and are numerous. See: NetServerOptions. |
token_cache_capacity |
int | Max token cache size. Default size is 100. |
| Note: edge-sip2 now requires two config files: the main bootstrap sip2.conf and tenant configuration: sip2-tenants.conf. The additional config file is required to support multi-tenants and runtime reloading of tenant configuration without restarting the edge-sip2 module. |
Here is a sample sip2-tenants.conf file:
{
"tenant": "default_single_tenant",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1",
"scTenants": [
{
"scSubnet": "11.11.00.00/16",
"tenant": "multi-tenant1",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1"
},
{
"scSubnet": "22.22.00.00/16",
"tenant": "multi_tenant2",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1"
}
]
}| Config option | Type | Description |
|---|---|---|
scTenants |
JSON array | Array of sip2 tenant configurations. |
scSubnet |
string | IPv4 CIDR of a tenant's self service kiosk. This is used to identify the tenant configuration for an incoming kiosk connection. |
tenant |
string | The FOLIO assigned tenant ID. |
errorDetectionEnabled |
boolean | Indicates whether or not the self service kiosk will be using SIP error detection in messages sent to and from this module. Defaults to "false". |
messageDelimiter |
string | The character sequence that indicates the end of a single SIP message. This is available in case the self check kiosk is not compliant with the SIP specification. The default is "\r" |
fieldDelimiter |
string | The character that the self service kiosk will use when encoding SIP messages. Defaults to "|". |
charset |
string | The character set SIP messages must be encoded with when sent and received by the self service kiosk. The charset must be defined as a "Canonical Name for java.nio API". See: Supported Encodings. Default is "IBM850". |
Edge-sip2 supports various locations for sip2-tenants.conf tenant configuration. Additionally, it supports S3 config. To include vertx-config-s3 libraries when building edge-sip2, include the maven profile command:
mvn -P vertx-config-s3
Here is a sample sip2.conf for storing tenant config in S3:
{
"port": 6443,
"okapiUrl": "https://folio-testing-okapi.dev.folio.org",
"tenantConfigRetrieverOptions": {
"scanPeriod": 300000,
"stores": [{
"type": "s3",
"format": "json",
"config": {
"region": "my-region",
"bucket": "my-bucket",
"key": "sip2/sip2-tenants.conf"
},
"optional": true
}]
}
}Certain properties are retrieved from FOLIO configuration once a user has logged in via SIP2. There are properties at the tenant level and properties per kiosk, which is defined as a FOLIO service point. Properties are stored as JSON via the configuration module. Missing configuration properties will lead to edge-sip2 runtime failures. The edge-sip2 properties listed below must be manually created via the POST /configurations/entries API using a tool such as curl or postman.
| Property | Type | Description |
|---|---|---|
statusUpdateOk |
boolean |
Indicates to the kiosk that the SIP service allows patron status updates from the kiosk. |
offlineOk |
boolean |
Indicates to the kiosk that FOLIO supports off-line operations. |
supportedMessages |
object[] |
An array objects that indicate to the kiosk which messages are supported by the edge-sip2 module. |
patronPasswordVerificationRequired |
boolean |
Indicates whether or not SIP commands that supply a patron password will attempt to verify the password by attempting a FOLIO login with these supplied patron credentials. A failed patron login will fail the SIP request. Defaults to false. |
invalidCheckinStatuses |
string |
A comma-separated list of item statuses that will block an attempt to checkin a given item via SIP2. |
usePinForPatronVerification |
boolean |
Indicates whether or not to use patron PIN instead of password for verification. Defaults to false. |
alwaysCheckPatronPassword |
boolean |
Indicates whether or not to check a provided patron password if patronPasswordVerificationRequired is disabled. Defaults to true. |
| Property | Type | Description |
|---|---|---|
messageName |
string |
The name of the message. See: Messages |
isSupported |
string |
Y or N to indicate to the kiosk whether or not the message is supported |
{
"module": "edge-sip2",
"configName": "acsTenantConfig",
"enabled": true,
"value": "{\"supportedMessages\": [{\"messageName\": \"PATRON_STATUS_REQUEST\",\"isSupported\": \"N\"},{\"messageName\": \"CHECKOUT\",\"isSupported\": \"Y\"},{\"messageName\": \"CHECKIN\",\"isSupported\": \"Y\"},{\"messageName\": \"BLOCK_PATRON\",\"isSupported\": \"N\"},{\"messageName\": \"SC_ACS_STATUS\",\"isSupported\": \"Y\"},{\"messageName\": \"LOGIN\",\"isSupported\": \"Y\"},{\"messageName\": \"PATRON_INFORMATION\",\"isSupported\": \"Y\"},{\"messageName\": \"END_PATRON_SESSION\",\"isSupported\": \"Y\"},{\"messageName\": \"FEE_PAID\",\"isSupported\": \"N\"},{\"messageName\": \"ITEM_INFORMATION\",\"isSupported\": \"N\"},{\"messageName\": \"ITEM_STATUS_UPDATE\",\"isSupported\": \"N\"},{\"messageName\": \"PATRON_ENABLE\",\"isSupported\": \"N\"},{\"messageName\": \"HOLD\",\"isSupported\": \"N\"},{\"messageName\": \"RENEW\",\"isSupported\": \"N\"},{\"messageName\": \"RENEW_ALL\",\"isSupported\": \"N\"}, {\"messageName\": \"REQUEST_SC_ACS_RESEND\",\"isSupported\": \"Y\"}],\"statusUpdateOk\": false,\"offlineOk\": false,\"patronPasswordVerificationRequired\": true}"
}| Property | Type | Description |
|---|---|---|
retriesAllowed |
number |
Indicates to the kiosk the number of retries allowed by FOLIO. This should be a number between 0 and 999, where 999 means that the retry number is unknown. |
timeoutPeriod |
number |
Indicates to the kiosk the period of time before a transaction is aborted by the kiosk. The number should be between 0 and 999, where 0 means that FOLIO is not online and 999 means the time out is unknown. The number is expressed in tenths of a second. |
checkinOk |
boolean |
Indicates whether or not the kiosk is allowed to check in items. |
acsRenewalPolicy |
boolean |
Indicates that the kiosk is allowed by FOLIO to process patron renewal requests. |
checkoutOk |
boolean |
Indicates whether or not the kiosk is allowed to check out items. |
libraryName |
string |
The name of the library where the kiosk is located or whatever makes sense for the tenant. |
terminalLocation |
string |
This could be the location of the kiosk within the library or the UUID of the service point. |
{
"module": "edge-sip2",
"configName": "selfCheckoutConfig.e0ab8c91-2a4a-433d-a3cf-1837053c89a8",
"enabled": true,
"value": "{\"timeoutPeriod\": 5,\"retriesAllowed\": 3,\"checkinOk\": true,\"checkoutOk\": true,\"acsRenewalPolicy\": false,\"libraryName\": \"Datalogisk Institut\",\"terminalLocation\": \"e0ab8c91-2a4a-433d-a3cf-1837053c89a8\"}"
}| Property | Type | Description |
|---|---|---|
timezone |
string |
The tenant's time zone as set in FOLIO. |
currency |
string |
Currency code (ISO-4217). |
{
"module": "ORG",
"configName": "localeSettings",
"enabled": true,
"value": "{\"timezone\":\"America/New_York\",\"currency\":\"USD\"}"
}Currently, edge-sip2 implements select SIP messages. Below, is the list of all implemented messages.
| SIP Request | Implemented | Notes |
|---|---|---|
| Patron Status Request | Yes | |
| Checkout | Yes | Response SIP fields hardcoded: "renewal ok" is set to "N", "magnetic media" is set to "U". SIP field "desensitize" is set to "Y" is the FOLIO check out succeeded and "N" when there is failure. Fee/fines related fields are not implemented. The "due date" format is the same as other SIP date/time format strings: "YYYYMMDDZZZZHHMMSS". |
| Checkin | Yes | Response SIP fields hardcoded: "alert" is set to "N", "magnetic media" is set to "U". Most optional SIP fields are not implemented. The "resensitize" field will be set to "Y" if the FOLIO check in succeeded and "N" if there was a failure. |
| Block Patron | No | |
| SC Status | Yes | |
| Request ACS Resend | Yes | |
| Login | Yes | The request "location code" should contain the UUID of the service point for the kiosk. |
| Patron Information | Yes | Response SIP field "hold items count" currently only refers to FOLIO "Hold" requests and not "Page" requests. Only "Hold" request data is returned in the summary results as well. The "charged items count", "fine items count" and "unavailable holds count" are not supported. However, "unavailable holds count" is not implemented due to an oversight as "hold items count" includes all "Hold" requests in any "Open" state, instead of limited to "Open - Awaiting pickup". Likewise, "unavailable holds count" could contain "Hold" requests that are not "Closed" and not "Open - Awaiting pickup". This will likely need to be corrected. The response "patron status" field is partially supported via FOLIO manual blocks where a "borrowing" block will set all privilege codes to "N", a "renewals" block will set the SIP "renewal privileges defined" code to "N", and a "requests" block will set "hold privileges denied" and "recall privileges denied" to "N". |
| End Patron Session | Yes | |
| Fee Paid | Yes | |
| Item Information | Yes | |
| Patron Enable | No | |
| Hold | No | |
| Renew | Yes | |
| Renew All | Yes |
The SIP protocol does not consider security apart from providing the possibility of SC/ACS negotiated encryption algorithm for the password and user ID, which seems unlikely to be used. All communication over the wire, via TCP, is plain text. This may be fine in an environment that is locked down in some way. However, FOLIO, along with this module, can be hosted in the cloud and plain text communication is not acceptable.
We strongly recommend securing communication from the SC to edge-sip2. To this end, edge-sip2 can be configured to use TLS to encrypt communication. This requires the SC to communicate with TLS as well. It is our understanding that most self service kiosks do not have this ability natively and third party solutions must be employed. One such solution is stunnel.
A typical stunnel deployment will involve installing the stunnel service either on the SC or a machine that is locked down with the SC and provides a port that the SC will be configured to connect to for SIP communication. The SIP commands are then sent to and received from the stunnel port unencrypted. Communication from the stunnel to the TLS termination end point will be encrypted. There are several ways to terminate TLS and the advantages/disadvantages of these is out of scope for this document. Here, we will focus on enabling TLS termination via the edge-sip2 module. This is done via simple launch configuration options.
stunnel can be downloaded here: https://www.stunnel.org/downloads.html
Example FOLIO configuration section for stunnel.conf:
[FOLIO]
key = stunnel.pem
cert = stunnel.pem
client = yes
accept = 127.0.0.1:5555
connect = sip2.example.com:6443Example edge-sip2 configuration:
$ java -jar edge-sip2-fat.jar -conf '{"port":1234,"okapiUrl":"https://folio-snapshot-okapi.dev.folio.org","tenant":"diku","netServerOptions":{"ssl":true,"pemKeyCertOptions":{"certPaths":["cert.crt"],"keyPaths":["cert.key"]}}}'| Config option | Type | Description |
|---|---|---|
ssl |
boolean | Indicates whether or not to enable SSL (TLS) support for the server |
pemKeyCertOptions |
JSON object | Used when the certificate is in PEM format |
pfxKeyCertOptions |
JSON object | Used when the certificate is in PFX format |
keyStoreOptions |
JSON object | Used when the certificate is in JKS (Java Keystore) format |
pemKeyCertOptions |
type | Description |
|---|---|---|
certPath |
string | File system path to a PEM formatted certificate |
certPaths |
JSON array of strings | File system paths to PEM formatted certificates |
keyPath |
string | File system path to PEM formatted key |
keyPaths |
JSON array of strings | File system paths to PEM formatted keys |
pfxKeyCertOptions |
type | Description |
|---|---|---|
path |
string | File system path to PFX (PKCS #12) store |
password |
string | The password for the PFX (PKCS #12) store |
keyStoreOptions |
type | Description |
|---|---|---|
path |
string | File system path to JKS key store |
password |
string | The password for the JKS key store |
All permission associated with edge-sip2
circulation.check-in-by-barcode.post
circulation.check-out-by-barcode.post
circulation.requests.collection.get
search.instances.collection.get
circulation.loans.collection.get
configuration.entries.collection.get
configuration.entries.item.get
manualblocks.collection.get
manualblocks.item.get
accounts.collection.get
accounts.item.get
users.collection.get
users.item.get
patron-blocks.automated-patron-blocks.collection.get
inventory.items.collection.get
circulation.renew-by-barcode.post
usergroups.collection.get
users-bl.item.get
usergroups.item.get
usergroups.collection.get
inventory-storage.holdings.item.get
inventory.instances.item.get
feefines.collection.get
patron-pin.validate
For local development, there is no requirement to encrypt communications from a SIP2 client to edge-sip2. Unencrypted TCP sockets are the default when launching edge-sip2 as described in the Configuration section. Encrypted communication from a SIP2 client is only required when explicitly configured via the above options and is up to the developer to provide that secure connection for edge-sip2.
A GET /admin/health request sent to health check port gets a response with 200 HTTP status code.
The value of the health check port is defined by the environment variable HEALTH_CHECK_PORT or defaults to 8081 if not set.
This module makes use of Micrometer to collect SIP2, Vert.x and JVM metrics. The metrics need to be collected by a monitoring system backed. This is where Micrometer provides flexibility, by allowing the module to code to the Micrometer interface, which is vendor neutral. Once determined, the vendor specific backend binding is provided runtime and can be easily replaced.
By default, metrics are disabled. To enable Vert.x metrics pass the following Java argument:
-Dvertx.metrics.options.enabled=true
With metrics enabled, configuration must be supplied to the verticle. This can be done as follows:
-options '{"metricsOptions":{"labels":["LOCAL","REMOTE","HTTP_PATH","HTTP_METHOD","HTTP_CODE","CLASS_NAME"],"enabled":true,"prometheusOptions":{"enabled":true,"startEmbeddedServer":true,"embeddedServerOptions":{"port":8081}}}}'
The metricsOptions here indicate that the verticle should collect metrics with the supplied list of labels. Some of these labels, like REMOTE, may lead to high cardinality metrics. The default labels list is "HTTP_METHOD", "HTTP_CODE", "POOL_TYPE" and "EB_SIDE".
Also specified here are prometheusOptions. In this case, the backend will be Prometheus. Prometheus "scrapes" metrics via HTTP at a specified interval. The options specified here allow Vert.x to create an HTTP server to handle metrics scraping. Prometheus setup is outside the scope of this document. Other bindings could be used, like InfluxDB.
For a list of Vert.x metrics (HTTP Client and Net Server are the primary sources for metrics in this module) see: Vert.x core tools metrics
The following metrics are supplied by this module:
| Metric name | Labels | Type | Description |
|---|---|---|---|
org_folio_edge_sip2_command_timer |
command |
Timer | SIP2 command execution time |
org_folio_edge_sip2_invalidMessage_errors |
port |
Counter | A count of invalid message errors |
org_folio_edge_sip2_request_errors |
port |
Counter | A count of request errors |
org_folio_edge_sip2_response_errors |
port |
Counter | A count of response errors |
org_folio_edge_sip2_scResend_errors |
port |
Counter | A count of SC resend errors, which occurs when the module fails to send the SC a resend message when the prior received message was not understood |
org_folio_edge_sip2_socket_errors |
port |
Counter | A count of socket errors |
JVM metrics (memory, GC, threads, etc.) are supplied as well.
The Maven pom.xml contains 2 profiles, metrics-prometheus and metrics-influxdb. Building with either or both of these profiles active will include the appropriate dependencies required to use metrics with that registry.
$ mvn install -P metrics-prometheus
If metrics need to be enabled, it is probably best to add any required runtime binding jars to the fat jar as part of a build. If this is not possible, the module can still be launched via the community Docker image. N.B., we may find that this approach cumbersome and may need to come up with an alternative approach.
Copy the appropriate runtime binding jars to a directory:
$ cp micrometer-registry-prometheus-1.1.5.jar simpleclient_common-0.5.0.jar simpleclient-0.5.0.jar /my/metrics/libs
Then run a container from the FOLIO docker hub image (either snapshot folioci/edge-sip2 or released folioorg/edge-sip2):
$ docker run -v /my/metrics/libs:/metrics -p 6443:6443 --expose 8081 -p 8081:8081 -e JAVA_OPTIONS="-Dvertx.metrics.options.enabled=true " -e JAVA_CLASSPATH=/metrics/*:/usr/verticles/edge-sip2-fat.jar -e JAVA_MAIN_CLASS=io.vertx.core.Launcher folioci/edge-sip2 run org.folio.edge.sip2.MainVerticle -conf '{"port":6443,"okapiUrl":"https://folio-okapi.example.com","tenant":"diku","messageDelimiter":"\r","errorDetectionEnabled":true,"charset":"ISO-8859-1"}' -options '{"metricsOptions":{"labels":["LOCAL","REMOTE","HTTP_PATH","HTTP_METHOD","HTTP_CODE","CLASS_NAME"],"enabled":true,"prometheusOptions":{"enabled":true,"startEmbeddedServer":true,"embeddedServerOptions":{"port":8081}}}}'
This example shows how to launch with the Prometheus binding. Since Prometheus needs to scrape the metrics, we need to expose port for the HTTP server.
Edge-sip2 supports multi-tenant environments by dynamically resolving the correct tenant configuration for each SIP2 client connection. This is achieved through a set of pluggable Tenant Resolver classes, each designed to identify the tenant using different connection or protocol attributes. The supported resolvers and their resolution strategies are described below.
Tenant resolvers are configured with system property (sip2TenantResolvers) or environment variable
(SIP2_TENANT_RESOLVERS), default value is PORT, IP_SUBNET. It is a comma-separated values with
tenant resolver names.
There are 2 tenant detection phases:
-
Connection Phase (CONNECT): This phase occurs when a SIP2 client establishes a TCP connection with the edge-sip2 server. During this phase, the Tenant Resolver inspects connection-level attributes, such as the client's IP address or the port number used for the connection, to determine the appropriate tenant. This phase is crucial for initial tenant identification, especially in environments where multiple tenants share the same SIP2 server instance.
Note: This phase is essential and required to set the following parameters:
- message delimiter (
messageDelimiter) (default is\r) - encoding charset (
charset) (default isIBM850) - error detection (
errorDetectionEnabled) (default isfalse) - field delimiter (
fieldDelimiter) (default is|)
If these values are not specified in the multi-tenant configuration, the values from the single tenant configuration will be used, if they are not found either, then the default values will be applied.
- message delimiter (
-
Protocol Phase (LOGIN): This phase takes place when the SIP2 client sends a LOGIN message after establishing the connection. The Tenant Resolver analyzes protocol-level attributes, such as the "Location Code" or Username field in the LOGIN message, to further refine or confirm the tenant identification. This phase is essential for scenarios where the initial connection attributes may not be sufficient for accurate tenant resolution.
Note: This phase provides only a capability to change tenant. Connection details, such as message delimiter, field delimiter, error detection, and encoding charset, cannot be changed.
| Key | Value |
|---|---|
| Config Name | IP_SUBNET |
| Resolution Phase | CONNECT |
| Purpose | Resolves the tenant based on the client's IP address subnet. |
| How it works | Checks if the client's IP address falls within any configured subnet in the SIP2 tenants configuration. Uses IPAddressString for IP validation and subnet matching. If a match is found, returns the corresponding tenant configuration. IPv4 and IPv6 are supported. |
Configuration example:
{
"tenant": "default_single_tenant",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1",
"scTenants": [
{
"scSubnet": "11.11.00.00/16",
"tenant": "multi-tenant1",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1"
},
{
"scSubnet": "22.22.00.00/16",
"tenant": "multi_tenant2",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1"
},
{
"scSubnet": "1001:db8:1::/48",
"tenant": "multi_tenant3",
"errorDetectionEnabled": false,
"messageDelimiter": "\r\n",
"fieldDelimiter": "~",
"charset": "UTF-8"
}
]
}| Key | Value |
|---|---|
| Config Name | IP_SUBNET |
| Resolution Phase | CONNECT |
| Purpose | Resolves a tenant based on the client port from the SIP2 connection. |
| How it works | Inspects the client port from the connection details and matches it against the configured tenant port values. If a match is found, returns the corresponding tenant configuration. |
To configure sip2 for a port dedicated to a specific tenant, two modifications are necessary:
- Modify the existing port config property in the sip2.conf from an integer value to an array of integer values, as demonstrated below:
{ "port": [ 6443, 6444, 6445 ], "okapiUrl": "https://folio-testing-okapi.dev.folio.org", "tenantConfigRetrieverOptions": { "scanPeriod": 300000, "stores": [ { "type": "file", "format": "json", "config": { "path": "sip2-tenants.conf" }, "optional": false } ] } } - In the sip2-tenants.conf, include a new property named 'port' and assign it the dedicated port value as indexed in the array from the previous conf file, as shown below:
{ "scTenants": [ { "scSubnet": "11.11.00.00/16", "port": "6443", "tenant": "test_tenant1", "errorDetectionEnabled": true, "messageDelimiter": "\r", "fieldDelimiter": "|", "charset": "ISO-8859-1" }, { "scSubnet": "22.22.00.00/16", "port": "6444", "tenant": "test_tenant2", "errorDetectionEnabled": true, "messageDelimiter": "\r", "fieldDelimiter": "|", "charset": "ISO-8859-1" }, { "scSubnet": "33.33.00.00/16", "port": "6445", "tenant": "test_tenant3", "errorDetectionEnabled": true, "messageDelimiter": "\r", "fieldDelimiter": "|", "charset": "ISO-8859-1" } ] }
Note: Only 1 tenant can be assigned to a specific port. If multiple tenants are configured with the same port, only the first tenant found will be used.
| Key | Value |
|---|---|
| Config Name | LOCATION_CODE |
| Resolution Phase | LOGIN |
| Purpose | Resolves a tenant based on the SIP2 login location code. |
| How it works | Checks the session data for a location code and matches it against configured tenant location codes (locationCodes in scTenants config object). If a match is found, returns the corresponding tenant configuration. |
sip2-tenants.json example (if the same connection parameters can be applied to multiple tenants):
{
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1",
"scTenants": [
{
"tenant": "test_tenant1",
"locationCodes": [
"f79ed33a-d39e-4f39-a6b2-8d43504cfb1c",
"961b41ba-9bbd-4781-a735-2e1cf9a9c899"
]
},
{
"scSubnet": "22.22.00.00/16",
"tenant": "test_tenant2",
"locationCodes": [
"c3da3e63-edb0-4704-b5f9-f675f8756077",
"6326e2ed-12ba-40b0-ae65-ac7414ef7157"
]
}
]
}sip2-tenants.json example (if any of the tenants require special charset, message delimiter, etc.):
Note: Note that IP subnet being used to identify connection parameters in this example, and tenant will be defined during the login operation.
{
"scTenants": [
{
"scSubnet": "11.11.00.00/16",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "ISO-8859-1"
},
{
"scSubnet": "22.22.00.00/16",
"errorDetectionEnabled": true,
"messageDelimiter": "\r",
"fieldDelimiter": "|",
"charset": "UTF-8"
},
{
"tenant": "test_tenant1",
"locationCodes": [
"f79ed33a-d39e-4f39-a6b2-8d43504cfb1c",
"961b41ba-9bbd-4781-a735-2e1cf9a9c899"
]
},
{
"scSubnet": "22.22.00.00/16",
"tenant": "test_tenant2",
"locationCodes": [
"c3da3e63-edb0-4704-b5f9-f675f8756077",
"6326e2ed-12ba-40b0-ae65-ac7414ef7157"
]
}
]
}| Key | Value |
|---|---|
| Config Name | LOCATION_CODE |
| Resolution Phase | LOGIN |
| Purpose | Resolves a tenant based on a prefix in the SIP2 username. |
| How it works | Extracts the tenant identifier from the username by splitting it using a configurable delimiter (default: __). The prefix before the delimiter is used as the tenant identifier. Uses the delimiter from the system variable sip2TenantUsernamePrefixDelimiter or environment variable SIP2_TENANT_USERNAME_PREFIX_DELIMITER, defaulting to __ if not set. It uses only usernames containing delimiter, values without it are ignored. |
This log message happens when one or more of the FOLIO configuration key/value maps are missing when retrieved. Ensure that each set of properties is stored in FOLIO configuration and that the service point UUID for the kiosk configuration matches the "location code" in the SIP "Login" message. Another problem could be that the tenant locale settings may not be saved in the database. On the initial deployment of FOLIO, as of Edelweiss, the locale settings are defaulted by the UI and not stored in the database until the "save" button is pressed. Since the UI defaults to usable settings for many, it may be misleading that these settings are present for backend modules, like edge-sip2, to consume.
This log message happens when the location code (CP) is missing when SC status command is attempted then the error message is printed in the logs.
See project SIP2 at the FOLIO issue tracker.
Other modules are described, with further FOLIO Developer documentation at dev.folio.org