Pull to refresh

Представляем данные Lotus Domino в Oracle Database с помощью Oracle Data Cartridge Interface и Domino Java API

Reading time 6 min
Views 4.7K
Каждый из нас сталкивался с необходимостью интеграции разных систем. Я хотел бы рассказать о том, как предоставить возможность отобразить данные из базы Lotus Domino оператором SQL select в Oracle Database. Возможно, эта тема не будет интересна многим. Но, на мой взгляд, эти два коммерческих продукта заслуживают того, чтобы написать о возможностях, которые они предоставляют.

Желающие разобраться в теме могут предварительно ознакомиться с двумя документами: Example: Pipelined Table Functions: Interface Approach, часть Java Implementation of the ODCITable Methods и Java access to the Domino Objects
На их основе я создал следующий пример, целью которого является продемонстрировать принципиальную возможность использования данных из адресной книги Domino в запросах Oracle. Предполагается, что оба программных продукта установлены стандартным образом в linux, а сами файлы и действия расположены и выполняются в каталоге /home/user/java/oracle_domino. Необходимые дополнительные комментарии можно посмотреть в обоих документах.

Для начала, domino_names_odci_mem.java:
import lotus.domino.*;
import java.util.*;
import java.io.*;
import oracle.sql.*;
import java.sql.*;
import java.math.*;
import oracle.CartridgeServices.*;

import java.util.Calendar;
import java.text.SimpleDateFormat;

public class domino_StoredCtx
{
//сюда мы запишем данные, взятые из domino 
    Vector vnames;
}

//класс основывается на SQLData, это предоставит нам возможность отобразить результат в привычной форме
public class domino_names_odci_mem implements SQLData
{

    private BigDecimal key;
    
    final static BigDecimal SUCCESS = new BigDecimal(0);
    final static BigDecimal ERROR = new BigDecimal(1);
    
//методы интерфейса SQLData

    String sql_type;
    public String getSQLTypeName() throws SQLException
    {
        return sql_type;
    }
    
    public void readSQL(SQLInput stream, String typeName) throws SQLException
    {
        sql_type = typeName;
        key = stream.readBigDecimal();
    }
    
    public void writeSQL(SQLOutput stream) throws SQLException
    {
        stream.writeBigDecimal(key);
    }

//методы ODCI: ODCITableStart,ODCITableFetch,ODCITableClose (их несколько больше, чем использовано здесь)
    static public BigDecimal ODCITableStart(STRUCT[] sctx,String param)
    throws SQLException
    {
        Connection conn = DriverManager.getConnection("jdbc:default:connection:");
        
        domino_StoredCtx ctx = new domino_StoredCtx();

        StructDescriptor outDesc = StructDescriptor.createDescriptor("DOMINO_NAME", conn);
        Object[] out_attr = new Object[4];
        
//для начала вполне достаточно отобразить 10 записей
	int nrowsval = 10;
	ctx.vnames = new Vector();
	try {
//получение данных из адресной книги domino и запись в поле созданного контекста
	    lotus.domino.Session session = NotesFactory.createSession("ip_of_domino_server:DIIOP_port","user","password");
	    lotus.domino.Database db = session.getDatabase("", "names.nsf");
	    lotus.domino.View vw = db.getView("People");
	    lotus.domino.Document doc = vw.getFirstDocument();
	    while(nrowsval>0 && doc != null){
		String shortName = doc.getItemValueString("ShortName");
		String altFullName = doc.getItemValueString("AltFullName");
		lotus.domino.Name name = session.createName(altFullName);
		String commonName = name.getCommon();
		String employeeID = doc.getItemValueString("EmployeeID");
		out_attr[1-1] = (Object)new String(shortName);
		out_attr[2-1] = (Object)new String(commonName);
		out_attr[3-1] = (Object)new String(employeeID);
		out_attr[4-1] = (Object)new String(now());
		ctx.vnames.add((Object)new STRUCT(outDesc, conn, out_attr));

		nrowsval--;
		doc = vw.getNextDocument(doc);
	    }
        } catch(Exception e) {
            e.printStackTrace();
        }
    	
        int key;
        try {
//получение ключа контекста для его дальнейшего использования в ODCITableFetch
            key = ContextManager.setContext(ctx);
            } catch (CountException ce) {
            return ERROR;
        }
            
        Object[] impAttr = new Object[1];
        impAttr[0] = new BigDecimal(key);
        StructDescriptor sd = new StructDescriptor("DOMINO_NAMES_ODCI_MEM",conn);
        sctx[0] = new STRUCT(sd,conn,impAttr);

        return SUCCESS;
    }
    
    public BigDecimal ODCITableFetch(BigDecimal nrows, ARRAY[] outSet)
    throws SQLException
    {
        Connection conn = DriverManager.getConnection("jdbc:default:connection:");
        
        domino_StoredCtx ctx;
        try {
//извлечение контекста по ключу
            ctx=(domino_StoredCtx)ContextManager.getContext(key.intValue());
            } catch (InvalidKeyException ik ) {
            return ERROR;
        }
        
//метод ODCITableFetch вызывается неоднократно, для получения следующей порции данных
//т.к. пример упрощён, метод будет вызван всего 2 раза, если все данные отображены, то просто выходим
        if(ctx.vnames==null) return SUCCESS;

//иначе готовим данные для отображения
        Object out_arr[] = ctx.vnames.toArray();
        ArrayDescriptor ad = new ArrayDescriptor("DOMINO_NAMES_TABLE",conn);
        outSet[0] = new ARRAY(ad,conn,out_arr);
//сделаем так, чтобы больше порции данных не отображались        
        ctx.vnames=null;
        
        return SUCCESS;
    }
    
    public BigDecimal ODCITableClose() throws SQLException {

        domino_StoredCtx ctx;
        try {
            ctx=(domino_StoredCtx)ContextManager.clearContext(key.intValue());
            } catch (InvalidKeyException ik ) {
            return ERROR;
        }
        
        return SUCCESS;
    }

//методы для отображения дат в формате
    public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";

    public static String now() {
	Calendar cal = Calendar.getInstance();
	SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
	 return sdf.format(cal.getTime());
              
    }
    
}



Теперь shell-скрипт, который всё приготовит и отобразит.
NCSO.jar в случае стандартной инсталляции Domino можно взять из каталога /local/notesdata/domino/java

export ORACLE_SID=MYDB

#создаём аккаунт и предоставляем ему права
sqlplus '/as sysdba' <<EOF
drop user udomino cascade;
/
create user udomino identified by "pdomino";
grant connect,resource to udomino;
grant create any directory,drop any directory to udomino;
exec dbms_java.grant_permission( 'UDOMINO', 'SYS:java.net.SocketPermission', 'ip_of_domino_server:DIIOP_port', 'connect,resolve' );
EOF

#к Oracle Database не так просто поключить сторонние jar, как к Domino, где их просто можно положить в нужный каталог
#здесь их придётся загрузить в схему, т.к. Oracle требуется, чтобы всё было жёстко связано
loadjava -user udomino/pdomino -order -resolve -genmissing -verbose -resolver "((* UDOMINO) (* PUBLIC) (* -))" NCSO.jar

#подготовка необходимых типов для отображения данных и выполнения вызовов
sqlplus -S /nolog <<EOF
connect udomino/pdomino

drop type domino_names_odci_mem;                                                                                             
drop type domino_names_table;                                                                                                
drop type domino_name;                                                                                                       
drop function domino_names;                                                                                                  
drop java source domino_names_odci_mem_source;
drop directory javadir
/
create type domino_name as object
(
  shn varchar(20),
  fio varchar(256),
  tab_n varchar(20),
  dt varchar(20)
);
/
create type domino_names_table as table of domino_name;
/
create or replace directory javadir as '/home/user/java/oracle_domino';
/
create and compile java source named domino_names_odci_mem_source using bfile (javadir,'domino_names_odci_mem.java');
/
show errors

#тип для интерфейса ODCITable
create type domino_names_odci_mem as object
(
  key integer,

  static function ODCITableStart(sctx in out domino_names_odci_mem,param varchar2)
    return number
    as language java
    name 'domino_names_odci_mem.ODCITableStart(oracle.sql.STRUCT[],java.lang.String) return java.math.BigDecimal',

  member function ODCITableFetch(self in out domino_names_odci_mem, nrows in number,
                                 outSet out domino_names_table) return number
    as language java
    name 'domino_names_odci_mem.ODCITableFetch(java.math.BigDecimal, oracle.sql.ARRAY[]) return java.math.BigDecimal',

  member function ODCITableClose(self IN domino_names_odci_mem) return number
    as language java
    name 'domino_names_odci_mem.ODCITableClose() return java.math.BigDecimal'

);
/
show errors

create function domino_names(param varchar2) return domino_names_table pipelined using domino_names_odci_mem;
/
EOF

#собственно использование кода для вывода информации
export NLS_LANG=American_America.UTF8
sqlplus -S /nolog<<EOF
connect udomino/pdomino
set serveroutput on
call dbms_java.set_output(1000000);

set linesize 160                                                                                                             
set pagesize 1000                                                                                                            
set feedback off
col fio for a50                                                                                                           
col tab_n for a10                                                                                                   
col shn for a20                                                                                                   
col dt for a20                                                                                                   

select * from table(domino_names('some_string_param')) order by dt;

exit;
EOF



В результате будет выведено (в конце) примерно следующее:
SHN		     FIO			    TAB_N	DT
-------------------- ------------------------------ ---------- --------------------
user                 Фамилия Имя Отчество           12305      2011-08-25 11:55:14
....



То, что результат получен, является следствием многих действий по настройке, в частности, сервера Domino. Т.е. невозможно просто сложить файлы «куда надо» и выполнить shell-скрипт. Но, я думаю, желающим приведённые ссылки на документы и пример могут помочь добиться того, что им требуется.
Tags:
Hubs:
+3
Comments 5
Comments Comments 5

Articles