
The LAIConnector provides a reusable and scalable solution for inter library communication and conforms to the Jangle specification which is a RESTful API for web service development.
This document will provide an overview of the LAIConnector, some of the benefits of its use, and how to download and install it.
The LAIConnector is a tool for facilitating the sharing of information between disparate library systems. It was created to help aid in speeding the development of custom ILS connectors with the DRY or don't repeat yourself software engineering principle in mind. It is written in Perl, meant to be highly portable and essentially sits “on top” of your existing ILS and RESTfully facilitates communication with other systems via your web server. The main feature that allows this level of portability, is the decoupling of the connector's logic from that of the underlying system.
The LAIConnector is configuration file oriented, meaning that all variable functionality or actions that are subject to change are placed in the the configuration file. This allows the majority of the software to be installed and run as is, with only the configuration file needing alteration. The example below demonstrates how Config.pm, the configuration file for the LAIConnector, can be customized.
$UNIVERSAL_ITEM_GET_SINGLE="echo 'request open-ils.cstore open-ils.cstore.json_query.atomic {\"select\": {\"acp\":[\"id\",\"edit_date\",\"create_date\",\"holdable\",\"status\"],\"acn\":[\"record\"],\"circ\": [\"due_date\",\"checkin_tim e\",\"create_time\"],\"bre\":[\"fingerprint\"]},\"from\":{\"acp\":{\"acn \": {\"join\":{\"bre\":{}}},\"circ\":{\"field\":\"target_copy\",\"type\":\"left\"}}},\"where\":{\"+acp\": {\"id\":\"!myid!\"}}}' | /openils/bin/srfsh";
$UNIVERSAL_ITEM_GET_ALL="echo 'request open-ils.cstore open-ils.cstore.json_query.atomic {\"select\":{\"acp\":[\"id\",\"edit_date\",\"create_date\",\"holdable\",\"status\"],\"acn\":[\"record\"],\"circ\":[\"due_date\",\"checkin_time\" ,\"create_time\"],\"bre\":[\"fingerprint\"]},\"from\":{\"acp\":{\"acn\":{\"join\":{\"bre\":{}}},\"circ\":{\"field\":\"target_copy\",\"type\":\"left\"}}}}' | /openils/bin/srfsh";
This probably warrants some explanation, but it's not very difficult to understand and unless you are adding functionality to the LAIConnector itself, Config.pm will be the only file that you should need to change. First off, the variables whose names begin with $UNIVERSAL are global variables for the connector and are set in Config.pm. The naming of the variables correlate to the Jangle specification's naming convention for objects and are meant to be descriptive of the actions they evoke. For example, the first variable $UNIVERSAL_ITEM_GET_SINGLE uses the bash shell command echo, to return the results of a query for a single item in an Evergreen ILS installation. The results are stored in the variable and returned to the LAIConnector when CommandClass.pm executes the command that $UNIVERSAL_ITEM_GET_SINGLE holds.
Using this technique, an implementor can run what ever method calls in what ever ILS's API written in any language to return the requested data. The only requirements are that the data be encoded in JSON and that the keys follow certain naming conventions which will be discussed later. For example, say you have a script written in Python called getSingleBib.py that returns a resource and takes as a parameter, the ID of the particular resource that you wish to search for. To give the LAIConnector access to that data, you would do the following:
$UNIVERSAL_RESOURCE_GET_SINGLE=”echo 'python my/code/lives/here/getSingleBib.py !myid!' ”;
$UNIVERSAL_RESOURCE_GET_RANGE=”echo 'python my/code/lives/here/getRangeOBibs.py !myrangestart! myrangeend!' ”;
The LAIConnector is not limited by the language the host ILS is written in. If the data can be extracted and formated in a LAIConnector readable way, it can be used. See the section titled JSON Data Format For Item, Resource And Actor Objects for examples.
The LAIConnector currently downloads with two configuration files. Evergreen_Config.pm and Demo_Config.pm. Evergreen_Config.pm is a demonstration configuration file for the Evergreen ILS. Demo_Config.pm is a template file of which you can base your Config.pm and test your installation of the LAIConnector. It will return “dummy” data when requested if the LAIConnector is installed properly. When the LAIConnector is initially installed, the Config.pm is just a renamed copy of Demo_Config.pm
You can filter the data by using the LAIConnector's special variables which are listed in Evergreen_Config.pm, the demo Evergreen configuration file that comes with the LAIConnector and “initialized” in CommandClass.pm. If you look at Figure 1, you will see that in the where clause there is a variable !myid!. CommandClass replaces this variable with the id of the item requested which is supplied by Translator.pm, which in the case of the URI /connector/items/121/ is 121.
The Config.pm MUST contain a function called commandline_data_extractor(). This can be customized to fit the needs of any particular ILS. The function's purpose is to clean up any “garbage” that is returned along with data that the LAIConnector requested. Below are examples of how the data MUST be presented to the LAIConnector.
Item data must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:
edit_date status create_date checkin_time create_time holdable fingerprint record due_date id
Example:
[ { 'edit_date' : '2011-02-03T11:14:53-0500', 'status' : 1, 'create_date' : '2010-04-07T00:00:00-0400', 'checkin_time': undef, 'create_time': '2011-02-03T11:14:53-0500', 'holdable' : 't', 'fingerprint' :'1984borman', 'record' :1949, 'due_date' : '2011-02-17T23:59:59-0500', 'id' :121 } ]
Resource data must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:
edit_date source owner tcn_value creator share_depth active create_date deleted fingerprint last_xact_id editor marc id quality tcn_source
Example:
[ { 'edit_date' : '2010-03-22T14:52:10-0400', 'source' :undef, 'owner' : undef, 'tcn_value' : '000374', 'creator' :1, 'share_depth' : undef, 'active' :'t', 'create_date' : '2010-03-22T14:52:10-0400', 'deleted' :'f', 'fingerprint' : 'anighttorememberlord', 'last_xact_id' : 'IMPORT-1269281162.4401', 'editor' :1, 'marc' : '<record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/ standards/marcxml/schema/ MARC21slim.xsd" xmlns="http://www.loc.gov/MARC 21/slim"><leader>00995cam a2200289 i 4500</leader><controlfield tag="001">000374</ controlfield><controlfield tag="005">19940530211547.7</controlfield><controlfield tag="008">760323s1976 nyua 00110 eng </controlfield><datafi eld tag="010" ind1=" " ind2=" "><subfield code="a">75005462</subfield></datafield><datafield tag="020" ind1=" " ind2=" "><subfield code="a">0030150760 :</subfield><subfield code="c">$12.95</subfield></ datafield><datafield tag="040" ind1 =" " ind2=" "><subfield code="a">(BRO)</subfield></datafield><datafield tag="050" ind1="0" ind2=" "> <subfield code="a">G530.T6</subfield><subfield code="b">L6 1976</subfield></datafield><datafield tag="082" ind1=" " ind2=" "><subfield c ode="a">910/.09/1631</subfield></datafield><datafield tag="100" ind1="1" ind2="0"><subfield code="a">Lord, Walter,</subfield><subfield code="d">1917-</subfield></datafield><datafield tag="245" ind1="1" ind2="2"><subfield code="a">A nigh t to remember /</subfield><subfield code="c">Walter Lord.</subfield></datafield><datafield tag="260" ind1=" " ind2=" "><subfield code="a">New York :</subfield><subfield code="b">Holt, Rinehart and Winston,</ subfield><subfield code="c">1976.</subfield></datafield><datafield tag="300" ind1=" " ind2=" "><subfield code="a">232 p. :</subfield><subfield code="b">ill. ;</subfield><subfield code="c">26 cm.</subfield></ datafield><datafield tag="500" ind1=" " ind2=" "><subfield code="a">Includes index.</subfield></ datafield><datafield tag="610" ind1="2" ind2="0"><subfield code="a">Titanic (Steamship).</subfield></ datafield><datafield tag="852" ind1=" " ind2=" "><subfield code="b">DECATUR</subfield></datafield><datafield tag="910" ind1=" " ind2=" "><subfield code="a">12/29/77</subfield><subfield code="b">7843</subfield><subfield code="c">14</subfield><subfield code="f">C</subfield><subfield code="l">DPL</subfield><subfield code="o">DPL</subfield><subfield code="p">8.08</subfield><subfield code="s">BT</subfield></datafield><datafield tag="910" ind1=" " ind2=" "><subfield code="a"> 9/01/95</ subfield><subfield code="b">25329</subfield><subfield code="c">14</subfield><subfield code="f">G</ subfield><subfield code="l">DPL</subfield><subfield code="o">DPL</subfield><subfield code="p">10.00</ subfield><subfield code="s">G</subfield></datafield><datafield tag="998" ind1=" " ind2=" "><subfield code="a">a6818</subfield></datafield><datafield tag="092" ind1=" " ind2=" "><subfield code="a">910.4 LOR</ subfield></datafield><datafield tag="999" ind1=" " ind2=" "><subfield code="a">910.4 LOR</subfield><subfield code="w">DEWEY</subfield><subfield code="c">1</subfield><subfield code="i">000007843</ subfield><subfield code="d">11/29/2007</subfield><subfield code="e">11/26/2007</subfield><subfield code="l">NONFICTION</subfield><subfield code="m">DECLIB</subfield><subfield code="n">14</subfield><subfield code="p">$8.08</subfield><subfield code="r">Y</subfield><subfield code="s">Y</subfield><subfield code="t">BOOK</subfield><subfield code="u">9/20/2000</subfield></datafield><datafield tag="999" ind1=" " ind2=" "><subfield code="a">910.4 LOR</subfield><subfield code="w">DEWEY</subfield><subfield code="c">2</ subfield><subfield code="i">000025329</subfield><subfield code="d">8/24/2007</subfield><subfield code="e">8/15/2007</subfield><subfield code="l">NONFICTION</subfield><subfield code="m">DECLIB</ subfield><subfield code="n">5</subfield><subfield code="p">$10.00</subfield><subfield code="r">Y</ subfield><subfield code="s">Y</subfield><subfield code="t">BOOK</subfield><subfield code="u">9/20/2000</ subfield></datafield><datafield tag="901" ind1=" " ind2=" "><subfield code="a">000374</subfield><subfield code="b">Unknown</subfield><subfield code="c">1</subfield><subfield code="t">biblio</subfield></datafield></ record>', 'id' :1, 'quality' :128, 'tcn_source' : 'Unknown' } ];
Actor data must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:
mailing_address day_phone create_date barcode family_name first_given_name email evening_phone id
Example:
[ { 'mailing_address':undef, 'day_phone' :undef, 'create_date' :'2010-03-22T13:28:26-0400', 'barcode' :'101010101010101', 'family_name' :'Test User', 'first_given_name' :'ImaTester', 'email' :undef, 'evening_phone':undef, 'id' :1 } ]
The GET_TOTAL_PAGES variable for all request types, ie Actor, Item, Resource, must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:
id_count
Example:
[ {'id_count':70116} ]
The LAIConnector expects the total number of results that are returned from a search. The calculation of the total number of pages is done internally.
Data returned from a hold request must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:
success (boolean) message
Example
[ { 'success':'false', 'message':'User could not be authenticated' } ]
The LAIConnector's API mostly conforms to the Jangle specification with a few modifications. To read more about jangle visit www.jangle.org.
LAIConnector introduces some additional GET variables that are not currently found in the Jangle spec which extend the connector's functionality, these are:
Usage:
beforeDate=[timestamp]
Description:
Returns all records with an edit date before the timestamp that is provided.
Usage:
date=[timestamp]
Description:
Returns all records with an edit date that matches the timestamp provided
Usage:
afterDate=[timestamp]
Description:
Returns all records with an edit date after the timestamp provided
You can request a list of holds on a particular resource by making a GET requests with the following URI prototype: /connector/resources/1/hold?u=myid&p=mypassword
To place actually place a hold on the remote system, you would use the same URI prototype but with a PUT request instead.
To remove a hold, use the same URI prototype but with a DELETE request instead.
The LAIConnector will perform the necessary action based upon the HTTP request type.
The Jangle specification details how unavailable item data should be returned at http://jangle.org/drupal/connector/api/item. The LAIConnector follows this convention.
The LAIConnector complies with Jangle protocol, which in turn, is based upon the Atom Publishing protocol. In order to fulfill a Jangle compliant request, the LAIConnector must first translate the request into statements of intent that will dictate the actions of the connector. Those statements or “decrees” are then passed to a factory class called EntityFactory.pm that instantiates a kind of a command class (A class that serves as a method for another class. The LAIConnector uses a variation of the command design pattern) aptly named CommandClass.pm. EntityFactory.pm will then pass all of the necessary parameters in the form of a hash to the command class's constructor. Shortly after, EntityFactory.pm instantiates an entity object, the type of which depends on the requestType variable supplied by Translator.pm.
For example, if the uri is /connector/items/121/, EntityFactory.pm will create an Item object and pass an instance of the command class to its constructor. When the entity object executes the command object's execute() method, the action specified during the translation process is carried out. In this instance, the action was to get a single item with the id of 121. The results are returned to EntityFactory.pm, which then wraps the data in additional meta data via FeedWrapper.pm which is converted it to a JSON object and transported over HTTP to the original requester.
The LAIConnector uses SSL certificates to verify the identity of connector clients and servers. User ID and password parameters are also passed to the host ILS for additional authentication.
To use the LAIConnector on your system, several steps need to be taken. First, make sure that you have all of the required prerequisites installed. Second, check out the LAIConnector from our subversion server at svn://fulfillment-ill.org/FulfILLment/trunk/Open-ILS/src/perlmods/OpenILS/Application/LAIConnector
Next, configure your Apache2 installation to use the LAIConnector modules and add the LAIConnector's directory to your perl library path. If all goes well, you should be able to point a browser to http://youserver/connector/items/121/ and get back results. The following sections will detail each step.
Apache2 web server http://www.apache.org/ mod_perl2 http://perl.apache.org (You may need to consult the mod_perl documentation if using mod_perl 1) Perl v5.10.0 (Has not been tested with any earlier versions) and the following Perl modules
Marc::Record Marc::File::XML Tie::iCal Exporter Class::Interface Text::vCard Text::vCard::Addressbook JSON::XS
Documentation on installing perl modules can be found here http://www.cpan.org/modules/INSTALL.html
The connector is still under development, but can be seen in action at https://fulfillment1.esilibrary.com/connector/add/your/uri/ and is a part of the Fulfilment project. To get the latest version of the LAIConnector, check it out from our SVN server at svn://fulfillment-ill.org/FulfILLment/trunk/Open-ILS/src/perlmods/OpenILS/Application/LAIConnector
Add these settings to your Apache2 configuration file
<LocationMatch /connector/(actors|items|resources)/*> SetHandler perl-script PerlResponseHandler LAIConnector::Connector Options +ExecCGI PerlSendHeader On allow from all <LimitExcept GET POST OPTIONS PUT DELETE> Allow from all </LimitExcept> </LocationMatch> <LocationMatch /connector/services/> AddOutputFilter INCLUDES;XMLENT .xml SetHandler perl-script PerlResponseHandler LAIConnector::lib::Services Options +ExecCGI PerlSendHeader On allow from all </LocationMatch>
You can place the LAIConnector any where on your system as long as the LAIConnector directory is in the perl include path.
When using the Bourne shell, you can do this by adding the path to the LAIConnector to the PERL5LIB environment variable.
Example
PERL5LIB=/home/path/lib:/path/to/LAIConnector; export PERL5LIB
Or you can using the perl -I command line parameter. See the perl man pages for information on how to use this command.
Or if you have administration privileges, you can install it in the standard library path
The LAIConnector is designed to help speed the development of additional connectors by providing a reusable web service that can communicate with any ILS. At the time of this writing, the LAIConnector is still under development, but can be seen in action at https://fulfillment1.esilibrary.com/connector/add/your/uri/. To subscribe to the Fulfillment general discussion list, go to http://esilibrary.com/cgi-bin/mailman/listinfo/fulfillment-general.
— [[msmith@esilibrary.com|Michael Davadrian Smith] 2011/03/11 11:11