barbitoff programmer`s blog

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

пятница, 10 февраля 2012 г.

Broadcast-сообщение всем пользователям Linux

Выполняется командой wall, которая умеет читать из файла:
echo "Vsem privet" > mess
wall < "mess"
Получим:
                                                                           
Broadcast Message from root@myserver                                      
        (/dev/pts/0) at 8:44 ...                                            
                                                                             
Vsem privet                                          
                                   

четверг, 9 февраля 2012 г.

Регистронезависимое сравнение строк в PostgreSQL

В MySQL для регистронезависимого сравнения строк предусмотрены caseinsensitive collations (collation`ы с "_ci" на конце). В Postgres, на сколько я знаю, collation установить невозможно, поэтому остается использовать приведение обеих сравниваемых строк к одному регистру (через lower() или upper()) или использование регистронезависимого ILIKE. Оба варианта могут привести к тому, что в запросе не будет использоваться индекс, даже если поле, по которому ведется сравнение, проиндексировано. Также отсутствие регистронезависимого сравнения приводит к тому, что UNIQUE-ограничения также регистрозависимы.
Обсуждение данной темы есть тут: http://habrahabr.ru/qa/2445/.

Автозапуск СУБД eXist под Windows

Задача:
Запускать eXist автоматически при включении сервера от имени Network Service.

Решение:
В отличие от, скажем, томката, eXist не имеет возможности инсталляции в качестве сервиса, поэтому приходится использовать другое решение, а именно, планировщик заданий:
  1. Пуск -> Все программы -> Стандартные -> Служебные -> Планировщик заданий
  2. Действие -> Создать простую задачу
  3. Ввести для задачи какое-то имя, далее выбрать "При запуске компьютера" 
  4. Выбрать "Запустить программу" и выбрать server.bat из директории /bin eXist`а. В качестве рабочей папки указать директорию /bin eXist`а.
  5. Нажать "Готово", после чего зайти в свойства только что созданной задачи (или сразу перед нажатием на "Готово" установить соотв. галочку)
  6. На вкладке "Общие" нажать кнопку "Изменить" рядом с именем пользователя, от которого производится запуск, и выбрать Network Service.
  7. На вкладке "Параметры" снять галочку "Останавливать задачу, выполняющуюся дольше", иначе винда будет убивать eXist через указанный промежуток времени, что нам вовсе не нужно.
Также нужно убедиться, что у Network Service есть права на запись в папку eXist`а.

среда, 8 февраля 2012 г.

Ошибка "NonAlpha 95" при добавлении службы Windows для Tomcat 6

Проблема:
Добавляем томкат как службу Windows:
%CATALINA_HOME%\bin\service.bat install mytomcat
В результате выполнения команды появляется не сильно информативное окно с заголовком "Application system error" и текстом "NonAlpha 95" (или другим числом вместо 95), и служба не добавляется.

Причина:
Символ "_" (его ASCII-код как раз таки и равен 95) содержится либо в %CATALINA_HOME%, либо в имени сервиса (в моем случае - это "mytomcat", и в нем точно нет "_"). Если ошибка имеет вид "NonAlpha 45" - то речь идет о символе дефиса.

Решение:
Не использовать символы "_", "-" и, возможно, другие символы, в %CATALINA_HOME% и имени сервиса. Спасибо http://drumcoder.co.uk/blog/2012/jan/10/nonalpha-95/).

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

Кодировка GET параметров в Tomcat 6

Не знаю, можно ли в томкате, как в Glassfish, настраивать кодировку параметров на уровне веб-приложения (http://barbitoff.blogspot.com/2011/07/postget-glasshfish-2.html), но на уровне всего сервера кодировка GET-параметров настраивается атрибутом URIEncoding коннектора в server.xml (http://tomcat.apache.org/tomcat-6.0-doc/config/http.html). Например, для UTF-8:
<Connector URIEncoding ="UTF-8" ... />
Много полезной информации по кодировкам в Tomcat есть тут: http://wiki.apache.org/tomcat/FAQ/CharacterEncoding.

четверг, 2 февраля 2012 г.

Использование JNDI DataSource в Spring Secutiry

При конфигурации Spring Security можно задать bean с явными настройками соединения с БД, в которой хранится информация о пользователях:
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url" value="jdbc:postgresql://localhost:5432/myuserdb"/>
<beans:property name="username" value="postgres"/>
<beans:property name="password" value="postgres"/>
</beans:bean>
<beans:bean id="userDetailsService"
 class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<beans:property name="dataSource" ref="dataSource"/>      
</beans:bean>

Однако существует возможность извлекать dataSource, используя JDNI-интерфейс:
<beans:bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
  <beans:property name="jndiName" value="java:/comp/env/jdbc/myuserdb"/>
</beans:bean>
Такой подход позволяет в качестве dataSource использовать пул соединений с БД (как настроить его, я писал ранее тут).


Быстрый старт: использование пула соединений с БД в веб-приложении, разворачиваемом на Tomcat 6

Одной из возможностей, предоставляемых контейнером сервлетов является использование пула соединений с БД, позволяющего более эффективно взаимодействовать с ней благодаря возможности повторного использования уже открытых соединений вместо создания новых.
Неплохое HOWTO по этой теме есть в документации Tomcat, ниже я приведу короткую выдержку оттуда для случая создания пула соединений к Postgres и его использования в сервлете.
1) Описываем JNDI-ресурс в context.xml веб-приложения (META-INF/context.xml, подробнее про элемент Context можно почитать тут), разместив внутри тега <Context> следующее:
<Resource name="jdbc/myDb"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="postgres"
password="postgres"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/myDB"/>

Здесь "jdbc/myDb" - это имя ресурса, по которому он будет доступен из приложения.
2) Описываем ссылку на ресурс в web.xml приложения:
<resource-ref>
<description>It`s myDb DataBase</description>
<res-ref-name>jdbc/myDb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

3) Теперь в коде сервлета мы можем получить соединение следующим образом:

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.Connection;
// ...
Context initContext = new InitialContext();
Context envContext  = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/myDb");
Connection jdbcConn = ds.getConnection();
4) Завершив работу с соединением, его можно закрыть, как обычно:
jdbcConn.close();
jdbcConn = null;
При этом запись null`а позволит Вам случайно не закрыть это соединение повторно где-нибудь в блоке finally, что очень опасно при использовании пула соединений: если первый вызов close() всего лишь сигнализирует томкату, что приложение больше не нуждается в соединении и он может отдать его другому потоку, то повторный вызов действительно закроет соединение, которое на момент этого вызова может быть уже отдано другому потоку!