1. Introduction
1.1. Overall Description
Dit document bevat ontwerpspecificaties voor de Klukkluk-applicatie, die gebruikt zal worden door schaakvereniging UVS om spelers bij te houden, indelingen te genereren voor verschillende competitietypen en om scores voor deze competities in te voeren.
1.2. Purpose of this document
Het doel van het SDD is om een gedetailleerde technische beschrijving te geven van het ontwerp van de ontwikkelde Klukkluk applicatie. Dit document bevat een schema van de databasestructuur, gepaard met diagrammen die de structuur van de Java-applicatie detailleren. Ook is dit document bedoeld voor toekomstige ontwikkelaars om een beeld te scheppen van de opbouw van de applicatie, en om gemaakte keuzes door de projectgroep toe te lichten.
2. Architectural Overview
3. Detailed Design Description
3.1. Deployment Diagram
Filesysteem
Klukkluk heeft een Java Virtual Machine van Java 17 nodig om te runnen op een systeem. Het kijkt dan in het file systeem van het systeem in kwestie naar een properties bestand in de "Klukkluk" directory onder "Documents" ("[User_home]/Documents/Klukkluk/klukkluk.properties"). In dit bestand slaat klukkluk de filepath op voor de database als het wordt aangewezen in de settings. Uit dit bestand haalt het ook de filepath voor de database wanneer het programma hierna wordt opgestart.
FTP
Verder maakt klukkluk ook verbinding met een FTP server, de login info van deze FTP server (username, password, server address, output filepath) staat ook in klukkluk.properties.
Systeem
Klukkluk is ontwikkelt op windows 10 en 11, KDE plasma 6 onder fedora linux 40. Het is ook bedoelt om te draaien op MacOS Ventura en Ubuntu linux (22.04).
3.2. Package Diagram
Voor de packages zijn een aantal keuzes gemaakt. Als eerste is er per klasse type een package gemaakt. Voor de repository klassen is dus een repositories package gemaakt, en voor de mapper klassen is een mappers package gemaakt. In de app package zitten alle controllers, zoals te heeft deze een connectie met services en repositories. Normaal gesproken zouden de controllers via de service een connectie hebben met de repositories. Bij ons was dit in het begin ook het geval, maar in sommige service klassen zat eigenlijk totaal geen functionaliteit en riepen deze alleen de repository aan, dit vonden wij niet echt nuttig en daarom zijn er enkele repositories zonder services waardoor de app package een directe connectie met de service package moet hebben. Ook is er gekozen om een algemeen utils package te maken, hierin staan vooral wat losse klassen die niet echt bij een andere package passen. In de repositories package zit ook een utils package, dit is gedaan voor de EntityManagerFactory. De EntityManagerFactory hoort niet echt direct bij de repositories en daarom zit deze in een aparte package.
3.3. Design Class Diagrams
3.3.1. App package
In de App package zitten vooral de main klassen van de applicatie zoals de MainWrapper en de Controller klassen. Om de applicatie te starten moet de main methode van de MainWrapper klasse aangroepen worden. In de Controller klassen staat alle code waarmee de front-end geregeld wordt. Voor elk scherm in de applicatie is een aparte controller gemaakt die communiceert met het front-end bestand. Op deze manier is de code van elke scherm gescheiden van elkaar.
3.3.2. DTO package
De methodes die in de klassen zitten van de DTO package zijn niet opgenomen in het bovenstaande diagram. Dit is niet opgenomen aangezien dit alleen maar getters en setters zijn en voor de rest geen lastige methodes bevatten. De DTO's zijn de Data Transfer Objects en bestaan om de data vanuit de database over te dragen naar de applicatie. De getters en setters zijn dus nodig om de variabelen binnen de klassen te vullen zodat deze data gebonden kan worden aan deze klassen.
3.3.3. Entities
De Entity klassen zijn eigenlijk een soort representatie van de database. De attributen van de entity klassen moeten overeen komen met de kolommen uit de database. De repositories gebruiken deze entities om data uit de database op te halen en daarom zijn deze entities dus gemaakt. Door entities samen met JPA te gebruiken kan er makkelijker gewisseld worden tussen database systemen omdat de JPA taal zelf regelt met welk database systeem gecommuniceert wordt.
3.3.4. Exceptions
In dit class diagram staan de exceptions die binnen het systeem gebruikt worden. De DatabaseException wordt gebruikt voor foutmeldingen die omhoogkomen bij het gebruik van de database. Naast de DatabaseException is er ook nog een ResourceException en een UserInputException. De ResourceException is net zoals de DatabaseException een RuntimeException en handelt foutmeldingen af die ontstaan door ontbrekende data. Stel dat er bijvoorbeeld een FXML bestand mist binnen de applicatie moet er wel een manier zijn om deze error op te vangen. Hierbij wordt dan dus de ResourceException gebruikt. Als laatste is er ook nog een UserInputException. Deze exception wordt gebruikt voor foutmeldingen die te maken hebben met de input die de gebruiker van de applicatie (onbedoeld) creëert. Stel dat de gebruiker een fout maakt met het invoeren van een rating, bijvoorbeeld dat deze per ongeluk wat letters invoert waar die niet de bedoeling is, dan wordt er met de UserInputException gewerkt om deze error af te handelen.
3.3.5. Mappers
De mappers zijn verschillende klassen die inkomende objecten omzetten naar een ander type object. Neem bijvoorbeeld de CompetitionTypeManger, deze class heeft een methode genaamd setCompetitionType die een entity ontvangt en een CompetitionTypeDTO teruggeeft. Een entity is informatie direct uit de database, een DTO bevat informatie die nog naar de database moet gaan. Om deze informatie te manipuleren wordt een entity dus eerst naar een DTO omgezet zodat er binnen de applicatie mee kan worden gewerkt. Vervolgens kan dit dan weer in de database worden gezet. Om dit zo te laten werken moet er dus wel een mogelijkheid zijn om de entities om te zetten naar DTO's. Daar zijn deze klassen dus voor.
3.3.6. Repositories
De repository functies beheren alle queries die uitgevoerd moeten worden op de database. Geen van de andere klassen kunnen direct op de database queries uitvoeren. Deze klassen kunnen gebruik maken van de methodes binnen de repository klassen om deze taken uit te voeren. De klassen kunnen ook de foutmeldingen van de database afhandelen door de exceptions te gebruiken uit de exceptions package binnen ons systeem. Dit zou dan de DatabaseException zijn.
3.3.7. Services
De services zijn de connectie tussen de controllers en de repositories ofwel de database. Deze laag zit er tussen om bijvoorbeeld te valideren of de data wel klopt.
3.3.8. Utils
In de Utils package staan verschillende soorten klassen. Er is bijvoorbeeld voor gekozen om hier de RatingCalculator klasse in te zetten omdat deze niet echt bij een andere package past. De RatingCalculator is gemaakt op basis van het sequence diagram van hoofdstuk 3.5.3. Omdat het maken van de indeling voor een toernooi gebruik maakt van een aparte java applicatie moesten er een aantal klassen gemaakt worden om tussen de twee systemen te kunnen communiceren. De gemaakte communicatie klassen zijn hierdoor opgenomen in de "Swiss" package binnen de utils.
3.4. Sequence Diagrams
3.4.1. SD UC1.2 createPlayer
3.4.2. SD UC2.1 createCompetition
3.4.3. CalculateNewRating
Voor het berekenen van de score heb je drie waarden nodig: rating1, rating2 en de score van rating1. De functie berekent altijd de score voor rating1. Als eerste wordt een expected score berekend, dit is een getal tussen 0 en 1. Met de rating, K-factor, score en expectedScore wordt de nieuwe rating berekend.
Dit systeem is gemaakt op basis van informatie uit de wikipedia pagina van een "Elo rating system" (Wikipedia contributors, 2024). Het gebruikte systeem wordt bij de FIDE (International Chess Federation) ook gebruikt.
3.4.4. SD UC8: Periodecompetitie indelingen
3.4.5. SD UC8: Meerkamp indelingen
3.4.6. SD UC8: Toernooi indelingen
3.4.7. SD UC9 uploaden naar website
3.4.8. SD UC 10 Printen indeling
In dit diagram word uitgelegd hoe het uploaden van de verschillende tabellen zit. Wanneer de gebruiker op de upload knop drukt wordt de pageservice aangeroepen met de geselecteerde competitie. De pageservice roept de methodes aan die horen bij het competitietypen. Deze methodes geven html files terug. Aan het einde wordt ook nog de globale ranglijst gemaakt aangezien dit voor alle typen gemaakt moet worden. Daarna worden de files geupload met behulp van de htmlservice.
3.5. Database Design
Zie hier het gemaakte PDM. Samen met het PDM bestand in de bestandenlijst dat o.a. te openen is via Powerdesigner zou het duidelijkheid moeten brengen over hoe het systeem in elkaar staat.
3.6. Design decisions for the sub-systems
3.6.1. Usecases
3.6.1.1. USECASE 1 - Beheren van spelers
Op het scherm voor het beheren van de spelers is gekozen voor een tabel waarin alle informatie over spelers staat, met daarboven een aantal invulvelden en knoppen waarmee de data bewerkt kan worden. Dit is volgens de projectgroep de meest overzichtelijke manier om een grote lijst met spelers snel en eenvoudig te beheren. Indien nodig kan de tabel namelijk per kolom gesorteerd worden, waardoor het vinden van specifieke spelers gestroomlijnd kan verlopen. Het inactief en actief maken van spelers en het vastleggen van de startrating zijn belangrijke handelingen, en zijn daardoor voorzien van een pop-up die om bevestiging van de actie vraagt, zodat bijvoorbeeld een speler niet per ongeluk inactief kan worden.
Voor deze implementatie wordt gebruikgemaakt van een servicelaag die de inputs van de gebruiker controleert op een aantal afgestelde regels, bijvoorbeeld of alle velden vereiste velden zijn ingevuld bij het invoeren van een nieuw lid of gast.
3.6.1.2. USECASE 2 - Beheren van competities
Het beheren van een competitie werkt in essentie hetzelfde als het beheren van spelers, maar een competitie heeft meer opties die de gebruiker moet kunnen bewerken, en deze opties hoeven niet in de tabel zichtbaar te zijn. Er is voor gekozen om alle instellingen voor een competitie in een kolom naast de tabel met competities te zetten. Ook is ervoor gekozen om op basis van welke soort competitie wordt gekozen bepaalde waarden automatisch in te vullen met een standaardwaarde. Dit allemaal om het gebruiken van de applicatie zo gestroomlijnd en gemakkelijk mogelijk te maken.
Ondanks dat er geen gebruik van wordt gemaakt is er ook voor gekozen om het aantal punten dat kan worden verdiend met een winst, verlies, gelijkspel etc. aanpasbaar te maken. Dit maakt Klukkluk flexibel mocht deze functionaliteit later gewenst zijn.
Ook deze usecase maakt gebruik van een servicelaag om de inputs van de gebruiker te controleren.
3.6.1.3. USECASE 3 & 4 - Beheren van competitiegroepen & Beheren van spelers in competitiegroep
Het scherm voor het beheren van competitiegroepen bevat veel informatie. Hierom is ervoor gekozen om de data weer te geven in een drietal tabellen, waarbij er onderscheid gemaakt wordt tussen de spelers die niet in een groep zitten, de groepen van de competitie, en de spelers die in de geselecteerde groep zitten. Op deze manier heeft de gebruiker overzicht over in welke groep deze bezig is, welke spelers hierin zitten en welke niet.
Als een competitie wordt aangemaakt worden aan de hand van het op het competitiescherm gekozen aantal, een aantal groepen automatisch aangemaakt, gelabeld "A, B, C" enzovoort.
Er is voor deze implementatie geen servicelaag aanwezig, er is namelijk bij het aanmaken van de groepen geen data aanwezig die de gebruiker op dit scherm aan kan passen. Het enige wat de gebruiker aan kan passen is de naam van de gegenereerde groepen.
3.6.1.4. USECASE 6 - Ronde resultaat invoeren
Bij het invoeren van ronde resultaten is gekozen om een scherm te maken waar je op basis van een groep de ronden en wedstrijden kunt zien, zodat duidelijk is waar een wedstrijd bij hoort. Voor het invoeren van resultaten zijn er keyboard shortcuts gemaakt voor Winst, Verlies en Gelijk, deze knoppen kun je activeren door op F1, F2 of F3 te drukken. Dit maakt het makkelijker voor de gebruiker om resultaten in te voeren, omdat er niet steeds op een knop gedrukt hoeft te worden. In de tabel is ook nog een systeem gemaakt waarmee de geselecteerde rij automatisch één naar beneden springt nadat er een resultaat ingevoerd wordt, hierdoor hoef je dus niet steeds opnieuw op een tabel rij te drukken om een resultaat in te voeren.
3.6.1.5. USECASE 7 - Resultaat externe ronde invoeren
Het invoeren van resultaten bij extern gespeelde rondes werkt op basis van de rating van de externe speler. De gebruiker kan een searchable combobox (drop-down menu) gebruiken om de juiste speler uit de database te selecteren, waarna er in een invulveld de rating van de externe speler ingevuld kan worden. Daarna kan de uitslag van de match uit een drop-down menu gekozen worden.
Het aanpassen van de rating van een speler is een belangrijke actie, daarom wordt er zodra de gebruiker op "opslaan" drukt een pop-up weergegeven met de vraag of de aanpassing bevestigt moet worden. Op deze pop-up wordt ook de nieuwe rating van de speler al getoond. De pop-up wordt gebruikt om te voorkomen dat de gebruiker per ongeluk de rating van de interne speler updatet wanneer dit niet de bedoeling is.
Er is gekozen voor een searchable combobox omdat deze in het geval van deze usecase voldoende informatie kan tonen, en het zoeken van enkele spelers eenvoudiger maakt dan een gehele tabel door moeten spitten.
3.6.1.6. USECASE 8 - Indeling genereren voor competitie
Het genereren van indelingen gaat op basis van vooraf gedefiniëerde systemen. Dit betekent dat de gebruiker, nadat deze groepen heeft gemaakt, alleen maar aan Klukkluk hoeft aan te geven dat deze indelingen wil laten genereren. De applicatie zal hierna op basis van het competitietype en de geselecteerde manier van indelen (relevant bij Heller-tabellen, waarbij er verschillende varianten zijn) de spelers in de groepen automatisch in rondes indelen.
3.6.1.6.1. Meerkamp
Het indelingssysteem voor Meerkamp maakt gebruik van een indeling op basis van de tabellenstructuur zoals beschreven in het door ons verrichtte onderzoek. Om deze indelingen te generen worden de spelers in zowel een lijst voor witte als zwarte spelers ingedeeld. Daarna worden deze lijsten door middel van SecureRandom gehusseld en wordt er daarna per ronde voor de matches een indeling gemaakt op basis van deze twee lijsten. Elke gemaakte matchup wordt tijdelijk opgeslagen om te voorkomen dat dezelfde indeling twee keer voorkomt. Op deze manier is elke meerkamp indeling anders en weten we zeker dat iedere speler altijd tegen elkaar speelt.
Indien een groep een oneven aantal spelers heeft wordt degene die overblijft ingedeeld tegenover een niet-ingevulde zwarte speler en wordt de match oneven verklaard. Nog steeds word ernaar gekeken dat elke speler tegen elkaar speelt.
3.6.1.6.2. Periodecompetitie
Het indelingssysteem voor de periodecompetitie gebruikt verschillende schema's om zijn indeling te maken. Deze worden gekozen voordat de indeling gemaakt wordt. De gebruiker moet kunnen kiezen in welk schema de competitie gegenereerd wordt vandaar dat het van te voren is gedaan.
De functie begint met het sorteren van de spelers op de volgorde van hoogste rating naar het laagste om te zorgen dat de gekregen schema's goed zouden werken. Hierna wordt er gecontroleerd hoeveel spelers er in de gekozen groep zit, zodat er rekening kan worden gehouden met eventuele oneven spelersaantallen. Een match met een ontbrekende speler (null) wordt bij ons als oneven getoond in de matches tabellen binnen een groep.
Hierna wordt de goede variatie gekozen d.m.v. het aantal spelers. Dit is gedaan met een switch case omdat het zo makkelijk is om mogelijk nieuwe opties toe te voegen in de toekomst. Om de matches te genereren wordt er door de variaties tabel geloopt zodat het altijd voor het juiste aantal rondes gebeurt. Mocht er dus een nieuwe variatie komen binnen de variatie tabel met bijvoorbeeld 6 rondes i.p.v. 5 dan zal het systeem zichzelf er op aanpassen.
Binnen deze loop van de rondes wordt er door generateLayout de matches gegenereerd. Deze matches worden toegevoegd aan een list van matches. De spelerslijst wordt samen met de ronde variatie, een rondeID en een groepID gebruikt om de matches te maken. Van ter voren worden de spelers omgezet naar players 1 en 2 in dezelfde volgorde van hoge rating naar lage rating.
Om te zorgen dat de mogelijk toegevoegde null speler ( oneven speler ) goed neergezet wordt wordt dit hierna gecheckt. Mocht er een null speler zijn wordt deze altijd neergezet als de zwartspeler. Het resultaat kan ook al worden ingevoerd in dit geval.
Na het aanmaken van de matches worden deze teruggestuurd en dan kan deze worden toegevoegd aan de ronde binnen de loop. Na het één keer aflopen van de loop is er ook één ronde gemaakt met matches. Deze kan samen met de matches na de loop worden meegegeven aan een nieuwe CompetitionLayoutDTO om zo de functie af te ronden.
Daarna worden de matches uit de geretourneerde layout gehaald om deze op te zetten in de database.
3.6.1.6.3. Toernooi
Om een toernooi in te delen is er veel data nodig, waaronder de spelers, het aantal rondes dat gespeed kan worden, de matches die voor de huidige matches gespeeld zijn, en de ronde die ingedeeld moet worden. Van deze data maakt de methode een lijst van matches met de spelers die meedoen, de ronde waarin de matches plaatsvinden, de groep waartoe de spelers behoren, en eventuele resultaten die al duidelijk zijn (bij oneven spelers die een bye krijgen).
Het deelt deze spelers in met behulp van de JaVaFo API. Alles dat de layoutStrategy doet is in feite het veranderen van PlayerDTOs en MatchDTOs naar iets dat de JaVaFo API kan begrijpen:
Eerst sorteert de methode de spelers op rating, zodat de rangorde juist is, en in de eerste ronde de juiste spelers prioriteit geeft. Vervolgens vertaalt het de matchDTOs naar individuele matchresultaten voor de 2 spelers, vanwege de eisen van JaVaFo. Als het een bye tegenkomt (blackPlayer is null) maakt het er een matchresultaat van. Vervolgens berekent het de score om door te geven aan JaVaFo. Dit was nodig voor de matchmaking volgens Fide.
Het resultaat dat uit JaVaFo komt wordt vervolgens weer vertaald naar matchDTOs met een andere mapper.
Deze indelingstrategie moet voor elke ronde uitgevoerd worden, maar alleen als de resultaten van de vorige match al duidelijk is. Als het voor JaVaFo onmogelijk is om een ronde te genereren (aantal spelers/2 > aantal rondes) of het maximaal aantal rondes in de competitionDTO wordt overschreden gooit de API een RuntimeException.
3.6.2. Patterns
3.6.2.1. Strategy pattern
Voor het indelingsysteem is er gekozen om gebruik te maken van een strategy pattern. De verwachte resultaten zijn immers hetzelfde, maar de manier waarop de indelingen gemaakt worden verschilt. Er is dus voor gekozen om een strategy te maken die voor nu drie implementaties heeft: Toernooi, Periodecompetities en Meerkamp. Door gebruik te maken van het strategy pattern zouden er in de toekomst nieuwe indelingssysytemen kunnen worden toegevoegd, zonder dat de backend veranderd hoeft te worden.
3.6.2.2. Layered architecture
Binnen de applicatie is gebruik gemaakt van layered architecture, waarbij we ervoor hebben gekozen om het project in te delen in de packages die in het eerder getoonde package diagram te zien zijn. De packages zijn opgesplitst op basis van functionaliteit, waarbij de controller-klassen bijvoorbeeld bij elkaar in het app-package staan en de repositories in het repository-package. Op deze manier vonden wij het als projectgroep makkelijk om binnen het project de juiste klassen terug te vinden, en is het duidelijk waar nieuwe klassen zouden worden toegevoegd.
3.6.2.3. USECASE 9 - Gegevens publiceren op website
Voor het publiceren van gegevens hebben wij gekozen om de tabellen die rokade maakt na te maken zover als dit mogelijk is. Aangezien niet elke competitietype dezelfde tabellen vereist hebben wij ervoor gezorgd dat alleen de tabellen aangemaakt worden die nodig zijn voor het geselecteerde type. Dit hebben we gedaan door gebruik te maken van een switch functie. Wanneer je een competitie meegeeft aan de publicatie service kiest deze service de goede tabellen. Daarnaast word de globale ranglijst altijd aangemaakt aangezien deze iedere keer geüpdatet moet worden wanneer er nieuwe wedstrijden zijn gespeeld.
3.6.2.4. USECASE 10 - Printen ronde indeling
Voor het uitprinten van de rondes hebben wij besloten het op een eigen pagina te zetten. Op deze pagina kan er voor twee werkwijzen gekozen worden. Er kan namelijk per competitie en per ronde een PDF gegenereerd worden of per datum.
3.6.2.4.1. Per datum
Als er voor de datum optie gekozen wordt, wordt de datum meegegeven aan de generateMatchesPerDatePDF methode. Deze methode is beschikbaar door de instantie van de PDFService die de methodes bevat voor alles wat met het genereren van de PDF te maken heeft. Aan de methode moeten ook nog het pad waar het bestand opgeslagen gaat worden (pdfPath) en de datum die geselecteerd is door de gebruiker (datePicker) meegegeven worden. In de PDFService worden vervolgens binnen de generateMatchesPerDatePDF methode alle competities (competitions) en competitiegroepen opgehaald (competitionGroups). Om namelijk alle data van een dag op te halen moet dit wel gedaan worden per competitie. De wedstrijden worden zo dus per ronde, per groep en per competitie opgehaald. Dit is een stuk duidelijker dan alle data door elkaar te hebben binnen de PDF. Vervolgens worden de rondes gecontroleerd om te kijken of deze ook wel echt op de ingevoerde datum gehouden worden. Zodra de wedstrijden per group en per competitie opgehaald zijn wordt de naam van het document gegenereerd aangezien deze naam de eerder genoemde informatie nodig heeft. Voor het maken van de naam in de methode generatePDFName wordt de huidige tijd opgehaald om altijd een unieke bestandsnaam te hebben. Als deze namelijk niet uniek is wordt het vorige bestand met die naam overschreven. Vervolgens wordt er gecontroleerd of er daadwerkelijk wedstrijden zijn op de datum die ingevuld is en als dit zo is wordt er een PDF opgesteld met de drawPDF methode. Stel dat er geen rondes op de ingevoerde dag of competitiegroepen of wedstrijden zijn wordt er een melding in het scherm gebracht met een foutmelding. De drawPDF methode wordt dan ook niet aangeroepen. Iedere keer dat de drawPDF methode aangeroepen wordt telt de pdfCounter 1 bij zichzelf op. Dit is later belangrijk voor het weergeven van het aantal gegenereerde PDF's. Anders is het namelijk nogal onduidelijk of er überhaupt wel PDF's gegenereerd zijn. In de drawPDF methode wordt er met iText een PDF gegenereerd met de wedstrijddata van de eerder ingevoerde dag. Als het bestand niet aangemaakt kan worden wordt er een exceptie gegooid die aangeeft dat er geen bestand aangemaakt kan worden.
3.6.2.4.2. Per competitie en ronde
Als er voor de optie wordt gekozen om de PDF te genereren per competitie en ronde wordt er voor iedere keer dat de combobox die alle competities bevat (competitionSelector) geopend en gesloten word een if statement uitgevoerd om te kijken of er een competitie is geselecteerd is of niet. Als er geen een geselecteerd is wordt automatisch de eerste optie uit de lijst gekozen. Dit is gedaan om errors te voorkomen die te maken hebben met het ophalen van de rondes. Als er namelijk geen competitie is opgehaald in de combobox is deze null. Er bestaan natuurlijk geen rondes voor een competitie die null is dus wordt er een error gegooid. Ook wordt voor dezelfde reden eerst de ronde selectie combobox (roundSelector) button uitgezet. Deze wordt aangezet als er een competitie geselecteerd is. Als de competitie geselecteerd is worden alle rondes die binnen de competitie vallen opgehaald en in de combobox neergezet. Ook worden dubbele waardes eruit gefilterd, want dit was een bug die omhoog kwam tijdens het maken van de code. Iedere keer dat dit alles gebeurd wordt eerst de ronde combobox leeggegooid zodat er geen rondes van een andere competitie in het veld blijven staan. Als alle velden ingevuld zijn en er een pad gekozen is waar het bestand opgeslagen gaat worden veranderd de button voor het genereren van de PDF van onklikbaar naar klikbaar. Vervolgens wordt er een PDF gegenereerd met deze informatie.
3.6.3. Overig
3.6.3.1. JaVaFo
Voor het genereren van een competitionlayout van een toernooi is een extern programma gebruikt, omdat het genereren van een zwitserse indeling wellicht te foutgevoelig zou zijn als het geprogrammeerd werd door iemand die niet volledig thuis is in het domein. JaVaFo, gemaakt door Roberto Ricca, is een in Java geprogrammeerde matchmaking software. Het heeft als input een document nodig dat specifiek is aan de schaakorganisatie Fide (.trf). Om dit te genereren zijn er een aantal klassen aangemaakt om dit te regelen. "DocumentMaker" kan met wat speciale DTOs waar de data in is opgeslagen een string genereren waarmee JaVaFo een indeling kan maken. "JaVaFoDocuPlayer" en "JaVaFoDocuResult" zijn DTO's om de data van spelers en ronderesultaten op te slaan. JaVaFo maakt van de input van DocumentMaker een output string die vervolgens vertaald kan worden naar match DTO's.
De syntax van het TRF document is gebaseerd op "Format of TRF" (Christian Krause, 2015) van FIDE.
Bij het maken van de inputstring is de spacing van alle waardes erg belangrijk, waarvoor "inflate" functies zijn gemaakt. Deze functies voegen white space (' ') tekens toe, tot de input string gelijk is aan de lengte die voor dat stuk nodig is. Bij nummers wordt inflate left gebruikt (want 0-9 moeten op de meest rechtse plaats staan, en moeten naar links uitbreiden) en bij letters wordt inflate right gebruikt (want het eerste teken moet zo links mogelijk staan en naar rechts uitbreiden).
3.6.3.2. SQLite Connection Provider
Om verbinding te maken met de database is ervoor gekozen gebruik te maken van Hibernate en JPA. Dit heeft als voordeel dat er later in de levensduur van de applicatie gemakkelijk van database provider kan worden gewisseld indien dit gewenst is. Voor de applicatie wordt nu gebruik gemaakt van SQLite als de database provider, omdat het een lokaal bestand betreft en dus geen hosting-kosten met zich meebrengt, en toch een SQL database is die makkelijk naar een MySQL server kan worden overgezet indien dit later gewenst is. Een later ondervonden nadeel van SQLite is dat foreign key constraints niet standaard worden toegepast als er verbinding wordt gemaakt met de database. Hierdoor kunnen we geen gebruik maken van de default hibernate connection provider. Als oplossing hebben we ervoor gekozen een custom connection provider te maken, speciaal voor gebruik met SQLite.
Deze connection provider doet twee dingen:
- Hij zet zodra het programma gestart wordt de foreign keys aan binnen de SQLite database, zodat de database naar behoren kan werken.
- Hij laadt de locatie van de database in via een aangemaakt .properties bestand. Omdat de database een lokaal bestand is, gepaard met de wens van UVS om de locatie van de database aan te kunnen passen, is er geen vaste locatie waar het bestand staat. De locatie wordt dus in dit .properties bestand opgeslagen en door de custom connection provider opgehaald wanneer het programma opgestart wordt.
4. Bibliografie
- Wikipedia contributors. (2024, 29 mei). Elo rating system. Wikipedia. Geraadpleegd op 31 mei 2024, van https://en.wikipedia.org/wiki/Elo_rating_system#Mathematical_details
- Kraus, C. (2015, August 10). Format of TRF (tournament report file) player section. https://www.fide.com/FIDE/handbook/C04Annex2_TRF16.pdf