Welcome: The Fulfillment Project
Open Source Integrated Library System
About Fulfillment Documentation and Resources Blog Chat Mailing Lists Download

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.

What is the LAIConnector?

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.


Example settings from Config_Evergreen.pm

 $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:

Give the LAIConnector the ability to search for a single bibliographic record

$UNIVERSAL_RESOURCE_GET_SINGLE=”echo 'python my/code/lives/here/getSingleBib.py !myid!' ”;

Give the LAIConnector the ability to search for a range of bibliographic records using your python script called getRangeOBibs.py

$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.

Important Notes About Config.pm

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

Filtering the Data

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.

Taking Out The Garbage

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.

JSON Data Format For Item, Resource And Actor Objects

Item Data

Item data must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:



          '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

Resource data must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:



          '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

Actor data must be presented to the LAIConnector in the form of a JSON array of objects with the following attribute names:



          'day_phone' :undef, 
          'create_date' :'2010-03-22T13:28:26-0400', 
          'barcode' :'101010101010101', 
          'family_name' :'Test User', 
          'first_given_name' :'ImaTester', 
          'email' :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:




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.

Hold Requests

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':'User could not be authenticated'

The LAIConnector's RESTful API

The LAIConnector's API mostly conforms to the Jangle specification with a few modifications. To read more about jangle visit www.jangle.org.

Additions to the Jangle specification.

LAIConnector introduces some additional GET variables that are not currently found in the Jangle spec which extend the connector's functionality, these are:


Returns all records with an edit date before the timestamp that is provided.


Returns all records with an edit date that matches the timestamp provided


Returns all records with an edit date after the timestamp provided

Listing,Placing And Deleting Holds

Listing Holds

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

Placing Holds

To place actually place a hold on the remote system, you would use the same URI prototype but with a PUT request instead.

Deleting Holds

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.

Item Availability

The Jangle specification details how unavailable item data should be returned at http://jangle.org/drupal/connector/api/item. The LAIConnector follows this convention.

Under the hood

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.

Installing The LAIConnector

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


Documentation on installing perl modules can be found here http://www.cpan.org/modules/INSTALL.html

Getting The LAIConnector

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

Apache2 configuration

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 
        Allow from all 

<LocationMatch /connector/services/> 
    AddOutputFilter INCLUDES;XMLENT .xml 
    SetHandler perl-script 
    PerlResponseHandler LAIConnector::lib::Services 
    Options +ExecCGI 
    PerlSendHeader On 
    allow from all 

System Settings

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.

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

laiconnector.txt · Last modified: 2015/09/14 10:21 by
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Debian Driven by DokuWiki