Chapter 9. OpenAPI Programming

Index:

  1. Extend SQL functions
  2. Create/Remove/Start/Stop Server Programmatically with/without GUI manager
  3. Customer Connection

Extend SQL functions

HXTT Cobol supports more than 230 SQL functions. Please email us if you wish to complement some new SQL functions. HXTT Cobol supports also user-defined SQL functions, and you should use only this feature to provide special SQL functions in your project.
First, you need to implement com.hxtt.sql.ExtendedFunctionInterface.

public interface ExtendedFunctionInterface {
    /**
     * Used to verify whether functionName is supported, and has a correct prarameter count.
     * @param functionName the name of function
     * @param parameters the parameter list of function,  which can be null
     * @return value
     * @throws SQLException if has an incorrect parameter number
     */
     public boolean isExtendedFunction(String functionName,Object[] parameters)throws SQLException;

    /**
     * Used to evaluate function value.
     * @param functionName the name of function
     * @param values the value list of function, which can be null
     * @return value
     * @throws SQLException if failed to calculate the function
     */
    public Object evaluate(String functionName,Object[] values)throws SQLException;

    /**
     * Used to get the SQL type of the value that is expected to be returned when evaluate() is called.
     * @param functionName
     * @return the SQL type or Types.NULL if functionName is supported
     */
    public int getType(String functionName);

    /**
     * Used to get the SQL types of the parameter values that are expected to be returned when evaluate() is called.
     * return null if function hasn't any parameter, or you wish to use the default SQL types.
     * use Types.NULL for that specific parameter if you wish to get the default SQL type.
     * @param functionName
     * @return the SQL type list or null if functionName is supported
     */
    public int[] getParameterTypes(String functionName);

    /**
     * Used to estimate the maximum number of characters that should be contained in a String returned by evaluate(String functionName,Object[] values).
     * Zero is returned if this value object does not represent Types.VARCHAR, Types.BINARY, Types.LONGVARCHAR, or Types.LONGBINARY.
     * @param functionName
     * @return maximum size
     * @throws SQLException  if functionName is supported
     */
    public int estimateValueSize(String functionName) throws SQLException;
}

Let us see a sample:

import com.hxtt.sql.ExtendedFunctionInterface;
import java.sql.SQLException;
import java.sql.Types;

/**
 * Show how to complement some sql functions.
 * This sample complements tostring(value) and random() for demo purpose
 */
public class Functions implements ExtendedFunctionInterface {
    public Functions() {
    }

    /**
     * Used to verify whether functionName is supported, and has a correct prarameter count.
     * @param functionName the name of function
     * @param parameters the parameter list of function,  which can be null
     * @return value
     * @throws SQLException if has an incorrect parameter number
     */
    public boolean isExtendedFunction(String functionName, Object[] parameters) throws SQLException {
        if (functionName.equalsIgnoreCase("tostring")) {
            if (parameters != null && parameters.length == 1) {
                return true;
            }
            else {
                throw new SQLException("Invalid parameter value in tostring function");
            }
        }
        else if (functionName.equalsIgnoreCase("random")) {
            if (parameters == null) {
                return true;
            }
            else {
                throw new SQLException("Invalid parameter value in random function");
            }
        }
        return false;
    }

    /**
     * Used to evaluate function value.
     * @param functionName the name of function
     * @param values the value list of function, which can be null
     * @return value
     * @throws SQLException if failed to calculate the function
     */
    public Object evaluate(String functionName, Object[] values) throws SQLException {
        if (functionName.equalsIgnoreCase("tostring")) {
            return values[0] + "";
        }
        else if (functionName.equalsIgnoreCase("random")) {
            return new Double(Math.random());
        }
        throw new SQLException("Inner Error:(");
    }

    /**
     * Used to get the SQL type of the value that is expected to be returned when evaluate() is called.
     * @param functionName
     * @return the SQL type or Types.NULL if functionName is supported
     */
    public int getType(String functionName) {
        if (functionName.equalsIgnoreCase("tostring")) {
            return Types.VARCHAR;
        }
        else if (functionName.equalsIgnoreCase("random")) {
            return Types.DOUBLE;
        }
        return Types.NULL;

    }

    /**
     * Used to get the SQL types of the parameter values that are expected to be returned when evaluate() is called.
     * return null if function hasn't any parameter, or you wish to use the default SQL types.
     * use Types.NULL for that specific parameter if you wish to get the default SQL type.
     * @param functionName
     * @return the SQL type list or null if functionName is supported
     */
    public int[] getParameterTypes(String functionName) {
        if (functionName.equalsIgnoreCase("tostring")) {
            return new int[] {
                Types.VARCHAR};
        }
        return null;
    }

    /**
     * Used to estimate the maximum number of characters that should be contained in a String returned by evaluate(String functionName,Object[] values).
     * Zero is returned if this value object does not represent Types.VARCHAR, Types.BINARY, Types.LONGVARCHAR, or Types.LONGBINARY.
     * @param functionName
     * @return maximum size
     * @throws SQLException  if functionName is supported
     */
    public int estimateValueSize(String functionName) throws SQLException {
        if (functionName.equalsIgnoreCase("tostring")) {
            return 20;
        }
        else if (functionName.equalsIgnoreCase("random")) {
            return 8;
        }
        return 10;

    }
}

Then you can use com.hxtt.sql.OpenAPI.registerExtendedFunction("Functions"); to regiester Functions class. Then you can use those user-defined functions in SQL. For instance, "select abs(random()),tostring(date) from test;".


Create/Remove/Start/Stop Server Programmatically

If you wish to create,remove,start a GUI server for remote connections from your application, you can call four functions of com.hxtt.sql.admin.Admin class:
public String createServer(String serverConfigName,String serverConfigURL,boolean serverAutoStart,boolean isServerLog,String serverLogFilePath) throws Exception
public void removeServer(String serverName)
public void startServer(String serverName)throws SQLException
public void stopServer(String serverName)throws SQLException

For instance:
        try {
            com.hxtt.sql.admin.Admin admin = new com.hxtt.sql.admin.Admin();

            admin.show();//It can be invisible too.
						
              String createResult = admin.createServer("test1","jdbc:cobol://192.168.1.1:1027/mnt/cobolfiles",true,true,"/tmp/test1.log");
                    			
            if (createResult!=null)
               System.out.println("Failure to create this server for " + createResult);
            			
            admin.startServer("test1");

            admin.stopServer("test1");

            admin.stopServer("test4");
            
            admin.removeServer("test1");

        }
        catch (SQLException e) {
            System.out.println(e.getMessage());
        }

On LINUX and UNIX, if you got "Cannot connect to X11 window server. The environment variable DISPLAY is not set.", you should use -Djava.awt.headless=true to run Java in headless mode. On OS/400, if you got still a java.awt.HeadlessException thrown with -Djava.awt.headless=true, you should read Run HXTT CobolServer as Windows Service or Linux(Solaris) Daemon to consider running directly com.hxtt.sql.admin.HxttService. If you wish Create/Remove/Start/Stop Server Programmatically without GUI or invisible GUI, call four same functions of com.hxtt.sql.admin.HxttService class:
public String createServer(String serverConfigName,String serverConfigURL,boolean serverAutoStart,boolean isServerLog,String serverLogFilePath) throws Exception
public void removeServer(String serverName)
public void startServer(String serverName)throws SQLException
public void stopServer(String serverName)throws SQLException

For instance:
        try {
            com.hxtt.sql.admin.HxttService admin = new com.hxtt.sql.admin.HxttService();

              String createResult = admin.createServer("test1","jdbc:cobol://192.168.1.1:1027/mnt/cobolfiles",true,true,"/tmp/test1.log");
					
                    			
            if (createResult!=null)
               System.out.println("Failure to create this server for " + createResult);
            			
            admin.startServer("test1");

            admin.stopServer("test1");

            admin.stopServer("test4");
            
            admin.removeServer("test1");

        }
        catch (SQLException e) {
            System.out.println(e.getMessage());
        }


Customer Connection

First, let us know the relation of TCP/IP connection and java.sql.Connection. java.sql.Connection objects can share TCP/IP connection. The max number of alive TCP/IP connections between one client and one server is 20, but maybe more than 1000 alive java.sql.Connection objects are using those 20 TCP/IP connections. One java.sql.Connection object maybe build 0, 1, or more than one TCP/IP connections too.
If you haven't read SSL Connection, please read.
To construct your customer connection, you need to implement two interface(com.hxtt.sql.common.SocketLayer and com.hxtt.sql.common.ServerSocketLayer). For SocketLayer, you should have one construction method( public YourSocketLayer(String host, int port)throws IOException). For ServerSocketLayer, you should have one construction method( public YourServerSocketLayer(int port, int backlog, InetAddress bindAddr) throws IOException). Then you can use:
java -Dhxtt.socketclass=yourPackage.YourServerSocketLayer -cp yourClassPath com.hxtt.sql.admin.Admin
Or
java -Dhxtt.socketclass=yourPackage.YourSocketLayer -cp yourClassPath com.hxtt.sql.admin.Admin
Or
java -Dhxtt.socketclass=yourPackage.YourServerSocketLayer -cp yourClassPath yourApplication
Or
java -Dhxtt.socketclass=yourPackage.YourSocketLayer -cp yourClassPath yourApplication
hxtt.socketclass can be used for client connection property too. The class name should be yourPackage.*Socket* and yourPackage.*ServerSocket* so that HXTT CobolServer can guess the other class name according to one class name.
com.hxtt.sql.common.SocketLayer and com.hxtt.sql.common.ServerSocketLayer are pasted below. A simple sample for ip filter, id verfication, and XOR encrypt/decrypt, is showed below too. To keep code neat, there's no remark since you can find all functions in java.net.Socket or java.net.ServerSocket. If you need help, please email us.

/******* SocketLayer.java *********/
package com.hxtt.sql.common;

import java.io.IOException;
import java.net.SocketException;
import java.net.InetAddress;

public interface SocketLayer {
    public boolean isClosed();
    public void close() throws IOException;

    public void write(byte b[], int off, int len) throws IOException;
    public void flush() throws IOException;

    public int read(byte b[], int off, int len) throws IOException;

    public int getSoTimeout() throws SocketException;
    public void setSoTimeout(int timeout) throws SocketException;

    public InetAddress getLocalAddress();
    public int getLocalPort();

    public InetAddress getInetAddress();
    public int getPort();
}

/******* ServerSocketLayer.java *********/
package com.hxtt.sql.common;

import java.net.Socket;
import java.io.IOException;
import java.net.SocketException;

public interface ServerSocketLayer{
    public boolean isClosed();
    public void close() throws IOException;

    public SocketLayer accept() throws IOException;

    public void setSoTimeout(int timeout) throws SocketException;

}

/******* XorSocketLayer.java *********/
package demo;

import java.net.Socket;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.IOException;

import java.net.SocketException;
import java.net.InetAddress;

import com.hxtt.sql.common.SocketLayer;

public class XorSocketLayer implements SocketLayer{
    private Socket socket;
    private InputStream in;
    private OutputStream out;

    public XorSocketLayer(String host, int port)throws IOException {
        Socket socket=new java.net.Socket(host, port);

        //just a check demo
        try{
            check(socket);
        }catch(IOException ioe){
            socket.close();
            throw ioe;
        }

        init(socket);
    }

    private void check(Socket socket)throws IOException{
        if(socket.getInetAddress().getHostAddress().startsWith("192.168.10")
           || socket.getInetAddress().getHostAddress().startsWith("127.0.0.1")
            ){
            socket.getOutputStream().write("1234".getBytes("ISO8859_1"));
        }else{
            throw new IOException("Prevent logon based upon IP address");
        }
    }

    protected XorSocketLayer(Socket socket)throws IOException {
        init(socket);
    }

    private void init(Socket socket)throws IOException{
        this.socket = socket;
        try{
            in = socket.getInputStream();
            out = socket.getOutputStream();
        }catch(IOException ioe){
            socket.close();
            throw ioe;
         }
    }

    public boolean isClosed() {
        //Valid for JDK1.4.X
        return socket.isClosed();
//        return false;//For older JDK1.3.X, JDK1.2.X,...
    }

    public void close() throws IOException{
        out = null;
        in = null;
        socket.close();
    }

    public void write(byte b[], int off, int len) throws IOException{
        for(int i=0;i< len;i++){
            out.write( (b[off+i] ^ pattern) & 0xFF);
        }
    }

    public void flush() throws IOException {
        out.flush();
    }

    private static final byte pattern=(byte)0x21;

    public int read(byte b[], int off, int len) throws IOException {
        int numBytes = in.read(b, off, len);

        if (numBytes <= 0)
            return numBytes;

        for (int i = 0; i < numBytes; i++) {
            b[off + i] = (byte) ( (b[off + i] ^ pattern) & 0xFF);
        }

        return numBytes;
    }

    public int getSoTimeout() throws SocketException{
        return socket.getSoTimeout();
    }

    public void setSoTimeout(int timeout) throws SocketException{
        socket.setSoTimeout(timeout);
    }

    public InetAddress getLocalAddress(){
        return socket.getLocalAddress();
    }

    public int getLocalPort(){
        return socket.getLocalPort();
    }

    public InetAddress getInetAddress(){
        return socket.getInetAddress();
    }

    public int getPort(){
        return socket.getPort();
    }

}

/******* XorServerSocketLayer.java *********/
package demo;

import java.io.*;
import java.net.*;

import com.hxtt.sql.common.SocketLayer;
import com.hxtt.sql.common.ServerSocketLayer;

public class XorServerSocketLayer implements ServerSocketLayer {
    private ServerSocket serverSocket;

    public XorServerSocketLayer(int port, int backlog, InetAddress bindAddr) throws IOException {
        this.serverSocket=new ServerSocket(port,  backlog, bindAddr);
    }

    public boolean isClosed(){
        return serverSocket.getLocalPort()<=0;
    }

    public void close() throws IOException{
        serverSocket.close();
    }

    public SocketLayer accept() throws IOException {
        Socket socket=serverSocket.accept();

         //just a check demo
        try{
            check(socket);
        }catch(IOException ioe){
            socket.close();
            throw ioe;
        }

        return new XorSocketLayer(socket);
    }

    private void check(Socket socket)throws IOException{
        if(socket.getInetAddress().getHostAddress().startsWith("192.168.10")
           || socket.getInetAddress().getHostAddress().startsWith("127.0.0.1")
            ){
            byte[] id=new byte[4];
            int count=socket.getInputStream().read(id);
            if(count!=id.length || !"1234".equals(new String(id))){
                throw new IOException("Prevent logon based upon id");
            }
        }else{
            throw new IOException("Prevent logon based upon IP address");
        }
    }

    public void setSoTimeout(int timeout) throws SocketException {
        serverSocket.setSoTimeout(timeout);
    }
}


Copyright © 1999-2012 Hongxin Technology & Trade Ltd. | All Rights Reserved. |