среда, 21 апреля 2010 г.

Wicket работа с Ajax

Рассмотрим как работает Wicket с Ajax. Для демонстрации рассмотрим следующий пример: при нажатии на гиперссылку, меняется содержимое другой области страницы.
Шаблон страницы:

Класс страницы:

Из кода видно, что при клике на гиперссылке, происходит ajax вызов метода onClick класса гиперссылки. Внутри этого метода обновляется значение поля totalAmountLabel. Чтобы обновление действительно произошло нужно вызвать target.addComponent(). Конечно, таким образом можно обновлять и поля формы, в зависимости от изменений других полей.

понедельник, 19 апреля 2010 г.

Wicket кастомизация html при рендеринге компонентов.


Зачастую при написании приложений на основе компонентных фреймворков, стандартный шаблон компонента требуется подправить. Например, поменять стиль, динамически вставить дополнительный элемент html разметки. В этой статье я разберу как это можно сделать в Wicket.

В базовом классе Component есть два метода для динамического добавления/изменения содержимого компонента:

Этот метод позволяет изменять содержимое компонента, то есть добавлять новые теги или заменять их.

С помощью данного метода можно заменять, добавлять атрибуты в тег компонента.

Рассмотрим случай, когда по какой-то причине мне нужно добавить атрибут class со специфичным значением в компонент AjaxFallbackLink.


Код довольно прост. В заивсимости от какого-то условия я добавляю (или меняю уже существующее значение) атрибута class у тега гиперссылки. Аналогичным образом можно удалить этот же атрибут. Для этого можно использовать следующий метод:

Теперь рассмотрим случай, когда ссылки добавляются динамически. Из предыдущей статьи известно что для этого используется вспомогательный компонент RepeatingView. Проблема в том, что компонент-ссылка содержится в WebMarkupContainer, а последний в RepeatingView. И сразу непонятно где именно нужно переопределять метод onComponentTag, чтобы добраться до самой ссылки. Опытным путем я пришел к тому, что переопределять его нужно так же в самой ссылке. Не знаю почему, но для меня это было неочевидно. Я перепробовал варианты с переопределением этого метода как для RepeatingView, так и для WebMarkupContainer. В итоге пришел к самой ссылке.

Рассмотрим пример с изменением содержимого тега компонента.


Сначала проверяю условие, если оно не выполняется, то тело тега остается без изменения. Если же условие выполняется, то формирую строку, на которую хочу заменить содержимое компонента, а потом вызываю метод заменяющий тело тега компонента.

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

четверг, 15 апреля 2010 г.

Wicket Работа с динамическими списками элементов

Теперь, когда я рассказал про общую концепцию, установку и валидацию в Wicket, перейдем к работе с его компонентами.


Задача. Необходимо отображать данные, количество которых меняется, то есть неизвестно заранее сколько их будет. Это может быть таблица товаров, перечень допустимых действий над объектом или что-то еще. Все это объединяет тот факт, что мы не знаем в момент написания шаблона, сколько табличных или списочных элементов нам понадобится.


Для этих целей используется компонент RepeatingView, он не отображается сам при отрисовке страницы. Его основное назначение - быть контейнером для динамических данных.


Сразу перейдем к примеру и его объяснению. Я буду отображать на странице некие статические данные (понятно, что здесь может быть вызов сервиса, предоставляющего данные из базы). Шаблон страницы (Example.html) выглядит так:



Шаблон довольно простой. Стоит заметить, что для всех элементов, содержащихся в interestLinksList будут повторяться только внутренние элементы. То есть span повторяться не будет.


Рассмотрим класс страницы.

Теперь разберем этот код более подробно. Класс ListItem вспомогательный. Он создан лишь для удобства работы со списками. Статическая константа LIST необходима тоже лишь для демонстрации, поскольку в обычном приложении будет использоваться поставщик данных из сервис слоя. Более интересно наличие промежуточного компонента WebMarkupContainer. Этот компонент необходим для того, чтобы Wicket мог отличить различные элементы динамического списка. Для этого разработчик создает этот промежуточный компонент и устанавливает ему id с помощью вызова

Замечу, что в Tapestry 5, этот процесс автоматизирован и скрыт от глаз разработчика, что, по моему мнению, является правильным шагом. Здесь же нужно это делать самому. Таким образом после выполнения программы мы получим страницу, содержащую html примерно такого вида:

Уникальные id я опустил. Главное, что нет никаких вспомогательных тегов и повторяющийся контент содержится внутри основного тега контейнера. RepeatingView точно также можно использовать и с повторяющимися элементами формы. Я покажу это в статьях, посвященных различной работе с формами.

среда, 14 апреля 2010 г.

Wicket - первое приложение.

Собственно с этой статьи и надо было начинать рассказ про Wicket, но лучше поздно чем никогда. Итак, я предполагаю использование maven. Cтруктура каталогов соответствующая.

1. Добавляем в pom.xml зависимость:

Сюда же можно добавить поддержку wicket-security, но об этом я расскажу в статьях, посвященных интеграции с этой подсистемой.

2. Создаем страницу Index.
Общее описание коцепций я приводил здесь. Ниже шаблон и класс страницы, а так же properties файл.
Шаблон

Класс страницы.

properties файл.

3. Создаем класс WicketApplication.
Это класс расширяет WebApplication, в котором находятся методы, управляющие различными свойствами Wicket приложения. Я в нем хочу переопределить то какую страницу Wicket будет отдавать как "домашнюю".

Класс WebApplication содержит много интересных методов. Я буду разбирать их в следующих статьях на тему Wicket.

4. Добавить WicketApplication в spring контекст.

5. Изменить web.xml.
Он должен иметь следующий вид:

Здесь требуется пояснение. Первая строка необходима, чтобы загрузить в контекст бин wicketApplication. SpringWebApplicationFactory - это реализация интерфейса IWebApplicationFactory, позволяющая получать WebApplication объект из контекста Spring.

Теперь после запуска приложения, мы всегда будем попадать на стартовую страницу.

понедельник, 12 апреля 2010 г.

Wicket - Специфика работы с валидаторами полей и ошибками

Задача. Обеспечить проверку данных, вводимых в форму, а так же информирование об ошибках ввода.

Информирование об ошибках.
Чтобы ошибки отображались в форме, нужно добавить FeedBackPanel как в шаблон, так и в класс страницы.


Обязательные поля
Если поле является обязательным, то можно выделить его с помощью "красной звездочки", но выделение это выглядит не очень красиво.Для этого используется FormComponentFeedbackBorder. Ниже пример использования


Можно вместо звездочки сделать свою разметку.

Валидаторы.
Базовые валидаторы Wicket достаточно скудные. Мне в конкретной задаче понадобился валидатор, который проверяет, что поле содержит ровно 12 цифр. Оказалось, что для этого нужно писать собственный валидатор. Ниже я привожу сам валидатор, класс страницы.

Остановимся чуть подробнее на этом классе. Конструктор принимает имя поля, на которое навешивается валидатор и размер этого поля. Метод непосредственно осуществляющий проверку не представляет особого интереса, в нем вызывается метод error, записывающий ошибку в feedbackpanel данной формы. Тут нужно заметить, что если Вы забыли добавить компонент FeedBackPanel в форму, то ошибку Вы не увидите, хотя валидатор отработает и не допустит некорректного ввода в форму. Метод resourceKey возвращает префикс, с которого начинается локализованное сообщение об ошибке, хранящееся в properties - файле страницы.

Ну и последний метод предоставлет значения для замены placeholder'ов в сообщении об ошибке. Теперь остается подключить валидатор к полю:


Те кто имеют опыт работы с Tapestry оценят насколько Wicket отстает в развити от данной технологии. Для Tapestry такие валидаторы писать просто нет нужды, все уже сделано за нас.Сравнение этих технологий я проведу позднее. А пока про валидаторы все.

пятница, 9 апреля 2010 г.

JPBM - часть 6 - производительность.

После пяти статей про JBPM самое время написать про основную фобию разработчиков перед такого рода движками - ПРОИЗВОДИТЕЛЬНОСТЬ. Именно это магическое слово я слышу каждый раз когда речь заходит о workflow или process management продуктах. Одной статьей развеять эту убежденность не получится, но я все же попробую начать.

Я провел несколько тестов. В чем они заключались? На входе имеем сервлет, обрабатывающий запросы следующим образом: на основе входных параметров(v1, v2, v3), создается объект и передается в экземпляр процесса, который после этого запускается. Использовался типовой процесс бизнес-приложения(25 нодов, в среднем 10 переходов). Сервер приложений jboss-5.0.1.GA . Для тестирования использовался Jmeter. Тест состоит из трех ThreadGroup, каждая из которых содержит 100 пользователей, посылающих запросы в систему.

Тестирование отклика системы.
Проверялось сколько запросов система готова обработать за единицу времени. Рассматривались два случая: асинхронное и синхронное исполнение процесса со стороны JBPM. В первом случае сервлет заканчивал обработку запроса запуском процесса, после чего последний выполнялся в отдельной нитке. Во втором варианте сервлет ожидает окончания исполнения процесса и только после этого заканчивает обработку входящего запроса.

Синхронное исполнение


Из таблицы видим, что в этом случае обрабатывается 10.1 запроса в секунду. Максимальное время исполнения процесса 3 секунды, минимальное 10мс. 90% запросов исполняются за время < 1с.

Асинхронное исполнение

Видим, что разница в 9.5 раз по скорости, имеем 95.2 запросов в секунду. Максимальное время исполнения процесса в данном случае - 30 секунд. Минимальное -
100мс. 80% запросов исполняются за время < 1 c.

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

XML - интерфейсы WebMoney и Java

У WebMoney есть X-интерфейсы. Они предназанчены для того, чтобы программным способом взаимодействовать с этой платежной системой. Выставлять счета, получать различную статистику.

При этом порядок работы разный и заивсит от того как вы проходили регистрацию в платежной системе. Если через Light, то у вас p12 ключ и некоторые параметры (ваш wmid и подпись через Signer) передавать не надо. Если регистрация проходила через Keeper Classic, то у вас kwm ключ, и вам необходимо указывать ваш wmid и подписывать сообщения через Signer.

Для работы через эти интерфейсы есть хорошая библиотека WebmoneyJava Я работал через нее. Кошелек был зарегистрирован через Keeper Light. Но тут мне понадобилось перевести приложение на другой акканут, который был зарегистрирован через Keeper Classic. Вот тогда и началаись проблемы. Чтобы работать c ключами classic, необходимо:


  • Сохранить ключ из кипера в файл.
  • С помощью KeyExtractor преобразовать этот ключ в Base64
  • Положить получившийся файл в то место где его будет видеть сервис. Указать путь к нему в самом сервисе.

Трудности начинаются со второго пункта. Я тщетно пытался найти на сайте WebMoney ссылку на приложение KeyExtractor. После долгих поисков, я все же ее нашел. KeyExctractor можно скачать здесь.

Дальше меня поджидала еще одна проблема: выяснилось, что изменился формат хранения classic ключей. Сейчас KeyExtractor преобразует их в xml Base64. Таким образом библиотека webmoneyjava не работала с новым представлением classic ключей. Я нашел обновленную версию соответствующей библиотеки, написанной на C#. После чего поправил код webmoneyjava. Исправления затронули :


  • SignerImpl
  • wmsignerjx.Signer
  • wmsignerjx.Montgomery

Ниже я привожу код изменненых классов.






Теперь можно смело использовать соответствующий сервис для работы с Classic ключами.

пятница, 2 апреля 2010 г.

JBPM - Часть 5 - Интеграция со Spring.

Если использовать стандартный механизм взаимодействия с JBPM, то дотсуп к основным объектам фреймворка получается не очень удобным способом. В моем приложении активно используется Spring, поэтому я решил получать доступ к JBPM через него. Посмотрим как же этого добиться.

Мне необходимо работать со следующими операциями:
- Деплоить процесс или несколько процессов
- Запускать процессы
- Возобновлять процессы, находящиеся в ожидании.

Для этих целей я ввел два интерфейса: DeployService, ProcessService. Их код представлен ниже.





В реализации DeployService используется реализация JBPM интерфейса RepositoryService. А в ProcessService добавляется использование ExecutionService. Ниже приводится реализация этих интерфейсов.






Можно заметить, что в реализациях я использую стандартную аннотацию Autowired, что означает наличие соответствующих бинов в контексте приложения. Чтобы они там появились необходимо добавить в контекст следующие строчки



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



Вот и все. Теперь я могу спокойно деплоить процессы с помощью


и запускать например так



Вот такая достаточно простая интеграция получилась.