Ceridwen 3M SIP Circulation Library for Java

3M SIP is an industry standard protocol by 3M to allow automatec check out terminals communicate with library systems.

The Ceridwen 3M SIP Circulation Library for Java is an Open Source (GPL v3) implementation of the 3M SIP version 2 protocol (also known as SIP2). It includes both client and server implementations and support both telnet and socket based communications. 

Download 

The current 3M SIP v2 protocol library can be downloaded here:

The very latest unstable build can be downloaded from here.  

Earlier versions of the 3M SIP2 protocol library are also available:

The java source code to the client is available under an open source license (GPL V3) from a subversion repository, and may be used by developers of other applications which require 3M SIP connectivity.The repository contains source code for the SelfIssue client as well as the standalone 3M SIP Java library.

Problems and Issues

For general problems please contact development@ceridwen.com. For bugs and feature requests, please use our online issue tracker

License

The Ceridwen Self Issue Client is available as open source under GPL v3. Contact development@ceridwen.com for other licensing options.

Sample Application 

The following hava code demonstrates the use of the library. It starts up a simple server implementation, and then uses the client API to check out a book.

public class Sample {
    static SocketDaemon thread;

    public static void startServer() {
        /**
         * Run simple socket server
         */

        Sample.thread = new SocketDaemon("localhost", 12345, new MessageHandlerDummyImpl());
        Sample.thread.setStrictChecksumChecking(true);
        Sample.thread.start();
    }

    public static void checkOut() {
        /**
         * Now try basic client commands
         */
        Connection connection;
        Message request, response;

        connection = new SocketConnection();
        ((SocketConnection) connection).setHost("localhost");
        ((SocketConnection) connection).setPort(12345);
        ((SocketConnection) connection).setConnectionTimeout(30000);
        ((SocketConnection) connection).setIdleTimeout(30000);
        ((SocketConnection) connection).setRetryAttempts(2);
        ((SocketConnection) connection).setRetryWait(500);

        try {
            connection.connect();
        } catch (Exception e1) {
            e1.printStackTrace();
            return;
        }

        /**
         * It is necessary to send a SC Status with protocol version 2.0 else
         * server will assume 1.0)
         */

        request = new SCStatus();
        ((SCStatus) request).setProtocolVersion(ProtocolVersion.VERSION_2_00);

        try {
            response = connection.send(request);
        } catch (RetriesExceeded e) {
            e.printStackTrace();
            return;
        } catch (ConnectionFailure e) {
            e.printStackTrace();
            return;
        } catch (MessageNotUnderstood e) {
            e.printStackTrace();
            return;
        } catch (ChecksumError e) {
            e.printStackTrace();
            return;
        } catch (SequenceError e) {
            e.printStackTrace();
            return;
        } catch (MandatoryFieldOmitted e) {
            e.printStackTrace();
            return;
        } catch (InvalidFieldLength e) {
            e.printStackTrace();
            return;
        }

        if (!(response instanceof ACSStatus)) {
            System.err.println("Error - Status Request did not return valid response from server.");
            return;
        }

        /**
         * For debugging XML handling code (but could be useful in Cocoon)
         */
        response.xmlEncode(System.out);

        /**
         * Check if the server can support checkout
         */
        if (!((ACSStatus) response).getSupportedMessages().isSet(SupportedMessages.CHECK_OUT)) {
            System.out.println("Check out not supported");
            return;
        }

        request = new CheckOut();

        /**
         * The code below would be the normal way of creating the request
         */

        ((CheckOut) request).setPatronIdentifier("2000000");
        ((CheckOut) request).setItemIdentifier("300000000");
        ((CheckOut) request).setSCRenewalPolicy(Boolean.TRUE);
        ((CheckOut) request).setTransactionDate(new Date());

        try {
            response = connection.send(request);
        } catch (RetriesExceeded e) {
            e.printStackTrace();
            return;
        } catch (ConnectionFailure e) {
            e.printStackTrace();
            return;
        } catch (MessageNotUnderstood e) {
            e.printStackTrace();
            return;
        } catch (ChecksumError e) {
            e.printStackTrace();
            return;
        } catch (SequenceError e) {
            e.printStackTrace();
            return;
        } catch (MandatoryFieldOmitted e) {
            e.printStackTrace();
            return;
        } catch (InvalidFieldLength e) {
            e.printStackTrace();
            return;
        }

        if (!(response instanceof CheckOutResponse)) {
            System.err.println("Error - CheckOut Request did not return valid response from server");
            return;
        }
        response.xmlEncode(System.out);

        // System.out.println(((PatronInformationResponse)response).getPersonalName());
        // System.out.println(((PatronInformationResponse)response).getEMailAddress());

        connection.disconnect();
    }

    public static void stopServer() {
        /**
         * Stop simple socket server
         */

        Sample.thread.shutdown();
    }

    public static void main(String[] args) {
        Sample.startServer();
        Sample.checkOut();
        Sample.stopServer();

    }
}