• Nebyly nalezeny žádné výsledky

2020ŠtěpánPotsch AbsolvováníindividuálníodbornépraxeIndividualProfessionalPracticeintheCompany VŠB–TechnickáuniverzitaOstravaFakultaelektrotechnikyainformatikyKatedrainformatiky

N/A
N/A
Protected

Academic year: 2022

Podíl "2020ŠtěpánPotsch AbsolvováníindividuálníodbornépraxeIndividualProfessionalPracticeintheCompany VŠB–TechnickáuniverzitaOstravaFakultaelektrotechnikyainformatikyKatedrainformatiky"

Copied!
42
0
0

Načítání.... (zobrazit plný text nyní)

Fulltext

(1)

VŠB – Technická univerzita Ostrava Fakulta elektrotechniky a informatiky

Katedra informatiky

Absolvování individuální odborné praxe

Individual Professional Practice in the Company

2020 Štěpán Potsch

(2)
(3)
(4)
(5)

Rád bych poděkoval společnosti TietoEVRY a mému manažerovi Mgr. Zdeňku Dřízgovi za mož- nost absolvování bakalářské praxe. Dále bych chtěl poděkovat Mgr. Ing. Michalu Krumniklovi, Ph.D. za vedení a pomoc při vypracování mé práce. Na závěr chci poděkovat mému kolegovi Janu Bauerovi a celému týmu stážistů, bez kterých by tato práce nikdy nevznikla.

(6)

Abstrakt

Tato práce popisuje průběh mé individuální bakalářské praxe ve společnosti TietoEVRY a také vysvětluje, proč jsem se rozhodl pro volbu bakalářské praxe místo absolvování školní bakalářské práce. Na úvod si představíme společnost TietoEVRY a moje působení na několika projektech na pozici software developera. Poté se detailně věnuji analýze, návrhu, implementaci a testo- vání aplikace MessageCourier, jakožto hlavního projektu mé bakalářské praxe. V závěru shrnuji dosažené výsledky a hodnotím bakalářskou praxi ve společnosti.

Klíčová slova: bakalářská praxe, TietoEVRY, Java, Maven, Spring Framework, Hibernate, JPA, PostgreSQL, UCMA, C#, back-end

Abstract

This Bachelor Thesis describes the course of my individual Bachelor Practice in TietoEVRY and also explains why I decided to choose my Bachelor Practice instead of completing my Bachelor Thesis at school. At the beginning, we will introduce TietoEVRY and my work on several software developer projects. I deal in detail with the analysis, design, implementation and testing of MessageCourier as the main project of my bachelor work. In conclusion I summarize the achieved results and evaluate the bachelor’s practice in the company.

Keywords: bachelor practice, TietoEVRY, Java, Maven, Spring Framework, Hibernate, JPA, PostgreSQL, UCMA, C#, back-end

(7)

Obsah

Seznam použitých zkratek a symbolů 8

Seznam obrázků 9

Seznam zdrojových kódů 10

1 Úvod 11

2 O společnosti TietoEVRY 13

2.1 Tieto . . . 13

2.2 EVRY . . . 13

2.3 Čím se společnost zabývá? . . . 13

3 Moje působení v TietoEVRY 15 3.1 Projekty . . . 15

3.2 Text to speech . . . 15

4 Webová aplikace MessageCourier 17 4.1 Analýza požadavků . . . 17

4.2 Use-case . . . 18

4.3 Vzhled . . . 19

4.4 Architektura . . . 20

4.5 Volba technologií . . . 21

4.6 Relační datový model . . . 22

4.7 Doménový model . . . 24

5 Popis zvolených technologií 26 6 Implementace 27 6.1 Jádro systému . . . 27

6.2 Skype služba . . . 34

7 Testování 36 7.1 Unit testy . . . 36

7.2 Integrační testy . . . 38

8 Závěr 40

Literatura 42

(8)

Seznam použitých zkratek a symbolů

API – Application Programming Interface

BCNF – Boyce–Codd normal form

BI – Business Intelligence

CRM – Customer Relationship Management

CRUD – Create Read Update Delete

DOM – Document Object Model

ERP – Effective radiated power

JPA – Java Persitence API

JSON – JavaScript Object Notation

LDAP – Lightweight Directory Access Protocol REST – Representational State Transfer

SMS – Short Message Service

UCMA – Unified Communications Managed API

UML – Unified Modeling Language

UUID – Universally Unique Identifier

(9)

Seznam obrázků

1 Zjednodušený use-case aplikace MessageCourier . . . 18

2 Front-end - Registrace interní aplikace do systému MessageCourier . . . 19

3 Front-end - Správa aplikace a jejich uživatelů . . . 19

4 Zjednodušená architektura aplikace Message Courier . . . 20

5 UML diagram relačního datového modelu v BCNF . . . 23

6 Zjednodušené schéma třídního diagramu . . . 24

7 Sekvenční diagram - žádost o kontaktování zaměstnanců podle přednastavení . . 25

8 Konfigurace PostgreSQL databáze v souboru application.yml . . . 27

(10)

Seznam zdrojových kódů

1 Definice UUID ve třídě UserDB na perzistentní vrstvě . . . 28

2 Vazba 1:N implementována ze strany rodiče (ApplicationDB) v tomto vztahu . . 29

3 Vazba N:1 implementována ze strany potomka (PresetDB) v tomto vztahu . . . 29

4 Třída reprezentující vztah mezi uživatelem, aplikací a aplikační rolí . . . 30

5 Rozhraní IMapper bez implementace výchozích funkcí pro mapování kolekcí . . . 31

6 Hlavička třídy UserMapper . . . 32

7 Funkce ve třídě SecurityUtils - ověřuje, zda je uživatel správce aplikace . . . 32

8 Implementace funkce update ve třídě ApplicationController . . . 33

9 Unit test na uložení aplikačního přednastavení s rolí MAINTAINER . . . 37

10 Funkce ve třídě UserControllerTests s anotací @BeforeEach . . . 38

11 Funkce ve třídě UserControllerTests s anotací @AfterEach . . . 39

12 Integrační test pro vytvoření uživatele s již existujícím loginem . . . 39

(11)

1 Úvod

Během svého studia jsem se rozhodl pro absolvování bakalářské praxe hned z několika důvodů.

Jeden z nejhlavnějších důvodů bylo mě již známé prostředí společnosti TietoEVRY a možnost podílení se na interních projektech. Mým cílem bylo získat nové praktické zkušenosti v prostředí nadnárodní společnosti a učit se od profesionálů vývoj aplikací.

Moje práce je rozdělena do několika částí. V první části si představíme společnost Tieto- EVRY, která se na začátku mé praxe jmenovala pouze Tieto a uvedeme si největší zásluhy této firmy. Dále popisuji své působení ve společnosti na pozici software developera a zmiňuji projekty, na kterých jsem měl možnost se podílet.

Další část je věnována popisu interní aplikace MessageCourier, která je hlavním předmětem této práce. Tato aplikace má za úkol umožnit zasílání zpráv z aplikací vyvíjených v TietoEVRY všem zaměstnancům společnosti, převážně na platformu Skype for Business. Na tomto projektu jsem pracoval s mým kolegou Janem Bauerem. Jelikož jsem v té době měl zkušenosti převážně s vývojem back-end částí systémů, rozhodli jsme se, že kolega bude zodpovědný za návrh a implementaci front-end části a já budu mít na starosti back-end. Největší motivací pro mě byla možnost vyzkoušet si kompletní vývoj softwaru od jeho návrhu až po jeho nasazení.

Protože jsme tvořili zcela nový systém, velice důležitou částí mé bakalářské praxe byla ana- lýza požadavků. Ze začátku byly požadavky na systém nejasné a jednalo se spíše o testování možností komunikačního rozhraní Skype for Business. Pro tyto účely jsem musel požádat tech- nickou podporu o založení testovacího Skype for Business účtu. Teprve po první úspěšně odeslané textové zprávě a úspěšně navázaném audio hovoru se začaly řešit jednotlivé případy použití, v té době ještě bezejmenné aplikace. Jelikož hlavním případem použití je právě doručení zprávy zaměstnancům, dostala aplikace název MessageCourier. Ostatní případy použití se týkaly pře- vážně administrace registrovaných aplikací. Z těchto případů použití jsem poté navrhl relační datový model pro databázi.

Obrovská výhoda nově vznikající aplikace byla možnost volby technologií. Díky této možnosti jsem mohl pracovat s moderními, v praxi běžně používanými technologiemi jako je například framework Spring. Protože používaných technologií na tomto projektu nebylo vůbec málo, věnuji tomuto tématu dvě sekce. V sekci Volba technologií si popíšeme kde a proč jsme využili zvolené technologie a v sekci Popis zvolených technologií si tyto technologie detailněji představíme.

V práci si také ukážeme vzhled výsledné aplikace, který se podle mého názoru kolegovi velice povedl. Uživatelské rozhraní je přívětivé a jednotlivé prvky rozumně umístěné. Navíc již v úvodu prozradím, že pro tvorbu uživatelského rozhraní využil velice populární knihovnu React, která mě velice zaujala svou myšlenkou rozdělit uživatelské rozhraní do co nejmenších, znovupoužitelných komponent, které výrazně redukují duplicitu kódu.

Další kapitola se věnuje implementaci vybraných komponent v back-end částech a popisuje použití jednotlivých nástrojů v praxi. Implementace systému je rozdělena do dvou podsekcí, protože se aplikace dělí z hlediska back-endu na dvě hlavní části. První část se zabývá imple-

(12)

mentací jádra systému. Druhá část je věnována implementaci služby zodpovědné za komunikaci se Skype for Business.

Po implementaci přichází na řadu testování a s ním spojené úkoly. Během bakalářské praxe jsem se setkal s dvěma typy testů. Jedny mají za úkol otestovat pouze určitou komponentu nebo chování pouze jedné funkce. Těmto testům se říká Unit testy. Účelem je rozdělit systém na co nejmenší části, které je možné testovat. Implementace takovýchto testů je velice jednoduchá a provádí se běžně již při implementaci systému. Druhý typ testů má otestovat funkčnost několika komponent dohromady, tyto testy se nazývají integrační. Jsou poměrně složitější a píší se větši- nou při dokončení větších, souvislých komponent. Implementace obou typů testů je popsána v sekci Testování.

(13)

2 O společnosti TietoEVRY

TietoEVRY se sídlem ve Finsku zaměstnává kolem 24 000 odborníků po celém světě. Společnost obsluhuje tisíce zákazníků z veřejného sektoru ve více než 90 zemích. Roční obrat TietoEVRY je přibližně 3 miliardy EUR a její akcie jsou kótovány na NASDAQ v Helsinkách a Stockholmu, jakož i na Oslo Børs. [1] Tato společnost vznikla spojením dvou obrovských společností Tieto a EVRY v prosinci 2019.

2.1 Tieto

Tieto je největší skandinávská IT společnost, která v Ostravě a v Brně zaměstnává více než 2600 lidí. Podílejí se na projektech pro severské zákazníky, za kterými pravidelně každý měsíc až 200 z nich cestuje. Tieto má vlastní start-upový program Tieto Nerds, v rámci kterého pod- poruje kreativní nápady českých inovátorů a spojuje je s byznysem svých zákazníků. Společnost je známá svou severskou kulturou založenou na respektu, důvěře a vyváženosti pracovního a osobního života. Dlouhodobě patří mezi pět vysněných IT společností českých studentů. [2]

2.2 EVRY

EVRY je jednou z největších technologických a poradenských společností v severském regionu s více než 8 800 zaměstnanci, kteří pracují se vším od služeb datových center a implementace podnikových systémů, přes odborné poradenství a AI. [3]

2.3 Čím se společnost zabývá?

Produkty společnosti usnadňují každodenní život a automatizují procesy milionům lidí na celém světě. Největší dopad mají hned v několika odvětvích.

2.3.1 Telekomunikace

S telekomunikacemi má Tieto už více než třicet let zkušeností. Za tu dobu vytvořili řadu aplikací a stali se jedním z největších telekomunikačních odborníků na světě. Dnes se díky softwaru vyvinutému v TietoEVRY ve světě uskuteční každou sekundu telefonní hovor.

Mezi top produkty lze zařadit produkt s názvem Evolved Signaling Controller, který umí řídit a směrovat signalizace v sítích 2G, 3G a 4G a v nadcházející síti 5G. Umožňuje provozovatelům sítí snadno znovu využít kapacitu, Tento produkt také slouží jako náhrada za řešení, kterými jsou signaling transfer point (STP), signaling relay point (SRP) a intelligent signaling gateway (SGW). Zahrnuje také funkci signalizace brány firewall pro ochranu sítí před bezpečnostními hrozbami.

(14)

2.3.2 Výrobní průmysl

Výrobní průmysl je dnes větší a rychlejší než kdykoli předtím. Aby byly firmy schopné se v takovém prostředí pohybovat, potřebují software. TietoEVRY k tomuto přispívá automatizací výroby, budováním chytrých továren, vyhodnocováním výrobních dat a programováním robotů nebo 3D tiskáren.

2.3.3 Energetický, ropný a plynárenský průmysl

Projekty z tohoto odvětví má TietoEVRY po celém světě, nejvíce pak v severských zemích. Tvoří například systémy sledující výrobu a dodávky energií v reálném čase nebo komplexní klientská prostředí pro odběratele.

2.3.4 Zdravotnictví a sociální služby

Největším projektem na kterém společnost v tomto odvětví pracuje je on-line zdravotní karta, díky které doktoři v cizí zemi hned ví potřebné informace. Součástí tohoto projektu je také systém, ve kterém se uživatel může podívat kdy byl naposled nemocný nebo kdy by bylo dobré zajít na preventivní kontrolu k doktorovi. Společnost zároveň přináší inovace do nemocnic, na kliniky, do lékařských laboratoří nebo do systému domácí péče a péče o seniory.

2.3.5 Strojírenství a lesnictví

8 z 10 největších lesnických, papírenských a balicích společností na světě jsou zákazníci Tie- toEVRY. Zajímavé jsou například systémy, které umožňují ovládání strojů přes X-box Kinect ke Google Glass. TietoEVRY vytváří a spravuje komplexní systémy pro lesnické a strojírenské firmy. Automatizuje procesy, hlídá výroby, kontroluje stroje a umožňuje přehlednou komunikaci se zákazníky.

2.3.6 Maloobchod

Každý maloobchodní prodej má trochu jiná specifika. V TietoEVRY se proto řeší jak větší sys- témy obsahující funkčnosti spadající do kategorií ERP, BI, CRM nebo Big Data, tak taky menší aplikace využitelné konkrétním prodejcem v místě prodeje. Často na tabletu nebo v mobilním telefonu. Takové aplikace mohou obsahovat individuální záznamy konkrétních zákazníků, aktu- ální trendy, komplexní informace o nabízeném zboží, vyhodnocování prodejů a podobně. To vše navíc často už v cloudu.

(15)

3 Moje působení v TietoEVRY

Do společnosti TietoEVRY jsem nastoupil na pozici software developera v prvním ročníku baka- lářského studia. Před nástupem jsem musel absolvovat přijímací pohovor a vstupní test. Začátky byly velice těžké, neboť bylo potřeba seznámit se se spoustou technologií a nástroji. Za zmínku stojí především nástroj Git, bez kterého si dnes běžný programátor jenom těžko dovede před- stavit svoji práci.

3.1 Projekty

První rok jsem se podílel na vývoji Android aplikace s názvem Quizzer, která slouží k otes- tování znalostí nově příchozích stážistů. Na tomto projektu jsem se naučil pracovat se sadou softwarových balíčku pro android a se správcem balíčků Gradle.

Ve druhém ročníku jsem dostal za úkol vypracovat back-end šablonu projektu určeného pro nováčky, který má za úkol seznámit je s používanými technologiemi. Zde jsem se naučil pracovat s Java frameworkem Spring a také používat správce balíčků Maven. Během roku jsem se také zapojil do úprav interní aplikace Locker.

Před začátkem třetího ročníku za mnou přišel manažer s návrhem, zda nechci provést výzkum technologií sloužících k převodu textu na řeč. Z tohoto návrhu se později zrodila aplikace s názvem MessageCourier, kterou popisuji dále v této práci.

3.2 Text to speech

Při výzkumu technologií v oblasti převodu textu na řeč jsem narazil na tři největší zastupitele v tomto odvětví. Jako první jsem narazil na společnost Amazon Web Services. Jejich technologie umožňující převod textu na řeč se jmenuje Amazon Polly1. Tento produkt podporuje dva styly mluvení. První stylčtení je přizpůsobený případům, kde je potřeba sdělit zprávu a druhý styl mluvení je ideální pro obousměrný přenos komunikace. Tato služba umožňuje měsíčně převést na řeč až 5 miliónů znaků zdarma a má podporu pro 30 jazyků.

Další zkoumaný produkt byl od společnosti Microsoft s názvem Speech2. Jejich možnosti byly srovnatelné s technologií Amazon Polly. Speech podporuje až 60 různých jazyků a umožňuje mluvit až 75 různými hlasy. V době mého výzkumu však byla plynulost řeči v českém jazyce znatelně horší, proto jsem od této technologie nakonec ustoupil.

Jako poslední jsem zkoumal produkt Cloud Text-to-Speech3 od společnosti Google. Jejich technologie umožňuje mluvit 180 různými hlasy ve více než 30 jazycích. Pro převod textu na řeč je možné zvolit použití technologie WaveNet od společnosti DeepMind, která zmenšuje mezery mezi jednotlivými slovy až o 70%, čímž výrazně zvyšuje plynulost řeči. Cloud Text-to-Speech umož-

1https://aws.amazon.com/polly/

2https://azure.microsoft.com/cs-cz/services/cognitive-services/text-to-speech/

3https://cloud.google.com/text-to-speech

(16)

ňuje měsíčně převod až 4 miliónů znaků zdarma a podporuje jakékoliv zařízení nebo aplikaci, která je schopná poslat REST požadavek. Pro tyto přednosti jsem zvolil právě tuto technologii.

(17)

4 Webová aplikace MessageCourier

Cílem projektu bylo vytvořit komunikační rozhraní mezi interními aplikacemi a zaměstnanci společnosti. Jedním z hlavních požadavků na systém bylo umožnit interním aplikacím kontak- tovat zaměstnance pomocí komunikačního kanálu Skype for Business a to pomocí textové a hlasové zprávy. Další důležitý požadavek byl navrhnout systém tak, aby byl lehce rozšiřitelný o další komunikační kanály jako jsou Email, Slack nebo Teams.

Kvůli hlasové zprávě byla nutná funkcionalita převodu textu na řeč, protože implementace takové knihovny byla v rámci mého projektu nemyslitelná, rozhodl jsem se udělat výzkum exis- tujícíh knihoven umožňujícíh převod textu na řeč. Nejlépe mým požadavkům vyhovoval produkt od společnosti Google s názvem Cloud Text-to-Speech. Další výzkum bylo nutné provést kvůli technologii umožňující komunikaci s aplikací Skype for Business. Požadavky na tuto technologii byly prosté. Navázání spojení se Skype serverem, odeslání textové zprávy uživateli, navázání audio hovoru s uživatelem a přehrání hlasové zprávy. Zde jsem využil výhody veliké společnosti a obrátil se na zkušenějšího kolegu, který má na starost správu firemního komunikačního kanálu Skype for Business. Pro tyto účely mi doporučil použití sady pro vývoj softwaru UCMA 5.0 od společnosti Microsoft. Obě technologie si představíme dále v sekci Popis zvolených technologií.

4.1 Analýza požadavků

V této sekci se věnuji analýze požadavků pomocí zodpovězení klíčových otázek.

4.1.1 Co?

Cílem je navrhnout informační systém, který umožní interním aplikacím informovat zaměstnance o nějaké události, například kritickém stavu aplikace. Tyto interní aplikace jsou vyvíjeny týmem stážistů a slouží například pro správu sdílených míst k sezení ve firmě nebo k rezervaci skříněk.

Aplikace může zaslat přímý požadavek nebo požadavek podle přednastavení, nejdříve však musí být řádně registrovaná v administrační části našeho systému. V přímém požadavku musí být uvedeni zaměstnanci, kteří mají být kontaktováni, zpráva, která má být poslána a služby, kterými mají být zaměstnanci kontaktováni. V požadavku podle přednastavení se zasílá pouze UUID existujícího přednastavení, podle kterého jsou zaměstnanci, zpráva a služby načteny.

4.1.2 Jak?

Implementace agilním vývojem za použití metodiky Scrum.

4.1.3 Kde?

Aplikace bude složena z několika částí. Nejdůležitější částí bude jádro systému (message-courier- backend-core) odpovědné za komunikaci s datovým zdrojem a jednotlivými komunikačními služ- bami. Jádro systému bude přijímat požadavky od micro služby (message-courier-micro-service),

(18)

což bude rozhraní definující možnosti naší aplikace. Poslední částí projektu je webový klient pro administraci našeho systému a správu přednastavených požadavků.

4.1.4 Kdo?

Uživatel v aplikaci může vystupovat ve třech rolích

• ADMIN - úplná kontrola nad systémem

• MAINTAINER - práva na správu registrovaných aplikací a vytvořených přednastavení

• USER - má přístup k aplikacím, u kterých má přiřazenou roli

Každý uživatel s rolí USER může být spojen s registrovanou aplikací těmito rolemi

• APP_MAINTAINER - může spravovat aplikaci a její přednastavení

• APP_USER - má přístup k aplikaci a může používat její přednastavení 4.1.5 Kdy?

Když bude potřeba kontaktovat zaměstnance o stavu interní aplikace. Tahle potřeba může být pro každou aplikaci odlišná a záleží na uživateli, pro jaké typy zpráv tento systém využije.

4.1.6 Proč?

Kritické stavy aplikací vyžadují rychlé jednání, proto je potřeba včas informovat pověřené osoby ohledně stavu aplikace.

4.2 Use-case

Při návrhu systému jsem si případy použití vyjádřil hned několika obrázky. Pro účely této práce jsem vytvořil zjednodušený use-case viz obr. 1, který zobrazuje hlavní případy použití aplikace.

(19)

4.3 Vzhled

Na front-end části bylo potřeba navrhnout uživatelské rozhraní pro správu aplikací, předna- stavení a uživatelů. Celý vzhled aplikace navrhoval a implementoval můj kolega z týmu Jan Bauer, proto se tato práce zabývá především řešením problémů back-end částí. Zde můžeme vidět ukázky uživatelského rozhraní z administrační sekce aplikace viz obr. 2, 3.

Obrázek 2: Front-end - Registrace interní aplikace do systému MessageCourier

Obrázek 3: Front-end - Správa aplikace a jejich uživatelů

(20)

4.4 Architektura

Dalším úkolem bylo navrhnout architekturu systému. Rozdělit systém na jednotlivé komponenty a rozhodnout, jak spolu budou komunikovat. Po několika návrzích jsem došel k závěru, že se bude aplikace skládat z pěti hlavních komponent [4] .

• message-courier-backend-core - Jádro systému. Vyřizuje požadavky od klienta (message- courier-frontend) a od našeho balíčku definující komunikační rozhraní (message-courier- micro-service)

• message-courier-frontend - Webová aplikace s uživatelským rozhraním pro správu aplikací, přednastavení a pro administraci systému.

• message-courier-micro-service - Rozhraní definující komunikaci s jádrem. Obsahuje imple- mentaci všech dostupných požadavků pro kontaktování zaměstnance.

• message-courier-skype-service - Zajišťuje komunikaci s platformou Skype for Business.

Zodpovědná za navázání a ukončení spojení, odeslání textové zprávy nebo provedení audio hovoru.

• relační databáze - Aplikační data budou uložena v relační databázi. Zde bude potřeba ukládat informace o uživatelích, o provedených požadavcích a jejich výsledcích.

(21)

4.5 Volba technologií

Na řadu přišla volba technologií pro jednotlivé komponenty. U většiny komponent jsem si mohl vybrat, kterou technologii zvolím. Jediná komponenta, u které jsem byl nucen použít platformu .NET Framework je skype služba. Tato potřeba vyplývá z použití vývojové sady UCMA 5.0, která je na .NETu závislá.

4.5.1 Databáze

Jako datový zdroj jsem zvolil relační databázi PostgreSQL 11. S platformou PostgreSQL mám dobré předchozí zkušenosti, proto jsem se rozhodl spolehnout na ni. K databázi se dá přistupovat přes nástroj PgAdmin, který je dostupný na všech platformách.

4.5.2 Back-end

Back-end systému se skládá ze dvou hlavních částí.

• Jádro - jádro systému zajišťující komunikaci s databází a Skype službou jsem se rozhodl implementovat v jazyce Java s využitím aplikačního rámce Spring, protože jsou mi tyto technologie dobře známé z předchozích projektů. Potřebné knihovny budou spravovány pomocí nástroje Apache Maven, který je určen pro správu, řízení a automatizaci buildů aplikací. Ačkoliv je možné použít tento nástroj pro projekty psané v různých programo- vacích jazycích, podporován je především jazyk Java. Jako implementaci rozhraní JPA využiji aplikační rámec Hibernate, který umožňuje objektově relační mapování.

• Skype služba - kvůli použití vývojové sady UCMA 5.0 a její závislosti na .NET Framework 4.5 využijeme programovací jazyk C#. Tvorba webové aplikace v jazyce C# pro mě byla zcela nová, proto jsem musel věnovat náležitý čas studiu jeho dokumentace. Použití této technologie tedy pro mě bylo nejvíce bolestivé, k čemuž přispěla i míra zastaralosti plat- formy .NET ve verzi 4.5.

4.5.3 Front-end

Jako hlavní jazyk pro front-end aplikace vybral kolega Javascript s velmi populární knihovnou React. Tato knihovna je založena na myšlence rozdělení uživatelských prvků do co nejmenších komponent, které redukují duplicity a umožňují maximální znovupoužitelnost kódu. Vykreslo- vání uživatelského rozhraní probíhá zcela na straně klienta, což maximalizuje rychlost provedení příkázů nezávislých na odpovědi back-end části systému.

(22)

4.6 Relační datový model

Dalším úkolem byl návrh relačního datového modelu, který vycházel z jednotlivých případů použití, které jsou shrnuty ve zjednodušeném obrázku [1]. V aplikaci je potřeba ukládat infor- mace o zaměstnancích ve dvou podobách. Jednou jako uživatele, který má přidělenou roli v systému a může mít také aplikační role svázané s registrovanou aplikací. Druhá možnost, jak se může zaměstnanec v aplikaci vyskytnout, je jako kontakt, kterému má být doručena zpráva z registrované aplikace. Tyto informace reprezentují následující entity.

• EmployeeDB - Udržuje informace o uživateli, včetně jeho fotografie.

• UserDB - Zaměstnanci je přidělena uživatelská role. Uživateli je umožněno přihlásit se pomocí webového klienta do administrační sekce a podle přiřazených oprávnění může se systémem zacházet.

• ContactDB - Spolu s informacemi o zaměstnanci může udržovat ještě telefonní číslo, na kterém je možné zaměstnance zastihnout. Zaměstnanec se nemůže přihlásit do adminis- trační sekce a nemá přístup k žádným registrovaným aplikacím.

Dále je v aplikaci potřeba ukládat registrované aplikace a jejich přednastavení. Tento vztah je reprezentován vazbou 1:N ze strany aplikace. Stejným vztah s aplikací mají také požadavky na kontaktování zaměstnance a entity reprezentující vztahy mezi uživateli, aplikacemi a aplikačními rolemi.

• ApplicationDB - Udržuje data o registrované aplikaci, která používá funkcionalitu systému Message Courier a je rozšířena o balíček message-courier-micro-service

• PresetDB - Přednastavení můžeme chápat jako šablonu pro často se opakující požadavky.

• UserApplicationRoleDB - Reprezentuje vztah mezi uživatelem, aplikací a aplikační rolí.

Asi nejdůležitější informace v aplikaci jsou data o provedených požadavcích a jejich vý- sledcích. Tyto informace jsou uchovávány v entitách RequestDB a ResultDB. Jejich vztah je reprezentován vazbou 1:1. Vlastníkem cizího klíčeresultId je entita RequestDB.

• RequestDB - Obsahuje informace o požadavku na kontaktování zaměstnance.

• ResultDB - Výsledek požadavku na kontaktování zaměstnance.

(23)

Obrázek 5: UML diagram relačního datového modelu v BCNF

(24)

4.7 Doménový model

V této sekci si ukážeme dva diagramy. První diagram bude třídní. Popisuje statickou strukturu systému, znázorňuje datové struktury, možné operace a souvislosti mezi objekty. Druhý bude sekvenční diagram pro hlavní případ použití naší aplikace. Sekvenční diagram zachycuje časově uspořádanou posloupnost zasílání zpráv mezi objekty.

4.7.1 Třídní diagram

Protože třídní diagramy všech částí aplikace jsou velice obsáhlé, vybral jsem jako ukázku třídní diagram doménové vrstvy jádra systému [6]. Tato vrstva definuje celkové chování systému. Roz- hraní EmailServiceLocal a SkypeService specifikují možnosti pro dané platformy. Rozhraní User- Service, ContactService, ApplicationService a PresetService definují převážně CRUD metody.

Poslední rozhraní RequestService obsahuje dvě funkce pro zpracování dvou různých požadavků na kontaktování zaměstnance. Jedna funkce je pro přímý požadavek, druhá funkce slouží pro požadavek podle přednastavení.

(25)

4.7.2 Sekvenční diagram

Jako příklad jsem vybral sekvenční diagram pro hlavní případ použití aplikace, tedy pro žádost o kontaktování zaměstnance z registrované aplikace v systému. Tato funkcionalita je podporována ve dvou režimech. Jednou jako přímý požadavek, podruhé jako požadavek podle přednastavení.

Uvedený sekvenční diagram [7] popisuje druhou variantu.

Obrázek 7: Sekvenční diagram - žádost o kontaktování zaměstnanců podle přednastavení

(26)

5 Popis zvolených technologií

PostgreSQL je výkonný, objektově relační databázový systém, který používá a rozšiřuje ja- zyk SQL v kombinaci s mnoha funkcemi, které bezpečně ukládají a škálují nejsložitější pracovní zatížení dat. Původ PostgreSQL sahá do roku 1986 jako součást projektu POSTGRES na Uni- versity of California v Berkeley a má více než 30 let aktivního rozvoje na základní platformě.

[4]

Spring Framework je nejoblíbenější framework pro vývoj aplikací pro podnikovou Javu.

Miliony vývojářů po celém světě používají Spring Framework k vytvoření vysoce výkonného, snadno testovatelného a opakovaně použitelného kódu. Spring framework je open source plat- forma Java. Původně jej napsal Rod Johnson a byl poprvé vydán pod licencí Apache 2.0 v červnu 2003. Spring je velice malý, pokud jde o velikost. Základní verze frameworku Spring má kolem 2 MB. Základní vlastnosti platformy Spring Framework lze použít při vývoji jakékoli aplikace Java, navíc existují rozšíření pro vytváření webových aplikací na platformě Java EE. [5]

Apache Maven je nástroj pro správu, řízení a automatizaci buildů aplikací. Ačkoliv je možné použít tento nástroj pro projekty psané v různých programovacích jazycích, podporován je pře- devším jazyk Java. [6]

Hibernate je open-source framework, který poskytuje určitou abstrakční vrstvu, což znamená, že se programátor nemusí starat o implementaci některých funkcí. Hibernate provádí implemen- tace interně, jako je navázání spojení s databází, psaní dotazu pro provádění CRUD operací nebo objektově relační mapování. [7]

.NET Framework je platforma pro vývoj softwaru vyvinutá společností Microsoft. Hlavním cílem je vytvářet aplikace, které fungují na platformě Windows. [8]

Unified Communications Managed API (UCMA) 5.0 je platforma pro vývoj aplikací s přístupem k informacím společnosti Microsoft. Hlavní funkcionality, které v projektu využívám, jsou zasílání zpráv a telefonní hovory.

Cloud Text to speech převádí text na řeč podobnou člověku ve více než 180 hlasech ve více než 30 jazycích a variantách. Poskytuje průkopnický výzkum v syntéze řeči (WaveNet) a

(27)

6 Implementace

Protože smyslem této práce není kompletní dokumentace systému, nebudeme si popisovat všechny komponenty. Pro každou vrstvu si však vysvětlíme základní principy implementace a předsta- víme si nejzajímavější úkoly a jejich řešení.

6.1 Jádro systému

Jako první jsem z firemního GitLabu stáhl šablonu pro Spring Boot projekt. Tato šablona má již přednastavené závislosti na balíčky určené pro tvorbu webové aplikace poskytované skupinou org.springframework.boot. Jádro se skládá celkem ze tří vrstev. Každá vrstva má svoje vlastní modely a struktura kódu je rozložena do oddělených balíčků.

6.1.1 Perzistentní vrstva

Perzistentní vrstva má za úkol čtení a zápis do databáze. Balíček pro tuto vrstvu jsem nazval repositories. Jako první bylo potřeba stáhnout klienta pro databázi PostgreSQL s názvem PgAd- min a vytvořit databázi. Informace o databázi je potřeba umístit do konfiguračního souboru s názvemapplication.properties nebo application.yml. Podle přípony se liší struktura konfigurač- ního souboru. Pro projekt MessageCourier jsem zvolil příponuyml. V této konfiguraci je potřeba uvést platformu naší databáze, url adresu na které je databáze přístupná, ovladač k databázi a uživatelské jméno s heslem pro ověřený přístup. Konfigurace pro platformu PostgreSQL [8].

Obrázek 8: Konfigurace PostgreSQL databáze v souboru application.yml

Největší výzva na perzistentní vrstvě byla implementace vazby mezi uživatelem, aplikací a aplikační rolí. Problém jsem řešil vytvořením entity UserApplicationRoleDB se složeným primár- ním klíčem, nejprve si však popišme entity UserDB a ApplicationDB. Entita UserDB představuje uživatele systému. Někoho, kdo bude spravovat registrované aplikace a přednastavení, nebo bude k nim bude mít alespoň přístup. Tato třída udržuje základní informace o uživateli. Obsahuje uživatelovo ID, login, jméno, příjmení, email, fotku, datum vytvoření uživatele a uživatelskou

(28)

roli. Entita ApplicationDB představuje registrovanou aplikaci v systému. Takto registrovaná aplikace poté může používat systém MessageCourier a skrze něj posílat zprávu zaměstnancům společnosti. Tato třída obsahuje aplikační ID, jméno, datum registrace, jméno uživatele, který provedl registraci, všechny aplikační přednastavení a požadavky na kontaktování zaměstnance, které aplikace provedla.

Nad obě třídy umístíme anotaci @Entity, která je součástí balíčku javax.persistence.Entity. V této anotaci můžeme uvést nepovinný parametrname, který udává název tabulky v databázi.

Pokud tento parametr neuvedeme, tabulka bude mít jméno podle třídy. Abych třídy v projektu udělal přehlednější, pro implementaci getterů, setterů a konstruktorů, používám v projektu kni- hovnuLombok a její anotace @Data, @NoArgsConstructor a @AllArgsConstructor.

Pro označení primárního klíče umístíme nad proměnnou anotaci @Id. Pro třídu UserDB chceme vyjádřit primární klíč jako číselnou hodnotu, proto bude proměnná primitivního typu long. U třídy ApplicationDB použijeme třídu UUID z balíčkujava.util. Primární klíč poté může vypadat takto 28dc8c12-8766-d35a-3e55-c3bfcfa73321. Pomocí anotace @GeneratedValue mů- žeme nastavit způsob generování primárního klíče. Tato anotace může obsahovat dva parametry strategy agenerator. Prvnímu parametrustrategy můžeme nechat výchozí hodnotuGeneration- Type.AUTO. Druhý parametr generator nastavíme pouze u třídy ApplicationDB na libovolný řetězec, který bude reprezentovat název našeho generátoru. Tento název poté použíjeme v další anotaci @GenericGenerator jako první parametrname a druhý parametrstrategy nastavíme na org.hibernate.id.UUIDGenerator, což nám zaručí automatické generování našich UUID. Jelikož je tato proměnná instance třídy a ne primitivní typ, může v aplikaci nabývat hodnotynull, což v databázi nechceme. Také nechceme, aby bylo možné tento primární klíč aktualizovat. Toto chování nám zaručí anotace @Column tím, že nastavíme její parametryupdatable anullable na false. Tato anotace umožňuje další omezení na databázi, například pomocí paramatruuniquena- stavuje jedinečnost hodnoty v databázi nebo pomocí parametrulength udává maximální velikost řetězce. Výsledná definice UUID poté může vypadat takto [1].

@Id

@GeneratedValue(generator = "UUID")

@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")

@Column(updatable = false, nullable = false) private UUID id;

Zdrojový kód 1: Definice UUID ve třídě UserDB na perzistentní vrstvě

(29)

a List<RequestDB>. Tímto jsme definovali jako rodiče těchto vztahů třídu ApplicationDB. Pro- tože u třídy reprezentující přednastavení chceme přistupovat i k rodiči od potomka, musíme za- vést oboustrannou vazbu. Toho docílíme přídáním anotace @ManyToOne do třídy PresetDB nad proměnnou typu ApplicationDB. Je důležité, jak tuto proměnnou pojmenujeme, protože se na ni poté odkazujeme v parametru anotace @OneToMany. Tento parametr má názevmappedBy. Protože chceme po smazání registrované aplikace odstranit i její potomky, přídáme do této anotace ještě parametrcascades hodnotou CascadeType.REMOVE. Implementaci oboustranné vazby můžeme vidět ve zdrojových kódech [2] a [3].

/**

* One to Many mapping from ApplicationDB - parent in this relationship

*/

@OneToMany(mappedBy = "application", cascade = CascadeType.REMOVE) private List<PresetDB> presets;

Zdrojový kód 2: Vazba 1:N implementována ze strany rodiče (ApplicationDB) v tomto vztahu

/**

* Many to One mapping from PresetDB - child in this relationship

*/

@ManyToOne(fetch = FetchType.LAZY) private ApplicationDB application;

Zdrojový kód 3: Vazba N:1 implementována ze strany potomka (PresetDB) v tomto vztahu Nyní víme jak vypadají primární klíče u aplikací i uživatelů, můžeme tedy sestavit složený klíč. Pro tyto účely jsem vytvořil třídu s názvem UserApplicationId. Tato třída musí implemen- tovat rozhraní Serializable z balíčkujava.io a nad třídu musíme uvést anotaci @Embeddable z balíčkujava.persistence. Nesmí chybět také dvě proměnné. Jedna proměnná primitivního typu long s názvem userId a druhá instance třídy UUID s názvem applicationId.

Složený klíč máme vytvořený, nyní je potřeba implementovat třídu, která bude reprezentovat tabulku v databázi. Třídu jsem nazval UserApplicationRoleDB a přidal jí již známou anotaci

@Entity. Naše tabulka se bude skládat ze tří sloupců. První sloupec bude ID uživatele, druhý ID aplikace a poslední sloupec bude Enum vyjadřující roli uživatele. Pro každý sloupec v tabulce bude naše třída potřebovat proměnnou a to jednu typu UserDB, druhou ApplicationDB a třetí bude Enum, který jsem nazval EApplicationRole. Navíc však bude mít instanci vytvořeného složeného klíče, před kterou přidáme anotaci @EmbeddedId. Díky této anotaci Spring ví, že má s proměnnou zacházet jako se složeným klíčem. K tomu, aby byl schopen správně namapovat objekty do proměnných typu UserDB a ApplicationDB, však bude potřeba přidat ještě dvě anotace před tyto proměnné. První anotace je @ManyToOne s parametrem nastaveným

(30)

na hodnotuFetchType.LAZY, která nám u uživatele zajistí, že bude moci vystupovat v několika aplikacích najednou a u aplikace nám zaručí, že s ní může mít svázaných hned několik uživatelů.

Druhá anotace @MapsId přijímá parametr typu String. Zde uvedeme názvy našich proměnných z třídy UserApplicationId reprezentující náš složený klíč. Pro uživatele to tedy bude userId a pro aplikaciapplicationId. Implementace třídy UserApplicationRoleDB [4].

@Data

@NoArgsConstructor

@Entity(name = "user_application_role") public class UserApplicationRoleDB {

@EmbeddedId

private UserApplicationId userApplicationId;

@ManyToOne(fetch = FetchType.LAZY)

@MapsId("userId") private UserDB user;

@ManyToOne(fetch = FetchType.LAZY)

@MapsId("applicationId")

private ApplicationDB application;

@Column(nullable = false)

@Enumerated(EnumType.STRING)

private EApplicationRole applicationRole;

public UserApplicationRoleDB(

UserDB user, ApplicationDB application, EApplicationRole applicationRole) { this.userApplicationId =

new UserApplicationId(user.getId(), application.getId());

this.user = user;

this.application = application;

this.applicationRole = applicationRole;

} }

Zdrojový kód 4: Třída reprezentující vztah mezi uživatelem, aplikací a aplikační rolí Zde již máme vytvořené třídy určující strukturu dat v databázi. Nyní musíme implemen-

(31)

žaduje referenci na naši třídu s anotací @Entity, v tomto případě tedy UserDB a druhý parametr přijímá datový typ jejího ID, tedy primitivní datový typlong. Tímto máme zajištěno, že kompo- nenta UserRepository bude mít implementována všechny CRUD operace nad entitou UserDB.

Spring nabízí více rozhraní, než pouze CrudRepository, jako například PagingAndSortingRepo- sitory nebo JpaRepository, které jsou obohaceny o další funkcionality.

6.1.2 Doménová vrstva

Na doménové vrstvě je řešena veškerá logika aplikace. Rozhraní, které tuto logiku rozdělují do jednotlivých funkcí se nazývají služby nebo-liservices. Každá služba má na starosti chování jediné entity. Rozhraní vyjadřující chování uživatele v systému jsem nazval UserService. Chování tohoto rozhraní poté implementuje třída s příponouImpl.

Prvním úkolem bylo vytvořit modely pro tuto vrstvu. Začal jsem tedy duplikovat modely z perzistentní vrstvy ochuzené o anotace. Během vývoje došlo k různým úpravám nad těmito modely a také bylo potřeba vytvořit několik dalších pomocných modelů. Jelikož každá vrstva má své vlastní modely, dochází v aplikace k časté potřebě namapovat modely z jedné vrstvy na modely vrstvy druhé. K tomuto účelu jsem vytvořil rozhraní s názvem IMapper. Rozhraní přijímá tři generické datové typy. První datový typ je model z vrstvy koncových bodů, druhý datový typ je model z doménové vrstvy a poslední datový typ je model z vrstvy perzitentní.

Rozhraní IMapper definuje funkce pro mapování modelů ze sousedních vrstev a implementuje výchozí funkce pro mapování kolekcí. Implementace rozhraní IMapper bez výchozích funkcí [5].

public interface IMapper<DTO, PO, DB> {

DTO mapPOtoDTO(PO source);

PO mapDTOtoPO(DTO source);

DB mapPOtoDB(PO source);

PO mapDBtoPO(DB source);

}

Zdrojový kód 5: Rozhraní IMapper bez implementace výchozích funkcí pro mapování kolekcí Nyní, když máme definovanou abstrakci maperů, můžeme implementovat mapery pro jed- notlivé modely. Pro uživatele jsem vytvořil třídu s názvem UserMapper. Tato třída implemen- tuje vytvořené generické rozhraní s těmito datovými typy IMapper<UserDTO, User, UserDO>.

Protože UserDTO ještě neexistuje, vytvořil jsem prozatím prázdnou třídu. Nyní bylo potřeba implementovat vytváření nového objektu z modelu jiné vrstvy. Pro tyto účely dobře poslou- žil návrhový vzor Builder. Abychom mohli používat funkcionalitu aplikačního rámce vkládání závislostí, je potřeba umístit nad naši třídu anotaci @Component [6].

Další zajímavý problém na doménové vrstvě bylo řešení oprávnění k určitým operacím. Jako příklad si uvedeme aktualizace registrované aplikace. Provést tuto operaci smí uživatel s rolí

(32)

@Component

public class UserMapper implements IMapper<UserDTO, User, UserDB>

Zdrojový kód 6: Hlavička třídy UserMapper

ADMIN nebo MAINTAINER, ale také uživatel s rolí USER, který má u této registrované apli- kace aplikační roli APP_MAINTAINER. Pro tyto účely jsem vytvořil třídu s názvem Securi- tyUtils. Zde přistupuji k informacím o uživateli, který zaslal požadavek a kontroluji, zda má požadované role. Abych však zkontroloval jestli má uživatel nějakou roli spjatou s registrova- nou aplikací, bude zapotřebí nejprve načíst aplikaci a všechny s ní svázané role z databáze.

Objekty představující tuto vazbu se nazývají UserApplicationRole a mají tři proměnné, stejně jako na perzistentní vrstvě. Tyto proměnné jsou ID uživatele, ID aplikace a Enum aplikační role. Poté procházím výsledky a hledám shodu s uživatelem, který poslal požadavek na aktua- lizaci registrované aplikace. Pokud je shoda nalezena, provede se kontrola, zda se aplikační role rovná APP_MAINTAINER. Pouze pokud se shodují i role, vrací funkce boolean hodnotu true.

Implementace funkce pro zjištění informace, zda je majitel požadavku aplikační správce [7].

public boolean isApplicationMaintainer(Application application) { User user = getSignedInUser();

for (UserApplicationRole userApplicationRole : application.getUserApplicationRoles()) {

if (userApplicationRole.getUserId() == user.getId() &&

userApplicationRole.getApplicationRole() .equals(EApplicationRole.APP_MAINTAINER)) { return true;

} }

return false;

}

Zdrojový kód 7: Funkce ve třídě SecurityUtils - ověřuje, zda je uživatel správce aplikace Jelikož s aktualizací registrované aplikace je spojené také ukládání vztahů mezi uživateli a aplikacemi, může nastat situace, kdy tato funkce bude během svého vykonávání zapisovat více řádků do databáze. Abychom v případě selhání některé z operací předešly problémům s nekon- zistentní databází, můžeme využít anotaci @Transactional, která nám zajistí, že s funkcí bude

(33)

umístil do balíčku s názvem controllers. Konvence pojmenování tříd zůstává stejná jako na doménové vrstvě, pouze přípona Service se mění na Controller. Modely pro tuto vrstvu mají příponu DTO. V jejich definicích používám anotace z balíčkujavax.validation.constraints, které nám umožní validovat data příchozího požadavku, pouze díky anotaci @Valid.

Komunikace s rozhraním REST probíhá primárně prostřednictvím URI adres, HTTP metod a textového obsahu. V aplikaci MessageCourier používám pět základních metod. Metodu POST pro vytváření zdroje, PUT pro aktualizace, DELETE pro mazání, GET pro získání a OPTIONS využívá front-end pro zjištění možností koncového bodu. V mém projektu jsou data přenášena ve formátu JSON. Abych jádru aplikace umožnil přijímat tyto požadavky, bylo potřeba vytvořit tzv. REST kontroler. V rámci zachování kontextu si ukážeme implementaci kontroléru, který zpracovává požadavek na aktualizaci registrované aplikace. Pro tyto účely jsem vytvořil třídu s názvem ApplicationController, před kterou jsem umístil anotaci @RestController. Další potřebná anotace je @RequestMapping, která vyžaduje jako parametr textový řetězec definující část URI adresy, pod kterým tento koncový bod bude dostupný. Protože ApplicationController bude mít na starosti všechny požadavky týkající se registrovaných aplíkací v našem systému, pro tento parametr jsem zvolil textový řetězec /application. Dále do této třídy musíme přidat závislosti na námi vytvořené komponenty ApplicationService a ApplicationMapper. V celém projektu převládá implementace vkládání závislostí pomocí konstruktoru, která je využita i zde. Dále implementuji funkci s názvem update, která vrací datový typ ApplicationDTO a také přijímá parametr stejného datového typu. Před tento parametr jsem umístil anotace @Valid, která nám zvaliduje objekt podle námi zvolených anotací ve třídě DTO a anotaci @RequestBody, která zaručí, že uvedený parametr je posílán v těle požadavku. Uvnitř této funkce provádím potřebné mapování a volám metodu pro aktualizaci aplikace z komponenty ApplicationService. Výsledná implementace funkceupdate ve třídě ApplicationController [8].

/**

* Check for permissions in Service layer

* Only Admins, Maintainers and App_Maintainers are allowed update application

*/

@PutMapping

public ApplicationDTO update(@Valid @RequestBody ApplicationDTO applicationDTO) { return applicationMapper.mapPOtoDTO(

applicationService.update(

applicationMapper.mapDTOtoPO(applicationDTO)) );

}

Zdrojový kód 8: Implementace funkce update ve třídě ApplicationController

(34)

6.2 Skype služba

Dalším úkolem byla implementace Skype služby. Tato služba má na starosti komunikaci s inter- ním Skype for Business serverem. Zodpovídá za navázání spojení, přenos textových nebo audio dat a ukončení spojení. Tato služba byla vyvíjena v programovacím jazyku C# pro cílenou plat- formu .NET Framework 4.5. Její hlavní komponentou je sada pro vývoj softwaru UCMA 5.0.

Aby možnosti této sady byly funkční, je potřeba nainstalovat modul UcmaRuntimeSetup.exe.

Tato služba se podobně jako jádro systému skládá z vrstvy koncových bodů, na které posílá jádro požadavky a z doménové vrstvy, která implementuje chování Skype služby.

6.2.1 Audio hovor

Na doménové vrstvě byla jednoznačně nejzajímavějším úkolem implementace audio hovoru.

Tento hovor, díky technologii Enterprise Voice, nemusí být pouze na klienta Skype for Busi- ness, ale může být proveden také na telefonní číslo.

6.2.1.1 Koncový bod

Pro přijímání požadavků na audio hovory jsem vytvořil třídu s názvem CallController. Tato třída dědí ze třídy ApiController, která je definována ve jmenném prostředíSystem.Web.Http. V této třídě implementuji funkci MakeCall, která přijímá jako parametr datový typ CallRequestWrap- per. Tento objekt obsahuje zprávu v textové podobě, bytové pole s audio zprávou, list s kontakty, kterým má být zpráva doručena a informaci, zda chceme volat na Skype for Business klienta nebo telefonní číslo. Nad funkci MakeCall je třeba umístit do hranatých závorek zvolenou HTTP metodu, v našem případěHttpPost. Poslední příkaz, který je nutno v kontroleru provést, je vy- tvoření objektu z doménové vrstvy s názvem CallService, zavolat na něj metodu ProcessCalls a předat jí jako parametr náš objekt datového typu CallRequestWrapper.

6.2.1.2 Doménová vrstva

Hlavní komponentou doménové vrstvy je výše zmíněná třída SkypeService. Její metoda Pro- cessCalls zapouzdřuje správné provedení audio hovorů nekolika zaměstnancům najednou. Pro zajištění paralelního provedení hovorů bylo potřeba pro každý hovor vytvořit nové vlákno. V tomto vlákně se poté vytvoří UserEndpoint, reporezentující zaměstnance, kterého se snaží sys- tém kontaktovat. Poté je potřeba vytvořit objekt typu Conversation, který se skládá z instance třídy UserEndpoint a instance třídy ConversationSettings obsahující nastavení spojení. Takto vytvořenou konverzaci poté předáme jako parametr do konstruktoru třídy AudioVideoCall, která

(35)

6.2.2 Textová zpráva

Dalším zajímavým úkolem byla implementace zasílání zpráv na Skype for Business klienta. V případě telefonních čísel máme smůlu, protože zasílání SMS naše sada pro vývoj softwaru UCMA neumožňuje.

6.2.2.1 Koncový bod

Pro příjem požadavků na zaslání textových zpráv slouží třída s názvem MessageController.

Tato komponenta dědí, stejně jako CallController, ze třídy ApiController. Existuje v ní pouze funkce SendMessage, před kterou je umístěna v hranatých závorkách HTTP metodaHttpPost. Tato metoda přijímá parametr datového typu MessageRequestWrapper a jako odpověď vrací datový typ MessageReposnseWrapper. Uvnitř těla funkce vytvářím instanci třídy MessageSer- vice z doménové vrstvy a následně volám její funkci ProcessMessages s parametrem datového MessageRequestWrapper. Její výsledek poté vracím jádru našeho systému.

6.2.2.2 Doménová vrstva

Na doménové vrstvě je řešení problému velice podobné implementaci audio hovoru, avšak na- rozdíl od paralelního volání jsem zvolil sériové posílání zpráv, a to především kvůli rychlosti vyřizování požadavků. Logiku posílání zpráv implementuje třída s názvem MessageService a její metoda ProcessMessages, která prochází jednotlivé kontakty a pro každý kontakt volá funkci SendMessage. Tato metoda, podobně jako při navázní audio hovoru, vytvoří nejprve UserEn- dpoint a ConversationSettings. Tyto dva objekty předá do kontruktoru třídy Conversation, ze které poté vytvoří instanci třídy InstantMessagingCall. Tato instance již obsahuje vše potřebné k odeslání textové zprávy, stačí na ni pouze zavolat funkci BeginEstablish. U poslání textové zprávy implementuji pouze pozorovatel změny stavu našeho spojení, abych byl schopen určit, zda se zpráva poslala.

6.2.3 Výjimky

Jelikož při komunikaci se Skype for Business serverem může dojít ke spoustě vyjímek, bylo potřeba tyto vyjímky patřičně ošetřit a dám vědět našemu jádru systému, co se vlastně stalo. Pro tyto účely jsem vytvořil třídu ExceptionWrapper, která je součástí každé odpovědi na požadavek audio hovoru nebo textové zprávy. Tato třída v sobě uchovávábool hodnotu o tom, zda nastala nějaká vyjímka. Kromě této hodnoty obsahuje také zprávu s popisem vyjímky a její stavový kód. Na straně jádra systému poté nahlížím do těchto objektů a zjišťuji, zda vše proběhlo v pořádku nebo nastala nějaká chyba.

(36)

7 Testování

Už v průběhu vývoje aplikace jsem psal po dokončení implementace komponenty jednotkové testy (Unit), které se soustředí čistě na vybranou komponentu a její závislosti nahrazuje tzv.

Mocky. Mock je objekt, který simuluje chování skutečné služby kontrolovaným způsobem. Po- sledním velkým úkolem v mém projektu bylo kompletní testování aplikace. Takovému testování se říká integrační. V tomto projektu integrační testy posílají požadavky na implementované REST API a kontrolují správnost odpovědí. V projektu k testování využívám aplikační rámce JUnit a Mockito. Práci s nimi si ukážeme v následujících kapitolách.

7.1 Unit testy

Pro vytvoření Unit testů je potřeba vytvořit třídu a přidělit jí potřebné anotace. Jako pří- klad si uvedeme testování komponenty zajišťující služby ohledně přednastavení. Tato kompo- nenta se jmenuje PresetServiceImpl, naše testovací třída tedy bude mít název PresetService- ImplTest. Nejdůležitější anotací nad třídou je anotace @SpringBootTest, kterou můžeme po- užít k vytvoření kontextu aplikace obsahujícího všechny objekty, které potřebujeme pro výše uvedené typy testů. Další důležíté anotace jsou @RunWith(SpringRunner.class) a @Extend- sWith(MockitoExtension.class). První zmíněná anotace má za úkol propojit knihovny aplikač- ního rámce JUnit s testovacím prostředím ve Springu. Druhá anotace toto testovací prostředí rozšiřuje o aplikační rámec Mockito, na který je však potřeba nejprve uvést závislost v souboru pom.xml, který spravuje naše závislosti v celé aplikaci. Poslední anotace nad třídou @ActivePro- files("unit") zaručí spuštění testů s nastavením ze souboruapplication-unit.yml.

Všechny komponenty, které chceme v testech používat bez modifikací, uvedeme jako třídní proměnné s anotací @Autowired, která automaticky zajistí vkládání závistlostí, tedy nemusíme tyto třídy již nikde vytvářet pomocí klíčového slovanew. Komponenty, které však netestujeme a chceme určitým způsobem modifikovat jejich chování, označíme anotací @MockBean. V našem případě jsem tuto anotaci umístil nad komponentu LdapService, která získává data o uživatelích z firemního úložiště pomocí protokolu LDAP. Chování této komponenty chceme modifikovat z důvodu závislosti na aktuálních zaměstnancích firmy. Jelikož upravovat přednastavení pro registrovanou aplikaci můžou pouze pověřené osoby, bude potřeba používat také dříve zmíněnou komponentu SecurityUtils. Abychom mohli modifikovat její chování, umístíme před ni anotaci

@MockBean.

Protože k vytvoření aplikačního přednastavení potřebujeme mít registrovanou aplikaci, bu- deme v každém testu nuceni vytvářet aplikaci znovu a znovu. Abychom předešli duplikování

(37)

MAINTAINER a nebo APP_MAINTAINER. Díky rozšíření frameworku Mockito, je nahrazení chování komponenty SecurityUtils velice snadné. Stačí přidat před příkaz provádějící uložení aplikace do databáze volání metody Mockito.when(), která přijímá jako parametr funkci, kte- rou chceme modifikovat. Tato funkce vrací objekt datového typu OngoingStubbing, na kterém můžeme zavolat funkcithenReturn(), které jako parametr předáme námi požadovanou hodnotu true. Nyní volání metodyisAdmin() bude v testu vracet vždy boolean hodnotutrue.

Nyní můžeme přejít k samotným testům. Každý test musí být funkcí s návratovou hodno- tou void. Před funkcí nesmí chybět anotace @Test, která způsobí, že s funkcí bude zacházeno jako s testem. V těchto testech poté simluji vytváření nebo úpravu přednastavení aplikace a kontroluji správnost navrácených hodnot pomocí třídy Assert z balíčkuorg.junit. Pokud však v testu neočekáváme navrácení hodnoty, ale vyhození vyjímky, můžeme tuto vyjímku definovat v parametruexpected anotace @Test. Výsledná anotace tedy může vypadat takto @Test(expected

= PermissionException.class). Zdrojový kód Unit testu na uložení přednastavení [9].

@Test

public void savePresetTest_MAINTAINER() { // Mockito features

when(securityUtils.isAdmin()).thenReturn(false);

when(securityUtils.isMaintainer()).thenReturn(true);

// Define properties

List<Contact> contacts = Arrays.asList(

new Contact(0, "testlog1", "test@mail1", "testName1", null, null, null), new Contact(0, "testlog3", "test@mail2", "testName2", null, null, null) );

List<EServiceType> serviceTypes = Arrays.asList(

EServiceType.PHONE_CALL, EServiceType.SKYPE_CALL, EServiceType.SKYPE_MESSAGE );

// Save preset

Preset preset = presetService.save(

new Preset(null, null, message, name,

EPresetType.APPLICATION, applicationUUID, null, contacts, serviceTypes));

// JUnit features

Assert.assertNotNull(preset.getId());

Assert.assertEquals(contacts.size(), preset.getContacts().size());

Assert.assertEquals(serviceTypes.size(), preset.getServiceTypes().size());

Assert.assertEquals(preset.getApplicationUUID(), preset.getApplicationUUID());

}

Zdrojový kód 9: Unit test na uložení aplikačního přednastavení s rolí MAINTAINER

(38)

7.2 Integrační testy

Na závěr přišly integrační testy, se kterými jsem neměl doposud žádné zkušenosti. Začal jsem tedy hledat způsoby, jak se ve Springu takové testy dělají. K těmto účelům jsem využil technologii JUnit4, o které se zmiňuji v předchozí kapitole. Po několika testech jsem však usoudil, že je konfigurace zbytečně složitá a zkusil novější verzi JUnit5, která byla publikována na konci října v roce 2018. S novější verzí se mi pracovalo mnohem lépe, proto jsem se rozhodl zůstat u ní. S tímto přechodem byly také spojeny změny v aplikačních závislostech.

Jako příklad si uvedeme testování našeho kontroloru zodpovědného za přijímání požadavků ohledně uživatelů aplikace. Testovací třída ponese název UserControllerTests a bude mít celkem čtyři anotace. Nejdůležitější anotací je @SpringBootTest, která třídě umožňuje používat funkcio- nalitu testovacího prostředí aplikačního rámce Spring. Další důležitá anotace je @TestInstance, která se používá ke konfiguraci životního cyklu testovacích instancí pro anotovanou testovací třídu nebo testovací rozhraní. Poslední anotace jsou @ExtendWith(SpringExtension.class), která zajišťuje propojení testovacího prostředí s aplikačním rámcem JUnit5 a @ActiveProfile, která definuje konfigurační soubor.

Nejdůležitější třídou celého integračního testování je třída MockMvc, která umožňuje posílat požadavky na vystavené koncové body a testovat tak funkcionalitu celého systému. Abychom tuto komponentu mohli inicializovat, potřebujeme v naší třídě vytvořit proměnnou datového typu WebApplicationContext a označit anotací @Autowired. Nyní můžeme vytvořit instanci třídy MockMvc pomocí statické metodywebAppContextSetup na třídě MockMvcBuilder, která přijímá náš webový kontext aplikace dodaný pomocí vkládání závislostí. Tato statická metoda nám vrací objekt datového typu DefaultMockMvcBuilder, na kterém musíme zavolat metodu build()pro získání objektu MockMvc. Tato inicializace bude probíhat v metodě s anotací @Be- foreEach, která bude volána před každým testem v naší třídě UserControllerTests. Zdrojový kód metodybeforeEach, která je volána před každým testem [10].

@BeforeEach

public void beforeEach() throws Exception { this.mockMvc =

MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();

// Create dummy User before each test

UserDTO userDTO = mockMvcUtils.postForUser(mockMvc);

userId = userDTO.getId();

}

(39)

proměnné userId, podle které jsem schopen uživatele kdykoliv načíst z databáze a po každém testu uživatele smazat v metodě s anotací @AfterEach. Zdrojový kód metoduafterEach, která je volána po každém testu v testovací třídě [11].

@AfterEach

public void afterEach() throws Exception { // Delete dummy User after each test

this.mockMvc.perform(MockMvcRequestBuilders.delete("/users/{id}", userId)) .andExpect(status().isNoContent());

}

Zdrojový kód 11: Funkce ve třídě UserControllerTests s anotací @AfterEach

Samotné testy musí být funkce v naší testovací třídě s návratovou hodnotou void a anotací

@Test umístěnou před naší funkcí. Naše funkce může vyhodit vyjímku typu Exception kvůli využití funkceperform(RequestBuilder), která je součástí třídy MockMvc.

Jako příklad si ukažeme test, který se snaží vytvořit uživatele s již existujícím loginem.

Protože naše aplikace vyžaduje unikátnost loginu, očekáváme selhání testu s návratovým kódem 400, značícím špatný požadavek. Jako první nastavíme parametr výše zmíněné funkceperform na hodnotu naší HTTP metody a uvedeme cestu k našemu koncovému bodu. Tomuto požadavku je potřeba také nastavit typ obsahu požadavku a jeho samotný obsah, o což se postarají settery na našem Builderu, který vrací metodaperform. Implementace integračního testu, který se snaží vytvořit uživatele s již existujícím loginem [12].

@Test

void createUserWithExistingLogin() throws Exception {

// Create user with the same login as user created in @BeforeEach method Object user = new UserDTO(null, userLogin, userLogin,

userFirstName, userLastName, null, userRoles);

this.mockMvc.perform(MockMvcRequestBuilders.post("/users") .contentType(MediaType.APPLICATION_JSON)

.content(objectMapper.writeValueAsBytes(user)) .accept(MediaType.APPLICATION_JSON))

.andExpect(status().isBadRequest());

}

Zdrojový kód 12: Integrační test pro vytvoření uživatele s již existujícím loginem

(40)

8 Závěr

Během mé bakalářské praxe ve společnosti TietoEVRY se mi podařilo splnit všechny zadané úkoly. Na vlastní kůži jsem si vyzkoušel všechny fáze vývoje informačního systému MessageCou- rier. Na začátku bylo potřeba provést výzkum technologií spojených s převodem textu na řeč a s komunikací s firemní aplikací Skype for Business. Tento výzkum jsem považoval za velice důležitý, protože rozhodoval o tom, jestli se aplikace vůbec bude vyvíjet. Po otestování několika technologií jsem zvolil službuCloud Text to Speech pro převod textu na řeč a pro komunikaci s aplikací Skype for Business jsem použil balíček pro vývoj softwaru UCMA 5.0.

Jakmile jsem věděl s čím mohu v těchto oblastech pracovat, přišel na řadu návrh celé aplikace.

Požadavky na systém se během vývoje několikrát změnily, v této práci však převážně popisuji finální stav aplikace. Požadavky jsem analyzoval metodou zodpovězení šesti klíčových otázek.

Po analýze bylo potřeba rozkreslit jednotlivé případy použití. Mezitím co můj kolega Jan Bauer připravoval návrh vzhledu administrační sekce, zabýval jsem se architekturou systému a s ní spojenou volbou technologií pro jednotlivé části systému. Mezi klíčové technologie použité na back-endu patří Java a C#, na fron-endu je to Javascript s knihovnou React. Další návrh se týkal datové vrstvy a sestavení relačního datového modelu pro ukládání potřebných dat. Bylo potřeba definovat jednotlivé entity a jejich vzájemné vztahy. Na doménové vrstvě bylo potřeba rozdělit systém na komponenty zodpovědné pouze za určitou činnost a definovat jejich chování.

Tyto komponenty jsem popsal třídními diagramy a průběh jejich funkcí a komunikaci mezi jednotlivými objekty v čase jsem zaznamenal diagramy sekvenčními.

Jakmile byly návrhy hotové, mohli jsme přejít k implementaci systému. Mým úkolem byla implementace dvou back-end částí. První část se jmenuje message-courier-backend-core a je napsána v jazyce Java. Tato část je zodpovědná za zpracování všech HTTP požadavků a za komunikaci s databází. Dále je zodpovědná za komunikaci s druhou částí, kterou jsem měl za úkol implementovat. Tuto část jsem nazval message-courier-skype-service. Je zodpovědná za komunikaci s aplikací Skype for Business a je implementována v programovacím jazyce C#. V této práci se zabývám oběma částmi systému a detailně popisuji implementaci stěžejních částí aplikace na každé vrstvě.

Během vývoje systému MessageCourier jsem se setkal se dvěma typy testů. Jako první jsem psal Unit testy. Cílem těchto testů je ověřování správné funkčnosti dílčích částí zdrojového kódu. Tyto testy jsem psal již během implementace, po dokončení jednotlivých komponent.

Druhé testy, se kterými jsem se setkal, jsou testy integrační. Tyto testy jsem psal až na konci implementační fáze. Mají za úkol otestovat celý systém, tedy funkcionalitu komponent spojených

(41)

flexibilnímu návrhu systému, který předpokládal rozšíření aplikace o další komunikační kanály, je tato aplikace otevřená dalšímu vývoji nových služeb.

Svou praxi ve firmě TietoEVRY hodnotím velice pozitivně. Největším přínosem byla možnost pracovat s moderními technologiemi na novém projektu. Během působení ve firmě jsem měl možnost spolupracovat se staršími a zkušenějšími kolegy, od kterých jsem se toho spoustu naučil.

Velice mě potěšila také možnost práce v týmu, při které jsem se naučil správně plánovat úkoly a rozšířil své dovednosti s nástrojem Git. Díky velikosti společnosti jsem měl možnost komunikace s kolegy ze zahraničí, při čemž jsem mohl upevnit své znalosti anglického jazyka. Poprvé jsem měl možnost vyzkoušet v praxi fungovaní agilní metodiky Scrum, kterou jsem znal pouze z teoretického hlediska. Absolvováním této praxe jsem nasbíral mnoho zkušeností, které věřím a pevně doufám, dokážu uplatnit jak v pracovním, tak v osobním životě.

(42)

Literatura

1. TietoEVRY [online] [cit. 2020-10-03]. Dostupné z: https : / / www . tietoevry . com / en / about-us/our-company/.

2. Tieto [online] [cit. 2020-10-03]. Dostupné z:https://www.tieto.com/cz/about-us/our- company/.

3. EVRY [online] [cit. 2020-10-03]. Dostupné z: https://www.evry.com/en/about- evry/

company-information/.

4. PostgreSQL[online] [cit. 2020-10-03]. Dostupné z:https://www.postgresql.org/about/. 5. Spring Framework [online] [cit. 2020-10-03]. Dostupné z: https://www.tutorialspoint.

com/spring/spring_overview.htm.

6. Apache Maven [online] [cit. 2020-10-03]. Dostupné z: https://maven.apache.org/what- is-maven.html.

7. Hibernate [online] [cit. 2020-10-03]. Dostupné z: https : / / www . geeksforgeeks . org / introduction-to-hibernate-framework/.

8. .NET Framework [online] [cit. 2020-10-03]. Dostupné z: https : / / dotnet . microsoft . com/learn/dotnet/what-is-dotnet.

9. Cloud Text to speech [online] [cit. 2020-10-03]. Dostupné z: https://cloud.google.com/

text-to-speech.

10. React[online] [cit. 2020-10-03]. Dostupné z:https://www.tutorialspoint.com/reactjs/

reactjs_overview.htm.

Odkazy

Související dokumenty

Při řešení všech úkolů, které mně byly zadány, jsem využil teoretické znalosti, které jsem získal během studia na vysoké škole.. Rovněž bylo velice důležité

Systém VIKIPID je propojen s eAPI platební brány ČSOB. Zákazník přistupuje k platební bráně skrz webovou aplikaci VIKIPID Brána, ve které si před přesměrováním k

Měl jsem za úkol vytvořit plugin, který bude sloužit pro vytváření dárků k objednávce, které zákazník dostane zdarma při nákupu nad určitou cenu.. Tento plugin má za

4.4.2.2 Vstup pro výběr předdefinovaných dat s výběrem pouze jedné položky HTML elementy typu input nebo select, díky kterým si zákazník vybere nastavení z předdefi-

Byl to sice úkol jen na cca 3 hodiny a šlo čistě jen o připravení vzhledu, ale byl jsem rád, že jsem tento úkol dostal právě já, protože drobné úpravy na již

Student měl během práce na starosti vývoj automati- zovaných testů uživatelského rozhraní pro programy Sencha Architect, Sencha Themer a Liferay, dále se podílel na úpravě

Architekti TIXu v něm navíc z nějakého důvodu nechtějí implementovat stránkování a řazení záznamů na straně serveru, z toho důvodu to bylo nutné implementovat ve

Vývoj DivvyPay je poměrně dynamický, průběžně vznikají nové funkce a opravují se chyby, je proto nutné mít vždy k dispozici poslední sestavení aplikace.. 4.2.2