logo

2 окт. 2009 г.

BIP: блокирование управляющих элементов отчета до его завершения

Иногда приходится разрабатывать в BIP «тяжелые» отчеты, которые обрабатывают большие объемы данных, и время выполнения которых исчисляется десятками минут.

Что если такой отчет будет использоваться человеком нетерпеливым? Да еще и мало знакомым с «этой вашей системой»…


Промоделируем ситуацию:
1. Отчет благополучно найден в интерфейсе BIP.
2. Введены все необходимые параметры.
3. Нажата кнопка «Просмотр».
4. Появляется картинка с «часиками» – очевидно, что отчет «думает».
5. «Этот неприятный программист» что-то говорил вчера, что отчет выполняется минут 10-15 – можно сходить за кофе.
6. Прошло 7 минут. Кофе выпито. «Часики» с экрана пропали (они действуют лишь 2 минуты). Отчета все еще нет.
7. - Дурацкая система!!!
8. Нажму-ка я еще разок на кнопку запуска отчета!
9. …
10. И еще!!!

Во что это выливается:

1.Создадим простой отчет в BIP на основании SQL запроса к схеме SH Oracle:
select * from sales a

2. Создадим и присоединим к отчету произвольный RTF-шаблон разметки.

3. Если не настроено логгирование BIP – сделаем это.

4. Очистим директорию логов.

5. Перейдем в режим просмотра нашего отчета и нажмем на кнопку «Просмотр». Затем, выждав 3-5 секунд, снова нажнем на кнопку «Просмотр». И так еще 2 раза.


6. Троекратное нажатие приводит к появлению следующего набора файлов в лог-директории BIP.


То есть каждое нажатие кнопки просмотра (другие тоже «хороши») приводит к выделению новых ресурсов BIP-сервера на генерацию отчета. Старые незаконченные процессы генерации отчета не прерываются.

Все это печально. Особенно если у вас полностью отключено кеширование.

Предлагаю следующее решение:
1. Перейдите в каталог задеплоенного приложения xmlpserver. На моей локальной машине с WinXP и базовой установкой BIEE это c:\OracleBI\oc4j_bi\j2ee\home\applications\xmlpserver\xmlpserver
2. Создайте файл XX_runstatus.jsp с текстом

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="oracle.apps.xdo.servlet.SystemProperties" %>
<%@ page import="java.net.URLDecoder" %>
<%
out.clear();
String reportAbsPath = request.getParameter(SystemProperties.PARAM_REPORT);
if (reportAbsPath != null)
{
reportAbsPath = URLDecoder.decode(reportAbsPath.trim(), "UTF-8");
boolean cont = true;
int waitTime = 0;
int sleepInterval = 2000;
while (cont)
{
if (session.getAttribute(reportAbsPath) != null)
{
try
{
Thread.sleep(sleepInterval);
}
catch (InterruptedException e)
{
}
waitTime += sleepInterval;
if (waitTime > 1200000)
{
out.print("stopped");
cont = false;
}
}
else
{
out.print("stopped");
cont = false;
}
}
}
out.flush();
%>

3. Перейдите из текущего каталога в подкаталог xdo\jslib.
4. Сохраните исходную версию файла xdo.js (или создайте копию с расширением «.original»).


5. Внесите изменения в файл xdo.js. Изменялся файл от версии 10.1.3.4.

function XX_lockButtons()
{
var buttons = document.getElementsByTagName('BUTTON');
for (var i=0;i<buttons.length;++i)
{
var button = buttons[i];

// if (button.className == 'x7d')
{
button.disabled = true;
}
}

setTimeout("XX_runStatusCheck('/xmlpserver/XX_runstatus.jsp?_xdo="+ encodeURIComponent(document.xdoRptForm._xdo.value) + "', 0)",
2000);
}

function XX_runStatusCheck(rpath, start) {

var req = new Ajax();
req.doPost(rpath, "", function(res)
{
var buttons = document.getElementsByTagName('BUTTON');
for (var i=0;i<buttons.length;++i)
{
var button = buttons[i];
// if (button.className == 'x7d')
{
button.disabled = false;
}
}
return false;
});
return false;
}

function writeReport(ctxpath, theFormName, hideFrame) {

XX_lockButtons();

xdoCtxPath=ctxpath;
if (hideFrame) {
if (document.getElementById("xdo-message")) {
document.getElementById("xdo-message").style.display= 'none';
}
if (document.getElementById("xdo-bin-body")) {
document.getElementById("xdo-bin-body").style.display= 'none';
}
if (document.getElementById("xdo-report-body")) {
document.getElementById("xdo-report-body").style.display= 'block';
}
if (document.getElementById("xdoLoading")) {
document.getElementById("xdoLoading").style.display= 'block';
}
}
var qs = "?"+buildQueryString(theFormName);
_params = qs;
var myframe = document.getElementById('xdo-report-body');
myframe.src=ctxpath+'/formposta.html';
var theForm = document.forms[theFormName];
var rpath = ctxpath + '/runstatus.jsp?_xdo=' + encodeURIComponent(theForm._xdo.value);
setTimeout("runStatusCheck('" + rpath + "', 0)", 2000);
return false;
}

function writeBinaryReport(ctxpath, theFormName, hideFrame) {

XX_lockButtons();

xdoCtxPath=ctxpath;
if (document.getElementById("xdo-message")) {
document.getElementById("xdo-message").style.display= 'none';
}
if (document.getElementById("xdo-report-body")) {
document.getElementById("xdo-report-body").style.display= 'none';
}
var theForm = document.forms[theFormName];
if (document.getElementById("xdoLoading")) {
var fvalue = theForm._xf.value;
// if (theForm && ((!isie && (fvalue=='ppt'|| fvalue=='mhtml' || fvalue=='excel' || fvalue=='excel2000' || fvalue=='rtf')) || fvalue =='xml' || fvalue=='text' || fvalue=='data' || fvalue=='csv'))
// document.getElementById("xdoLoading").style.display= 'none';
// else
document.getElementById("xdoLoading").style.display= 'block';
}
var qs = "?"+buildQueryString(theFormName);
_params = qs;
if (document.getElementById("xdo-bin-body")) {
var myframe = document.getElementById('xdo-bin-body');
myframe.style.display= 'block';
myframe.src=ctxpath+'/formpostb.html';
}
var rpath = ctxpath + '/runstatus.jsp?_xdo=' + encodeURIComponent(theForm._xdo.value);
setTimeout("runStatusCheck('" + rpath + "', 0)", 2000);
return false;
}

function exportReport(formName, actionURL) {

XX_lockButtons();

theForm = document.forms[formName];
if (theForm) {
if (theForm._xf.value == 'analyze') {
window.alert(ANALYZER_TEMPLATE_OPERATION_NOT_SUPPORTED);
return false;
}
var qs = buildQueryString(formName);
if (qs && qs.length<1800)
{
theForm.method='GET';
}
if (theForm._xf.value == 'html') {
window.open('', 'exportwin', 'width=600,height=700,menubar=yes,toolbar=no,location=yes,directories=no,status=yes,scrollbars=yes,resizable=yes');
theForm._xpt.value='1';
theForm.target='exportwin';
theForm.action=actionURL;
theForm.submit();
} else {
theForm._xpt.value='1';
theForm.target='_self';
theForm.action=actionURL;
theForm.submit();
}
}
return false;
}


6. Очистите Кеш браузера и попробуйте теперь воспроизвести «проблему нетерпеливого пользователя».

Открытые вопросы:
1. Блокирование кнопок будет происходить до окончания формирования текущего отчета, либо до истечения 20 минут [+ 2 секунды]. Увеличить это значение можно в файле XX_runstats.jsp.
2. Не совсем верно «лочить» все кнопки. Но пока ничего дельного не придумал.

Решение грубое, так как предполагает модификацию javascript-библиотек BIP-сервера. Использовать его или нет – решать вам. Но обязательно сделайте копии исходных файлов и сохраните в укромном месте.
Также помните, что любое изменение версии BIP влечет повторное редактирование js-файлов.

P.S. Функциональность решения тестировалась в браузерах IE 6,7.

Комментариев нет:

Отправить комментарий