<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Игорь Артамонов &#187; Tips</title>
	<atom:link href="http://artamonov.ru/category/tips/feed/" rel="self" type="application/rss+xml" />
	<link>http://artamonov.ru</link>
	<description>Посмотрим, глубока ли кроличья нора</description>
	<lastBuildDate>Wed, 11 Apr 2012 09:28:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Миграция БД</title>
		<link>http://artamonov.ru/2008/03/06/database-migration-tips/</link>
		<comments>http://artamonov.ru/2008/03/06/database-migration-tips/#comments</comments>
		<pubDate>Thu, 06 Mar 2008 06:32:27 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Базы данных]]></category>
		<category><![CDATA[db]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[postgres]]></category>
		<category><![CDATA[ror]]></category>
		<category><![CDATA[архитектура]]></category>
		<category><![CDATA[миграция]]></category>

		<guid isPermaLink="false">http://artamonov.ru/2008/03/06/database-migration-tips/</guid>
		<description><![CDATA[Бывает что при обновлении версии работающего приложения тратится иногда по нескольку часов на приведение структуры БД к новому виду. Ну т.е. добавление колонок, переименовывание, смена связей и пр. При этом DBA сидит и по diff двух инициализационных sql (для текущего приложения и для нового) пытается понять что менялось и как нужно прописать все эти ALTER [...]]]></description>
			<content:encoded><![CDATA[<p>Бывает что при обновлении версии работающего приложения тратится иногда по нескольку часов на приведение структуры БД к новому виду. Ну т.е. добавление колонок, переименовывание, смена связей и пр. При этом DBA сидит и по diff двух инициализационных sql (для текущего приложения и для нового) пытается понять что менялось и как нужно прописать все эти <code>ALTER TABLE ...</code>, или того хуже UPDATE по хитрым условиям. Когда то, по неопытности, и мы так делали, при этом приложение клиента ждало (т.е. не работало) иногда по нескольку часов. Слава богу у них в это время была ночь и заказчик сладко спал, иначе бы много чего могли бы наслушаться.<br />
<span id="more-63"></span><br />
Позже, на другом проекте, был подход написания sql патчей, в котором разработчик прописывал все свои изменения структуры БД. К тому же надо было не порушить текущие данные, в результате писались апдейты на несколько страниц (ну это нормально). Правда в первый раз мы все равно косячнули, т.к. пытались писать патч в одном файле, на весь релиз. Во-первых не совсем удобно всем лезть в один файл (и постоянно мержить), во-вторых он быстро разрастался, ну и в третьих все равно не всегда работал (и фиг ведь найдешь кто виноват) <img src='http://artamonov.ru/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  Последнее правда поправимо, надо лишь договориться с тем как пополнять скрипт.</p>
<p>Далее все выросло до следующего варианта: при выполнении задачи пишется <code>###.название.sql</code>, где <code>название</code>"" лишь для визуальной идентификации, а вот эти <code>###</code> для очередности выполнения скриптов. Для небольшого проекта это простой счетчик. т.е. файлы <code>001.extend_user.sql</code>, <code>002.optimize_prod_view.sql</code> и т.д. Да, и если номера совпали у двух разработчиков, то чаще всего проблемы не возникнет, если они не меняли одну область БД. Когда же проект побольше, то можно нумеровать в виде <code>yyMMdd.title.sql</code> или даже <code>yyMMdd.HHmm.title.sql</code>. Хотя в любом случае нужно разруливать на уровень выше, при планировании задач связанных с БД.</p>
<p>А запустить полученные скрипты может как ДБА, так и shell скрипт, который написать совсем не проблема. Для упрощения можно еще завести табличку version содержащую актуальный номер (тот самый, с которого начинаются наши файлы sql) и тогда процедура обновления версии вовсе станет автоматической.</p>
<p>Все это не претендует на новизну, лишь совет при планировании начальной архитектуры, почему то часто об этом забывают. Ну а вообще в <a href="http://rubyonrails.ru">RoR</a> это сразу встроено. К <a href="http://grails.org">GRails</a> есть отдельный плагин. Да и отдельно для Java есть <a href="http://www.liquibase.org/">библиотека</a> облегчающая такой процесс. Правда она добавляет свой оверхед по написанию этих апдейтов, так что тут дело вкуса. </p>
<p>PS: <a href="http://www.pgadmin.org/">pgAdmin</a> (менеджер для PostgreSQL) в данном случае очень удобен, по нажатию на любой объект, будь то таблица, колонка, индекс, вьюха или что угодно, он сбоку покажет SQL для удаления и создания этого объекта. В результате все эти alter table писать не приходится, достаточно скопировать.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2008/03/06/database-migration-tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Указываем редактируемые поля</title>
		<link>http://artamonov.ru/2008/02/21/ukazyvaem-redaktiruemye-polya/</link>
		<comments>http://artamonov.ru/2008/02/21/ukazyvaem-redaktiruemye-polya/#comments</comments>
		<pubDate>Thu, 21 Feb 2008 11:10:20 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://artamonov.ru/2008/02/21/ukazyvaem-redaktiruemye-polya/</guid>
		<description><![CDATA[При редактировании объекта через форму есть потенциальная уязвимость в системе, т.е. даже если мы в самой форме не указали внутренние поля (id, role, и пр) то хакер всегда может передать их в запросе сам. Конечно ему нужно знать какие поля есть в объекте, что бы передать для них значения, но это отнюдь нас не защищает. [...]]]></description>
			<content:encoded><![CDATA[<p>При редактировании объекта через форму есть потенциальная уязвимость в системе, т.е. даже если мы в самой форме не указали внутренние поля (id, role, и пр) то хакер всегда может передать их в запросе сам. Конечно ему нужно знать какие поля есть в объекте, что бы передать для них значения, но это отнюдь нас не защищает. Некоторые интересные поля можно найти перебором по словарю.</p>
<p>Так вот, я к тому что Spring предоставляет возможность указать какие поля позволено менять извне. И при формировании объекта, из переданных в POST значений, будут заполненны лишь определенные поля.<br />
Указывается все очень просто:</p>
<pre><code>protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
        super.initBinder(request, binder);
        binder.setAllowedFields(new String[] {"title", "content"});
}</code></pre>
<p>По хорошему, в зависимости от ролей пользователя, нужно менять список доступных для редактирования полей. Админу разрешить  менять вообще все (это по умолчанию), а остальным указать что можно.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2008/02/21/ukazyvaem-redaktiruemye-polya/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JYaml в качестве DSL</title>
		<link>http://artamonov.ru/2007/04/13/jyaml-v-kachestve-dsl/</link>
		<comments>http://artamonov.ru/2007/04/13/jyaml-v-kachestve-dsl/#comments</comments>
		<pubDate>Fri, 13 Apr 2007 07:27:15 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Мысли]]></category>
		<category><![CDATA[Новые технологии]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[dsl]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[yaml]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2007/04/13/jyaml-v-kachestve-dsl/</guid>
		<description><![CDATA[Есть вот такая вот интересная задачка: приложение должно выполнять серию команд, внешне даже однотипных и настраиваемых через разные параметры. При этом описание очереди команд должно быть не в коде, а во внешнем файле, который можно отредактировать, и, без перекомпиляции приложения, запустить очередь заново. Да и вообще файл со списком команд указывать каким то параметром приложению, [...]]]></description>
			<content:encoded><![CDATA[<p>Есть вот такая вот интересная задачка: приложение должно выполнять серию команд, внешне даже однотипных и настраиваемых через разные параметры. При этом описание очереди команд должно быть не в коде, а во внешнем файле, который можно отредактировать, и, без перекомпиляции приложения, запустить очередь заново. Да и вообще файл со списком команд указывать каким то параметром приложению, т.к. будут различные файлы с разными очередностями команд.<br />
<span id="more-57"></span><br />
Этакий файл с описание фильтров для обрабатываемой информации, который редактируют не обязательно программисты.<br />
Как варианты для реализации: придумать какой то свой формат, потом его интерпретировать. Но такой интерпретатор та еще задача, кучу времени потребует. Еще можно воспользоваться XML, из которого через Castor, к примеру, воссоздавать все наши объекты / фильтры / команды. Но вот какого объёма будет требуемый нам файл с описанием, страшно представить.<br />
Ну а так как это получается некий узкоспециализированный язык, то я вот и предложу как упростить эту задачу. Идея растет из того же XML, но в более упрощённом виде, в виде <a href="http://yaml.org">YAML</a> описания.<br />
Итак, нам, к примеру, надо следующие команды:</p>
<ul>
<li>замена в определённом поле</li>
<li>удаление по определённому регекспу</li>
<li>сортировка</li>
<li>удаление пробелов</li>
</ul>
<p>Получаем вот такой вот файлик:</p>
<pre><code>--- !replace
from: __UNKNOWN__
to: Computer
atField: author
--- !remove
regex: [^\\d]+
atFields:
  - year
  - phone
--- !sort
withComparator: !defaultComparator
  direction: desc
--- !transform
withTransformer: !trim{}</code></pre>
<p>Этакий Domain Specific Language получается. Может на первый взгляд не так все просто, но если написать небольшое описание синтаксиса нашего языка, или знакомство с документацией по yaml, все встанет на свои места, и редактирование подобного списка команд становится несложной задачей, с которой может справится продвинутый пользователь. В общем я сейчас сильно в синтаксис не буду вдаваться, кому надо глянут на <a href="http://yaml.org">yaml.org</a> и <a href="http://jyaml.sourceforge.net/">jyaml.sourceforge.net</a><br />
Второй момент как это прочитать, т.е. как построить их этого файла наши объекты. Делается все просто, через упомянутый <a href="http://jyaml.sourceforge.net/">JYaml</a>:</p>
<pre><code>List&lt;Command&gt; list = new ArrayList&lt;Command&gt;();
YamlDecoder dec = new YamlDecoder(in);
try {
    while (true) {
        Command command = (Command) dec.readObject();
        list.add(command);
    }
} catch (EOFException e) {
    log.debug("Finished reading stream.");
} finally {
    dec.close();
}</code></pre>
<p>ну и т.к. в файле мы использовали не полный имена классов, то надо настроить связь между именем и самим классом, это нужно сделать <strong>до чтения</strong> самих объектов, следующим образом:</p>
<pre><code>BiDirectionalMap&lt;String, String&gt; classes = new BiDirectionalMap&lt;String, String&gt;();
classes.put("replace", ReplaceCmd.class.getName());
classes.put("remove", RemoveCmd.class.getName());
classes.put("trim", Trim.class.getName());
classes.put("sort", SortCmd.class.getName());
classes.put("defaultComparator", DefaultComparatorCmd.class.getName());
classes.put("transform", TransformCmd.class.getName());
YamlConfig.getDefaultConfig().setTransfers(classes);</code></pre>
<p>На самом деле можно такой мини язык делать не только для списка команд, в общем то почти любой класс так можно описать и десериализовать после в объект, а текущая задача она применима к моим условиям. Правда тут возникла проблема: хотелось бы чтобы эти объекты помимо описания в этом файле имели настройки в Spring. Т.е. все связи с другими объектами настроить в Spring контексте, а саму очерёдность и дополнительные настройки брать уже из этого файла. Так вот это я не знаю как реализовать, не расширяя YamlDecoder. Хотя, т.к. jyaml проект open source&#39;ный, это тоже вполне реализуемо.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2007/04/13/jyaml-v-kachestve-dsl/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Проверка строки</title>
		<link>http://artamonov.ru/2006/04/18/proverka-stroki/</link>
		<comments>http://artamonov.ru/2006/04/18/proverka-stroki/#comments</comments>
		<pubDate>Tue, 18 Apr 2006 11:09:12 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2006/04/18/proverka-stroki/</guid>
		<description><![CDATA[Имхо вот это: if ( !StringUtils.isEmpty(value) ) { } гораздо красивее чем то, что я постоянно встречаю: if ( value != null &#38;&#38; value.length() > 0 ) { } StringUtils это из Jakarta Commons Lang. В Jakarta Commons вообще много чего интересного]]></description>
			<content:encoded><![CDATA[<p>Имхо вот это:</p>
<pre>
  if ( !StringUtils.isEmpty(value) ) {
  }
</pre>
<p>гораздо красивее чем то, что я постоянно встречаю:</p>
<pre>
  if ( value != null &amp;&amp; value.length() > 0 ) {
  }
</pre>
<p>StringUtils это из <a href="http://jakarta.apache.org/commons/lang/">Jakarta Commons Lang</a>. В <a href="http://jakarta.apache.org/commons/">Jakarta Commons</a> вообще много чего интересного <img src='http://artamonov.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2006/04/18/proverka-stroki/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Конфликт библиотек Tomcat 5.5 и JSTL</title>
		<link>http://artamonov.ru/2006/02/13/konflikt-bibliotek-tomcat-55-i-jstl/</link>
		<comments>http://artamonov.ru/2006/02/13/konflikt-bibliotek-tomcat-55-i-jstl/#comments</comments>
		<pubDate>Mon, 13 Feb 2006 14:19:38 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2006/02/13/konflikt-bibliotek-tomcat-55-i-jstl/</guid>
		<description><![CDATA[Уже раза 3 попадал на ошибку SEVERE: Servlet.service() for servlet jsp threw exception org.apache.jasper.JasperException: Unable to read TLD "META-INF/c-1_0.tld" from JAR file "file:/**/jakarta-tomcat-5.5.4/webapps/**/WEB-INF/lib/standard-tags.jar": org.apache.jasper.JasperException: Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs.standard.tlv.JstlCoreTLV Раз в полгода парюсь с час над этой ошибкой (вот как сейчас было), потом ищу в гугле и выхожу на этот пост в [...]]]></description>
			<content:encoded><![CDATA[<p>Уже раза 3 попадал на ошибку </p>
<pre><code>SEVERE: Servlet.service() for servlet jsp threw exception
org.apache.jasper.JasperException: Unable to read TLD "META-INF/c-1_0.tld" from JAR file "file:/**/jakarta-tomcat-5.5.4/webapps/**/WEB-INF/lib/standard-tags.jar": org.apache.jasper.JasperException: Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs.standard.tlv.JstlCoreTLV</code></pre>
<p>Раз в полгода парюсь с час над этой ошибкой (вот как сейчас было), потом ищу в гугле и выхожу на этот пост в блоге Ryan&#39;на Scraps&#39;а: <a href="http://ryandaigle.com/pebble/2005/01/27/1106856324774.html">Frustrating Tomcat 5.5.x Issue Solved (conflicting jars...)</a>. Там первое &laquo;спасибо&raquo; и то мое <img src='http://artamonov.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
В общем ошибка в том что не надо складывать <code>jsp-api.jar</code> <code>servlet-api.jar</code> со своим Web-приложением. И ведь помню, что надо запрещать складывание в WAR этих библиотек, но всеже иногда проскакивают.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2006/02/13/konflikt-bibliotek-tomcat-55-i-jstl/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Русские буквы в Django</title>
		<link>http://artamonov.ru/2006/02/07/russkie-bukvyi-v-django/</link>
		<comments>http://artamonov.ru/2006/02/07/russkie-bukvyi-v-django/#comments</comments>
		<pubDate>Tue, 07 Feb 2006 18:38:03 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2006/02/07/russkie-bukvyi-v-django/</guid>
		<description><![CDATA[Привыкнув к Java, с её идеей о том что все строки всегда хранятся в Unicode, я сильно парюсь в Python. Гдето чтото не так написал, или не сконвертировал из нужной кодировки в другую нужную, и все, и все полетело Вот тут, в Django, например, чтобы заменить регекспом строку на русском, надо делать так: #-*- coding: [...]]]></description>
			<content:encoded><![CDATA[<p>Привыкнув к Java, с её идеей о том что все строки всегда хранятся в Unicode, я сильно парюсь в Python.</p>
<p>Гдето чтото не так написал, или не сконвертировал из нужной кодировки в другую нужную, и все, и все полетело <img src='http://artamonov.ru/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  Вот тут, в Django, например, чтобы заменить регекспом строку на русском, надо делать так:</p>
<pre><code>#-*- coding: cp1251 -*-
import re
instr = unicode(req.POST['param'], 'utf-8')
pat = re.compile(u'этоубрать', re.U)
instr = re.sub(pat, '_', instr)</code></pre>
<p>а при выплевывании на страницу надо так</p>
<pre><code>messages.append(unicode('Наше сообщение', 'cp1251').encode('utf-8'))</code></pre>
<p>А я все то там, то тут пропускаю, то unicode () то encode () не в том месте, а они все поочереди идут, на выходе непонятно что получается <img src='http://artamonov.ru/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  Теперь разобрался вроде.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2006/02/07/russkie-bukvyi-v-django/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>MessageResourceBundle в Spring</title>
		<link>http://artamonov.ru/2006/02/02/messageresourcebundle-v-spring/</link>
		<comments>http://artamonov.ru/2006/02/02/messageresourcebundle-v-spring/#comments</comments>
		<pubDate>Thu, 02 Feb 2006 12:08:45 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2006/02/02/messageresourcebundle-v-spring/</guid>
		<description><![CDATA[Когда пишешь resource bundle для Web-приложения часто мешает: что для обновления текста на страницах нужно перегружать приложение надо конвертить текст написанный по русски в Unicode. Т.е. дергаем всякие native2ascii или Ant&#39;ом пересобираем и перезапускам приложение. А в Spring Framework есть замечательный класс ReloadableResourceBundleMessageSource, который решает все эти проблемы. Пишем в spring.xml: &#60;bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"&#62; &#60;property [...]]]></description>
			<content:encoded><![CDATA[<p>Когда пишешь resource bundle для Web-приложения часто мешает:</p>
<ul>
<li>что для обновления текста на страницах нужно перегружать приложение</li>
<li>надо конвертить текст написанный по русски в Unicode.</li>
</ul>
<p>Т.е. дергаем всякие native2ascii или Ant&#39;ом пересобираем и перезапускам приложение.<br />
А в <a href="http://www.springframework.org/">Spring Framework</a> есть замечательный класс <code>ReloadableResourceBundleMessageSource</code>, который решает все эти проблемы.</p>
<p><span id="more-13"></span></p>
<p>Пишем в spring.xml:</p>
<pre><code>&lt;bean id="messageSource"
          class="org.springframework.context.support.ReloadableResourceBundleMessageSource"&gt;
        &lt;property name="basenames"&gt;
            &lt;list&gt;
                &lt;value&gt;/WEB-INF/messages/messages&lt;/value&gt;
            &lt;/list&gt;
        &lt;/property&gt;
        &lt;property name="useCodeAsDefaultMessage" value="true"/&gt;
        &lt;property name="defaultEncoding" value="Windows-1251"/&gt;
        &lt;property name="cacheSeconds" value="5"/&gt;
    &lt;/bean&gt;</code></pre>
<p>Теперь Spring читает файлики <code>/WEB-INF/messages/messages.properties</code>, <code>/WEB-INF/messages/messages_ru.properties</code> и т.д. Если к моменту запроса они обновились, то перечитывает заново. И к томуже читает в указанной кодировке, что избавляет нас от запуска всяких лишних программ.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2006/02/02/messageresourcebundle-v-spring/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Аппендер для Log4J</title>
		<link>http://artamonov.ru/2006/01/27/appender-dlya-log4j/</link>
		<comments>http://artamonov.ru/2006/01/27/appender-dlya-log4j/#comments</comments>
		<pubDate>Fri, 27 Jan 2006 12:33:12 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2006/01/27/appender-dlya-log4j/</guid>
		<description><![CDATA[Я неоднократно натыкался на различные обертки для Log4J. Иногда это мотивировалось тем что вдруг мы решим использовать другой логгер или нужно &#171;чтото свое&#187; В первом случае можно взять Jakarta Commons Logging который говорят и является оберткой поверх логгеров. Хотя по мне так вероятность замены логгера очень близка к нули и это лишь трата времени и [...]]]></description>
			<content:encoded><![CDATA[<p>Я неоднократно натыкался на различные обертки для Log4J. Иногда это мотивировалось тем что вдруг мы решим использовать другой логгер или нужно &laquo;чтото свое&raquo;</p>
<p>В первом случае можно взять Jakarta Commons Logging который говорят и является оберткой поверх логгеров. Хотя по мне так вероятность замены логгера очень близка к нули и это лишь трата времени и забивание головы лишними мыслями &laquo;а вдруг?&raquo;.</p>
<p>Во втором это совсем не причина отказа, т.к. Log4J прекрасно меняется под наши условия, нужно только доки прочитать повнимателней. Можно написать свой appender  который куда угодно запишет.<br />
<span id="more-12"></span><br />
Вот, например, могу показать как писать лог в базу. Хотя подобный аппендер есть в стандартной поставке, но он stack-trace не пишет. Попробуем это исправить:</p>
<pre><code>public class DBLogAppender extends AppenderSkeleton {

    private String SQL = "insert into logs(time, location, message, trace, level) " +
            " values(?, ?, ?, ?, ?)";

    protected synchronized void append(LoggingEvent loggingEvent) {
        Connection conn = null;
        try {
            conn = getConnection();
            PreparedStatement query = conn.prepareStatement(SQL);
            query.setTimestamp(1, new Timestamp(loggingEvent.timeStamp));
            StringBuilder buf = new StringBuilder();
            //делаем удобочитаемую строчку для нахождения где у нас собсно вывалилось
            buf.append(loggingEvent.getLocationInformation().getClassName());
            buf.append(" ");
            buf.append(loggingEvent.getLocationInformation().getFileName());
            buf.append(":");
            buf.append(loggingEvent.getLocationInformation().getLineNumber());

            query.setString(2, buf.toString());

            query.setString(3, loggingEvent.getMessage().toString());

            //Делаем stack-trace
            if ( loggingEvent.getThrowableStrRep() != null
                 &#038;& loggingEvent.getThrowableStrRep().length &gt; 0) {

                buf = new StringBuilder();
                for ( String line : loggingEvent.getThrowableStrRep() ) {
                    buf.append(line);
                    buf.append("\n");
                }

                query.setString(4, buf.toString());
            } else {
                query.setString(4, null);
            }

            query.setInt(5, loggingEvent.getLevel().toInt());

            query.executeUpdate();
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean requiresLayout() {
        return false;
    }

    public void close() {
        try {
            getConnection().close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p>метод getConnection () написать думаю будет несложно.</p>
<p>а потом в <code>log4j.properties</code> дописываем чтото типа того:</p>
<pre><code>log4j.appender.db=com.mycompany.project.DBLogAppender
log4j.appender.db.url=jdbc:postgresql://localhost/mydatabase
log4j.appender.db.driver=org.postgresql.Driver
log4j.appender.db.user=loguser
log4j.appender.db.password=pasword</code></pre>
<p>да, в саммом классе я не показал сеттеры и геттеры для url, driver, user и password, чтобы не загромождать пост. В общем таким вот образом можно передать параметры в класс, как String а дальше использовать, как в нашем случае для настройки коннекшена к базе.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2006/01/27/appender-dlya-log4j/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Tomcat и кодировка GET запроса</title>
		<link>http://artamonov.ru/2006/01/18/tomcat-i-kodirovka-get-zaprosa/</link>
		<comments>http://artamonov.ru/2006/01/18/tomcat-i-kodirovka-get-zaprosa/#comments</comments>
		<pubDate>Wed, 18 Jan 2006 09:06:49 +0000</pubDate>
		<dc:creator>splix</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.artamonov.ru/2006/01/18/tomcat-i-kodirovka-get-zaprosa/</guid>
		<description><![CDATA[При написании Web-приложения на Java под Tomcat у меня, и судя по IRC, у многих других возникала проблема по раскодированию того что нам приходит в GET запросе. Например на сайте может быть формочка поиска, которую принято отправлять GETом. А принимающий сервлет/контроллер получает какуюто чушь. Вроде приложение выдает UTF-8, принимает POST как UTF-8, а в GET [...]]]></description>
			<content:encoded><![CDATA[<p>При написании Web-приложения на Java под Tomcat у меня, и судя по IRC, у многих других возникала проблема по раскодированию того что нам приходит в GET запросе. Например на сайте может быть формочка поиска, которую принято отправлять GETом. А принимающий сервлет/контроллер получает какуюто чушь. Вроде приложение выдает UTF-8, принимает POST как UTF-8, а в GET чтото не то.</p>
<p>А решение на самом деле простое: прописать в <code>server.xml</code>, для нужного connector&#39;а аттрибут <code>URIEncoding="UTF-8"</code>, иначе он думает что там ISO-8859-1 и мы получаем совсем не то.</p>
]]></content:encoded>
			<wfw:commentRss>http://artamonov.ru/2006/01/18/tomcat-i-kodirovka-get-zaprosa/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

