Задача: разработать удобный механизм, позволяющий вводить и изменять выражения на специальном языке и получать результат их выполнения в любом месте приложения. Выражения вводятся, изменяются и вычисляются «на лету» без компиляции и остановок приложения.
Данная задача, безусловно, может очень часто встречаться в самых разных бизнес-приложениях:
Наш проект представляет собой клиент-серверную систему, где клиентское приложение построено на базе платформы Eclipse RCP. Кроме того, у нас уже использовался BIRT для построения различных отчетов. Исходя из этих предпосылок, было решено использовать именно возможности данного проекта для решения задачи. Выражения в нем представляют собой сценарии на языке JavaScript, т.е. имеется поддержка большинства функций и возможностей данного языка. Кроме того, стандартные функции JavaScript можно дополнить своими собственными и это немаловажно.
- расчет показателей на основе часто меняющихся данных (котировки акций, коэффициенты ставок и т.д.)
- разнообразные преобразования данных из одного представления в другое
- расчет параметров на основе введенных пользователем данных
- и т.п.
Ввод и редактирование выражений
Выражения можно вводить прямо в приложении используя специальный редактор из платформы BIRT (см. картинку). Как видно, ребята из проектной группы BIRT постарались облегчить ввод сценариев на JavaScript для непрофессионалов. Есть три основных категории функций, которые выполняют функцию справочника и позволяют добавлять функции в пару кликов мышкой. Если бы добавить сюда автоматическое форматирование кода и средства навигации - цены бы не было этому редактору. А так - на больших выражениях придется помучиться, неудобно. Как хранить введенные таким образом выражения - решать вам. Важно только то, что на исполнении они должны представлять из себя строку (java.lang.String).Собственные функции
Как уже писалось выше есть возможность определять собственные функции для использования внутри выражений. Они будут добавляться в категорию «Функции BIRT». Сделать это проще простого. Для начала нужно расширить extension-point org.eclipse.birt.core.ScriptFunctionService и описать новую функцию в plugin.xml:- <extension point="org.eclipse.birt.core.ScriptFunctionService"
- id="extension_id"
- name="Extension_Name">
- <Category
- desc="category description"
- factoryclass="foo.bar.TestFunctionFactory"
- name="CategoryName">
- <Function
- desc="function description"
- name="myBirtFunction">
- <DataType value="Object"/>
- <Argument name="param1">
- <DataType value="String"/>
- </Argument>
- <Argument name="param2">
- <DataType value="Integer"/>
- </Argument>
- </Function>
- </Category>
- </extension>
- public class SampleFunctionFactory implements IScriptFunctionFactory{
- @Override
- public IScriptFunctionExecutor getFunctionExecutor(String functionName)
- throws BirtException {
- if ("myBirtFunction".equals(functionName)){
- return new MyBirtFunctionExecutor();
- }
- return null;
- }
- }
- public class MyBirtFunctionExecutor implements IScriptFunctionExecutor{
- @Override
- public Object execute(Object[] args) throws BirtException {
- if (args.length == 2
- && args[0] instanceof String
- && args[1] instanceof Integer){
- return "Hello, world!";
- }
- return null;
- }
- }
Выполнение выражений
Без лишних предисловий приведу код для выполнения выражений. Он довольно компактный:- ExecutionContext context = new ExecutionContext();
- try {
- IReportContext reportContext = new ReportContextImpl(context);
- context.setReportContext(reportContext);
- context.getScriptContext().registerBean("context", someObject);
- // hack with classloader
- context.setApplicationClassLoader(new ClassLoaderExtension(getClassLoader()));
- return context.evaluate(expression);
- } catch (BirtException e) {
- }finally{
- context.unregisterBean("context");
- }
Заключение
По моему мнению BIRT дает довольно удобное средство для поддержки динамических выражений. Конечно, человек, который вводит выражения, должен знать хотя бы самые базовые основы программирования. Но, в любом случае, для ввода сложных выражений с разветвленной логикой эти основы знать придется, даже если ввод осуществляется исключительно с помощью компонентов GUI. Всю полностью платформу BIRT использовать при этом необязательно. Она довольна большая и тяжелая. По моим наблюдениям, достаточно использовать следующие ее части:- org.eclipse.birt.core
- org.eclipse.birt.data
- org.eclipse.birt.report.engine
- org.eclipse.birt.report.designer.core;
- org.eclipse.birt.report.designer.ui;
- org.eclipse.birt.report.model;
- org.eclipse.birt.report.data.adapter
- org.eclipse.birt.report.model.adapter
- org.mozilla.rhino
- Домашняя страница проекта BIRT - все основные ресурсы тут
- Статья о BIRT в википедии
- Небольшой учебник по платформе BIRT на английском
Релоцировались? Теперь вы можете комментировать без верификации аккаунта.