«История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

38
История разработки Raimonds Simanovskis @rsim

Transcript of «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Page 1: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

История разработки

Raimonds Simanovskis@rsim

Page 2: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Из Латвии

Page 3: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Из Юрмалы

Page 4: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

В Москвев 2003 году

Page 5: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Что такое

Easy-to-useBusiness Intelligence

web application

?

Page 6: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Различные источники данных

Импорт данных

Page 7: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Простое создание отчетов

Page 8: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Много разных диаграмм

Page 9: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Мощные расчеты

Page 10: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)
Page 11: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

История разработки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

Page 12: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

2014 Custom REST API, SQL importIntegrations with other JIRA plugins

2015 JIRA Data Center supportSeparate child JVM process

2016 New UI design improvements

История разработки

Page 13: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Упрощенная архитектураИсточники данных

JIRA импорт

REST импорт

CSV импорт

МногомерныйOLAP куб

ИзмеренияФакты

схема “звезды”

Pасчетные формулы используя язык MDX

Создание табличных отчетов

Создание панелей из несколько отчетов

Гаджеты на рабочем столе JIRA и на страницах Confluence

Создание диаграмм разных типов

Page 14: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Основные технические компоненты

MySQLPostgre

SQLOracle MS

SQL

JRuby on Rails

Mondrian OLAP

Page 15: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)
Page 16: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)
Page 17: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

<?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 или …

Page 18: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 19: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Фреймворк веб приложенийRuby on Rails

ActionController

ActiveRecord

ActionView

Browser

Request Router

Response

Database

SQL

Page 20: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Продукты

eazyBICloud

eazyBIfor JIRA

PrivateeazyBI

Page 21: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 22: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

ИнтеграцияeazyBI / JRuby

c JIRA Java API

Page 23: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Вызов 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

Page 24: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Поддержка разных версий 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

Page 25: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Исследование, как получить данные из

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

Page 26: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Извлечение файлов из 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

Page 27: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Поддержка разных СУБД

Page 28: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 29: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 30: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 31: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 32: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Другие различия

• Размер имени таблиц/колонок в Oracle (до 30 символов)

• Разный синтаксис и функции SQL

• Разные типи данних

• Разные исключения и ошибки

Page 33: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Общая JIRA JVM JIRA JVM process heap

JIRA objects…

……

Plugin 1…

……

Plugin 2…

……

eazyBI…

……

Mondrian OLAP engine…

……

Results cache

Page 34: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Дочерний JVM процесс JIRA JVM process heap

JIRA objects…

……

Plugin 1…

……

eazyBI…

……

eazyBI child processMondrian OLAP engine

……

eazyBI…

……

Results cache

HTTP

Page 35: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Atlassian Connect –фреймворк для

JIRA Cloud плагинов

Page 36: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

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

Page 37: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Импорт 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

Page 38: «История разработки eazyBI», Raimonds Simanovskis (eazyBI, Латвия)

Ключевые факторы успеха

• Гибкая архитектура

• JVM платформа

• Повторное использование существующих библиотек

• Участие в open source проектах:JRuby, Ruby on Rails, Mondrian