Каждый из нас сталкивался с необходимостью интеграции разных систем. Я хотел бы рассказать о том, как предоставить возможность отобразить данные из базы 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:
Теперь shell-скрипт, который всё приготовит и отобразит.
NCSO.jar в случае стандартной инсталляции Domino можно взять из каталога /local/notesdata/domino/java
В результате будет выведено (в конце) примерно следующее:
То, что результат получен, является следствием многих действий по настройке, в частности, сервера Domino. Т.е. невозможно просто сложить файлы «куда надо» и выполнить shell-скрипт. Но, я думаю, желающим приведённые ссылки на документы и пример могут помочь добиться того, что им требуется.
Желающие разобраться в теме могут предварительно ознакомиться с двумя документами: 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-скрипт. Но, я думаю, желающим приведённые ссылки на документы и пример могут помочь добиться того, что им требуется.