Система обработки бизнес-логики server-side приложения на Groovy

Содержание

Слайд 2

Задача

Возможность изменять бизнес-логику server-side Java EE приложения «на лету»:
С минимальными обращениями к

Задача Возможность изменять бизнес-логику server-side Java EE приложения «на лету»: С минимальными
разработчикам системы
Без перекомпиляции
Без shutdown/redeploy системы на сервере
С защитой от синтаксических и семантических ошибок

Слайд 3

Применение

Биллинговые системы:
Операторы связи
Такси
Генерация разнообразных отчетов
Пример:
«Клиенту, сделавшему 3 заказа в прошлом месяце и

Применение Биллинговые системы: Операторы связи Такси Генерация разнообразных отчетов Пример: «Клиенту, сделавшему
с днем рождения на этой неделе, сделать скидку в 10% после 15-й минуты поездки»

Слайд 4

Типичные решения

Фиксированные параметры и настройки логики – недостаточно гибко
Скриптинг:
JavaScript (Mozilla Rhino, http://www.mozilla.org/rhino/)
Groovy

Типичные решения Фиксированные параметры и настройки логики – недостаточно гибко Скриптинг: JavaScript
(http://groovy.codehaus.org/)

Слайд 5

Groovy

Dynamic language for the Java Virtual Machine:
Динамическая типизация
Удобный и краткий синтаксис работы

Groovy Dynamic language for the Java Virtual Machine: Динамическая типизация Удобный и
с коллекциями, картами, массивами, строками
Возможность runtime-компиляции в JVM байт-код и работы с другим Java кодом и библиотеками

Слайд 6

Архитектура

Java EE – JBoss Application Server
ORM – EJB JPA Persistence (Stateless &

Архитектура Java EE – JBoss Application Server ORM – EJB JPA Persistence
Entity Beans)
Service MBeans
HTTP/SOAP Client Connectors

Слайд 7

Сервис команд

Service MBean:
Invoker:
Object invoke(String mapping, Object[] args)
Commands:
Object invoke(Object[] args)

Сервис команд Service MBean: Invoker: Object invoke(String mapping, Object[] args) Commands: Object invoke(Object[] args)

Слайд 8

Оформление команд

Команда: Groovy Script (класс)
Runtime компиляция в JVM байт-код, создание объектов и

Оформление команд Команда: Groovy Script (класс) Runtime компиляция в JVM байт-код, создание
хранение в памяти:
GroovyClassLoader loader = new GroovyClassLoader();
Class groovyClass = loader.parseClass(content);
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
Файлы исходников команд расположены вне EAR/WAR/SAR-архивов
Мониторинг изменений директории исходников через JBoss Deployer для runtime отслеживания изменений

Слайд 9

Класс команды

Аннотация на класс – mapping команды:
@ScriptMapping("/createOrder")
Имплементация Java интерфейса:
public interface GenericScript {

Класс команды Аннотация на класс – mapping команды: @ScriptMapping("/createOrder") Имплементация Java интерфейса:

void init(Object... args);
Object invoke(Object... args);
void onInterrupt(Object... args);
}
Хранение скомпилированных объектов в сервисе в виде ассоциативного массива [Mapping -> Object]
Выполнение прямым вызовом метода invoke без использования Reflections:
GenericScript s = scripts.get(mapping);
s.invoke(args);

Слайд 10

Базовый контекст выполнения скрипта

Новое выполнение – новый объект (аналогично HttpServletRequest)
Утилитные методы:
Object getAttribute(String

Базовый контекст выполнения скрипта Новое выполнение – новый объект (аналогично HttpServletRequest) Утилитные
key);
void setAttribute(String key, Object value);
Object invoke(String mapping, Object[] args);
void log(String message);

Слайд 11

Типы команд

Разделение контекстов выполнения команд:
Calculation (базовый): без доступа к Persistence
Read-only: с доступом

Типы команд Разделение контекстов выполнения команд: Calculation (базовый): без доступа к Persistence
к Persistence на чтение
Read/Write: с доступом к Persistence на чтение/обновление

Слайд 12

Организация доступа к данным

EJB JPA Persistence:
Все сущности предметной области – @Entity
Утилитный Stateless

Организация доступа к данным EJB JPA Persistence: Все сущности предметной области –
Bean:
public interface BaseDAO {
List getAll(Class c);
List getEntitiesByKey(Class c, String key, Object value);
T getEntityById(Class c, Object id);
T createEntity(T entity);
void mergeEntity(Object entity);
void removeEntity(Class c, Object id);
}
Методы Stateless Bean доступны через контекст скрипта

Слайд 13

Организация доступа к данным

Имплементация Stateless Bean, примеры:
T createEntity(T entity) {
entityManager.persist(entity);
return entity;
}

Организация доступа к данным Имплементация Stateless Bean, примеры: T createEntity(T entity) {
List getAll(Class c) {
Query query = entityManager.createQuery("select c from " + c.getName() + " c");
return query.getResultList();
}

Слайд 14

Управление транзакцией

Работа с транзакцией в Stateless Bean:
@TransactionManagement(value = TransactionManagementType.CONTAINER)
@TransactionManagement(value = TransactionManagementType.BEAN)
При использовании

Управление транзакцией Работа с транзакцией в Stateless Bean: @TransactionManagement(value = TransactionManagementType.CONTAINER) @TransactionManagement(value
CMT – аннотации на методах:
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@TransactionAttribute(TransactionAttributeType.SUPPORTS)

sessionContext.setRollbackOnly();// откат
В обоих случаях, нельзя:
myStatelessBean.startTransaction();
doSomething();
myStatelessBean.commitTransaction();

Слайд 15

Управление транзакцией

Решение:
Специальные методы-обертки в Stateless Bean:
//для Read/Write контекста
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Object wrapTransactionRequired(ScriptWrapper sw)
//для Read-Only

Управление транзакцией Решение: Специальные методы-обертки в Stateless Bean: //для Read/Write контекста @TransactionAttribute(TransactionAttributeType.REQUIRED)
контекста
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public Object wrapTransactionSupports(ScriptWrapper sw)
Вызов метода invoke скрипта-команды и связывание с Stateless Bean – внутри методов wrapTransactionRequired и wrapTransactionSupports

Слайд 16

Многопоточное исполнение

Исполнение в очереди - ExecutorService:
singleThreadExecutor: один поток, контроль времени выполнения
multiThreadExecutor: несколько

Многопоточное исполнение Исполнение в очереди - ExecutorService: singleThreadExecutor: один поток, контроль времени
потоков, контроль времени выполнения
debugThreadExecutor: несколько потоков, без контроля времени выполнения
Определение типа команды и таймаута выполнения в аннотации к классу скрипта:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ScriptMapping {
//…
long runTimeout() default -1;
ScriptThreadingType type() default ScriptThreadingType.MULTI;
}

Слайд 17

Контроль времени выполнения

Два вложенных Callable на выполнение команды:
1) Внутренний: запуск скрипта
2) Внешний:

Контроль времени выполнения Два вложенных Callable на выполнение команды: 1) Внутренний: запуск
контроль времени выполнения через FutureTask.get(timeout)
Внутренний ExecutorService на N+1 поток

Слайд 18

Контроль времени выполнения

1) TimeoutException в FutureTask.get(timeout)
2) Вызов метода onInterrupt() у скрипта команды

Контроль времени выполнения 1) TimeoutException в FutureTask.get(timeout) 2) Вызов метода onInterrupt() у
для предупреждения о завершении
3) sleep(timeout)
4) stop() у потока
5) Запись в журнал ошибок

Слайд 19

Асинхронный режим

Вызывающий клиент имплементирует Callback для взаимодействия с командой во время выполнения,

Асинхронный режим Вызывающий клиент имплементирует Callback для взаимодействия с командой во время выполнения, а получает Future:
а получает Future:

Слайд 20

Контроль ошибок

1) Проверка синтаксиса при компиляции:
GroovyClassLoader loader = new GroovyClassLoader();
Class groovyClass =

Контроль ошибок 1) Проверка синтаксиса при компиляции: GroovyClassLoader loader = new GroovyClassLoader();
loader.parseClass(content);
- throws CompilationFailedException при синтаксическиой ошибке
2) Проверка времени исполнения по таймауту
3) При таймауте скрипта больше K раз – исключение из Invoker

Слайд 21

Отладка

Поддержка синтаксиса Groovy в IDE
Удаленная отладка (JPDA) из IDE
Выполнение в отдельном потоке

Отладка Поддержка синтаксиса Groovy в IDE Удаленная отладка (JPDA) из IDE Выполнение
без контроля таймаута

Слайд 22

Интерфейс администрирования

Create, Read, Update, Delete команд
Версионность для отката изменений
Мониторинг:
Количество команд в

Интерфейс администрирования Create, Read, Update, Delete команд Версионность для отката изменений Мониторинг:
очереди
Exceptions
Отключенные команды

Слайд 23

Пример

@ScriptMapping(value = "/SetOrderToBoard", runTimeout = 10000L)
class SetOrderToBoard extends ReadWriteScript {
def invoke(context,

Пример @ScriptMapping(value = "/SetOrderToBoard", runTimeout = 10000L) class SetOrderToBoard extends ReadWriteScript {
orderUuid, boardUuid) {
def success = false;
def order = context.findByKey("Order", "uuid", orderUuid);
def boards = context.findAll("Board");
for (board in boards) {
if (board.status == "free") {
board.currentOrder = order;
order.board = board;
if (new Date().getTime() - order.creationTime > 10*60* 1000) {
order.discount += 10;
}
context.update(board);
context.update(order);
success = true;
break;
}
}
return success;
}
}

Слайд 24

Другие платформы

Эквивалентное выполнение скриптов:
.NET - перенос в контекст отличающихся по синтаксису методов:
sqrt,

Другие платформы Эквивалентное выполнение скриптов: .NET - перенос в контекст отличающихся по
pow, round, equal, etc

Слайд 25

Выводы

Разработанный сервис:
Глубокая настройка бизнес-логики приложения
Понятный юзерам язык и API
Работа с сущностями предметной

Выводы Разработанный сервис: Глубокая настройка бизнес-логики приложения Понятный юзерам язык и API
области системы
Защита от ошибок
Возможность расширения на другие платформы
Имя файла: Система-обработки-бизнес-логики-server-side-приложения-на-Groovy.pptx
Количество просмотров: 147
Количество скачиваний: 0