среда, 2 марта 2011 г.

Smooks: парсим xml с помощью ... xml

Smooks - отличный инструмент, который решает задачу парсинга xml используя xml-маппинг тэгов и аттрибутов на объекты и их свойства. Вообще продукт позиционируется как инструмент для трансформации, биндинга, валидации и обработки данных в различных форматах (CSV, XML, EDI). Я рассматриваю этот продукт как достойную альтернативу других механизмов парсинга xml - JAXB, JAXP, Digester и пр.

Предположим нам надо распарсить такой вот xml:

Xml необходимо распарсить в List из объектов типа PlayerRole:

Для начала создадим xml-маппинг необходимый для преобразования данных в объекты:

В Smooks все метаданные, необходимые для парсинга участков xml, представляются в виде бинов с сылками друг на друга. Адресация в xml осуществляется с помощью xpath-выражений. Если при парсинге необходима какая-то пост-обработка данных можно воспользоваться возможностью выполнения groovy-скриптов (тэг g:groovy), при этом код работы с xml будет более лаконичн чем на java. Из groovy также возможны обращение к бинам smooks.

Ну и наконец пример запуска механизма парсинга данных с приведенным конфигом:

Чтобы получить результат парсинга надо выбрать бин, обрабатывающий root-овый тэг, в нашем случае это бин с id="roles-bean".

Я выбраю этот движок для разбора xml т.к. он почти не требует кода и интегрирован с groovy. Использую его когда в проекте требуется распарсить различные конфигурационные ресурсы на этапе запуска сервера.

пятница, 14 января 2011 г.

Использование Javassist для генерации прокси в Spring Framework

Известно, что проект cglib давно находится в заброшенном состоянии, также при работе с ним возникают некоторые проблемы, описанные здесь. Наиболее популярная альтернатива этому проекту - javassist. Он используется в таких проектах как JBoss AS, Hibernate, Weld ...

Только вот в Spring он еще не появился. Замена библиотеки cglib, используемой для генерации proxy-объектов, на javassist, судя по плану проекта, состоится в версии 3.1 проекта. Вот jira-таск. В этом же таске я прикрепил аттачи в виде трех классов и пары патчей, которые позволяют окончательно перейти на Javassist.

Для включения поддержки Javassist вам понадобится пристроить к себе в проект вот эти три класса - JavassistAopProxy, JavassistAopProxyFactory и JavassistApplicationContext. Затем вместо spring-овой реализации ApplicationContext-а задействовать org.springframework.aop.framework.JavassistApplicationContext. Если вы не создаете его напрямую, а используете org.springframework.web.context.ContextLoaderListener сконфигурированный в web.xml, то вам необоходимо будет добавить в этот же web.xml такие строки:

суббота, 6 ноября 2010 г.

"Хорошая" новость от Oracle...

Хотя это событие было предсказуемо, после коммерциализации MySQL и OpenOffice, верить в него не хотелось. Похоже oracle хочет разделить версии JVM на "free" и "premium", подробнее тут.

среда, 3 ноября 2010 г.

Поиск по ключу входящему в числовой диапазон.

Дана таблица по которой, в зависимости от опыта игрока, определяется его уровень:

  Диапазон опыта     Уровень

0 < exp <= 12 1
12 < exp <= 30 2
30 < exp <= 67 3
... ...
231 < exp <= 300 10

Задача: реализовать алгоритм поиска уровня.

Для решения задачи я задействую класс java.util.TreeMap. Почему этот класс? Все просто, он реализует важный интерфейс - java.util.NavigableMap, появившийся с версии Java 1.6. Его метод

Map.Entry<K,V> ceilingEntry(K key)

как раз позволяет найти запись в map-е удовлетворяющую условию K(n) < key <= K(n+1) и при этом будет содержать значение по ключу K(n+1). Таким образом, остается составить map-у из записей: ключ - макс. значение опыта на уровне, значение - уровень. Код решения:

Для наглядности я захардкодил map-у в коде, на деле же она создается из xml.

пятница, 29 октября 2010 г.

Обновление максимального значения без использования блокировок

При реализации грамотных многопоточных механизмов, порой используют только синхронизованные блоки кода. Но, не следует также забывать и о функции CAS (Compare and swap, представленной соответствующей процессорной командой). Данная функция присутствует во всех классах пакета java.util.concurrent.atomic.

Алгортимы с использованием CAS являются безблокировочными, ведь потокам не приходится ожидать блокировок для их исполнения. Операция CAS выполняется успешно или неуспешно, но независимо от исхода она завершается в предсказуемые сроки. В случае неуспешности выполнения программа может сделать попытку выполнения этой функции, либо выполнить другие операции.

До недавнего времени примение CAS-у в своей практике я не находил. Однако, когда потребовалось реализовать многопоточный алгоритм обновления максимального значения, он оказался весьма уместен:

воскресенье, 8 августа 2010 г.

Реализация concurrent HashSet-а в Java

К сожалению, в JDK нет полноценной реализации concurrent HashSet-а, как в случае для HashMap - java.util.concurrent.ConcurrentHashMap. Есть CopyOnWriteArraySet, использующий внутри себя CopyOnWriteArrayList, но у него есть некоторые недостатки:

  • поиск элементов будет медленне ибо в List-ах он выполняется по equals, а не по hashcode -> equals.
  • невозможность удаления объектов при итерации (iterator.remove() - не реализован) и понятно почему, ведь при итерации используется копия коллекции.

Но выход есть, подобие ConcurrentHashSet можно сделать на основе ConcurrentHashMap, записывая как ключ элемент, а в значение какой-нибудь dummy-объект. Такая реализация представлена в виде org.jboss.util.collection.ConcurrentSet из бибилиотеки jboss-common-core.

вторник, 6 апреля 2010 г.

Транзакционные синхронизации в Spring Framework

Выполнение определенной логики по окончанию текущей транзакции в Spring Framework можно "подключать" динамически с помощью так называемых транзакционных синхронизаций.

Транзакционная синхронизация - это по сути callback-объект типа org.springframework.transaction.support.TransactionSynchronization, который содержит в себе определенные методы вызываемые из AbstractPlatformTransactionManager на соответствующие действия над транзакцией (afterCompletion, afterCommit, afterRollback, suspend и т.д.). org.springframework.transaction.support.TransactionSynchronizationManager - менеджер со статическими методами, используемый для регистрации и управления синхронизациями. При написании своей синхронизации в качестве базового класса удобно использовать org.springframework.transaction.support.TransactionSynchronizationAdapter. Вот пример: