#

# SDLIP DASL Transport Mapping

SDLIP document map and recommended reading sequence (click to navigate):

This document describes the mapping of the Simple Digital Library Interoperability Protocol (SDLIP-Core) to the DAV Searching & Locating (DASL) protocol [DASL]. This specification defines how SDLIP methods are mapped onto DASL messages and discusses compatibility of services using the SDLIP/DASL protocol mapping and native DASL services. Client or server application builders do not need to understand this mapping. Available code libraries make the mapping process transparent. However, if you do choose to read this document: knowledge of DASL is assumed.

The goal of the SDLIP/DASL mapping is (i) to have a comprehensive HTTP transport for SDLIP-client/SDLIP-server interactions, and (ii) to allow as much interaction as possible among SDLIP services and client applications on the one hand, and native DASL services and client applications on the other.

Content:

    1. Overview of DASL
    2. Search Interface Mapping
      2.1 Search Request
      2.2 Search Result
      2.3 Search Redirection
    3. Result Access Interface Mapping
    4. Metadata Interface Mapping
    5. Exceptions
    References

## 1. Overview of DASL

The search model of DASL is a stateless request-reply model. The DASL protocol is an application of the HTTP 1.1 protocol. A client search request has the following structure:

`SEARCH [server path] HTTP/1.1`
`Content-type: text/xml`
`Content-length: ...`
`[more header values]*`
`[empty line]`
`<?xml version="1.0"?>`
`<d:searchrequest xmlns:d="DAV:">`
`[search query]`
`</d:searchrequest>`

The type of the search query is uniquely identified by a qualified tag name of the query. A qualified tag is a tag that has a namespace prefix. Every DASL-compliant server has to support a DASL-defined search query format recognized by the tag name `DAV:basicsearch`. The query schema for the basic search query is specified in [DASL]. The namespace of all DASL XML elements is `"DAV:"`. Note that `"DAV:"` is a URI schema identifier like `"http:"`, `"ftp:"` etc.

A successful reply to a search request has the following format:

`HTTP/1.1 207 Multi-Status`
`Content-type: text/xml`
`Content-length: xxxxx`
`[more header values]*`
`[empty line]`
`<?xml version="1.0"?>`
`<d:multistatus xmlns:d="DAV:">`
`[<d:response>...</d:response>]*`
`</d:multistatus>`

DASL supports a single method `search` whereas SDLIP offers a greater variety of methods. For cases where SDLIP clients communicate with native DASL servers, the only SDLIP method that needs to be mapped onto DASL is therefore the `search` method in the Search Interface. The ResultAccess Interface methods do not have equivalent counterparts in DASL because all native DASL servers are stateless. When using DASL as transport between SDLIP clients and stateful SDLIP servers, DASL therefore needs additional capabilities. This mapping attempts to add these extensions to DASL as unobtrusively as possible, always attempting to stay within DASL's design framework.

## 2. Search Interface Mapping

The SDLIP Search Interface defines a single method `search` whose interface is repeated below for reference:

    void search(

      Long clientSID,          // {0} Client-side session ID (unique within client)
      XMLObject subcols,       // {service's default (or sole) subcollection}
                               // Choice of collections to search w/in LSP.
      XMLObject query,         // The query.
                               // (e.g. <ADL:GazeteerLang>Lake Tahoe</ADL:GazeteerLang>)
      Long numDocs,            // {-1} Number of documents to return right away (-1: all)
      XMLObject docProps,      // {all possible properties} Properties to return
                               // for each result doc
                               // (e.g. <propList><Abstract/><Title/>, ...)
      Long stateTimeoutReq,    // {0} Request for number of seconds to
                               // maintain state at server. -1: request unlimited time
      XMLObject queryOptions,  // {none} Additional info for the LSP.
      OUT Long expectedTotal   // {0} -1 if unknowable. -2 if not yet known.
      OUT Long stateTimeout,   // {0} Time server is willing to maintain state
      OUT Long serverSID,      // {0} ID by which server identifies this session
      OUT XMLObject serverDelegate, // {same as for original query} For followup requests
      OUT XMLObject result     // XML-Encoded result list.

    )

The next sections describe how the SDLIP search invocation is mapped onto `DAV:searchrequest`, how the SDLIP search output parameters are extracted from a `DAV:multistatus` reply, and how redirection is handled.

### 2.1 Search Request

In all examples below we assume that the namespace shortcut "d" refers to the `"DAV:"` namespace and the namespace shortcut `"s"` refers to the SDLIP namespace. One may think of every XML structure below as if every top element of it would have the following two attributes:

`xmlns:d="DAV:" xmlns:s="http://interlib.org/SDLIP/1.0#"`

Both SDLIP and DASL allow any query types to be used in a search. However, the DASL specification requires every DASL-compliant service (client or server) to support the `DAV:basicsearch` query type. To facilitate interoperation between native DASL services and SDLIP/DASL services, we distinguish the following cases:

- SDLIP client calls `search` method, passing a `DAV:basicsearch` query in the `query` parameter.
  - `DAV:basicsearch` query contains neither `select` nor `from` clause.
  - SDLIP client specifies a complete `DAV:basicsearch` query (i.e. the query contains either `DAV:select` or `DAV:from` or both)
- SDLIP client uses a different query language (query schema), which is not `DAV:basicsearch`

We discuss each case in turn.

Case 1) SDLIP client calls `search` method, passing a `DAV:basicsearch` query in the `query` parameter.

Case 1a) `DAV:basicsearch` query contains neither `select` nor `from` clause.

For example, assume that the SDLIP client invokes the following search request:

`search(..., "<d:basicsearch><d:where>...</><d:orderby>...</></d:basicsearch>", ...):`

This request causes the following XML structure to be sent to the server:

`<d:searchrequest>`
`<d:basicsearch>`
`<d:select>...</> <- inserted*`
`<d:from>...</> <- inserted`
`<d:where>...</> <- original*`
`<d:orderby>...</> <- original`
`...`
`<s:clientSID>...</> <- inserted`
`<s:stateTimeoutReq>...</> <- inserted`
`<s:queryOptions>...</> <- inserted`
`</d:basicsearch>`
`</d:searchrequest>`

`*original:` | if the information is present in the SDLIP `search` method's query parameter, it is copied from there into the DASL XML request structure
`*inserted:` | the SDLIP/DASL transport module generates the element from information in the SDLIP `search` method's parameters and inserts it into the outgoing message

SDLIP-specific elements (`s:clientSID`, `s:stateTimeoutReq` etc.) are inserted at the end of the `d:basicsearch` element.

Case 1b) SDLIP client specifies a complete `DAV:basicsearch` query (i.e. the query contains either `DAV:select` or `DAV:from` or both):

`search(..., "<d:basicsearch><d:select>...</d:select>...</d:basicsearch>", ...):`

In this case, the following XML structure is delivered over the wire:

`<d:searchrequest>`
`<d:basicsearch>`
`<d:select>...</> <- original`
`<d:from>...</> <- original`
`<d:where>...</> <- original`
`<d:orderby>...</> <- original`
`...`
`<s:clientSID>...</> <- inserted`
`<s:stateTimeoutReq>...</> <- inserted`
`<s:queryOptions>...</> <- inserted`
`</d:basicsearch>`
`</d:searchrequest>`

Case 2) SDLIP client uses a different query language (query schema), which is not `DAV:basicsearch`:

`search(...., "<my:query>...</my:query>", ...)`

Then the following XML structure is generated:

`<d:searchrequest>`
`<s:SearchRequest>`
`<s:clientSID>...</> <- inserted`
`<s:stateTimeoutReq>..</> <- inserted`
`<s:subcols>...</> <- inserted`
`<s:numDocs>...</> <- inserted`
`<s:props>...</> <- inserted`
`<s:queryOptions>...</> <- inserted`
`<s:query>`
`<my:query>...</my:query> <- original`
`</s:query>`
`</s:SearchRequest>`
`</d:searchrequest>`

The rest of this section describes the translation between the XML structures used in the SDLIP `search` method and the XML structures used in the DASL protocol.

The `subcols` parameter of the `search` method is structured is follows:

`<s:subcols>`
`<s:subcolName>[subcollection URL]</s:subcolName>*`
`<s:resSet>[server sessionID]</s:resSet>*`
`</s:subcols>`

Thus, with SDLIP we can identify multiple subcollections and refer to the results of previous sessions. On the other hand, DASL allows us to specify at most one collection using a URL. In cases where SDLIP clients want to query multiple collections at once, the SDLIP/DASL mapping uses multiple DASL `scope` specifications. Naturally, native DASL servers may fail to answer such queries. Session IDs are encoded into URLs using a special prefix which allows server-side transport modules to distinguish them from regular collections. Of course, result set references are invalid for native DASL servers, since DASL servers are stateless. But SDLIP clients would know this because native DASL servers would not specify any state timeout. The timeout therefore always defaults to zero for DASL servers.

The content of the subcols parameter maps to the following `d:from` clause of `d:basicsearch`:

`<d:from>`
`<d:scope><d:href>[subcollection URL]</d:href></d:scope>`
`<d:scope><d:href>http://interlib.org/SDLIP/1.0/SID#[server sessionID]</d:href></d:scope>`
`</d:from>`

The `docPropList` parameter of the `search` method contains a list of properties to be retrieved:

`<s:propList>`
`<dc:creator/>`
`<dc:title/>`
`...`
`</s:propList>`

It is translated into the `d:select` clause:

`<d:select>`
`<d:prop>`
`<dc:creator/>`
`<dc:title/>`
`...`
`</d:prop>`
`</d:select>`

If no document properties are specified (i.e. `docPropList` is null or an empty XMLObject), the transport module assumes that all properties have to be delivered. Requests for all properties is expressed in DASL by a special tag `d:allprop` which is contained within the `d:select` clause. Thus, an empty property list maps onto the following DASL expression:

`<d:select>`
`<d:allprop/>`
`</d:select>`

If an SDLIP server receives a search request from a native DASL client, SDLIP-specific parameters are not present in the request. In this case, the `search` method of the server implementation is invoked by the server-side SDLIP/DASL transport module with the following default values (as specified in the SDLIP-Core specification):

- `clientSID: 0`
- `subcols: null (default collection of the search service)`
- `numDocs: Search.RETURN_ALL_DOCS`
- `docPropList: null (return all properties)`
- `stateTimeoutReq: Search.MAINTAIN_UNLIMITED`
- `queryOptions: null`

### 2.2 Search Result

For the DASL binding, the search results are delivered using the `DAV:multistatus` response format. The first `d:response` describes an SDLIP-specific URL and is used for delivering the `s:stateTimeout` and `s:serverSID` properties. Besides that, the sequence number of the document within the result set is included in every subsequent `d:response`. Since SDLIP delivers only properties that could be successfully retrieved, `d:status` of every document is set to "HTTP/1.1 200".

Below you see an outline of a DASL-encoded search result:

        <d:multistatus>

          <d:response>
            <d:href>http://interlib.org/SDLIP/1.0#SearchResult</d:href>
            <s:expectedTotal>...</s:expectedTotal>
            <s:stateTimeout>...</s:stateTimeout>
            <s:serverSID>...</s:serverSID>
          <d:response>

          <d:response>
            <d:href>...</d:href>
            <d:propstat>
              <d:prop>
                <dc:title>Fighting a Wind Mill</dc:title>
                <dc:creator>Don Quichote</dc:creator>
                ...
              </d:prop>
              <d:status>HTTP/1.1 200</d:status>
              <s:DID>1</s:DID>
            </d:propstat>
          <d:response>

          [<d:response>...</d:response>]*

        </d:multistatus>

The DASL-encoded search result depicted above is delivered to the SDLIP client in the `result` parameter of the `search` method after the structure is converted to the required SDLIP format:

`<s:SearchResult>`

`<s:doc>`
`<s:DID>1</s:DID>`
`<dc:title>Fighting a Wind Mill</dc:title>`
`<dc:creator>Don Quichote</dc:creator>`
`</s:doc>`
`...`
`[<s:doc>...</s:doc>]*`

`</s:SearchResult>`

The first `d:response` element in the DASL XML result structure carries SDLIP-specific protocol information. It must not contain `d:propstat`, because otherwise it would be interpreted by native DASL clients as a regular set of search result document properties. Note that a URI (within the `d:href` element of every result) is an inherent property of every searchable resource in the DASL model. In contrast, SDLIP does not require retrieved documents to have an identifier that is valid outside the context of the result set. To make DASL's document URI property available to SDLIP clients, the SDLIP/DASL transport module treats the `d:href` property in a special way. If the client requested the property in the search request, and the server that processes the request is a native DASL server, then the transport module has to extract the `d:href` property and place it into the property list returned to the SDLIP client:

`<s:SearchResult>`

`<s:doc>`
`<s:DID>1</s:DID>`
`<dc:title>Fighting a Wind Mill</dc:title>`
`<dc:creator>Don Quichote</dc:creator>`

`<d:href>...</d:href> <-- inserted by the transport module`

`</s:doc>`
`...`
`</s:SearchResult>`

An SDLIP/DASL server may generate any valid URIs for the `d:href` elements given that they are unique within the result set.

If a search result is returned by a native DASL server, the SDLIP-specific parameters are not present in the search result. In this case the SDLIP/DASL transport module delivers the following default values to the SDLIP client:

- `expectedTotal: 0`
- `stateTimeout: 0`
- `serverSID: 0`
- `serverDelegate: null`

Only those document properties are included into the `result` which have the `d:status` "HTTP/1.1 200". The sequence numbers (`s:DID`) become the ordinal numbers of the corresponding `d:response`s within the `d:multistatus` response.

If a native DASL server delivers a DASL error code 507 (Insufficient Storage) for some but not all of the requested document properties, then the overall reply is interpreted by SDLIP clients as successful. The unsuccessful properties will simply not be included in the result passed up to the SDLIP client application. Hence, SDLIP clients treat DASL replies
`HTTP/1.1 307 Multi-Status`
and
`HTTP/1.1 507 Insufficient Storage`
equally (compare Exceptions).

If the search result delivered by a native DASL server does not contain any successfully retrieved properties (i.e. with the status "HTTP/1.1 200"), the client-side SDLIP transport module raises an exception NOT_FOUND_EXC (see Exceptions).

### 2.3 Search Redirection

The semantics of SDLIP redirection differs from that of DASL. DASL requires the client to resend the original query. SDLIP assumes that the query execution starts and all subsequent invocations are performed on the delegate via the ResultAccess Interface.

#### Case 1: SDLIP server and DASL client

Since the DASL protocol does not provide functionality similar to the ResultAccess Interface, a DASL client would not be able to meaningfully interact with an SDLIP server that implements ResultAccess. A search request sent by a native DASL client does not contain a timeout request, which defaults to zero. Thus, no state will be maintained on the SDLIP server and no redirection will ever be delivered back to the client.

#### Case 2: SDLIP server and SDLIP client

If an SDLIP client specifies a positive timeout request, an SDLIP server may redirect subsequent requests. The list of delegates is packaged by the SDLIP/DASL transport module in the result set as follows:

    HTTP/1.1 207 Multi-Status
    Content-type: text/xml
    Content-length: xxxx
    ...
    <d:multistatus>

        <d:response>
            <d:href>http://interlib.org/SDLIP/1.0#SearchResult</d:href>
            <d:propstat>
              <d:prop>
                <s:expectedTotal>...</s:expectedTotal>
                <s:stateTimeout>...</s:stateTimeout>
                <s:serverSID>...</s:serverSID>
                <s:redirect>
                    <s:serverDelegate>[URL_or_IOR_1]</s:serverDelegate>
                    <s:serverDelegate>[URL_or_IOR_2]</s:serverDelegate>
                     ...
                </s:redirect>
              </d:prop>
            </d:propstat>
        <d:response>

        [<d:response>...</d:response>]*   <-- regular result documents

    </d:multistatus>

Upon receiving the above response from an SDLIP server the SDLIP client extracts the XML subtree identified by the `s:redirect` element and packs it into the SDLIP `serverDelegate` parameter of the `search` method:

`<s:redirect>`
`<s:serverDelegate>[URL_or_IOR_1]</s:serverDelegate>`
`<s:serverDelegate>[URL_or_IOR_2]</s:serverDelegate>`
`...`
`</s:redirect>`

#### Case 3: DASL server and SDLIP client

A native DASL server redirects search requests as follows:

`HTTP/1.1 400 Bad-Request`
`Content-Type: text/xml`
`Content-Length: xxxxx`
`...`
`<d:multistatus>`
`<d:response>`
`<d:href>[some URL]</d:href>`
`<d:status>HTTP/1.1 303 See Other</d:status>`
`<d:scopeerror/>`
`<d:redirectarbiter>[URL_1]</d:redirectarbiter>`
`<d:redirectarbiter>[URL_2]</d:redirectarbiter>`
`...`
`</d:response>`
`</d:multistatus>`

(Note that the HTTP response contains error code 400). On detecting such a reply, the SDLIP/DASL transport module transparently resubmits the search request to one of `[URL1]`, `[URL2]` etc. without interacting with the SDLIP client application.

## 3. Result Access Interface Mapping

This section summarizes the mappings of the methods used in the ResultAccess Interface. There are no equivalent operations in the DASL model. Consequently, a native DASL server will not respond to any of the following requests. Recall that SDLIP clients will not be tempted to make these requests to native DASL servers, because DASL servers will appear to SDLIP clients as stateless. On the other hand, stateful SDLIP servers will, of course, understand these methods.

### getSessionInfo

Request mapping:

`<s:getSessionInfo>`
`<s:serverSID>...</s:serverSID>`
`</s:getSessionInfo>`

Response mapping:

`<s:sessionInfo>`
`<s:expectedTotal>...</s:expectedTotal>`
`<s:stateTimeout>...</s:stateTimeout>`
`</s:sessionInfo>`

### getDocs

Request mapping:

`<s:getDocs>`
`<s:serverSID>...</s:serverSID>`
`<s:reqID> ...</s:reqID>`
`<s:propList>`
`<dc:title/>`
`<dc:creator/>`
`...`
`</s:propList>`
`<s:docSelection>1,3-5,7</s:docSelection>`
`</s:getDocs>`

Response mapping (see Search Result)

### extendStateTimeout

Request mapping:

`<s:extendStateTimeout>`
`<s:serverSID>...</s:serverSID>`
`<s:stateTimeoutReq>...</s:stateTimeoutReq>`
`</s:extendStateTimeout>`

Response mapping:

`<s:sessionInfo>`
`<s:stateTimeout>...</s:stateTimeout>`
`</s:sessionInfo>`

### cancelRequest

Request mapping:

`<s:cancelRequest>`
`<s:serverSID>...</s:serverSID>`
`<s:reqID>...</s:reqID>`
`</s:cancelRequest>`

Response mapping: none or exception (see Exceptions)

### removeDocs

Request mapping:

`<s:removeDocs>`
`<s:serverSID>...</s:serverSID>`
`<s:docSelection>...</s:docSelection>`
`</s:removeDocs>`

Response mapping: none or exception (see Exceptions)

## 4. Metadata Interface Mapping

This section describes the mapping of the SDLIP Metadata Interface methods. Similarly to the ResultAccess Interface, the Metadata Interface is an SDLIP-specific feature. If an SDLIP client attempts to invoke one of the following methods on a native DASL server, the latter will indicate failure with the status code 400 ("Bad Request") which raises SDLIP exception `INVALID_REQUEST_EXC` (see Exceptions).

### getVersion

Request mapping:

`<s:getVersion/>`

Response mapping (see the core document for the complete format description):

`<s:SDLIPVersion>`
`...`
`</s:SDLIPVersion>`

### getSubcollectionInfo

Request mapping:

`<s:getSubcollectionInfo/>`

Response mapping (see the core document for the complete format description):

`<s:subcolInfo>`
`...`
`</s:subcolInfo>`

### getPropertyInfo

Request mapping:

`<s:getPropertyInfo>`
`<s:subcolName>...</s:subcolName>`
`</s:getPropertyInfo>`

Response mapping (see the core document for the complete format description):

`<s:propInfo>`
`...`
`</s:propInfo>`

## 5. Exceptions

Exceptions are delivered in a format which is understandable both by DASL and SDLIP services. SDLIP servers may put additional SDLIP-specific information into DASL error messages:

`HTTP/1.1 [DASL error condition]`
`...`
`<d:multistatus>`
`<d:response>`
`<d:href>http://interlib.org/SDLIP/1.0#exception</d:href>`
`<d:propstat>`
`<d:prop>`
`<my:stackTrace>...</my:stackTrace>`
`<my:threadDump>...</my:threadDump>`
`[...any further exception properties]`
`</d:prop>`
`</d:propstat>`
`<s:exceptionCode>400</s:exceptionCode>`
`<d:responsedescription>Murphy isn't sleeping...</d:responsedescription>`
`</d:response>`
`</d:multistatus>`

The above example translates into the following SDLIP exception:

`SDLIPException {`
`getCode() -> 400`
`getDescription() -> "Murphy isn't sleeping..."`
`getProps() -> "<s:propList><my:stackTrace>...[any exception properties]"`
`}`

If the exception was raised by a native DASL service, `getDescription()` still delivers the content of `d:responsedescription;` `getProps()` defaults to `null`, and `getCode()` is derived from the DASL error code is follows:

- `400 (Bad Request) -> SDLIPException.INVALID_REQUEST_EXC`
- `422 (Unprocessable Entity) -> SDLIPException.BAD_QUERY_EXC`

Note that DASL defines only three error conditions: 400 ("Bad request"), 422 ("Unprocessable Entity"), and 507 ("Insufficient Storage"). Therefore, an SDLIP server raising SDLIP exceptions maps them to DASL error codes as follows ("`SDLIPException."` prefix omitted):

- `400 <- INVALID_REQUEST_EXC, UNAUTHORIZED_EXC, PAYMENT_REQUIRED_EXC, NOT_FOUND_EXC, INVALID_SESSIONID_EXC, MALFORMED_XML_EXC, SERVER_ERROR_EXC, NOT_IMPLEMENTED_EXC, SERVICE_UNAVAILABLE_EXC`
- `422 <- ILLEGAL_METHOD_EXC, QUERY_LANGUAGE_UNKNOWN_EXC, BAD_QUERY_EXC, INVALID_PROPERTY_EXC, INVALID_SUBCOLLECTION_EXC,`
- cannot be received by a DASL client, but is still mapped to `400: REQUEST_TIMEOUT_EXC`

The error condition 507 ("Insufficient Storage") delivered by a native DASL server is interpreted as a successful reply as long as at least one document property was successfully retrieved. Otherwise, `NOT_FOUND_EXC` is thrown.

If an SDLIP client attempts to call a method which is not implemented, the SDLIP/DASL transport module mapping should raise the `NOT_IMPLEMENTED_EXC` exception.

## References

[DASL] | Saveen Reddy, Dale Lowry, Surenda Reddy, Rick Henderson, Jim Davis, Alan Babich: DAV Searching & Locating, Internet Draft, June 3, 1999 http://www.webdav.org/dasl/protocol/draft-dasl-protocol-00.html