barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

пятница, 22 апреля 2016 г.

Linux: подсчет числа потоков в приложении

Задача

Необходимо узнать, сколько потоков имеет на текущий момент то или иное запущенное приложение.

Решение
ps -eLf | grep <app_name> | wc -l
 , где <app_name> может быть именем исполняемого файла или любой другой строкой, которая может отличить интересующий процесс от других в выводе команды ps.

среда, 13 апреля 2016 г.

PostgreSQL: unrecognized configuration parameter "row_security" при восстановлении из SQL-дампа

Проблема

Сняли дамп с БД в текстовом формате, пытаемся восстановить, получаем ошибку:
ERROR: unrecognized configuration parameter "row_security"
SQL-состояние: 42704
Версия СУБД, на которую накатывался дамп, совпадает с версией СУБД, откуда он снимался.

Решение

Если посмотреть внимательно на sql-ник дампа, в начале можно заметить строки:
-- Dumped from database version 9.4.4
-- Dumped by pg_dump version 9.5.0
, говорящие о том, что дамп снимался версией pg_dump 9.5.0. Она и добавила в дамп строчку:
SET row_security = off;
, не поддерживаемую СУБД 9.4.4. Удаляем эту строчку - дамп успешно накатывается.

понедельник, 11 апреля 2016 г.

Java: подмена HTTP-заголовка, выдаваемого сервлетом / JSP-страницей

Задача

Есть некий сервлет (или JSP-страница), недоступный для модификации. Необходимо подменить один из выдаваемых сервлетом HTTP-заголоков. Например, сервлет выдает для скачивания некий файл. Необходимо подменить имя этого файла, т.е. заголовок "Content-Disposition".

Решение

Делаем jsp-страничку, которая будет служить своего рода прокси-объектом для оригинального сервлета, в ней делаем следующее:
<%
javax.servlet.http.HttpServletResponseWrapper wrappedResponse = new javax.servlet.http.HttpServletResponseWrapper(response) {
public void setHeader(String name, String value) {
if(name.equals("My-Header")) {
value = "my_value";
}
super.setHeader(name, value);
} public void addHeader(String name, String value) {
if(name.equals("My-Header")) {
value = "my_value";
}
super.addHeader(name, value);
} };
request.getRequestDispatcher("MyServlet").forward(request, wrappedResponse);
%>
Т.е. заворачиваем объект оригинального HTTP-ответа во wrapper, переопределяем методы установки заголовков, после чего выполняем forward на целевой сервлет. В итоге значение заголовка HTTP-заголовка "My-Header", генерируемого сервлетом, развернутым по относительному пути "MyServlet", будет заменено на "my_value".

среда, 6 апреля 2016 г.

Birt: объединение по вертикали ячеек таблицы

Задача

Есть таблица с данными, сгруппированными по определенному полю. Причем в рамках группы значения ячеек нескольких колонок одинаковы. В итоге таблица выглядит примерно следующим образом:
Необходимо ячейки первых двух колонок, входящие в одну группу (и содержащие одинаковые значения) объединить по вертикали.

Решение

Решение вышло несколько нетривиальным. Birt умеет убирать дублирующиеся значения к ячейках колонки (путем установки свойства "Suppress duplicates"), но он при этом не объединяет ячейки, а просто делает все ячейки под первой ячейкой с определенным значением пустыми. Это решение не подходит для случая, когда значения ячеек длинные, т.к. тогда первая строка растягивается по высоте, чего не произошло бы, будь ячейки объединены:
В итоге пришлось задействовать скрипты:
  1. На загловочную строку группы вешаем обработчик onCreate со следующим содержимым:
    reportContext.setGlobalVariable("GROUP_ROW_CNT", 0);
    Т.е. мы устанавливаем глобальную переменную GROUP_ROW_CNT в 0. Эта переменная будет счетчиком строк в рамках группы.
  2. На ячейки первого и второго столбца также вешаем обработчик onCreate:
    var curGroupRowCnt = reportContext.getGlobalVariable("GROUP_ROW_CNT");
    curGroupRowCnt++;
    reportContext.setGlobalVariable("GROUP_ROW_CNT", curGroupRowCnt);
    if(curGroupRowCnt != 1) {
    this.getStyle().display = "none";
    } else {
    this.rowSpan = 1000; // заведомо большое число, т.к. мы на данном этапе не знаем, сколько строк в группе
    }
    Т.е. мы инкрементируем счетчик строк в группе, и далее, если строка первая - устанавливаем для нее значение rowSpan, заведомо большее, чем возможное число строк в группе, а если строка не первая - то скрываем ее.
Вуаля, получаем в точности то, что хотели:

Спасибо http://birtworld.blogspot.ru/2010/10/birt-duplicate-rows.html, подтолкнул в правильном направлении.

вторник, 5 апреля 2016 г.

Birt: отладка отчета и ошибка "Failed to initialize emitter ... Access is denied"

Проблема

Пытаюсь запустить отладку birt-отчета в Birt Report Designer 4.5, получаю ошибку в логе:
апр 05, 2016 9:34:32 PM org.eclipse.birt.report.engine.api.impl.EngineTask handleFatalExceptions
SEVERE: An error happened while running the report. Cause:
org.eclipse.birt.report.engine.api.EngineException: Failed to initialize emitter.
at org.eclipse.birt.report.engine.emitter.EmitterUtil.getOuputStream(EmitterUtil.java:82)
...
Caused by: java.io.FileNotFoundException: \Myreport.rptdesign.html (Access is denied)
at java.io.FileOutputStream.open0(Native Method)
...
Работаю в Windows 7.

Решение

Зайти в конфигурацию отладки (Run -> Debug Configurations) и сменить путь в поле "Temp folder" на существующую доступную для записи директорию. Применить изменения.