Общее·количество·просмотров·страницы

Java Dev Notes - разработка на Java (а также на JavaScript/Python/Flex и др), факты, события из АйТи

среда, 8 июля 2009 г.

Использование callback в Java

Callback (обратный вызов) - код, который вызывается при наступлении какого-либо события. В таких языках, как С/С++ колбэк обычно реализуется с помощью указателей на функции (или методы). В Java, где нет указателей, колбэк чаще всего реализуется с помощью интерфейсов.

Рассмотрим пример: несколько потоков выполняют одинаковую работу. Когда один из потоков завершит (первым) свою работу, ему надо уведомить программу об этом. При получении уведомления о завершении потоком работы, программа останавливает другие потоки. Получение уведомления как раз сделано при помощи колбэка.

вторник, 7 июля 2009 г.

Удаление сессий в Oracle

Время от времени нам требуется создавать заново схему БД - это делается во время ночных билдов (nightly builds) в КруизКонтроле. Это, однако, невозможно, если остаются пользователи, подключенные в БД. Поэтому для создания схемы надо убить все сессии.

Приведенная ниже процедура убивает все сессии в Oracle:

CREATE OR REPLACE PROCEDURE Kill_User_Sessions(Usernames IN VARCHAR2)
AUTHID CURRENT_USER
IS
Stmt_Str VARCHAR2(200);
Sid_V VARCHAR2(30);
SerialNum_V VARCHAR2(30);
CURSOR pri IS
SELECT Sid, Serial#, Username
FROM v$session
WHERE Username IS NOT NULL
AND Username IN (Usernames)
AND Status NOT IN ('KILLED','SNIPED');
BEGIN
FOR usr IN pri
LOOP
Sid_V := usr.Sid;
SerialNum_V := Usr.Serial#;
Stmt_Str := 'ALTER SYSTEM KILL SESSION ''' || Sid_V || ',' || SerialNum_V || '''';
EXECUTE IMMEDIATE(stmt_str);
END LOOP;
END;

Она используется следующим образом:

CALL Kill_User_Sessions('username');

- где username - имя пользователя, сессии которого следует удалить.

Обратите внимание также на строчку AUTHID CURRENT_USER. Если задана опция AUTHID CURRENT_USER, то учитываются привилегии, данные через роль. Если не задана - т.е. по умолчанию DEFINER, то роли не учитываются.

четверг, 2 июля 2009 г.

Правка CruiseControl

CruiseControl - утилита для непрерывной интеграции (continouos integration) приложений. У нас в настоящее время в КруизКонтроле (КК) крутится около десятка проектов. Схема использования такова: девелоперы вносят правки в код, тестируют его на локальных машинах, затем коммитят свои изменения в SVN. На каждом проекте в КК настроен слушатель (listener) SVN, который отслеживает изменения в репозитории. После внесения изменений, делается автоматический чек-аут кода в свою область в workspace КруизКонтроля, он собирается, а собранные артефакты (JAR, WAR файлы, возможно, SQL-скрипты) публикуются в назначенном каталоге. Ход сборки можно затем посмотреть через веб-приложение Dashboard, которое поставляется в составе КК.

Все бы было хорошо, но в КК версии 2.8.2 есть одна досадная бага, осложняющая просмотр лога сборки - лог сборки показывается в браузере одной сплошной строкой, без символов новой строки (которые в HTML должны заменяться тегами <br>). Теги br в этой строке есть, но у них угловые скобки земенены на &lt; и &gt;? поэтому они не отрабатывают. В этом сообщении показано, как поправить этот баг.

Я скачал исходники КК, и провел поиск файлов, содержащих строку errors_and_warnings_element - это id div-элемента, который содержит лог ошибок. Оказалось, что эта строка содержится в классе net.sourceforge.cruisecontrol.dashboard.widgets.ErrorsAndWarningsMessagesWidget,
код которого находится в файле CC_SRC_HOME\reporting\dashboard\src\net\sourceforge\cruisecontrol\dashboard\widgets\ErrorsAndWarningsMessagesWidget.java (где каталог CC_SRC_HOME - это каталог, который содержит исходники КК). В этом файле имеется метод errorsAndWarnings(List, String), код которого приведен ниже:



private String errorsAndWarnings(List messages, String currentHtml) {
StringBuffer sb = new StringBuffer();
for (Iterator iter = messages.iterator(); iter.hasNext();) {
BuildMessage message = (BuildMessage) iter.next();
MessageLevel level = message.getLevel();
if (MessageLevel.WARN.equals(level) || MessageLevel.ERROR.equals(level)) {
sb.append(message.getMessage()).append("<br/>");
}
}
String error = StringUtils.defaultIfEmpty(sb.toString(), "No errors or warnings");
String errorsAndWarningsHtml = StringUtils.replace(ERRORS_AND_WARNINGS_HTML, "$errors",StringEscapeUtils.escapeHtml(error));
boolean hasErrorsOrWarnings = !StringUtils.isEmpty(sb.toString());
return currentHtml + makeToggleable(errorsAndWarningsHtml, "errors_and_warnings_element", hasErrorsOrWarnings);
}


Проблема заключается в вызове StringEscapeUtils.escapeHtml(error). Нетрудно догадаться по названию, что метод StringEscapeUtils.escapeHtml(String str) - заменяет специальные символы (угловые скобки, амперсанды и т.п.) в строке str на escape-последовательности. Поэтому у тегов <br> были заменены угловые скобки! Если соответствующую строчку переписать как

String errorsAndWarningsHtml = StringUtils.replace(ERRORS_AND_WARNINGS_HTML, "$errors",error);

то проблема исчезнет, и лог ошибок будет отображаться в браузере в удобочитаемом виде. После исправления, данный класс можно перекомпилировать, и положить в каталог CC_HOME\webapps\dashboard\WEB-INF\classes\net\sourceforge\cruisecontrol\dashboard\widgets - где и находятся остальные class-файлы. При компиляции к качестве classpath следует использовать JAR-файлы из каталога CC_HOME\webapps\dashboard\WEB-INF\lib.

Можно также сделать и по другому: создать класс net.sourceforge.cruisecontrol.dashboard.widgets.ErrorsAndWarningsMessagesWidgetUpdated (его содержимое - полная копия класса ErrorsAndWarningsMessagesWidget),
заменить в нем строку в методе errorsAndWarnings(List, String), как показано выше. Скомпилировать его, и сделать либо JAR-файл, который положить в CC_HOME\webapps\dashboard\WEB-INF\lib, либо class-файл выложить в каталог CC_HOME\webapps\dashboard\WEB-INF\classes\net\sourceforge\cruisecontrol\dashboard\widgets. Затем в файле dashboard-config.xml (который находится в каталоге CC_HOME), который имеет следующее содержимое:


<dashboard>
<buildloop logsdir="" artifactsdir="" />
<features allowforcebuild=""/>
<trackingtool projectname="" baseurl="" keywords=""/>
<subtabs>
<subtab class="net.sourceforge.cruisecontrol.dashboard.widgets.ErrorsAndWarningsMessagesWidget" />
</subtabs>
</dashboard>


заменить имя класса на net.sourceforge.cruisecontrol.dashboard.widgets.ErrorsAndWarningsMessagesWidgetUpdated.

И в этом случае также все будет работать - т.е. лог ошибок показываться в dashboard в удобочитаемом виде.

Пример build.xml для сборки:


<project name="ccfix" default="compile">
<path id="ccpath">
<fileset dir="d:/cc/webapps/dashboard/WEB-INF/lib">
<include name="*.jar"/>
</fileset>
<pathelement location="d:/cc/webapps/dashboard/WEB-INF/classes"/>
</path>
<target name="compile">
<javac srcdir="src" destdir="build" classpathref="ccpath"/>
</target>
</project>

Постоянные читатели