понедельник, 29 декабря 2008 г.

Тестирование Spring приложений

Эта статья - заготовка, для быстрой организации тестирования спринг приложений.
Рассмотрим типичную конфигурацию Spring + Hibernate. Для тестирования БЛ будет использоваться JUnit4. Заполнять БД тестовыми данными будем при помощи DBUnit. Для запуска тестов будет использоватся Ant(на билдсервере) и Eclipse (для дебага).
Полезная л-ра:
Класная статья о тестировании Spring-a в JUnit-е http://samolisov.blogspot.com/2008/07/spring-junit.html
Класная статья о JUnit4 http://www.ibm.com/developerworks/ru/edu/j-junit4/index.html
Итак нам понадобятся следующие библиотеки:
  1. драйвер БД (в моем примере mqsql-5.0.4)
  2. hibernate 3.3.1, hibernate-annotations 3.4
  3. spring-2.5.5
  4. для работы спринга: cglib 2.1, commons-lang 2.4, spring-modules 0.9
  5. для тестирования спринга в JUnit 4: spring-test (из spring-modules)
  6. junit 4.4
  7. логирование: commons-loging 1.0.4, commons-login-api 1.0.4, log4j 1.2.13
  8. заполнение тестовой БД-х: dbUnit 2.4.2
В заготовке используется схема из двух таблиц "bookcase" и "book", с типичной связью один ко многим. Бизнес модель состоит из трех модулей: млодуля сервисов, модели и DAO. Модель описывает сущности, DAO - описывает методы сохранения и выборки сущностей из БД используя Hibernate Criteria Queries (обекстную модель построения запросов), сервисы же предоставляют высокоуровневые бизнес методы. Для реализации бизнес методов сервисы используют DAO, но также они могут использовать и бизнес методы других сервисов. Так в заготовке "BookcaseService" использует методы другого сервиса "AnotherService".

Для тестирования сервиса "BookcaseService" используется класс "BookceseServiceTest". В нем есть пример:
  • использования dbunit при тестировании
  • создания сессии для использования в тестах обьектов использующих "hibernate lazy loading"
  • замещения сервиса ""AnotherService" сервисом "AnotherTestOverrideService" для тестов
Ant-ский билд скрипт содержит цели для создания БД, запуска юнит тестов и построения веб репортов их результатов, создания javadocs по проекту, построения веб представления метрики проекта (сколько пакетов, класов и т.д., для етого используется утилита jdepend), а также svn статистики (используется statsvn)

Скачать исходники проекта с библиотеками (14мб)
Скачать исходники без библиотек

среда, 24 декабря 2008 г.

Библиотека urlrewrite

Недавно столкнулся с очень приятной библиотекой http://tuckey.org/urlrewrite/. Она представляет собой обычный фильтр который позволяет задавать свои настройки в хмл файле. Прелесть этой вещицы во первых в простоте (от первого знакомства до использования не более 5 минут), а во вторых в функционале (сейчас я с трудом себе могу представить как мои веб приложения обходились без нее).

Главная фича даной библиотеки: вы можете переформатировать запрос пользователя до не узнаваемости и затем перенаправить на нужный вам адрес. Это полезно во первых если вы хотите предоставить структурированые каким либо образом url-ы пользователю, во вторых, если вам просто нужно средиректить пользователя на другой адрес который имеет специфический формат и в третьих если ваши картинки, стили и ява скрипты запрашиваются клиентом по одному адресу, а вам по каким-либо причинам их удобно держать в другом.

Инсталяция: на сайте проэкта все детально описано, состоит из 3-х шагов: бросьте в папку WEB-INF/lib саму библиотеку urlrewrite.jar, в папку WEB-INF файл urlrewrite.xml (в котором вы будете описывать правила работы фильтра), и добавьте магические строки в web.xml:
1 <filter>
2 <filter-name>UrlRewriteFilter</filter-name>
3 <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
4 <init-param>
5 <param-name>logLevel</param-name>
6 <param-value>DEBUG</param-value>
7 </init-param>
8 <init-param>
9 <param-name>confReloadCheckInterval</param-name>
10 <param-value>5</param-value>
11 </init-param>
12 </filter>
13 <filter-mapping>
14 <filter-name>UrlRewriteFilter</filter-name>
15 <url-pattern>/*</url-pattern>
16 </filter-mapping>
в строке 6 указывается необязательный параметр - уровень вывода логов, а в строке 10 - интервал перечитывания файла urlrewrite.xml (даная конфигурация позволяет изменять его на лету, очень полезно на этапе разработки).

Конфигурирование файла urlrewrite.xml:
  1. может содержать несколько тегов rule, при этом они будут выполнятся один за другим сверху в низ
  2. для задания адресов используется Java Regular Expression. Кратко о синтаксисе можно прочитать например тут http://htmlweb.ru/java/regexp.php
  3. тег from - задает адреса на которые будет срабатывать фильтр
  4. тег to - указывает адрес куда будет перенаправлен пользователь (если используете redirect может пригодится внутренняя переменная %{context-path} - содержащая контекст вашего приложения).
    Пример:
    Если ваше приложение находится по адресу localhost/myapp то
    1 <to type="redirect">%{context-path}/index.jsp</to>
    пренаправит пользователя по адресу localhost/myapp/index.jsp
  5. condition - позволяет добавить дополнительные параметры, для того чтоб ограничить запросы на которые будет срабатывать фильтр.
    Пример:
    1 <condition type="request-uri" operator="notequal">/manager</condition>
    указывает что фильтр не должен срабатывать на запросы в которых встречается комбинация "/manager"
  6. set - позволяет записать информацыю в сессию, запрос, куки и т.д.
    Пример:
    1 <set name="publisherDomain" type="session">myDomain</set>
    записывает строку "myDomain" в переменную publisherDomain.
Маленький экскурс в регулярные выражения:
  • ^ - начало строки (пример: ^hi - значит что строка должна начинатся фразой "hi"
  • $ - конец строки

  • . - любой символ
  • [abc] - любой символ из заключенных в квадратные скобки
  • [^abc] - любой символ кроме заключенных в квадратные скобки
    можно также указать диапазон или тип символов

  • * - повторение символа 0 или более раз. (пример: ^/.* - строка начинается с / за которым следует любая комбинация символов)
  • + - как и * но обязательное повторение 1 раз или более
  • ? - повторение 0 или 1 раз

  • () -запомнить найденное выражение
  • $1, $2, ... - использовать запомненное выражение
    Пример:
    1 <rule>
    2 <from>^/(.+)$</from>
    3 <to type="redirect">/$1/login.html</to>
    4 </rule>
    Фильтр будет срабатывать на все адреса начинающиеся с "/" за которым следует хотя бы один символ и запоминать символы после "/". Т.е. если пользователь введет адрес /test, то фильтр перенаправит его на страницу /test/login.html
Для закрепления пример файла urlrewrite.xml:

1 <?xml version="1.0" encoding="utf-8"?>
2 <!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
3
"http://tuckey.org/res/dtds/urlrewrite3.2.dtd">

4
5 <urlrewrite>
6
7 <rule>
8 <from>^/portal$</from>
9 <to type="redirect">%{context-path}/portal/index.jsp</to>
10 </rule>
11
12 <rule>
13 <condition type="request-uri" operator="notequal">/portal</condition>
14 <condition type="request-uri" operator="notequal">/css</condition>
15 <condition type="request-uri" operator="notequal">/js</condition>
16 <condition type="request-uri" operator="notequal">/img</condition>
17 <condition type="request-uri" operator="notequal">/html</condition>
18 <from>^.*/(.*)/(.*)$</from>
19 <set name="publisherDomain" type="session">$1</set>
20 <to type="redirect">%{context-path}/portal/$2</to>
21 </rule>
22
23 </urlrewrite>
здесь первое правило будет срабатывать на запросы типа /portal и перенаправлять их на страницу /portal/index.jsp
Второе правило будет срабатывать на все остальные урлы кроме обращений связаных с загруской стилей, стат. страниц, картинок и т.д., далее оно будет вырезать выражение находящееся между первым и последним знаком "/"? и помещать его в сесию, а пользователя перенаправлять по адресу /myapp/portal/выражение_стоящее_за_последним_знаком_/

вторник, 23 декабря 2008 г.

Конвертация java кода в html

Не нашел нормальных средств для вставки java, xml, html, текстов в стандартном блоговском редакторе сообщений. Пришлось искать доп. средства. Пока использую http://www.palfrader.org/code2html/code2html.html хотя страшно не нравится. Хотелось бы иметь конвертор который один раз генерит стили и затем цепляет их к тексту, да еще чтоб и работало сходу под виндой. Из чего то похожего нашлось только java-code-export/. Класная програма жаль только она стили для каждого явовского файла каждый раз по разному генерит :)

Вызов спринговых бинов из фильтра

Если возникает необходимость вызова спринговых сервисов из фильтров можно использовать класс org.springframework.web.context.support.WebApplicationContextUtils, который позволяет обращатся к бинам по имени. По умолчанию имя бина совпадает с именем класа но начинается с маленькой буквы.
Например имеется бин PublisherService:

1 @Service
2 public class PublisherService {
3
4 @Autowired
5 private PubliherDAO publisherDAO;
6
7 //...
8 }

тогда его можно вызвать из фильтра следующим образом

1 public class MyFilter implements Filter {
2
3 private final Log log = LogFactory.getLog(getClass());
4
5 private PublisherService publisherService;
6
7 public void init(FilterConfig config) throws javax.servlet.ServletException {
8 if (null == publisherService) {
9 publisherService = (PublisherService) WebApplicationContextUtils
10 .getWebApplicationContext(config.getServletContext()).getBean(
11 "publisherService");
12 }
13 }
14
15 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
16 throws IOException, ServletException {
17
18 HttpServletRequest request = (HttpServletRequest) req;
19 HttpServletResponse response = (HttpServletResponse) resp;
20
21 // to do something with publisherService
22
23 chain.doFilter(req, resp);
24
25 }
26
27 public void destroy() {
28 }
29 }

web.xml файл при етом может выглядеть например так:

1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
4 xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation=
"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
6 version=
"2.4">

7
8 <display-name>MyApp</display-name>
9
10 <context-param>
11 <param-name>contextConfigLocation</param-name>
12 <param-value>
13 classpath:/**/applicationContext-*.xml,
14 </param-value>
15 </context-param>
16
17 <servlet>
18 <servlet-name>SpringMVC</servlet-name>
19 <servlet-class>
20 org.springframework.web.servlet.DispatcherServlet
21 </servlet-class>
22 <init-param>
23 <param-name>contextConfigLocation</param-name>
24 <param-value>classpath:**/SpringMVC-*.xml</param-value>
25 </init-param>
26 <load-on-startup>1</load-on-startup>
27 </servlet>
28
29 <context-param>
30 <param-name>log4jConfigLocation</param-name>
31 <param-value>/WEB-INF/classes/log4j.properties</param-value>
32 </context-param>
33
34 <filter>
35 <filter-name>MyFilter</filter-name>
36 <filter-class>mypack.MyFilter</filter-class>
37 </filter>
38 <filter-mapping>
39 <filter-name>MyFilter</filter-name>
40 <servlet-name>SpringMVC</servlet-name>
41 <dispatcher>REQUEST</dispatcher>
42 <dispatcher>FORWARD</dispatcher>
43 <dispatcher>INCLUDE</dispatcher>
44 </filter-mapping>
45
46 <servlet-mapping>
47 <servlet-name>SpringMVC</servlet-name>
48 <url-pattern>*.htm</url-pattern>
49 </servlet-mapping>
50
51 <welcome-file-list>
52 <welcome-file>index.html</welcome-file>
53 <welcome-file>index.jsp</welcome-file>
54 </welcome-file-list>
55
56 </web-app>

вторник, 22 апреля 2008 г.

JDeveloper, Настройка кодировки

В JDeveloper определяются IDE encoding - кодировка чтения записи файлов, Compiler Encoding - кодировка используемая при компиляции ява файлов.

Для их настройки используйте:

* IDE encoding - Tools|Preferences... menu -> Environment.
* Compiler Encoding - Tools|Project Properties... menu and select Compiler.

среда, 16 апреля 2008 г.

Локализация ADF Faces

Локализация в ADF Faces используется при генерации стандартных сообщений, елементов ( например при использовании элемента tree), а также при форматировании вывода чисел и дат. По умолчанию берется локализация ОС в которой запущен OC4J.
Локализацию можно задать явно. Для этого в файле faces-config.xml нужно указать:
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
...
   <application>
   ...
   <locale-config>
      <default-locale>ru</default-locale>
   </locale-config>
   </application>
</faces-config>

среда, 16 января 2008 г.

Краткий справочник по книге "Business Rules in ADF BC" An Oracle White Paper August 2007

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


Бизнес Правила(БП) можно разделить:
  1. Правила отвечающие состояниям системы
  2. Правила отвечающие за изменение сотояний системы
  3. Правила Авторизации
  4. автоматические тригеры, запускающие определенные действия при изменении состояния системы.

UML концепции БП:

  1. Инварианты - ограничения определяющие систему в стабильных состояниях. Обычно включаются в UML модель классов
  2. Предусловия - условия которые должны быть выполнены, для возможности перехода из одного состояния системы в другое. Обычно описываются в use-case диаграммах
  3. Постусловия - условия которые должны быть выполнены после перехода системы в новое состояние. Обычно описываются в use-case диаграммах

автоматические действия не являются бизнес правилами.

В книге рассмотрены такие БП:

  1. Constraint - ограничения на состояние системы и на переход из одного состояния в другое
  2. Change Event - определяют действия запускаемые при определенных условиях. (Пример: при определенном условии напечатать отчет или послать имеил)
  3. Authorization - ограничения связанные с авторизацией

Constraint rules:

Описывают ограничения на состояние системы и на переход из одного состояния в другое. Соответствуют UML инвариантам и UML пред условиям.

Constraint rules делят по обьектам к которым они относятся:

  1. Attribute - правило для конкретного атрибута одного обьекта
  2. Instance - правило для нескольких атрибутов одного обьекта
  3. Entity - правило для нескольких обьектов одного типа ентити
  4. MultyEntity - правило для более одного обьекта разных типов сущностей
Attribute:
  1. Attribute properties - ограничивает состояние атрибута:
    • Type - ограничение по типу атрибута (Пример: Departament должен быть Numeric)
    • Mandatory - определяет является ли атрибут обязательным
    • Updateble - определяет можно ли атрибут менять (Пример: OrderLine нельзя назначить другому Order (OrderLine.OrderId not Updateble)
  2. Domain - позволяет задать свой тип даных для атрибута (Пример: Поле YesNo может принимать значения либо "Y", либо "N")
  3. Validation:
    • Compare (Пример: Зарплата сотрудника должна быть больше 0)
    • List (Пример: состояние сотрудника должно быть одним из списка "S" (Single), "M" (Married), "D" (Divorced), "W" (Widowed) или null)
    • Renge (Пример: бюджет должен находится в пределах от 10 000 до 100 000)
    • Length (Пример: Код страны должен состоять из 2-х символов)
    • Regular (Пример: Почтовый код должен иметь формат **-**)
    • Method (Пример: состояние сотрудника может меняться только по правилам: divorced, widowed -> married; married -> divorced, widowed; null -> any value; any value -> null)
Instance:
  1. Instance Validator - реализуется с помощью метода в классе ентити или с помощью отдельного класа. (Пример1 : Рабочий который числится как "SALESMAN" обязательно должен иметь заполненное поле с комиссией) (Пример2: Нельзя изменять Rate, Role или PercentageAllocated для ProjectAssignment если он активен. (Закройте активный ProjectAssignment и создайте новый) (Пример3: Дата начала должна быть меньше даты конца)
  2. Delete Rules - запрещает удалять запись при определенных условиях (пример: Вы не можете удалять Заказ после доставки)
Entity:
  1. Unique Identifier - параметр среди всех обьектов данного типа ентити должен быть уникальным (Пример: название департамента должно быть уникально)
  2. Collection, no parent - ограничение относится к коллекции обьектов но не к родителю этой коллекции (Пример: В системе не может быть больше 20 департаментов)
  3. Other Entity - все остальные ограничения относящиеся к набору обьектов одного типа ентити
Multi Entity
  1. Association - описывает как классы ентити зависят друг от друга (Пример: каждый OrderLine должен иметь один и только один order) (Пример2: каждый сотрудник работает только в одном департаменте)
  2. Collection within Master(Parent) - ограничение касается коллекции и ее родителя (Пример: в департаменте должно быть не более одного работника-клерка)
  3. Simple Multi Entity - включают правила которые связаны с различными типами ентити, но которые применяются только к одному енити. (пример: вы не можете создать проектное задание потому что проект закрыт (дата проекта в прошлом))
  4. Complex Multi Entity - правила которые затрагивают много ентити и относятся также ко многим ентити.(пример: начальная дата проектного задания, должна попадать в диапазон даты начала и конца проекта)
Change Event rules:

Автоматические действия срабатываемые при изменении состояния системы

DML (Data Manipulation) - означают события связанные с операциями Create, Update, Delete

Change Event rules делят:

  1. Change Event rules with DML - связаные с опреацыями Create, Update, Delete
  2. Change Event rules without DML - не связаные с опреацыями Create, Update, Delete
Change Event rules with DML
  1. Default - Правила описывают какое значение должно принять поле в случае операции Create
    • Literal (Пример: По умолчанию после создания записи поле count должно содержать значение 1)
    • Calculated (Пример: При создании записи генерить Id на основании последовательности из БД)
  2. Change History Rules - запись в обьект информации о том когда и кем он был создан или модифицирован
  3. Other Derivaion Rules - При создании или изменении обьекта пересчитать значение атрибута (Пример: при записи переcчитывать значение totalPrice)
  4. Cascade Delete Rules - Удаление потомков при удалении родителя
  5. Other - все остальные правила не вошедшие в описанные выше случаи. (Пример1: Если изменилась дата начала проекта, то нужно изменить все даты начала проектных задач, которые получаются раньше новой даты начала проекта) (Пример2: если изменилось значение зарплаты или комиссии сотрудника, записать соответствующее сообщение в журнал)
Change Event rules without DML

Автоматический триггер отслеживающий изменение системы не связанное с опреациями Create, Update, Delete (Пример: послать email сообщение менеджеру когда изменится дата окончания проектной задачи