Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

3,479 views

Published on

eazyBI позволяет легко строить отчеты и графики, являясь одним из самих популярных JIRA-плагинов на Atlassian Marketplace. Основатель и главный разработчик eazyBI Раймондс Симановскиc приехал из Латвии, чтобы рассказать об эволюции eazyBI из отдельного веб-приложения в набор из нескольких продуктов с различными вариантами развертывания.

Published in: Software
  • Be the first to comment

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

  1. 1. История разработки Raimonds Simanovskis @rsim
  2. 2. Из Латвии
  3. 3. Из Юрмалы
  4. 4. В Москве в 2003 году
  5. 5. Что такое Easy-to-use Business Intelligence web application ?
  6. 6. Различные источники данных Импорт данных
  7. 7. Простое создание отчетов
  8. 8. Много разных диаграмм
  9. 9. Мощные расчеты
  10. 10. История разработки 2011 eazyBI.com hosted service REST API import2012 Private eazyBI standalone server eazyBI plugin 2013 Atlassian UI design framework eazyBI add-on for JIRA Cloud
 using Atlassian Connect data import
  11. 11. 2014 Custom REST API, SQL import Integrations with other JIRA plugins 2015 JIRA Data Center support Separate child JVM process 2016 New UI design improvements История разработки
  12. 12. Упрощенная архитектура Источники данных JIRA импорт REST импорт CSV импорт … Многомерный OLAP куб Измерения Факты схема “звезды” Pасчетные формулы используя язык MDX Создание табличных отчетов Создание панелей из несколько отчетов Гаджеты на рабочем столе JIRA и на страницах Confluence Создание диаграмм разных типов
  13. 13. Основные технические компоненты MySQL Postgre SQL Oracle MS SQL JRuby on Rails Mondrian OLAP
  14. 14. <?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 или …
  15. 15. 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
  16. 16. Фреймворк веб приложений Ruby on Rails Action Controller Active Record Action View Browser Request Router Response Database SQL
  17. 17. Продукты eazyBI Cloud eazyBI for JIRA Private eazyBI
  18. 18. Build & Deploy Ruby on Rails application JRubyTorqueBox Application Gems .com deploy Mondrian OLAP engine Other Java libraries Packaged application Application Gems TorqueBox Privatepackage plugin OSGi bundle JRuby *.jar Application Gems jruby-rack package
  19. 19. Интеграция eazyBI / JRuby c JIRA Java API
  20. 20. Вызов JIRA Java API module 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 end end
  21. 21. Поддержка разных версий 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 end end
  22. 22. Исследование, как получить данные из JIRA Service Desk jcft = 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.0 elsif 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
  23. 23. Извлечение файлов из jar арxива плагина # expand rails.root and gem.home bundle directories $bundle = $servlet_context.getClass.getClassLoader.getBundle m_archive_field = $bundle.java_class.declared_field("m_archive") m_archive_field.accessible = true bundle_archive = m_archive_field.value($bundle) jar_content = if bundle_archive.respond_to?(:getRevisionCount) bundle_archive.getRevision(bundle_archive.getRevisionCount - 1).getContent else bundle_archive.getCurrentRevision.getContent end %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
  24. 24. Поддержка разных СУБД
  25. 25. eazyBI accounts Account 1 Account 2 Account N Projects A,B Project C Projects X,Y,Z DB schema eazybi_jira_dwh_1 Measur Dimensi Dimensi DimensiDimensi DB schema eazybi_jira_dwh_2 Measur Dimensi Dimensi DimensiDimensi DB schema eazybi_jira_dwh_N Measur Dimensi Dimensi DimensiDimensi
  26. 26. MySQL databases eazybi_jira_dwh_1 jira_projects jira_statuses jira_issues … eazybi_jira_dwh_2 jira_projects jira_statuses jira_issues … eazybi_jira_dwh_3 jira_projects jira_statuses jira_issues … eazybi_jira users accounts cube_reports …
  27. 27. eazybi_jira database PostgreSQL, MS SQL schemas eazybi_jira_dwh_1 jira_projects jira_statuses jira_issues … eazybi_jira_dwh_2 jira_projects jira_statuses jira_issues … eazybi_jira_dwh_3 jira_projects jira_statuses jira_issues … default schema users accounts cube_reports …
  28. 28. 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 …
  29. 29. Другие различия • Размер имени таблиц/колонок в Oracle (до 30 символов) • Разный синтаксис и функции SQL • Разные типи данних • Разные исключения и ошибки
  30. 30. Общая JIRA JVM JIRA JVM process heap JIRA objects … … … Plugin 1 … … … Plugin 2 … … … eazyBI … … … Mondrian OLAP engine … … … Results cache
  31. 31. Дочерний JVM процесс JIRA JVM process heap JIRA objects … … … Plugin 1 … … … eazyBI … … … eazyBI child process Mondrian OLAP engine … … … eazyBI … … … Results cache HTTP
  32. 32. Atlassian Connect – фреймворк для JIRA Cloud плагинов
  33. 33. Atlassian Connect JIRA Cloud eazyBI Cloud iframe eazyBI web app … …JIRA Cloud accounts eazyBI jobs … … JIRA import REST API JWT authentication JWT authentication JIRA instance … … Data DB
  34. 34. Импорт JIRA issues используя REST API search startAt=0 maxResults=200 search startAt=200 maxResults=200 search startAt=400 maxResults=200 search startAt=600 maxResults=200 search startAt=800 maxResults=200 search startAt=1000 maxResults=200 HTTP 504 timeout
  35. 35. Ключевые факторы успеха • Гибкая архитектура • JVM платформа • Повторное использование существующих библиотек • Участие в open source проектах:
 JRuby, Ruby on Rails, Mondrian

×