The Ascert X.25 Library for Java contains a standard API for Java application to control and communicate with remote applications over X.25 connections.

See:
          Description

Packages
com.ascert.comms.driver.farsite Provides the specific driver implementation of the Java X.25 interfaces and classes for the FarSync range of X.25 cards, supplied by FarSite Communications Ltd.
com.ascert.comms.x25 Provides a standard set of interfaces and classes for Java applications to access X.25 connections.

 

The Ascert X.25 Library for Java contains a standard API for Java application to control and communicate with remote applications over X.25 connections.

The library is OSI Certified Open Source Software, and a copy of the license terms can be found here.

Overview

The library is divided into two sets of classes:

  • com.ascert.comms.x25 - contains a standard set of interfaces which applications use to access and communicate using X.25. In general, the user application can be coded against these interfaces and work with any specific X.25 card vendor's implementation.
  • com.ascert.comms.drivers.* - contains implementations of the X.25 API classes for various vendor's X.25 cards and software drivers.

    It will be advantageous to developers using this library to have at least a basic familiarity with X.25. A handy summary of various technical aspects such as packet formats, facility codes etc. is included here, reproduced by kind permission of it's author, Les Thompson (the original may be found here).

    Getting Started

    Pre-requisites

    To use the library, you will need the following:

  • a Java 1.4+ SDK or JRE
  • an installed and configured X.25 card and software drivers

    The library is supplied with driver implementations for the FarSite Communications Ltd range of X.25 cards. Note that to use these, in addition to an installed X.25 card and driver software, you must also install the Sockets API which should have been supplied with your card.

    Compiling programs with the library

    To compile programs using the library, you must ensure the library JAR is include on your classpath e.g.
            cd examples
            javac -classpath ..\lib\x25.jar Test1.java
    

    Some *very* basic example programs have been included showing basic usage of the various API methods. These were created and used during the initial development and testing of the library.

    Running programs with the library

    To run programs using the library, you must ensure the library JAR is include on your classpath, and that whatever classloader you are using can locate and load the required native libraries.

    In the simplest case, you will be using the standard system classloader, which uses a property to locate library paths e.g.

            java -cp lib\x25.jar;examples -Djava.library.path=lib Test1
    

    Batch scripts are provided to compile and run the example programs:

  • On Windows: - gotest.bat

    These can be run by typing the batch script name, followed by the example program number e.g.

            gotest 1
    

    Note, however, that some Java environments (e.g. J2EE, OSGi etc.) use custom classloaders that have different strategies for locating classes and native libraries. In these cases it will be necessary to ensure that the JAR file and native libraries are installed in appropriate directories, and the necessary configuration options are set to ensure correct loading.

    Further information on the native libraries provided, can be found in the vendor specific driver class documentation:

  • FarSync driver: see X25FactoryImpl

    Writing applications using the library

    Initialisation

    One of the first challenges in creating an API which supports multiple implementations is providing a means for object creation which does not force the application programmer to hard-code which implementation will be used. A common, and powerful approach to this is the use of Factory classes, which allow dynamic configuration of the specific implementation to be used. This is the approach taken in the Ascert X.25 Library for Java.

    Developer's create an X25SocketFactory instance, which is then used to construct and configure X25Socket objects to perform X.25 communications. The following code snippet is an example of this:

            ...
            // create an X.25 socket
            X25SocketFactory = new X25SocketFactory(null);
            X25Socket sock = factory.getSocket();
            ... IOException should be caught and handled...
    
    The X25SocketFactory can take an optional implementation class in it's constructor, which will force the factory to use a specific driver implementation. Typically though, a developer will want to leave this for selection at runtime to allow their applications to work with any implementation. If no implementation class is provided the default factory will be used, which can be specified by setting the System property com.ascert.comms.driver.farsite.X25FactoryImpl to the fully qualified classname of the X25Factory implementation class.

    Making connections

    Establishing X.25 calls is similar in concept to using TCP/IP sockets. An application can choose to either initiate a call to a remote party (connect), or wait for calls from a remote party (accept). On a single socket these operations are mutually exclusive, although an application can create multiple sockets, some of which make outgoing calls, and some of which receive incoming calls.

    Outgoing calls can be made as follows:

            ...
            // create socket to make a call to NUA 23420000222201
            X25Socket sock = factory.getClientSocket("23420000222201");
            ... sock is connected and can be used for data transfer...
            ... IOException should be caught and handled...
    
    Incoming calls can be received as follows:
            ...
            // create socket to accept calls to NUA 23420000222201
            X25Socket srv = factory.getServerSocket("23420000222201");
            X25Socket sock = srv.accept();
            ... sock is connected and can be used for data transfer...
            ... srv can now be used to accept further calls...
            ... IOException should be caught and handled...
            ...
    
    Both the examples use 'convenience' methods for creating client and server sockets with typical settings. For more detailed control, unconfigured sockets can be created using getSocket and then configured manually using the X25Socket interface.

    Sending and receiving data

    Sending and receiving data is also similar to using TCP/IP sockets albeit with one important, and subtle, distinction. X.25 is a packet based protocol as opposed to TCP/IP which is a stream based protocol. In general, what this means is that data is sent and received at the level of whole packets, and if the X.25 M-bit is used this can be extended to sending and receiving whole messages (buffer space permitting). This difference requires a slightly different approach to the conventional send and receive operations. Rather than just sending and receiving byte buffers, an X25Message object is used, allowing access to and control of both the message buffer, and message status indicators such as the M-bit and Q-bit.

    A simple example of sending data is as follows:

            ...
            String txt = "+++ This is my message to you +++";
            X25Message msg = new X25Message(txt.getBytes());
            sock.send(msg);
            ... IOException should be caught and handled...
            ...
    
    A simple example of receiving data is as follows:
            ...
            X25Message msg = new X25Message(new byte[bufsz]);
            if (sock.recv(msg) > 0)
            {
                //got some data, process it.
                String txt = new String(msg.getMsg(), 0, msg.getLen());                     
                System.out.println("Recv: " + txt);
            }
            else
            {
                //socket disconnected, close it
            }
            ... IOException should be caught and handled...
            ...
    
    Note that send and recv operations are blocking, as with the standard TCP socket calls. Multiple threads can be used to support concurrent sending and receiving of data.

    Closing connections

    When a connection is no longer needed, it can be disconnected using either the shutdown or close operation. In general, shutdown is a more 'graceful' operation, although in practice many driver implementations may treat these two as synonymous since X.25 does not strictly have a definition of a 'graceful' shutdown.

    An example of closing a connection is as follows:

            ...
            sock.shutdown()
            ... IOException should be caught and handled...
            ...
    
    Regardless of which method is used, applications should take care to close all sockets used, including server sockets prior to termination to ensure that resources are freed. One method to detect abnormal terminations and perform cleanup is to register shutdown threads using Runtime.addShutdownHook(). This is an inifintely preferably cleanup approach than using finalizers, which are not guaranteed to run on all exit scenarios, and which can seriously hamper the garbage collector if they contain possibly long running operations.

    Advanced X.25 options

    In addition to the basic operations described, the library also allows access to more advanced options:

  • Q and M-bit detection and setting (see X25Message.setMbit(boolean), X25Message.setQbit(boolean))
  • Setting and retrieval of Call User Data (see X25Socket.setCallUserData(byte[]))
  • Setting and retrieval of Call Clear cause and diagnostic codes (see X25Socket.setClearCodes(byte[]))
  • Setting and retrieval Facilities (see X25Socket.setRawFacilities(byte[]))
  • Use of PVC's (see X25Socket.connectPVC(java.lang.String))
  • Asssigning a socket to a specific physical line (see X25Socket.setPhysicalAssignment(java.lang.String))

    Building the sources

    Pre-Requisites

    The Ascert X.25 Library for Java is shipped with a pre-built JAR file of the Java classes, and with Windows and Linux native libraries supporting the FarSite Communications range of X.25 cards.

    Source code to all compiled components is also included should the user need to re-build from sources. The pre-requisites for building from source are as follows:

  • The Apache ANT build tool
  • A GCC compiler for your operating system. For Linux, it's likely that the version of GCC supplied with your Linux install will suffice. For Windows the MinGW toolkit is recommended. This is a GPL licensed C compiler, capable of creating Win32 usable DLL files such as those needed for JNI use.

    It's quite possible to use other build tools, and other C compilers. But the above are freely available, powerful, target multiple platforms, widely used, and are well supported.

    Important note for Windows users:

    There is one small change which is needed to the Java JNI header files when compiling under Windows. The include\win32\jni_md.h file needs to be modified as follows:

    	/*typedef __int64 jlong;*/
    	#ifdef __GNUC__
    	typedef long long jlong;
    	#else
    	typedef __int64 jlong;
    	#endif
    
    This is because __int64 is not a supported data type under GCC.

    Building with Ant

    An ANT build file for the library is included in /build/build.xml. This contains the following top level build targets:

  • build_win32 - to compile the Java classes, and build the native libraries for Windows.
  • build_linux- to compile the Java classes, and build the native libraries for Linux.
  • javadoc - create the javadoc documentation.
  • clean - to cleanup all compiled and built output files.

    For example, to build the library for Linux:

            cd build
            ant build_linux
            ...lot's of output, with hopefully a BUILD SUCCESSFUL at the end...
    
    Note: without some serious GCC configuration steps to support cross compilation, build targets must be performed on the target OS to which they apply.