вторник, 27 февраля 2018 г.

Java + SQL = JDBC

Select1.java:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Select1 {

    private static final String url = "jdbc:oracle:thin:@172.21.10.56:1521:ora";
    private static final String user = "AZ_USER";
    private static final String password = "AZ_PSWD";

    private static Connection con;
    private static Statement stmt;
    private static ResultSet rs;

    public static void main(String args[]) {
        String query = "select count(*) from sysuser";
        try {
            con = DriverManager.getConnection(url, user, password);
            stmt = con.createStatement();
            rs = stmt.executeQuery(query);

            while (rs.next()) {
                int count = rs.getInt(1);
                System.out.println("Total number of users: " + count + ".");
            }

        } catch (SQLException sqlEx) {
            sqlEx.printStackTrace();
        } finally {
            try { con.close(); } catch(SQLException se) { /*can't do anything */ }
            try { stmt.close(); } catch(SQLException se) { /*can't do anything */ }
            try { rs.close(); } catch(SQLException se) { /*can't do anything */ }
        }
    }
}

Компиляция:
javac Select1.java
Если поместить "ojdbc6.jar" в папку .\lib\ тогда команда запуска будет выглядеть так:
java -cp .;.\lib\ojdbc6.jar Select1
или так:
java -cp .;.\lib\* Select1

понедельник, 26 февраля 2018 г.

Groovy-скрипты для АЦК. Примеры.

Само выражение groovy-скрипта дожно быть условием (при этом указывать "if" необязательно, см.примеры ниже, сам groovy-скрипт всегда возвращает только 2 значения: "true" или "false" (по-умолчанию "false"), соответственно, пункт "Подписать" либо будет показан пользователю, либо - нет):
Примеры:
1) покажет пункт "Подписать" только если пользователь открывает меню действий документа класса 197:
document.documentclass_id.value == 197L;
2) покажет пункт "Подписать" только если пользователь открывает меню действий документа классов, у которых есть поле "CONTRACTOR_ID" (например, 3, 210, 197) и это поле содержит значение "302000014441":
document.contractor_id.value == 302000014441L;
Примечание: после слова "document" можно указывать те реквизиты, что упомянуты в классе, на который ссылается "Имя серверного класса обработчика документа".

Обратная связь:
Можно проверять значения реквизитов объектов, например, скрипт "println document.documentclass_id.value" будет выводить в окно консоли СП номер класса документа, который запустил скрипт.

Можно писать целые блоки:
import java.sql.*;
// Получаем ID органиации, которая указана в поле "Принадлежность к организации" текущего пользователя:
final PreparedStatement pstmt = con.prepareStatement("select u.org_id from usersession s join sysuser u on u.id=s.sysuser_id where s.id=?");
pstmt.setLong(1, con.session.getId());
//Можно применять запрос без параметров (см.конец следующей строки):
//final PreparedStatement pstmt = con.prepareStatement("select u.org_id from usersession s join sysuser u on u.id=s.sysuser_id where s.id=" + con.session.getId());
final ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
println rs.getString("org_id");
}
//Без этой строки в потоке вывода будет появляться предупреждение: "Some statements were not closed":
pstmt.close();

Еще пример:
import java.sql.*;
// Получаем ID организации из поля "Принадлежность к организации" текущего пользователя
Long usrOrgId = 0;
final PreparedStatement pstmt_usr = con.prepareStatement("select u.org_id from usersession s join sysuser u on u.id=s.sysuser_id where s.id=?");
pstmt_usr.setLong(1, con.session.getId());
final ResultSet rs_usr = pstmt_usr.executeQuery();
while (rs_usr.next()) {
usrOrgId = rs_usr.getLong("org_id");
}
pstmt_usr.close();
// Получаем ID бюджетополучателя текущего документа
Long docRecId = 0;
final PreparedStatement pstmt_doc = con.prepareStatement("select recipient_id from conbudget where contract_id=?");
pstmt_doc.setLong(1, document.id.value);
final ResultSet rs_doc = pstmt_doc.executeQuery();
while (rs_doc.next()) {
docRecId = rs_doc.getLong("recipient_id");
}
pstmt_doc.close();
//Сравниваем:
usrOrgId == docRecId;

В логе АЦК:

В логе СП АЦК информация о документе, связанном с ним groovy-скрипте, и результате выполнения этого скрипта выводится, начиная с уровня журнализации "DEBUG", в следующем виде (данные о документе отражаются после слова "document:", содержимое скрипта - после слова "script:", результат выполнения скрипта - после слова "result:", результатом выполнения скрипта могут быть три значения: "false", "null", "true" (примечание: если в правиле указан скрипт, тогда действие "Подписать" появляется у документа только при этом значении)), см. пример:

22.07.22 12:28:26.899,ORB-726433(535),DEBUG,GroovyExecutor,Script completed for:
document: EXPASSIGNMENT: ID=2400000129811;VERSION=3;DOCUMENT_ID=2400005674113;DOCUMENTCLASS_ID=128;DISPSTATUS_ID=0;...
script: return false;
result: false

четверг, 15 февраля 2018 г.

Для поиска в логе: запуск и завершение задания планировщика

25.10.18 13:13:37.234,ORB-2218563(53),DEBUG,TransactJob,Run TransactJob XML task=
<SESSIONCLEANERTASK action="run" sch_task="1"><PARAMS/></SESSIONCLEANERTASK>
25.10.18 13:13:37.235,ORB-2218563(53),DEBUG,TransactEngineImpl,Job started ID=53
25.10.18 13:13:37.235,ORB-2218563(53),DEBUG,SchTaskInfo,Running "Session cleaner" task
...
25.10.18 13:13:37.251,TRANSACT-53,DEBUG,XML,PROCESSOR: SESSIONCLEANERTASK: Processing input XML task<SESSIONCLEANERTASK action="run">
<PARAMS/>
</SESSIONCLEANERTASK>
...
25.10.18 13:13:37.625,TRANSACT-53,DEBUG,TransactEngineImpl,Job result=
<SESSIONCLEANERTASK completed="true"/>

вторник, 13 февраля 2018 г.

list_azkports.py

Аналог "azk_dir_port_listing.bat", только на Python3.
Отступы важны!
«
#22.04.2018 18:17 IRKT (изменен)
#13.02.2018 00:32 IRKT (создан)
#d.aryshtaev@bftcom.com

#Из названия папки, которая дожна быть именована в соответствии с форматом: <Версия АЦК>_<СУБД>_<порт СП>_<произвольный текст>
#утилита извлекает значение паттерна <порт СП> и сохраняет его в переменной s_port.
#Например, из названия папки "2.43.0.166e_FB_21013_BOD_170914" извлекает "21013".

import os, time, collections, sys, webbrowser

#Инициализация списков:
ls_port=[]
ls_port_ok=[]
ls_port_bad=[]
ls_port_dupl=[]
ls_port_ix = 0
ls_port_ok_ix = 0
ls_port_bad_ix = 0
ls_port_dupl_ix = 0

#Обработка папок:
ddirs = [d for d in os.listdir('.') if os.path.isdir(d)]
for d in ddirs:
  s_port = d[d.find("_",d.find("_")+1)+1:d.find("_",d.find("_",d.find("_")+1)+1)]
  try:
    i_port = int(s_port)
    ls_port_ix = ls_port_ix + 1
    ls_port.insert(ls_port_ix, i_port)
  except ValueError:
    ls_port_bad_ix = ls_port_bad_ix + 1
    ls_port_bad.insert(ls_port_bad_ix, s_port)

#Проверка списка ls_port на наличие дублей (информация о дублях заносится в список ls_port_dupl):
for tmpvar in ls_port:
  if ls_port.count(tmpvar) > 1:
    ls_port.remove(tmpvar)
    ls_port_dupl.insert(ls_port_dupl_ix, tmpvar)

#Убираем дубли из списков
ls_port = list(set(ls_port))
ls_port_dupl = list(set(ls_port_dupl))
ls_port_bad = list(set(ls_port_bad))

#Сортировка списков:
ls_port.sort()
ls_port_bad.sort()
ls_port_dupl.sort()

#Поиск пропущенных (по порядку) портов в списке:
for tmpvar in ls_port:
  ls_port_ok_ix = ls_port_ok_ix + 1
  if ls_port.index(tmpvar) > 0:
    if (tmpvar - ls_port[ls_port.index(tmpvar)-1]) > 1:
      #Если найдены пропущенные порты, то на их место ставим пустую строку, чтобы в конечном файле их было хорошо видно, затем найденный порт и приращиваем поисковый индекс:
      ls_port_ok.insert(ls_port_ok_ix, '')
      ls_port_ok.insert(ls_port_ok_ix, tmpvar)
      ls_port_ok_ix = ls_port_ok_ix + 1
    else:
      ls_port_ok.insert(ls_port_ok_ix, tmpvar)
  else:
    ls_port_ok.insert(ls_port_ok_ix, tmpvar)
#ls_port.insert(ls_port.index(tmpvar), 0)

#Вывод списков на экран:
#print("Все порты в названии папок:\n", ls_port, "\n")
#print("Дублирующиеся порты:\n", ls_port_dupl, "\n")
#print("Некорректные порты:\n", ls_port_bad, "\n")

#Вывод списков в файл:
filename = "azkport_listing.txt"
tmpdir=os.environ['TEMP']
filepath = os.path.join(tmpdir, filename)
ss_out = sys.stdout
f = open(filepath, 'w')
sys.stdout = f
if len(ls_port_ok) > 0:
  #print("Все порты в названии папок:\n", ls_port_ok)
  for tmpvar in ls_port_ok:
    print(tmpvar)

if len(ls_port_dupl) > 0: print("\nДублирующиеся порты:\n", ls_port_dupl)
if len(ls_port_bad) > 0: print("\nНекорректные порты:\n", ls_port_bad)
sys.stdout = ss_out
f.close()

#Открыть файл в ассоциированном приложении:
webbrowser.open(filepath)

#time.sleep(10)
»

понедельник, 5 февраля 2018 г.

Resultset after last row

При поиске причины ошибки
- для Oracle: "Resultset after last row" или "Набор результатов после последней строки");
- для Firebird: "The resultSet is not in a row, use next";
необходим лог (с полным текстом ошибки, включая ее стек).
При анализе методы из стека ошибки нужно сопоставлять "по смыслу" с XML-заданиями или SQL-запросами в логе.

azk_dir_port_listing.bat

@echo off

REM date-change 2018-02-05
REM date-create 2017-10-13
REM d.aryshtaev@bftcom.com
REM Утилита предназначена для сопровожденца АЦК.
REM Она выводит на экран текстовый файл со списком портов сборок (для удобства учета портов).
REM Ее нужно поместить в папку, в которой находятся сборки АЦК.
REM При этом наименования папок сборок должны соответсвовать формату <ВерсияАЦК>_<ИдентификаторСУБД>_<ПОРТ>_<ПРОИЗВОЛЬНЫЙ ТЕКСТ>, например:
REM 2.43.2.49e_21118_OR_AZ_IRKOBL_280917
REM 2.43.2.49e_21123_OR_AZ_LENOBL_8747_181017
REM 2.43.2.66e_21107_OR_AZ_AMUROBL_8898_221017
REM 2.43.2.72e_21114_FB_USTILIMSKE_170808

set tmp_rslt_file=%TEMP%\list_ports_result.csv
set rslt_file=%TEMP%\list_ports_result.txt
if exist %tmp_rslt_file% del %tmp_rslt_file%
for /f "delims=_, tokens=3" %%a in ('dir /A:D /B') do echo %%a>>%tmp_rslt_file%
sort %tmp_rslt_file%>%rslt_file%
start %rslt_file%

Архив