«История разработки eazybi», raimonds simanovskis (eazybi, Латвия)
Post on 14-Apr-2017
3.250 Views
Preview:
TRANSCRIPT
История разработки
Raimonds Simanovskis@rsim
Из Латвии
Из Юрмалы
В Москвев 2003 году
Что такое
Easy-to-useBusiness Intelligence
web application
?
Различные источники данных
Импорт данных
Простое создание отчетов
Много разных диаграмм
Мощные расчеты
История разработки2011 eazyBI.com hosted service
REST API import2012Private eazyBI standalone server
eazyBI plugin2013 Atlassian UI design framework
eazyBI add-on for JIRA Cloudusing Atlassian Connect
data import
2014 Custom REST API, SQL importIntegrations with other JIRA plugins
2015 JIRA Data Center supportSeparate child JVM process
2016 New UI design improvements
История разработки
Упрощенная архитектураИсточники данных
JIRA импорт
REST импорт
CSV импорт
…
МногомерныйOLAP куб
ИзмеренияФакты
схема “звезды”
Pасчетные формулы используя язык MDX
Создание табличных отчетов
Создание панелей из несколько отчетов
Гаджеты на рабочем столе JIRA и на страницах Confluence
Создание диаграмм разных типов
Основные технические компоненты
MySQLPostgre
SQLOracle MS
SQL
JRuby on Rails
Mondrian OLAP
<?xml version="1.0" encoding="UTF-8"?><Schema name="default"> <Cube name="Sales"> <Table name="sales"/> <Dimension foreignKey="customer_id" name="Customers"> <Hierarchy allMemberName="All Customers" hasAll="true" primaryKey="id"> <Table name="customers"/> <Level column="country" name="Country" uniqueMembers="true"/> <Level column="state_province" name="State Province" uniqueMembers="true"/> <Level column="city" name="City" uniqueMembers="false"/> <Level column="fullname" name="Name" uniqueMembers="false"/> </Hierarchy> </Dimension> <Dimension foreignKey="time_id" name="Time" type="TimeDimension"> <Hierarchy hasAll="false" primaryKey="id"> <Table name="time"/> <Level column="the_year" levelType="TimeYears" name="Year" type="Numeric" uniqueMembers="true"/> <Level column="quarter" levelType="TimeQuarters" name="Quarter" uniqueMembers="false"/> <Level column="month_of_year" levelType="TimeMonths" name="Month" type="Numeric" uniqueMembers="false"/> </Hierarchy> </Dimension> <Measure aggregator="sum" column="unit_sales" name="Unit Sales"/> <Measure aggregator="sum" column="store_sales" name="Store Sales"/> </Cube></Schema>
XML или …
schema = Mondrian::OLAP::Schema.define do cube 'Sales' do table 'sales' dimension 'Customers', foreign_key: 'customer_id' do hierarchy has_all: true, all_member_name: 'All Customers', primary_key: 'id' do table 'customers' level 'Country', column: 'country', unique_members: true level 'State Province', column: 'state_province', unique_members: true level 'City', column: 'city', unique_members: false level 'Name', column: 'fullname', unique_members: false end end dimension 'Time', foreign_key: 'time_id', type: 'TimeDimension' do hierarchy has_all: false, primary_key: 'id' do table 'time' level 'Year', column: 'the_year', type: 'Numeric', unique_members: true, level_type: 'TimeYears' level 'Quarter', column: 'quarter', unique_members: false, level_type: 'TimeQuarters' level 'Month', column: 'month_of_year', type: 'Numeric', unique_members: false, level_type: 'TimeMonths' end end measure 'Unit Sales', column: 'unit_sales', aggregator: 'sum' measure 'Store Sales', column: 'store_sales', aggregator: 'sum' end end
DSL в Ruby
Фреймворк веб приложенийRuby on Rails
ActionController
ActiveRecord
ActionView
Browser
Request Router
Response
Database
SQL
Продукты
eazyBICloud
eazyBIfor JIRA
PrivateeazyBI
Build & DeployRuby on Rails application
JRubyTorqueBox
Application Gems
.com
deploy
Mondrian OLAP engine
Other Java libraries
Packaged application
Application Gems
TorqueBox
Privatepackage
pluginOSGi bundleJRuby *.jar
Application Gems
jruby-rack
package
ИнтеграцияeazyBI / JRuby
c JIRA Java API
Вызов JIRA Java APImodule SAL { :userManager => Java::com.atlassian.sal.api.user.UserManager, :loginUriProvider => Java::com.atlassian.sal.api.auth.LoginUriProvider, :pluginSettingsFactory => Java::com.atlassian.sal.api.pluginsettings.PluginSettingsFactory, :applicationProperties => Java::com.atlassian.sal.api.ApplicationProperties }.each do |method_name, klass| mattr_accessor method_name send "#{method_name}=", JiraComponentAccessor.getOSGiComponentInstanceOfType(klass.java_class) end # get global plugin settings mattr_accessor :pluginSettings self.pluginSettings = pluginSettingsFactory.createGlobalSettings
if SAL.applicationProperties.getVersion.split('.').first.to_i >= 6 def self.get_base_url SAL.applicationProperties.getBaseUrl(Java::com.atlassian.sal.api.UrlMode::CANONICAL) end else def self.get_base_url SAL.applicationProperties.getBaseUrl end endend
Поддержка разных версий JIRA
JAVA reflection
def get_jira_user_key(jira_user) if jira_user.respond_to?(:getKey) jira_user.getKey || jira_user.getName elsif JIRA.userManager.respond_to?(:getUserByName) jira_user = JIRA.userManager.getUserByName(jira_user.getName) jira_user.getKey || jira_user.getName else jira_user.getName endend
Исследование, как получить данные из
JIRA Service Deskjcft = jcf.getCustomFieldType
if field = jcft.java_class.declared_fields.detect{|f| f.name == "goalService"} field.accessible = true @service_desk_goal_service = field.value(jcft)# Starting from JIRA Service Desk 3.1.0elsif field = jcft.java_class.declared_fields.detect{|f| f.name == "goalViewService"} field.accessible = true goal_view_service = field.value(jcft) field = goal_view_service.java_class.declared_field("goalService") field.accessible = true @service_desk_goal_service = field.value(goal_view_service)else raise ArgumentError, "Cannot get #{jcft.java_class} goalService"end
Извлечение файлов из jar арxива плагина
# expand rails.root and gem.home bundle directories$bundle = $servlet_context.getClass.getClassLoader.getBundlem_archive_field = $bundle.java_class.declared_field("m_archive")m_archive_field.accessible = truebundle_archive = m_archive_field.value($bundle)
jar_content = if bundle_archive.respond_to?(:getRevisionCount) bundle_archive.getRevision(bundle_archive.getRevisionCount - 1).getContentelse bundle_archive.getCurrentRevision.getContentend%w(rails.root gem.home).each do |directory_name| dir = jar_content.getEntryAsContent("META-INF/#{directory_name}") dir.getEntries.each{|e| dir.getEntryAsNativeLibrary(e)}end
Поддержка разных СУБД
eazyBI accountsAccount 1 Account 2 Account N
Projects A,B Project C Projects X,Y,Z
DB schemaeazybi_jira_dwh_1
Measur
Dimensi Dimensi
DimensiDimensi
DB schemaeazybi_jira_dwh_2
Measur
Dimensi Dimensi
DimensiDimensi
DB schemaeazybi_jira_dwh_N
Measur
Dimensi Dimensi
DimensiDimensi
MySQL databases
eazybi_jira_dwh_1jira_projects
jira_statuses
jira_issues
…
eazybi_jira_dwh_2jira_projects
jira_statuses
jira_issues
…
eazybi_jira_dwh_3jira_projects
jira_statuses
jira_issues
…
eazybi_jirausers
accounts
cube_reports
…
eazybi_jira database
PostgreSQL, MS SQL schemas
eazybi_jira_dwh_1jira_projects
jira_statuses
jira_issues
…
eazybi_jira_dwh_2jira_projects
jira_statuses
jira_issues
…
eazybi_jira_dwh_3jira_projects
jira_statuses
jira_issues
…
default schemausers
accounts
cube_reports
…
eazybi_jira schema
Oracle prefixed tables
#1_jira_projects
#1_jira_statuses
#1_jira_issues
…
#2_jira_projects
#2_jira_statuses
#2_jira_issues
…
#3_jira_projects
#3_jira_statuses
#3_jira_issues
…
users
accounts
cube_reports
…
Другие различия
• Размер имени таблиц/колонок в Oracle (до 30 символов)
• Разный синтаксис и функции SQL
• Разные типи данних
• Разные исключения и ошибки
Общая JIRA JVM JIRA JVM process heap
JIRA objects…
……
Plugin 1…
……
Plugin 2…
……
eazyBI…
……
Mondrian OLAP engine…
……
Results cache
Дочерний JVM процесс JIRA JVM process heap
JIRA objects…
……
Plugin 1…
……
eazyBI…
……
eazyBI child processMondrian OLAP engine
……
…
eazyBI…
……
Results cache
HTTP
Atlassian Connect –фреймворк для
JIRA Cloud плагинов
Atlassian Connect JIRA Cloud eazyBI Cloud
iframeeazyBI web app
……JIRA Cloud accounts
eazyBI jobs…
…JIRA import
REST API
JWT authentication
JWT authentication
JIRA instance…
…Data
DB
Импорт JIRA issues используя REST API
searchstartAt=0 maxResults=200
searchstartAt=200 maxResults=200
searchstartAt=400 maxResults=200
searchstartAt=600 maxResults=200
searchstartAt=800 maxResults=200
searchstartAt=1000 maxResults=200
HTTP 504 timeout
Ключевые факторы успеха
• Гибкая архитектура
• JVM платформа
• Повторное использование существующих библиотек
• Участие в open source проектах:JRuby, Ruby on Rails, Mondrian
top related