TOELATING TOT BRUIKLEEN
De auteurs geven de toelating deze scriptie voor consultatie beschikbaar te stellen en delen van het werk te kopiëren voor persoonlijk gebruik. Elk ander gebruik valt onder de bepaling van het auteursrecht, in het bijzonder met betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van resultaten uit dit werk.
Arnout Vanden Berghe & David Demanet
Gent, 30 juni 2011
Voorwoord en dankbetuiging Geachte lezer,
Deze meesterproef maakt deel uit van onze opleiding tot het behalen van de graad van Master na Master in de Toegepaste Informatica aan de Universiteit Gent.
Dit werk is tot stand gekomen uit het onderzoek naar een systeem voor het bewaren van experimentele resultaten in de vorm van een website, waarbij rekening moet worden gehouden met de verscheidenheid aan vereisten die elk project en experiment heeft. De reden waarom wij kozen voor deze meesterproef is omwille van het feit dat Drupal en PHP relatief nieuwe concepten voor ons waren. Het leek ons daarom interessant om ons te verdiepen in deze concepten.
Deze eindverhandeling kon enkel tot stand komen door de inbreng en steun van een aantal mensen. Wij wensen dan ook via deze weg deze personen van harte te bedanken voor hun bereidwillige medewerking aan deze meesterproef.
In eerste instantie danken wij onze promotors Prof. Koen De Bosschere, Andy Georges en Frederick Ryckbosch voor hun deskundige begeleiding en kritische interesse die ons geholpen hebben bij de voltooiing van dit werk.
Daarnaast willen wij ook Klaas Millet bedanken voor zijn deskundig advies bij de opbouw van de module en de bijhorende website.
Arnout Vanden Berghe & David Demanet
Gent, 30 juni 2011
Universiteit Gent Faculteit Ingenieurswetenschappen en Architectuur Voorzitter: prof. dr. ir. Jan Van Campenhout
Website voor het bijhouden en opvragen van experimentresultaten
Arnout VANDEN BERGHE, David DEMANET
Promotor : prof. dr. ir. Koen De Bosschere Begeleiders : Andy Georges, Frederick Ryckbosch
Master ingediend tot het behalen van de academische graad van Master in de toegepaste informatica Academiejaar 2010-2011 Samenvatting Onderzoekers hebben vaak te kampen met heel wat experimenten die zij uitvoeren binnen een project en de hieraan gelinkte resultaten en metadata. Dit gaat vaak gepaard met een onoverzichtelijk beheer van deze experimenten en een complexe methode om de hieraan gelinkte metadata op te vragen op de experimentcomputer. Hierdoor kwam het idee om een website te ontwikkelen die deze projecten en experimenten op een overzichtelijke manier kan bijhouden en beheren. Ook is het de bedoeling dat er een submitscript wordt gegenereerd die op een eenvoudige wijze de metadata kan opvragen aan een experimentcomputer. Deze functionaliteit werd geïmplementeerd aan de hand van het Content Management Systeem Drupal.
Trefwoorden Website, experimentresultaten, Drupal, module
Inhoudsopgave 1.Inleiding .........................................................................................................................................1 1.1
Probleemstelling ..................................................................................................................1
1.2
Content Management Systeem .............................................................................................1
1.3 Open source programmeertalen en software ...............................................................................2 1.3.1 Content management framework ........................................................................................2 1.3.2 Content management systeem (CMS) .................................................................................2 1.4 Drupal .......................................................................................................................................3 1.4.1 Drupal Framework..............................................................................................................4 1.4.2 Drupal Technologie ............................................................................................................4 1.4.3 Drupal Core .......................................................................................................................5 1.4.4 Administratieve interface ....................................................................................................5 1.4.5 Modules and hooks ............................................................................................................5 1.4.6 Nodes ................................................................................................................................5 1.5 PHP ..........................................................................................................................................5 2. De Expres module .........................................................................................................................7 2.1 Doelstelling ...............................................................................................................................7 2.2 De software levenscyclus ..........................................................................................................7 2.2.1 Software Engineering .........................................................................................................8 2.2.2 Vereisten ............................................................................................................................9 2.3 Het softwareproces .................................................................................................................. 11 2.3.1 Het watervalmodel............................................................................................................ 11 2.3.2 Het „rapid prototype‟ model .............................................................................................. 14 2.4 De ontwikkelingslevenscyclus ................................................................................................. 15 2.4.1 De vereistenfase ............................................................................................................... 15 2.4.2 Objectgeoriënteerde analyse ............................................................................................. 19 2.4.3 Objectgeörienteerd design................................................................................................. 24 2.4.4 Objectgeörienteerd programmeren .................................................................................... 31 Algemene conclusie ......................................................................................................................... 36 Bijlagen ........................................................................................................................................... 37 Bijlage A: Bespreking code Expres ............................................................................................... 37 Lijst van geraadpleegde werken ..................................................................................................... 65 Lijst van figuren en tabellen ........................................................................................................... 67
i
1.Inleiding 1.1 Probleemstelling Benchmarking is één van de fundamenten van de experimentele computerwetenschap. Bij vrijwel elk aspect, gaande van ontwerp tot evaluatie van hardware en software worden benchmarks gebruikt om kwantitatieve gegevens te verzamelen. Benchmarking is gebaseerd op het idee dat men de prestaties van een georganiseerd systeem kan evalueren door deze te vergelijken met exogene entiteiten. Webster, geciteerd door Lucertini, Nicolò en Telmon (1995), omschrijft een benchmark als: “A mark on a fixed and enduring object (as on an outcropping of rock or a concrete post set into the ground) indicating a particular elevation and used as a reference in topographical surveys and tidal observations. A benchmark is thus a point of reference from which measurements of any sort may be made.” In het Computer Systems Lab worden zeer veel metingen verricht bv. bij het simuleren van processors om na te gaan wat de impact van ontwerpbeslissingen (grootte van de cache, sprongvoorspeller, etc.) is op de prestatie, bij het opstellen van modellen voor het schatten en voorspellen van de prestatie van programma's op welbepaalde processors, bij het evalueren van de prestatie binnen een (Java) virtuele machine, alsook bij het opstellen van methodologieën om te meten op zich. Bij dergelijke experimenten worden steeds grote hoeveelheden data verzameld, waarbij elke onderzoeker een eigen systeem hanteert voor het bewaren en doorzoeken van de experimentele resultaten. Bovendien kunnen de data moeilijk gedeeld worden met anderen binnen of buiten de onderzoeksgroep en vereist het manueel kopiëren van bestanden of stukken ervan.
1.2 Content Management Systeem De communicatiemogelijkheden die aangeboden worden door het World Wide Web hebben geleid tot een explosie in het aantal websites, alsook in de rijkdom van hun inhoud. Deze trend is duidelijk merkbaar op het vlak van de oprichting en het beheer van internet, intranet en extranet sites. Om te reageren op deze trend hebben verscheidene producenten Content Management Systemen aangeboden als ondersteuning voor het publiceren van informatie op het web (Vitari, Ravarini & Rodhain, 2006). Content management systemen (CMS) zijn software-applicaties voor het creëren, publiceren, bewerken en beheren van content. Ze worden op grote schaal gebruikt door nieuws- en mediaorganisaties, e-commerce websites, bibliotheken, de omroep- en filmindustrie en educatieve instellingen om de inhoud efficiënt te behandelen (Laleci, Aluc, Dogac, Sinaci, Kilic & Tuncer, 2010). „Content‟ verwijst hierbij naar de informatie die gepubliceerd wordt op een bepaalde website. Deze informatie kan variëren van het eenvoudige ASCII-formaat tot de meest geavanceerde multimediaformaten. Vanaf het moment dat de informatie gepubliceerd wordt op een website, wordt deze beschouwd als „content‟, ongeacht het 1
formaat. Gegeven deze definitie zijn webpagina's documenten gebaseerd op deze inhoud en kunnen we een document bijgevolg definiëren als een object met bepaalde informatie. Inhoud mag echter niet worden verward met kennis, wat gedefinieerd wordt als “een mix van ervaringen, waarden, contextuele informatie en expertise die een kader bieden voor de evaluatie en integratie van nieuwe ervaringen en nieuwe informatie” (Vitari et al., 2006). Wel kan inhoud een bron van kennis worden, maar het kan niet worden beschouwd als kennis zelf. Gezien het feit dat de definitie van de inhoud beperkt is tot de informatie gepresenteerd op een website, kan “content management” dus alleen betrekking op het beheer van de inhoud van de website. In het algemeen kan dus gesteld worden dat content management systemen (CMS) softwaretools zijn om onder andere webpagina's en websites te creëren en te beheren (Vitari et al., 2006).
1.3 Open source programmeertalen en software 1.3.1 Content management framework
Een „content management framework‟ (CMF) is meestal opgebouwd uit een uitgebreide programmeertaal en een Application Programming Interface (API) voor de ontwikkeling van websites. CMFs zijn over het algemeen databankgedreven. Een veelgebruikte CMF is Zope, gebaseerd op de programmeertaal Python en op de Zope Public License. Zope biedt een krachtige API die soms gebruikt wordt als basis voor volledige CMS-toepassingen. Ruby on Rails is een ander voorbeeld van een open source CMF voor de ontwikkeling van web portals en content management applications. CakePHP is een keuze die nuttig is voor PHPontwikkelaars (Mooney & Baenzinger, 2007). 1.3.2 Content management systeem (CMS)
Content management systemen zijn voornamelijk gericht op ontwikkelaars met weinig programmeerervaring of op ontwikkelaars die de bestaande systemen verder willen uitbreiden. CMS‟en zijn over het algemeen volledig functioneel en gemakkelijk te gebruiken en gebaseerd op web-based installatieprocedures. Met een bestaande Apache web server, een MySQL database en supergebruikerstoegang zijn auteurs in staat om in minder dan een uur een CMS te installeren. De eenvoudigste CMS applicaties zijn compleet en web-based, zoals een wiki of een blog. Deze tools zijn bijzonder nuttig in de wetenschappelijke en academische omgevingen, maar missen vaak de mogelijkheid tot interoperabiliteit met andere „content management systeem‟toepassingen. Een zeer populaire open source tool is MediaWiki, die de PHP-gebaseerde software is achter het bekende Wikipedia. MediaWiki biedt eenvoudig te beheren, communiteitgedreven webpagina‟s aan. De volgende content management systemen zijn gericht op het aanbieden van een infrastructuur die een kader biedt voor interoperabiliteit. Voor de gebruiker betekent dit dat wikipagina‟s, blogposts en kalenders nauwkeurig kunnen worden geïntegreerd. 2
Veelgebruikte tools zijn de finalisten voor de Packt 2006 Open Source CMS Award (Mooney & Baenzinger, 2007). Drupal is hierbij één van de meest populaire open source CMS-tools en wordt vaak gebruikt voor communiteitgedreven websites. Net als vele andere Content management systemen, is Drupal meestal gebouwd op Apache, MySQL en PHP en is uitbreidbaar met behulp van modules. Xoops is net zoals Drupal gebaseerd op PHP en MySQL en gelicenseerd onder de GPL (General Public License). Zijn naam is een acroniem van „eXtensible Object Oriented Portal System‟. Xoops is goed ondersteund, maar er zijn minder modules beschikbaar dan bij Drupal. e107 is een andere open source CMS licentie onder de GPL en ontwikkeld in PHP. Dit CMS heeft het minst aantal beschikbare modules, plugins genoemd, in vergelijking met de andere besproken content management systemen. Plone is gebouwd op de eerder beschreven CMF Zope en biedt vele plugins. Joomla is de winnaar van de 2006 Packt CMS Award en is een afstammeling van een andere open source CMS, namelijk Mambo. Joomla ondersteunt modules, addons genoemd, die kunnen worden ontwikkeld in PHP en heeft geautomatiseerde component-, module- en pakketscripts, waardoor het beheer van het CMS volledig webpaginagedreven is (Mooney & Baenzinger, 2007). Tool Zope Ruby on Rails CakePHP MediaWiki Drupal Xoops e107 Plone Joomla
Type CMF CMF CMF Wiki CMS CMS CMS CMS CMS
URL http://www.zope.org/ http://www.rubyonrails.org/ http://www.cakephp.org/ http://www.mediawiki.org/wiki/MediaWiki http://www.drupal.org/ http://www.xoops.org/ http://www.e107.org/ http://www.plone.org/ http://www.joomla.org/
Tabel 1: Veel gebruikte CMF's en CMS'en
1.4 Drupal In dit eindwerk werd geopteerd voor het gebruik van Drupal, omdat Drupal goed ondersteund worden en volgens Mooney en Baenziger (2007) een waardige PHP-oplossing is. Bovendien heeft Drupal een uitbreidbaar en modulair design, dat de mogelijkheid biedt tot uitbreiding van het platform met verscheidene – al dan niet zelf geschreven – modules. Dit kenmerk zorgt ervoor dat men applicaties op maat kan bouwen zonder dat men de onderliggende webarchitectuur moet handhaven. Eén van de bijkomende voordelen van CMS-tools is dat ze bepaalde standaard functionaliteit aanbieden, waardoor ontwikkelaars zich meer kunnen toeleggen op het effectief ontwikkelen van de applicatie, in plaats van zich bezig te houden met de virtuele administratieve behoeften (authenticatie, autorisatie, etc.). Drupal bevat bovendien ook een aantal API‟s die webontwikkelaars toelaten op een efficiënte en snelle wijze webapplicaties te bouwen. Drupal is een open-source, content management systeem (CMS), bedoelt voor het ontwikkelen van websites. Dit kan gaan van een sociale netwerksite, een persoonlijke website tot bedrijfswebsites. Drupal is ontwikkelt door Dries Buytaert, een Belgische student die zijn doctoraat behaalde aan de Universiteit Gent, en biedt een breed 3
scala van functies en diensten, waaronder gebruikers administratie, discussie mogelijkheden en metadata functionaliteit met behulp van gecontroleerde woordenlijsten. Alsook maakt het gebruik van al dan niet zelf geprogerameerde modules voor het aanpassen van het uiterlijk, het weergeven en organiseren van inhoud en alledaagse taken zoals de registratie van gebruikers, waarbij gebruikersnamen en wachtwoorden beheert worden. Drupal is database onafhankelijk, het is namelijk gebouwd op de top van een database abstractie laag die u toelaat Drupal te gebruiken met Drupal MySQL en PostgreSQL. Drupal is niet moeilijk te installeren, maar het configureren van Drupal aan de specificaties van elke gebruiker vereist enige kennis van PHP. Om te beginnen werken met Drupal moet men analyseren welke modules beschikbaar zijn en een visie hebben op de manier waarop zij zouden kunnen worden gebruikt. Eenmaal geïnstalleerd en geconfigureerd, kan Drupal volledig worden beheerd via een webbrowser. Het belangrijkste kenmerk van Drupal is de flexibiliteit. Thema‟s kunnen gekozen worden of zelf ontwikkeld alsook de modules. Er is voortdurend een breed scala van modules beschikbaar, die kunnen worden geïnstaleerd. Op deze manier kan men de functionaliteit uitbreiden en de sites aanpassen aan de behoeften van de gebruiker. (Reilly & Williams, 2006) Wij kozen, zoals hoger vernoemd voor Drupal, voor het ontwikkelen van omze website omdat de kracht van Drupal ligt in het feit dat het heel fexibel is en meer biedt dan enkel het beheren van inhoud, terwijl het modulair genoeg is om het simpel te houden. Drupal biedt namelijk heel wat basisfunctionaliteit aan, dat kan uitgebreid worden naar eigen voorkeur. Een tweede belangrijke reden waarom wij voor Drupal kozen is omdat deze een heel actieve community van ontwikkelaars bezit, die ons zeker konden helpen bij eventuele vragen via forumposts. 1.4.1 Drupal Framework
Drupal is een softwarepakket dat ontwikkeld is om goed te kunnen draaien op goedkope “web hosting accounts” alsook ondersteunt het het ontwerp van complexe en ingewikkelde websites. Dit vereist een strakke, correcte codering gecombineerd met populaire technologie. 1.4.2 Drupal Technologie
De technology stack van Drupal bestaat uit 4 segmenten namelijk: 1) Het besturingssysteem: Het besturingsysteem is echter van weinig belang, vermits Drupal succesvol werkt op elk besturingssysteem dat PHP ondersteunt. 2) De webserver: De meest gebruikte webserver met Drupal is Apache, maar andere webservers zoals Microsoft IIS kunnen ook gebruikt worden. 3) De database: Drupal interageert met deze laag via een database abstractielaag, die volledig herwerkt is in Drupal 7. De database interface biedt een een API-gebaseerd PHP-dataobject aan en laat op deze manier toe dat Drupal elke database ondersteunt die PHP ondersteunt. De meest populaire databases gebruikt in Drupal zijn MySQL, PostgreSQL en SQLite.
4
4) De taal: Drupal is geschreven in PHP. Alle Drupal-code is dan ook onderworpen aan PHP-functionaliteit. Drupal zelf tracht echter bepaalde regels op te leggen aan de gebruiker zodat de code leesbaar, duidelijk en vrij foutloos kan blijven. 1.4.3 Drupal Core De drupal core is verantwoordelijk voor de basisfunctionaliteit, die gebruikt zal worden ter ondersteuning van andere delen van het systeem. De core omvat onder andere een bibliotheek met gemeenschappelijke functies, die vaak gebruikt worden in Drupal zoals: drupal_get_form en hook_menu. Modules die de basisfunctionaliteit aanbieden zoals het gebruikersbeheer en code die Drupal toelaat te reageren wanneer het een request ontvangt. 1.4.4 Administratieve interface
De administratieve interface is sterk geïntegreerd in Drupal. Alle administratieve functies zijn gemakkelijk toegankelijk via een administratief menu dat zich bevindt bovenaan de pagina wanneer je ingelogd bent als administrator. Deze functies kunnen niet gedesactiveerd worden, vermits hun mogelijkheden standaard zijn voor de werking van Drupal. 1.4.5 Modules and hooks
Drupal is een modulair framework, waarbij de functionaliteit ingebed zit in modules, die kunnen geactiveerd of gedesactiveerd worden. Functies kunnen toegevoegd worden aan een Drupal-website door modules te installeren van de Drupal Community of zelf geschreven modules. Hooks zorgen ervoor dat deze modules opgeroepen worden. De meeste modules zijn niets meer dan een verzameling van implementaties van deze hooks, die Drupal automatisch oproept wanneer deze zijn weg baant door de levenscyclus. Het is dus echter niet alleen de Drupal core die hooks verklaart en oproept. Elke module kan verklaren en haar eigen hook oproepen. 1.4.6 Nodes De inhoud van een Drupal-website wordt opgeslagen en behandeld in nodes. Deze nodes zijn inhoudstypes zoals blogs en forums die aan de hand van deze nodes verwerkt worden. De onderliggende datastructuur van deze inhoudstypes is is dan ook dezelfde. Doordat de inhoud van de website in nodes verwerkt wordt, creëert men de mogelijkheid om gemakkelijk functionaliteit toe te voegen of wijzigingen door te voeren. De website administrator kan dan bijvoorbeeld bij een blog gemakkelijk kiezen om de commentaren aan of uit te schakelen.
1.5 PHP Drupal is een software-pakket dat geschreven is in PHP. PHP staat voor Hypertext Preprocessor en is een veelgebruikte scriptingtaal die speciaal geschikt is voor het ontwikkelen van dynamische webpagina‟s. Ze is vergelijkbaar met Perl en Python, maar qua syntax lijkt deze het meeste op C. Doch is het in PHP echter mogelijk om zowel functiegeoriënteerd als objectgeoriënteerd te werken, wat niet het geval is bij C.
5
PHP kan gebruikt worden voor server-side scripting, waarbij het script aan de server-side uitgevoerd wordt, in plaats van aan de client-side zoals bij Javascript en VBScript. Hierbij wordt de code van de website op de webserver (waar PHP op geïnstalleerd is) uitgevoerd en doorgestuurd naar de gebruiker. De PHP-code is hierdoor dan ook niet zichtbaar voor de gebruiker. De grote kracht van PHP is zijn eenvoud voor nieuwe gebruikers, maar biedt ook vele geavanceerde functies voor de professionele programmeur. Opvallend is zijn omgang met variabelen. Variabelen worden in PHP – in tegenstelling tot C en JAVA – voorafgegaan door een $-teken en kunnen op een eenvoudige wijze door een webbrowser doorgegeven worden aan het PHP-script. Aangezien Drupal in PHP geschreven is start de opbouw van onze module dan ook met de tag wordt echter vaak weggelaten omdat deze slecht optioneel is en vaak voor validatieproblemen en andere problemen kan zorgen.
6
2. De Expres module 2.1 Doelstelling Het doel van deze scriptie is het creëren van een systeem voor het bewaren van experimentele resultaten, waarbij rekening moet worden gehouden met de verscheidenheid aan vereisten die elk experiment heeft. Bovendien zijn de parameters en de resultaten die worden bijgehouden anders voor elk experiment. Het is de bedoeling dat er een web front-end opgezet wordt, bij voorkeur in een degelijk raamwerk zoals Drupal, waar de onderzoeker kan specificeren welke metadata opgeslagen moeten worden. Hierbij moet bovendien een script worden gegenereerd dat de onderzoeker kan gebruiken in zijn experimentele omgeving om resultaten in de databank te stockeren. Daarnaast is het wenselijk dat de gegevens snel en overzichtelijk kunnen worden opgevraagd en beschikbaar zijn in de meeste courante exportformaten.
2.2 De software levenscyclus Een softwarelevenscyclus is een weergave van de volledige levensduur van een softwareontwikkeling (die een dienst of een onderdeel van een dienst levert aan een klant), vanaf het initiële concept tot de uiteindelijke ontmanteling. Het is een opeenvolging van stadia die softwaresystemen passeren. De levenscyclus bestaat uit de volgende fasen (Johnson & Higgins, 2007):
Het uitgangspunt: beginnend bij de eerste softwarespecificatie De ontwikkelingslevenscyclus: de periode die begint met het besluit tot de ontwikkeling van een softwareproduct en eindigt wanneer een acceptabel product wordt geleverd aan de klant (deze periode omvat het testen en de acceptatie van de software). Softwareonderhoud: de wijziging van een softwareproduct na levering met als doel fouten te voorkomen, prestaties te verbeteren of om het product aan te passen aan veranderde omgevingsfactoren.
Veel mensen stellen de term „software‟ gelijk met computerprogramma's. Software omvat meer dan alleen de programma's, het omvat ook alle bijbehorende documentatie en de gegevens die nodig zijn om deze programma‟s correct te laten functioneren. Een softwaresysteem bestaat meestal uit een aantal afzonderlijke programma's en configuratiebestanden, die worden gebruikt voor het opzetten van deze programma's, documentatie, die de structuur van het systeem beschrijft, en gebruikersdocumentatie, waarin wordt uitgelegd hoe het systeem en de website(s) functioneren (Sommerville, 2007).
7
2.2.1 Software Engineering
Software Engineering is een relatief jonge discipline en verschilt dan ook aanzienlijk van andere, meer volwassen „engineering‟-disciplines. Deze verschillen zorgen er vaak voor dat softwaresystemen over het algemeen een hoger falingspercentage hebben dan systemen gebouwd in andere technische disciplines (bijvoorbeeld bij het bouwen van huizen, elektronische systemen,…). In het algemeen kunnen er drie belangrijke verschillen worden aangeduid (Dhoedt, 2010). Ten eerste is het niveau van complexiteit veel hoger bij Software Engineering, wat impliceert dat het onmogelijk is om een systeem in de ontwikkelingsfase uitgebreid te testen. Ten tweede is de houding ten opzichte van falen anders, waardoor men minder streeft naar correcte software en er geen of beperkte middelen beschikbaar worden gesteld om gepaste methodologieën te ontwikkelen om fouten op te sporen in de software. De flexibiliteit van de software is een derde verschil. De flexibiliteit wordt vaak beschouwd als een groot voordeel, maar kan ook omslaan in kwetsbaarheid. Wijzigingen (die niet werden verwacht in de ontwerpfase) worden vaak achteraf uitgevoerd, wat kan resulteren in onstabiele producten. Bovendien moet software meestal gebouwd worden rekening houdend met de hardware, wat mogelijk resulteert in niet-optimale oplossingen Er worden twee definities gegeven om de term „Software Engineering‟ te verduidelijken. De eerste definitie, vermeld door het IEEE (het „Institute of Electrical and Electronics Engineers‟), geeft de juiste houding aan voor het ontwikkelen van software. Het toepassen van deze houding, evenals de studie van de methoden om deze houding te ontwikkelen, wordt aanzien als „Software Engineering‟ (geciteerd door Dhoedt, 2010): (1) “The application of a systematic, disciplined, quantifiable approach to the development, operation, and maintenance of software; that is, the application of engineering to software.” (2) “The study of approaches as in (1)” Een alternatieve definitie beschrijft „Software Engineering‟ indirect door het geven van het resultaat. Dit resultaat is foutloze software, die aan de behoeften van de gebruikers voldoet en die op tijd en binnen het budget wordt geleverd. Merk op dat beide definities duiden op de discipline die vereist is bij “Software Engineering”. Hierdoor wordt een duidelijk onderscheid gemaakt tussen de professionele softwareontwikkelaar (die in een team functioneert, met behulp van gedisciplineerde methoden) en de hacker (die voornamelijk individueel werkt, zonder gebruik te maken van methodiek behalve de “quick-and-dirty” en “try-and-error”methoden).
8
2.2.2 Vereisten
Software wordt geproduceerd om een specifiek probleem of een set van problemen op te lossen voor een bepaalde groep gebruikers. Daarom is het essentieel dat een softwareproduct aan de eisen van de gebruikers voldoet (ontevredenheid zal resulteren in een verzoek om de software te herzien of kan in het ergste geval leiden tot juridische acties). Er zijn twee fundamentele soorten van softwareproducten (Sommerville, 2007): 1. Generieke producten of Commercial Off The Shelf (COTS): dit zijn stand-alone systemen die worden geproduceerd door een ontwikkelingsorganisatie en worden verkocht aan iedere klant die in staat is om ze te kopen. Voorbeelden van dit soort producten zijn software voor PC's, zoals databases, tekstverwerkers, tekenpakketten en projectmanagementtools. 2. Op maat gemaakte producten: dit zijn systemen die in opdracht van een bepaalde klant worden geproduceerd. De software wordt speciaal voor die klant ontwikkeld. Voorbeelden van dit type software zijn onder andere controlesystemen voor elektronische apparaten, systemen geschreven ter ondersteuning van een bepaald bedrijfsproces, enz. Het is duidelijk dat software op maat in een hogere mate afgestemd zal zijn op de behoeften van de gebruiker dan COTS, omdat in het laatste geval rekening moet gehouden worden met de algemene behoeften van een grote groep potentiële gebruikers. In het geval van COTS kunnen de ontwikkelingskosten verdeeld worden onder een grote groep gebruikers, met als gevolg dat deze software meestal een aanzienlijk lagere prijs heeft. Bij het opstellen van de vereisten kan er een onderscheid gemaakt worden tussen drie algemene invalshoeken (Dhoedt, 2010): Software functionaliteit - Inspelen op de behoeften van de gebruiker betekent dat het product eenvoudig te gebruiken is, bijna altijd functioneert zoals verwacht (een gouden regel in de software engineering is “Verras de gebruiker niet!”) en presteert in overeenstemming met de verwachtingen van de gebruiker. In het onwaarschijnlijke geval dat het product faalt, moet het sierlijk falen, wat betekent dat de mogelijke gevolgen van de mislukking van het product (bv. verlies van data, hardwarecorruptie ...) moeten worden geminimaliseerd. Het ontwikkelde systeem moet ook in redelijke mate beveiligd zijn (indien beveiliging wordt vereist door de gebruiker). Dit kan betekenen dat een authenticatie voor het gebruik wordt vereist of de toegang tot gegevens ontzegd moet worden aan onbevoegde personen. Aangezien het onmogelijk is (behalve voor triviale producten) om garanties zoals „geen fouten‟, „absolute veiligheid‟ te beloven, worden meestal termen zoals „genoeg‟ en „meestal‟ gebruikt. Software levering - Meestal wordt op voorhand een prijs afgesproken en een tijdspanne overeengekomen waarbinnen de software geleverd moet worden. Om te voldoen aan de 9
verwachtingen van de klant is het cruciaal om het product op tijd en binnen het budget te leveren. Onderhoud - Een aanzienlijke kost in de softwarelevenscyclus wordt toegeschreven aan het onderhoud. Als de kosten voor de kleine wijzigingen (bijvoorbeeld als gevolg van gewijzigde wetgeving) laag gehouden kunnen worden, is dit een duidelijk voordeel van het product en een toepassing van goede „software engineering‟-praktijk. Voordat we verder gaan is het noodzakelijk om een onderscheid te maken tussen de verschillende partijen die betrokken zijn bij het bouwen van een softwareproduct: • •
•
De klant is het individu of (zoals in de meeste gevallen) de organisatie, dat nood heeft aan nieuwe software en bijgevolg een nieuw product aankoopt of laat maken. De gebruiker is de persoon of de organisatie die daadwerkelijk zal werken met het product. Vaak (maar niet altijd) behoren de gebruikers en de klant tot dezelfde organisatie. De ontwikkelaar is een lid van de organisatie, die verantwoordelijk is voor de bouw van het product.
10
2.3 Het softwareproces Het softwareproces is de verzameling van overeengekomen procedures en methoden voor de productie van het product. Er bestaan veel processen en het selecteren van de juiste processen voor een bepaald softwareproject is essentieel voor het succes (het zou nutteloos en zelfs contraproductief zijn om een zwaar proces te gebruiken om kleine producten te bouwen). Moderne processen (bijvoorbeeld RUP: Rational Unified Processen) maken het mogelijk om het proces af te stemmen op het product. Ondanks het groot aantal processen die beschikbaar zijn, is de aard van de geleverde zaken vergelijkbaar (Dhoedt, 2010):
Wanneer de vereisten zijn vastgelegd, wordt er een document opgesteld dat deze vereisten bevat en dat goedgekeurd wordt door de klant en de ontwikkelaar. Dit document is van essentieel belang voor het valideren van het hele proces. Hierbij moeten m.a.w. twee vragen gesteld worden, nl. bouwen we het juiste systeem? En bouwen we het systeem dat de klant heeft gevraagd?. De ontwerpfase levert een set van specificaties op, op basis waarvan de uitvoering kan starten. Ontwerpbeslissingen maken het mogelijk om het totale product op te splitsen in kleinere subsystemen, die geschikt zijn voor parallelle uitvoering en/of voor het herwerken van het ontwerp. Implementatie (en integratie) zijn de laatste stap in de productie van een eerste versie van het product, dat dan onderworpen wordt aan een reeks testen ter validatie en verificatie. Op basis van het testrapport kunnen corrigerende maatregelen genomen worden of kan het product worden geleverd aan de klant.
2.3.1 Het watervalmodel
In het algemeen kunnen processen opgedeeld worden in twee categorieën: „waterfall‟ processen (dit is de „traditionele‟ manier om software te produceren) en de meer moderne iteratieve processen. Waterfallstyle processen worden gekenmerkt door een sequentiële ordening van activiteiten, waarbij bv. de belangrijkste analyse-inspanningen worden gedaan voordat het ontwerp begint. Hoewel deze organisatie misschien logisch lijkt op het eerste gezicht zijn er grote nadelen verbonden aan deze benadering:
Er is geen interactie met de gebruiker (en er zijn dus geen correcties mogelijk door de gebruiker) is opgenomen tijdens de eigenlijke analysefase, ontwerpfase enz. Dit betekent dat de gebruiker pas wordt geconfronteerd met het product op het moment dat het reeds volledig is afgewerkt. Veranderingen zijn op dat moment moeilijk en duur om te implementeren. De gebruiker gebruikt het product voor het eerst wanneer de versie afgewerkt is. Het eerste gebruik van het product door de gebruiker is pas met de volledig afgewerkte versie. 11
Onderstaande figuren 1 & 2 stellen respectievelijk het watervalmodel van Royce en het aangepast watervalmodel van Boehm voor (Mohapatra, 2010). Merk op dat het oorspronkelijke model door Royce een „feed-forward‟-model was zonder enige feedback, terwijl het model van Boehm een terugkoppeling naar de direct voorafgaande fase voorstelt. Verder vereist Boehms model verificatie en validatie voordat de output van een fase wordt bevroren. Hierbij moet opgemerkt worden dat wanneer we over het watervalmodel spreken in de rest van de thesis hiermee het model van Boehm wordt bedoeld.
Figuur 1: Watervalmodel van Royce
12
Figuur 2: Watervalmodel van Boehm
Het watervalmodel werd intens gebruikt tijdens de jaren 80 en was in die tijd een succesvol model. De organisatie van de fasen is vrij eenvoudig (Dhoedt, 2010):
Fasen worden uitgevoerd in volgorde, te beginnen met de vereistenfase en eindigend met de integratie- en implementatiefase. In elke fase worden er testen uitgevoerd voordat de volgende fase wordt gestart. Deze testen zijn ook steeds fasespecifiek. Indien tijdens een fase een probleem ontdekt wordt, wordt de fase gestopt en wordt de vorige fase heropend. Als bijvoorbeeld een fout wordt gevonden tijdens de ontwerpfase, een fout, die duidelijk geen probleem omtrent het ontwerp is, wordt de specificatiefase terug opgestart. Hierbij worden alle werkzaamheden in de ontwerpfase opgeschort. Als in de specificatiefase wordt geconstateerd dat het probleem eigenlijk verband houdt met onjuiste eisen, dan wordt de vereistenfase heropend en worden alle
13
specificatieactiviteiten gestopt. Wanneer de fout opgelost is, wordt de normale volgorde hervat. Deze feedback tussen de fasen en de heropening van vorige fasen moet natuurlijk zoveel mogelijk vermeden worden aangezien dit herhalen kan leiden tot aanzienlijke vertragingen in het project. Bovendien stelt de aanwezigheid van deze feedback natuurlijk het moment uit waarop de cliënt voor het eerst wordt geconfronteerd met het product. Het feit dat de opdrachtgever slechts de laatste versie van het product ziet, wordt beschouwd als een duidelijke zwakte in dit model. 2.3.2 Het ‘rapid prototype’ model Het „rapid prototype‟ model lijkt zeer veel op het watervalmodel. De vereistenfase in het watervalmodel is hier vervangen door de bouw van een prototype. Het basisidee is om de klant zo spoedig mogelijk te confronteren met een werkend product. Op deze manier probeert men het risico op onvolledige of foutieve eisen te beperken. Het prototype zelf wordt geconstrueerd met behulp van een “build-and-fix” aanpak. Hierbij wordt een deelverzameling van de functionaliteit van het product (in het bijzonder de functionaliteit die direct zichtbaar is voor de eindgebruiker) gekozen en op basis van deze functionaliteit wordt snel een stuk software samengesteld. Gedurende opeenvolgende iteraties wordt dit prototype bewerkt totdat het voldoet aan de behoeften van de klant. Het prototype kan uiteraard enkel een subset van de gevraagde functionaliteit aanbieden. Items die kunnen worden weggelaten in het prototype zijn (Dhoedt, 2010):
geoptimaliseerde layout controle van de input ingewikkelde berekeningen die kunnen vervangen worden door eenvoudige benaderingen ...
Het “build-and-fix” model is volstrekt onaanvaardbaar voor een eindproduct, omdat producten die vervaardigd worden op deze manier niet kunnen worden gehandhaafd. Rapid prototyping volgt het “doe het twee keer”-principe bepleit door Brooks (1975). Hierbij wordt de eerste versie van de software slechts tijdelijk ontwikkeld om de vereisten van de klant te kunnen vastleggen. Daarna wordt dit model weggegooid en de tweede versie wordt ontwikkeld naar voorbeeld van het watervalmodel (Mohapatra, 2010). In het algemeen kan dus gesteld worden dat het experimenteren met een aantal prototypes, resulteert in het beter vastleggen van de vereisten. Dit is dan ook het model dat werd gebruikt als uitgangspunt bij het construeren van de eerste module.
14
2.4 De ontwikkelingslevenscyclus Dit hoofdstuk bespreekt concreet verschillende fasen in de levenscyclus van de software. We beginnen met een bespreking van de vereistenfase en de objectgeoriënteerde analyse (OOA). Beide fasen zijn gericht op het identificeren van wat nu precies verwacht wordt van het product, waarbij de vereistenfase gericht is op de eerste interactie met de klant. 2.4.1 De vereistenfase
Het doel van de vereistenfase is het vastleggen van de behoeften en beperkingen opgelegd door de opdrachtgever. Deze fase is essentieel om te ontdekken welk product gebouwd moet worden. De cliënt moet een centrale rol spelen bij de verificatie van „goede‟ software. Een perfect werkend product dat niet aan de behoeften van de klant voldoet, is nutteloos. Om tot een duidelijk specificatiedocument te komen, zijn de volgende stappen nodig (Dhoedt, 2010):
Uitlokking: het belangrijkste doel van deze stap is het op te lossen probleem begrijpen. Daarbij kunnen twee belangrijke bronnen van informatie worden geraadpleegd: de toekomstige gebruikers en het probleemdomein zelf. Informatie over het probleemdomein kan ingewonnen worden bij deskundigen, in literatuur, enz.
Specificatie: het voornaamste doel van deze stap is om het pakket van vereisten te beschrijven, wat resulteert in een vereistendocument. Dit document wordt vervolgens doorgegeven aan de gebruikers, om te dienen als feedback voor de volgende stap.
Validatie en verificatie: deze stap zorgt ervoor dat alle betrokken partijen het eens zijn over de specificaties. Dit houdt validatie (namelijk het verzekeren dat de juiste vereisten zijn opgenomen) en verificatie in (m.a.w. verzekeren dat deze vereisten goed zijn geïmplementeerd).
Het proces zelf bestaat meestal uit een aantal iteraties. Voor alle betrokken stappen bestaan veel technieken. Voor de uitlokking is menselijke interactie van het allergrootste belang en het is dan ook niet verwonderlijk dat sociale vaardigheden hierbij een cruciale troef zijn. Ook voor de specificatiestap is er een breed spectrum aan technieken beschikbaar. In dit hoofdstuk zullen we ons richten op objectgeoriënteerde analyse (OOA) als specificatiemethode. Het belangrijkste doel van de vereistenfase bestaat uit de verzameling van de werkelijke behoeften en beperkingen van de cliënt. Tijdens deze fase (en ook tijdens de OOA) is communicatie tussen ontwikkelaar en opdrachtgever cruciaal, want beginnen met verkeerde vereisten impliceert een enorme stijging van de kosten bij de ontwikkeling van het product. Om deze communicatie te vergemakkelijken en te structureren zijn technieken ontwikkeld (Dhoedt, 2010):
15
interviews: directe interactie tussen de cliënt en de ontwikkelingsorganisatie scenario's: een min of meer formele set van sequenties van de gebruikeracties van het product in ontwikkeling prototype: de bouw van een „product‟ met beperkte functionaliteit, dat later wordt weggegooid.
Snelle prototypes kunnen gebruikt worden om de toekomstige gebruikers met een embryonale versie van het product te laten experimenteren. Hierbij hoopt men nieuwe behoeften, problemen te ontdekken bij het uitvoeren van specifieke taken, enz. Een snel prototype is een werkend product dat een subset van de functionaliteit van het product implementeert. Om het prototype echt „snel‟ te maken moet deze subset zo klein mogelijk gemaakt worden, zonder de mogelijkheid om nieuwe vereisten te vinden te verhinderen. De functionaliteit die direct zichtbaar is voor de gebruikers moet worden opgenomen (zoals de gebruikersschermen, de gegenereerde rapporten, de menu's,...). Functionaliteit die kan worden weggelaten in het „rapid‟ prototype omvat het controleren van de samenhang/geldigheid van input, ingewikkelde berekeningen (slechts een eenvoudige berekening volstaat indien van toepassing), veiligheidsmaatregelen,... Wanneer het team en de opdrachtgever overeenkomen dat de nodige basisfunctionaliteit is opgenomen in het snelle prototype, wordt het prototype bevroren en eindigt de vereistenfase. Merk op dat het levenscyclusmodel dat wordt gebruikt voor het prototype van het „build-andfix‟-type is. Het belangrijkste probleem van dit model houdt verband met de buitengewone onderhoudskosten. Maar omdat het prototype toch weggegooid wordt, stelt dit probleem zich hier niet. 2.4.1.1 De basisfunctionaliteit
De basisvereisten en vormgeving van de website worden weergegeven in Figuur 3. Eerst en vooral zal de gebruiker een loginscherm te zien krijgen, waarbij nieuwe gebruikers zich kunnen registreren. Wanneer de gebruiker ingelogd is zal hij een lijst met de projecten waarnemen, waarvan hij de auteur is. Bovendien zal de gebruiker de mogelijkheid hebben om projecten toe te voegen, aan te passen en te verwijderen. Ieder experiment is steeds gelinkt aan een welbepaald project en bij het aanklikken van één van de projecten zal bijgevolg een lijst weergegeven worden met de experimenten eigen aan een specifiek project. Een andere vereiste is de mogelijkheid metadata toe te voegen aan een experiment bij de creatie ervan. Ook zal de gebruiker de mogelijkheid hebben om eigen metadatacommando‟s toe te voegen aan de databank.
16
Figuur 3: Eerste versie vormgeving
Wanneer men één van de experimenten in de lijst aanklikt, krijgt men het submitscript, de resultaten en de metadata. Het submitscript wordt automatisch gegenereerd aan de hand van de aangevinkte metadatacommando‟s bij de creatie van het experiment. Hierbij moet ook automatisch een URL gecreëerd worden, die extern aanroepbaar is zonder dat de gebruiker zich eerst moet inloggen op dit website. Bijgevolg kan het submitscript bv. via een simpele „wget‟ opgeroepen worden op de experimentmachine. De uiteindelijke resultaten en de metadata van het experiment in kwestie worden eveneens gestockeerd via een commando en dit moet alweer mogelijk zijn zonder verificatie van de inloggegevens. Bovendien werd geëist dat het niet mogelijk zou zijn om experimenten te verwijderen. 2.4.1.2 Use-case diagram
Use-case diagrammen zijn bedoeld om een visie op de software te presenteren vanuit het oogpunt van de gebruiker. De functionaliteit zoals waargenomen door de gebruiker, de interactie tussen gebruikers en het systeem en de verschillende soorten (klassen) van gebruikers zijn weergegeven in het diagram. De drie aspecten hebben een duidelijke grafische voorstelling:
gebruiker van het system: actor basisfunctionaliteit van het systeem: use-case interacties tussen gebruikers en het systeem worden aangegeven door lijnen tussen actoren en use-cases.
17
Op basis van de voorgaande vereisten werd een use-case diagram opgesteld, dat als doel heeft de verschillende relaties binnen „Expres‟ duidelijk weer te geven. Uit Figuur 4 kan afgeleid worden dat er drie actoren interageren met het systeem, namelijk:
De anonieme gebruiker De ingelogde gebruiker De administrator
Een niet-geregistreerde of anonieme gebruiker kan binnen de module een aantal acties uitvoeren. Eerst en vooral laat het systeem toe dat een anonieme gebruiker zich registreert op de website en na de goedkeuring van de administrator bijgevolg dezelfde mogelijkheden krijgt als de ingelogde of geregistreerde gebruiker. Bovendien zijn er drie webpagina‟s die altijd bereikt kunnen worden zonder dat de gebruiker zich moeten inloggen. Dit is noodzakelijk voor het uitvoeren van de Linux-commando‟s zonder dat men zich telkens opnieuw moet identificeren. Deze pagina‟s zijn voor het uploaden van resultaten en metadata en het opvragen van het submitscript. Deze vereiste vormt echter een belangrijk beveiligingsrisico, bijgevolg worden deze webpagina‟s beveiligd via het gebruik van een uuid. Deze Universally Unique Identifier zorgt ervoor dat de URL‟s zeer moeilijk achterhaald kunnen worden, maar dit zal later verder besproken worden. Een tweede actor is de ingelogde gebruiker. Deze gebruiker heeft een groot aantal mogelijkheden binnen het systeem. Zo kan hij net zoals de anonieme gebruiker resultaten en metadata uploaden en het submitscript ophalen. Bovendien is hij in staat om zijn reeds gecreëerde projecten te bekijken en deze aan te passen of te verwijderen. Hij heeft ook de mogelijkheid om extra projecten toe te voegen en hieraan extra gebruikers toe te kennen als additionele auteurs. Deze krijgen dan ook het aangemaakte project in hun lijst van projecten te zien, aangezien deze lijst gekoppeld is aan een gebruiker. Wanneer men op één van de projecten klikt, worden alle experimenten weergegeven die gelinkt zijn aan het aangegeven project. Ook experimenten kunnen aangepast worden, waarbij o.a. de naam en beschrijving van een experiment kan gewijzigd worden. Het is echter niet mogelijk experimenten te verwijderen uit de databank. Bij het toevoegen van experimenten aan een welbepaald project krijgt de auteur ook de mogelijkheid om een aantal opties omtrent metadata toe te voegen, die dan zullen toegevoegd worden aan het submitscript. De administrator is de derde actor en bezit alle mogelijkheden van de andere actoren. Bovendien heeft de administrator als enige de mogelijkheid de verzameling metadata die standaard bij elk experiment wordt getoond uit te breiden.
18
Figuur 4: Use-case diagram
2.4.2 Objectgeoriënteerde analyse
Het doel van de objectgeoriënteerde analyse is om de uiterlijkheden van het product aan te geven. Waar de vereistenfase informeel de behoeften en beperkingen verzamelt, vertoont het specificatiedocument (het resultaat van de analysefase) een zekere mate van formaliteit (in de mate dat dit document kan dienen als basis voor een juridisch contract). De OOA fase omvat daarom een aantal stappen om te komen tot het gewenste niveau van formaliteit en precisie. Aan de andere kant moet ook de architectuur van het softwareproduct worden gedefinieerd in de OOA fase. Het architecturaal ontwerp identificeert klassen en objecten van het probleemdomein (dat wil zeggen klassen en objecten met een directe en duidelijke relatie met het probleem in kwestie). Deze architectuur wordt verder aangevuld tijdens de ontwerpfase met het verschil dat tijdens OOA de architectuur wordt bepaald op basis van wat het product moet doen, terwijl tijdens de ontwerpfase wordt aangegeven hoe deze functionaliteit dient te worden uitgevoerd. OOA itereert meestal via volgende stappen (Dhoedt, 2010):
19
Het formaliseren van de vereisten (door gebruiker-ontwikkelaar interactie) Identificatie van klassen (welke klassen zijn nodig om de essentie van het probleemdomein vast te leggen) Ontwikkeling van een geschikte klassenhiërarchie (wat zijn de relaties tussen de verschillende klassen van het probleemdomein) Identificatie van de verbindingen tussen objecten (welke objecten zijn nodig en hoe werken ze samen) Identificatie van het objectgedrag (hoe veranderen objecten als functie van de tijd)
Wanneer de gebruikerseisen min of meer officieel zijn vastgelegd in use-case diagrammen, is de tijd gekomen om de essentiële klassen te identificeren van het probleem en om ze te structureren in een hiërarchie. Het is belangrijk op te merken dat tijdens de OOA alleen klassen van het probleemdomein worden geïdentificeerd. Deze klassen hebben betrekking op de fundamentele bouwstenen (bv. fysieke personen, fysieke objecten, evenementen, ...) van het probleem zelf. Om de software te implementeren, kunnen extra klassen nodig zijn. Deze extra klassen worden vastgesteld tijdens de ontwerpfase (waarin de laatste klassenhiërarchie wordt opgebouwd). In Figuur 5 wordt de structuur weergegeven van de klassen. Hierbij zijn alle tabellen eigen aan de module met uitzondering van de klasse „users‟, die eigen is aan Drupaldatabank. In elk klasseobject stelt de eerste waarde steeds de primaire sleutel van de desbetreffende tabel voor.
20
Figuur 5: Klassediagram
We overlopen kort de verschillende klassen:
Experiments: In deze klasse worden de experimenten opgeslagen, op basis van een door de gebruiker ingegeven titel en beschrijving. De eid wordt automatisch gegenereerd bij het aanmaken van een nieuw experiment en ook de pid van het gelinkte project wordt automatisch meegegeven. De created en changed-waarden registreren de tijd aan de hand van UNIX-tijdstempels.
Projects: De klasse „projects‟ registreren de projecten aan de hand van een ingegeven titel en beschrijving. De primaire sleutel wordt opnieuw automatisch gecreëerd bij het aanmaken van een nieuw project. Deze tabel is verbonden met de tabel „Experiments‟ door een associativeit van 1-0…*. Dit wil zeggen dat elk experiment steeds verbonden 21
is aan één project uit de tabel „Projects‟, maar een project kan wel gelinkt zijn aan 0 of meerdere experimenten.
Users & User_project: De tabel „users‟ is eigen aan Drupal, waarbij wij gebruik maken van de waarden „uid‟ en „name‟. De „uid‟ wordt gebruikt in de associatietabel „User_project‟, die de verbinding vastlegt tussen projecten en hun auteurs.
Experiments_uuid: Zoals reeds eerder vermeld, wordt omwille van de beveiliging van de openbare pagina‟s gebruik gemaakt van een „Universally Unique Identifier‟. Deze UUID creëert een unieke identifier telkens wanneer een experiment wordt toegevoegd. De klasse „Experiments_uuid‟ legt deze link tussen een experiment en zijn unieke UUID vast.
Experiments_submitscript: Bij het creëren van een nieuw experiment krijgt de gebruiker de mogelijkheid om commando‟s toe te voegen aan het submitscript van dat experiment. De gekozen commando‟s uit de tabellen „standard_commands‟ en „additional_commands‟ worden bij het opslaan van een experiment opgenomen in de klasse „Experiments_submitscript‟ aan de hand van de experimentidentifier en de gekozen commando‟s.
Standard_commands: Deze klasse bevat alle gecreëerde standaardcommando‟s die bij elk experiment toegevoegd kunnen worden. De titel en het bijhorende commando worden ingegeven door de administrator.
Additional_commands: De klasse met de additionele commando‟s is grotendeels gelijkaardig aan de klasse „standard_commands‟, behalve dat deze tabel ook de project identifier van het bijhorende project vastlegt.
De commando‟s zijn verdeeld in twee groepen, namelijk de standaardcommando‟s en de additionele commando‟s. De standaardcommando‟s zijn voor iedereen zichtbaar en kunnen dus door iedere auteur toegevoegd worden aan het submitscript van een welbepaald experiment. Om de lijst van standaardcommando‟s enigszins onder controle te houden, is enkel de administrator in staat om de commando‟s aan te passen. Een tweede groep zijn de additionele commando‟s, die in tegenstelling tot de standaardcommando‟s niet universeel zijn en afhankelijk zijn van het project. Dit geeft de mogelijkheid aan de auteur om additionale commando‟s toe te voegen aan de databank, die worden gelinkt aan een welbepaald project. Bijgevolg zijn deze commando‟s dan ook enkel zichtbaar bij het toevoegen en aanpassen van experimenten die tot dat project behoren.
Experiment_results: Wanneer een experiment vervolledigd is, worden de resultaten en de metadata doorgestuurd naar de uploadpagina van de website. Hierbij worden de resultaten opgeslagen op de server, en wordt de „filename‟ en de „uri‟ ingevoerd in de klasse „Experiment_results‟. De „uri‟ omvat hierbij de plaats van de resultaten op de 22
server, zodat deze later makkelijk opgevraagd kunnen worden. Verder wordt ook de datum vastgelegd in het „created‟-veld aan de hand van een Unix-tijdstempel en de „eid‟ van het bijhorende experiment. Deze tabel is verbonden met de klasse „Experiments‟ waarbij ieder resultaat steeds tot een experiment behoort, maar een experiment wel meerdere resultaten kan bevatten.
Experiment_metadata: Deze klasse bevat de metadata die opgevraagd worden aan de hand van het submitscript. Naast de experiment identifier wordt ook de „rid‟ opgeslagen, die elke lijn metadata aan een resultaat linkt. Dit maakt het mogelijk om bij het weergeven van een experiment de verscheidene lijnen metadata te groeperen en te linken aan een welbepaald resultaat.
Deze klassen vormen de basis voor het gebruikte databankmodel en worden gedefinieerd in de expres.install file. Deze file creëert bij de installatie van de module de noodzakelijke tabellen in de databank. De installatie van de module in een Drupal-omgeving wordt in het volgende deel verder besproken.
23
2.4.3 Objectgeörienteerd design
Eens het specificatiedocument opgesteld en getest is kan de ontwikkeling van de software overgaan naar de volgende fase, namelijk de ontwikkelingsfase of de objectgeörienteerde design. Design kan omschreven worden als een activiteit voor het omzetten van de specificatiebeschrijvingen naar beschrijvingen die klaar zijn voor de uitvoering en bevat de „zorgen van de productie‟. In deze fase is de hoofdvraag dan ook niet meer „Wat moeten we ontwikkelen‟, maar „hoe moet het ontwikkeld worden‟. Hiervoor zal het OOD-model zoveel mogelijk de modellen ontwikkeld in de analysefase gebruiken. Het objectgeoriënteerd ontwerp proces kan worden beschreven door de classificatie van activiteiten in verschillende fasen en onderdelen. Bijna alle onderzoek maakt het onderscheid tussen analyse, ontwerp, en de uitvoeringsfasen van ontwikkeling. Het doel van analyse kan worden gezien als verduidelijken wat de taak is, terwijl het ontwerp en implementatie de taakspecificatie zien als een gegeven om vervolgens de details van de oplossing uit te werken. Een ander punt van mening is dat dataobjecten in de analyse aanzienlijk verschillen van objecten in de uitvoeringsfase, omdat een object in de analyse onafhankelijk en autonoom is, terwijl een object in een objectgeoriënteerde omgeving meestal een enkele controledraad heeft met veel andere objecten. Vandaar dat de ontwerpfase een cruciale rol speelt bij de overbrugging tussen deze verschillende computationele objecten. (Liang & O‟Grady, 1998) Het ontwerpproces neemt dus objecten als basis ter ontwikkeling van de software. Het identificeren van de objecten binnen het systeem en hun onderlinge relaties is een belangrijke fase in het ontwerpproces. Dit is de verdeling van het volledige product in subsystemen en hun communicatieklassen. Om te beantwoorden op de onderzoeksvraag, namelijk hoe een systeem voor het bewaren van experimentele resulaten kan worden opgezet, waarbij rekening moet worden gehouden met de verscheidenheid aan vereisten die elk experiment heeft, ontwikkelden wij een website bestaande uit enkele pagina‟s. 2.4.3.1 View projects
Op deze pagina kan de ingelogde gebruiker nieuwe projecten toevoegen, alsook zijn reeds bestaande projecten bekijken en beheren. Een nieuwe gebruiker zal dus steeds, zoals weergegeven in figuur 6, starten met het aanmaken van een nieuw project. Hiervoor wordt hij doorverwezen naar de pagina „Create new project‟, waar het project een naam, een beschrijving en eventuele extra auteurs krijgt toegewezen. De naam van het project is een verplicht veld – aangeduid door een rood sterretje - en zal nadien weergegeven worden op de pagina „View projects‟. De beschrijving van het project en het toevoegen van eventuele extra auteurs zijn optionele velden. Deze eventuele extra auteurs kunnen toegevoegd worden door de checkbox “Add additional authors” aan te vinken zodat automatisch een dropbox gegenereerd wordt waarin alle andere geregistreerde auteurs worden weergegeven. Hier kan men bij de aanmaak van het project onmiddellijk tot 3 extra auteurs toevoegen. De gebruiker die effectief het project aanmaakt wordt namelijk automatisch gelinkt aan dit project als auteur. 24
Figuur 6: Create new project
Wanneer de gebruiker een project gecreëerd heeft wordt hij weer doorverwezen naar de pagina „View projects‟. Doch zal de input van de gebruiker eerst gevalideerd worden. Deze validatiefunctie wordt eerst uitgevoerd alvorens het project toegevoegd wordt aan de database. Een project met een leeg naamveld wordt echter niet aanvaard, alsook de creatie van een tweede project met eenzelfde naam krijgt een foutmelding als resultaat. Dit is ter bescherming van de gebruiker, opdat er achteraf geen verwarring ontstaat wanneer er auteurs aan een project toegevoegd worden. Wanneer een project gevalideerd en toegevoegd is zal de gebruiker deze kunnen beheren. (Figuur 7) De validatie van het project wordt weergegeven door een validatiemelding.Vervolgens kan de auteur de edit-button gebruiken om het project aan te passen waarna hij wordt doorverwezen naar de pagina „Edit project‟. Hier kan de auteur – zoals de naam het zelf zegt – een project aanpassen. De naam van het desbetreffende project wordt hiervoor ook steeds weergegeven bovenaan de pagina. Het aanpassen van het project houdt in dat hij de naam en van het project kan wijzigen alsook eventuele auteurs toevoegen of verwijderen. Dit kan hij doen door gebruik te maken van de dropboxen, waarin enkel de 25
auteurs gelinkt aan het project of net niet gelinkt aan het project worden weergegeven. Hier is het belangrijk te weten dat ook de originele auteur, of de gebruiker die initieel het project heeft aangemaakt ook kan verwijderd worden van het project. Een tweede belangrijke functionaliteit die men kan raadplegen op de pagina „View projects‟ is de delete-knop. Hiermee kan men een project definitief uit de database verwijderen, nadat men een definitieve bevestiging geconfirmeerd heeft. De hieraan gelinkte experimenten blijven echter wel in de database behouden.
Figuur 7: View projects
2.4.3.2 View experiments
Eens een gebruiker een project gecreëerd heeft kan hij via de hyperlink op de „View projects pagina‟ doorverwezen worden naar de pagina „View experiments‟. Allereerst wordt op deze pagina de naam van het project weergegeven en kan men via dynamische gebruikersmogelijkheden de beschrijving en de auteurs van het project bekijken. Doch bestaat de hoofdfunctionaliteit van deze pagina uit het aanmaken en beheren van experimenten. In de eerste plaats zal de auteur binnen een project zijn eerste experiment moeten aanmaken alvorens dit experiment op de experimentcomputer uit te voeren. Hiervoor komt men op de pagina „Create new experiment‟ terecht, zoals weergegeven is in figuur 8. Hier kan men het experiment, net zoals een project, een naam en een beschrijving geven. Beiden zijn hier echter slechts optionele velden opdat de onderzoeker snel aan de slag kan gaan en deze in een latere fase kan benoemen en definiëren.
26
Figuur 8: Create new experiment
Belangrijk zijn hier echter de velden standard commands en additional commands. Hier kan men zoals reeds uitgelegd in de objectgeorienteerde analyse Linux-commando‟s toevoegen aan het project. Afhankelijk of men een administrator is of een gewone geregistreerde gebruiker kan men standaard commando‟s of additionele commando‟s toevoegen. (Figuur 9) Voor het toevoegen van een standaard commando wordt de administrator doorverwezen naar de pagina „Add new standard command‟. Hier moeten 2 verplichte velden worden ingevoerd namelijk de naam van het commando en het Linux-commando zelf. Wanneer een van beiden niet ingevoerd is verkrijgt men opnieuw via de validatiefunctie een foutmelding en een validatiemelding indien de validatie geslaagd is. Vervolgens wordt men doorverwezen naar dezelfde pagina opdat men een nieuw standaard commando kan invoeren. Standard commando‟s zijn universeel voor Expres en dienen tot regelmatig gebruik. Hier hebben we het de onderzoekers gemakkelijk willen maken, opdat zij niet steeds bij elk project deze commando‟s moeten gaan invoeren. Doch hebben we hier ook rekening gehouden met een zekere beveiliging om misbruik tegen te gaan. De administrator zal deze commando‟s beheren, zodanig dat niet elke onderzoeker hier naar willekeur commando‟s aan kan blijven toevoegen.
27
Figuur 9: Add new standard command
Voor het toevoegen van een additioneel commando wordt men doorverwezen naar de pagina „Add new additional command‟ Ook hier dient men net zoals bij het toevoegen van standaard commando‟s, het commando een naam te geven en een Linux-commando in te voeren. Opnieuw zijn deze velden verplicht en wordt bij een ongeldige validatie een foutmelding gegenereerd. Deze commando‟s zijn echter niet universeel, maar eigen aan en gelinkt aan een welbepaald project via een pid. Na een geldige validatie, met bijbehorende validatiemelding wordt men hier doorverwezen naar de pagina “Create new experiment”, alwaar de auteur de creatie van een nieuw experiment kan verderzetten. Onder de tabs standard commands en additional commands worden nu verschillende checkboxen weergegeven van de verschillende commando‟s die zijn toegevoegd. Op deze manier kan de auteur aanvinken welke metadata hij wil laten genereren in het submitscript en opvragen aan de experimentcomputer. Wanneer een experiment is aangemaakt kan deze ook aangepast worden, op een gelijkaardige manier als een project. Men komt hier op de pagina „Edit an experiment‟ terecht, alwaar men de naam en de beschrijving kan aanpassen alsook zowel standaard als additionele commando‟s aan het experiment kan toevoegen of verwijderen via een dropbox.
28
Figuur 10: Edit an experiment
2.3.4.3 Submitscript
Wanneer de auteur finaal een experiment heeft aangemaakt wordt er een submitscript gegenereerd. Dit is een script waarin alle opgegeven standaard en additionele commando‟s gelinkt aan een experiment vervat zitten. De bedoeling van dit submitscript is dat de auteur van een experiment op een eenvoudige wijze vanop de experimentcomputer aan dit submitscript kan geraken. Opdat het niet mogelijk zou zijn om zonder voorkennis van het submitscript hier zomaar als onbevoegde gebruiker toegang tot te verkrijgen hebben we de URL van dit submitscript beveilig met een UUID, die gelinkt is aan elk experiment. Een UUID is een Universally Unique identifier, die gegenereerd wordt en quasi uniek is. Er bestaan verschillende versies van deze UUID of verschillende methoden waarop deze UUID kan gegenereerd worden. De hier gebruikte UUID is een versie 4 UUID en is gebaseerd op willekeurige getallen. Het algoritme is een pure PHP-implementatie en genereerd een UUID van 32 karakters bestaande uit een versienummer en een gereserveerde bit. Deze kan als volgt voorgesteld worden: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, waarbij 4 het versienummer is en y het karakter 8, 9, A of B. Wij hebben hier bewust niet gewerkt met functies zoals unique() omdat deze te voorspelbaar zijn en dus gemakkelijk achterhaalbaar. Het submitscript kan vervolgens via een eenvoudig „wget-commando‟ opgevraagd worden op de experimentcomputer. Op deze manier wordt de benodigde metadata, die bepaald werd bij het aanmaken van een experiment, opgevraagd aan de experimentcomputer, en automatisch opgeslagen in de database van Expres. Een voorbeeld van zo een submitscript kan u zien in figuur 11. Alsook kan u hier een voorbeeld van de gegenereerde UUID weervinden in de URL.
29
Figuur 11: Submitscript
2.4.3.4 Resultaat en metadata
Eens een experiment gefinaliseerd is op de experimentcomputer kan de onderzoeker vervolgens het resultaat uploaden op Expres. (Figuur 12) Dit gebeurt aan de hand van de button „Upload an experiment‟ op de „View experiment‟ pagina. Men wordt hierdoor doorverwezen naar de pagina „Upload a new file‟. Deze pagina is opgebouwd aan de hand van 2 file upload elementen, een voor de metadata en een voor de resultaten. Opnieuw wordt bovenaan de pagina de titel van het experiment weergegeven, zodat er geen verwarring kan ontstaan. Belangrijk hier ook is dat ook deze pagina toegankelijk is voor niet-geregistreerde gebruikers. Op deze manier kan een onderzoeker op een eenvoudige manier de resultaten van het experiment uploaden naar Expres van op de experimentcomputer en hoeft hij dus niet steeds opnieuw in te loggen wanneer een experiment is afgelopen. De beveiliging hiervan gebeurt opnieuw via een versie 4 UUID, die enkel gekend is door de aan het project gelinkte auteurs. De metadata werd echter reeds via het submitscript automatisch geupload.
Figuur 12: Upload a new file
30
2.4.4 Objectgeörienteerd programmeren
In het volgende deel wordt een korte bespreking gegeven van de bestanden die nodig zijn en code die nodig is om de module op een correcte manier te installeren. Info-file
Eerst maken we een module genaamd „Expres‟. De naam is een combinatie van EXPerimenten en RESultaten, die de twee basisprincipes van deze module zijn. Het eerste bestand dat noodzakelijk is voor de module is expres.info. Dit bestand declareert de naam van de module, een beschrijving, de kern die zal worden gebruikt en de bestanden die Drupal moet laden. Het bestand ziet er als volgt uit: name = Expres description = Final module core = 7.x package = Drupal 7 Development files[] = expres.module files[] = expres.pages.inc files[] = expres.install dependencies[] = field_ui Schema API
De tweede stap in het creëren van onze module, is het toevoegen van extra databasetabellen om de functionaliteit van onze module te ondersteunen. Omdat we gebruik maken van WAMP-server, is MySQL het gebruikte databanksysteem. Maar in plaats van de databanktabellen zelf te creëren, laten we Drupal dit voor ons doen met behulp van een deel van de databaselaag, namelijk de Schema API. Het Schema API maakt het mogelijk om databasetabellen te declareren aan de hand van een gestructureerde rij (vergelijkbaar met de Form API) en biedt API-functies aan voor het maken, verwijderen en het veranderen van tabellen, kolommen, sleutels en indexen (http://drupal.org/developing/api/schema). De tafels worden gedefinieerd in het expres.install bestand, dat gebruik maakt van „hooks‟ die Drupal enkel gebruikt wanneer de module wordt geïnstalleerd, verwijderd of aangepast. Bijgevolg moet dit bestand maar enkele keren worden ingeladen. De belangrijkste „hook‟ in expres.install is hook_schema(), die de databasetabellen van deze module declareert. De gecreëerde tabellen zijn gebaseerd op het klassediagram uit de objectgeoriënteerde analyse. We illustreren dit aan de hand van de tabel „projects‟: function expres_schema() { $schema['projects'] = array( 'description' => 'The base table for projects.', 'fields' => array( 'pid' => array( 'description' => 'The primary identifier for a project.', 31
'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'title' => array( 'description' => 'The title of this project.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), 'description' => array( 'description' => 'The description of this project.', 'type' => 'varchar', 'length' => 1000, 'not null' => TRUE, 'default' => '', ), 'created' => array( 'description' => 'The Unix timestamp when the project was created.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), 'changed' => array( 'description' => 'The Unix timestamp when the project was most recently saved.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), ), 'unique keys' => array( 'pid' => array('pid') ), 'primary key' => array('pid'), ); De eerste regel definieert de hook_schema() functie, waarbij „hook‟ wordt vervangen door de naam van de module. De waarden van de rij „schema‟ zijn de namen van de tabellen die moeten worden aangemaakt. Drupal eist dat de namen van tabellen enkelvoudige zelfstandige naamwoorden zijn. Elke tabel wordt op zijn beurt gedefinieerd als een geneste rij die de velden, indexen en andere gegevens van de tabel bepaalt. De primaire sleutel is het veld „pid‟ en wordt aangegeven op het einde. Voor het opslaan van de experimenten maken we gebruik van een andere tafel, genaamd „experiments‟: $schema['experiments'] = array( 32
'description' => 'The base table for experiments.', 'fields' => array( 'eid' => array( 'description' => 'The primary identifier for an experiment.', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'pid' => array( 'description' => 'The current project identifier.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'title' => array( 'description' => 'The title of this experiment.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', ), 'description' => array( 'description' => 'The description of this experiment.', 'type' => 'varchar', 'length' => 1000, 'not null' => TRUE, 'default' => '', ), 'created' => array( 'description' => 'The Unix timestamp when the experiment was created.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), 'changed' => array( 'description' => 'The Unix timestamp when the experiment was most recently saved.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), ), 'unique keys' => array( 'eid' => array('eid') ), 'primary key' => array('eid'), 'foreign keys' => array( 33
'projects' => array( 'table' => 'projects', 'columns' => array( 'pid' => 'pid', ), ), ), ); Deze tabel heeft veel gemeen met de tabel „projects‟, met uitzondering van het feit dat we ook een vreemde sleutel definiëren, namelijk „pid‟. Dit linkt elk experiment aan een specifiek project. Drupal creëert automatisch de corresponderende tabellen voor ons in de database, wanneer de module voor het eerst wordt ingeschakeld. Als onze module volledig verwijderd wordt, zal Drupal er ook voor zorgen dat de tabellen worden verwijderd. Naast deze twee tabellen zijn er nog zeven andere tabellen die we zullen declareren. De declaratie van een entiteit
We vertellen Drupal over onze nieuwe entiteit met behulp van twee methoden. De eerste is door het gebruik van een andere „hook‟ genaamd hook_entity_info(). Deze „hook‟ vertelt Drupal over de entiteit of entiteiten en biedt het Field UI systeem de informatie die zij nodig heeft om velden aan entiteiten te hechten. De tweede methode is een „controller class‟ genaamd DrupalDefaultEntityController, die is opgenomen in Drupal. Een controller is een „loader object‟ voor een entiteit. Alle entiteiten moet een controller hebben, maar meestal wordt gebruik gemaakt van de standaardcontroller “DrupalDefaultEntityController” (Butcher, 2010). Ook in deze module wordt gebruik gemaakt van de standaardcontroller. Laten we eerst een kijkje nemen naar de hook_entity_info(). We zullen opnieuw gebruik maken van grote gestructureerde rij, die alle informatie definieert die we nodig hebben om te communiceren met Drupal. Om de verschillende velden gedefinieerd in de rijen uit te leggen, zullen we ons focussen op de tabel „experiments‟. function expres_entity_info() { $return['experiments'] = array( 'label' => t('Experiment'), 'base table' => 'experiments', 'second table' => 'projects', 'fieldable' => TRUE, 'entity keys' => array( 'id' => 'eid', 'projects' => 'pid', 'bundle' => 'pid', 'label' => 'title', ), 'bundle keys' => array( 'bundle' => 'pid', ), 'static cache' => TRUE, 34
'bundles' => array(), ); return $return; } De string „experiments‟ zal fungeren als de machinenaam van deze entiteit. De machinenaam is de naam die gebruikt wordt in de code om te verwijzen naar deze entiteit. Het label geeft aan welke naam getoond moet worden aan de gebruiker. De „second table‟ declareert de tabel waar de vreemde sleutel naar verwijst. De objecten in de „entity keys‟ vertellen het entiteitsysteem hoe ons experiment opgeslagen en gebruikt zal worden door de standaardcontroller: • • •
De tabel waar experimenten worden opgeslagen heet „experiments‟, die als primaire sleutel „eid‟ heeft. De experimenten behoren tot een bepaald project en deze link wordt vastgelegd door de project-id. De naam van een bepaald experiment wordt opgeslagen in het titelveld.
Twee andere belangrijke objecten zijn de „cacheable‟ and „fieldable‟-vlaggen (Butcher, 2010): • •
„Static cache‟ geeft aan dat de controller een kopie van een entiteit moet bijhouden in het geheugen. „Fieldable‟ maakt aan de Field API duidelijk dat we velden kunnen hechten aan deze entiteit. Dit is heel belangrijk, want het is één van de belangrijkste methoden om een nieuw entiteitstype te definiëren.
Nu hebben we onze entiteit gedefinieerd en zijn we in staat om het te laden, maar we hebben nog geen manier voor het creëren of bewerken van entiteiten. We moeten nog de rest van de levenscyclus van een entiteit definiëren en er een „user interface‟ voor creëren. Dit deel wordt echter niet verder besproken in deze thesis (zie Bijlage 1).
35
Algemene conclusie Om een antwoord te kunnen bieden op onze onderzoeksvraag hebben we een Drupal-module ontwikkeld die onderzoekers helpt bij het beheer van projecten, experimenten en de bijbehorende metadata. Deze module bestaat uit een 3-tal belangrijke onderdelen, die ontworpen zijn om het beheer van onderzoek te vereenvoudigen.
Het beheer van projecten: Elke onderzoeker is steeds bezig met onderzoek. Dit onderzoek is vaak onderworpen aan administratieve omslachtigheden, zoals het ingeven van de benodigde metadata en het beheer van al de resultaten behorend tot een welbepaald project. Nu kan de onderzoeker via de ontwikkelde website projecten aanmaken, bewerken en eventueel verwijderen indien dit nodig zou zijn. Deze projecten zijn gemakkelijk hanteerbaar en vormen de grote basisstructuur van de ontwikkelde module.
Het beheer van experimenten: Elk project van een onderzoeker bestaat uit verschillende experimenten, waarmee men een antwoord wil bieden op verschillende onderzoeksvragen. De experimenten die onderdeel uitmaken van een welbepaald project kunnen nu eenvoudig aangemaakt en aangepast worden. Zo worden deze experimenten op een overzichtelijke manier opgeslagen op de server en kan men steeds eenvoudig de gebruikte metadata en resultaten opvragen.
Het submitscript: Dit script is gelinkt aan de verscheidenheid aan vereisten die elk experiment heeft. Men kan nu de benodigde metadata die verbonden is aan een project of experiment aanmaken en toewijzen aan een specifiek submitscript. Via een eenvoudig „wget-commando‟ wordt deze metadata verzameld op de experimentcomputer en opgeslagen op de server. Wanneer de resultaten van het experiment dan ook geupload worden bekomt men een webpagina van een experiment met de hieraan gelinkte resultaten en bijbehorende metadata.
Tot slot is er binnen de ontwikkelde module zeker nog plaats voor verdere uitwerking van nieuwe en uitgebreidere functionaliteit. Een volgens ons belangrijke uitbreidingsmogelijkheid betreft de raadpleging van de resultaten en de metadata. Wanneer men de metadata zou opslaan in de databank, alsook de hieraan gelinkte resultaten, zou men aan de hand van een metadatafilter deze resultaten dynamisch kunnen weergeven. Dit zou het opzoekwerk van het onderzoek nog vereenvoudigen. Men zou dan bijvoorbeeld slechts de resultaten gelinkt aan een welbepaalde CPU kunnen opvragen en weergeven. Op die manier hoeft men niet steeds op zoek te gaan in een vaak groot bestand vol gegevens.
36
Bijlagen Bijlage A: Bespreking code Expres
Entity management Managing projects
The second part of the expres.module file declares the different pages that will be used in our module. This is done using the hook_menu(), which enables us to first of all define the pages and secondly defines which pages should be shown in the menu. Viewing projects
function expres_menu() { $items['projects'] = array( 'title' => 'View projects', 'page callback' => 'expres_projects', 'type' => MENU_NORMAL_ITEM, 'access callback' => 'check_logged_in', 'weight' => 1, 'file' => 'expres.pages.inc', ); Once again the hook_menu() function is changed to incorporate the name of the module, resulting in the expres_menu() function. The first part of the function sets up our project landing page, where the authors projects can be viewed. The array starts with defining the title of the menu tab, namely „View projects‟. The second attribute („page callback‟) sets the function that needs to be called when visiting the page which is located in the file defined in the „file‟ field. The expres_projects function in expres.pages.inc that supports this page, is: function expres_projects() { global $user; $current_url = 'http://' .$_SERVER['HTTP_HOST']; $url = url($path = NULL); $img_url = $current_url.$url; $current_url .= $url."?q="; $result = db_query("SELECT p.pid, p.title FROM {projects} p INNER JOIN {user_project} u ON p.pid = u.pid WHERE u.uid='$user->uid'"); $list=array(); $items=array(); foreach ($result as $record) { $list[] = t("
".'@title '."  
37
< /a>  ", array( '@title' => $record->title, '@pid' => $record->pid, )); } $theme_args = array('items' => $list, 'type' => 'ol'); $output = theme('item_list', $theme_args); if (empty($list)){ $no_projects = t('No projects added yet.
'); $form = drupal_render(drupal_get_form('button_projects_form')); return $no_projects.=$form; }else{ $form = drupal_render(drupal_get_form('button_projects_form')); $output.=$form; return $output; } } With the global user function we get the userID of the current logged-in user. In the following four lines the current url is set which will be used to transfer the user to the experiment page. Through the database query we get a list of all the projects of the currently logged-in user. The list is created using the foreach-loop, which gets the pid and title of every project. The pid is then used in the link to redirect to user the the experiment page, where he will find a list of all experiments attached to this project. The theme() function uses the created list and creates the appropriate theme for listing the projects. The if-loop is in fact a simple check to see if there are projects assigned to the user, and if not returns a string. Finally the drupal_get_form function calls for the form 'button_projects_form': function button_projects_form($form, &$form_state) { $form['add'] = array( '#type' => 'submit', '#value' => t('Add'), '#weight' => 1, '#submit' => array('add_projects_form_submit'), ); return $form; } function add_projects_form_submit($form, &$form_state) { $form_state['redirect'] = 'projects/add'; }
38
This function simply defines a submit button, which calls the „add_projects_form_submit‟ function. This function redirects the user to the page where projects can be added. Adding projects
The redirect function sends the user to the „projects/add‟ page, which has to be created in the hook_menu(): $items['projects/add'] = array( 'title' => 'Add new project', 'page callback' => 'expres_add_project', 'type' => MENU_NORMAL_ITEM, 'access callback' => 'check_logged_in', 'weight' => 2, 'file' => 'expres.pages.inc', ); Once again a title is defined along with the function and the file in which the function is written. The function starts with the drupal_set_title function, which defines the title of the page. function expres_add_project() { global $user; drupal_set_title(t('Create new project')); $result = db_query("SELECT uid, name FROM {users} WHERE uid !='$user->uid'"); $list=array(); foreach ($result as $record) { $list[$record->uid] = t('@name', array( '@name' => $record->name, )); } return drupal_get_form('project_form', $list); } After that a db_query gets the userID and the name of all users except for the user who is logged in, because he is automatically assigned to the project which he creates. That list is added to the drupal_get_form function, which calls the project_form. function project_form($form, &$form_state, $list) { $form['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#weight' => 1, '#required' => TRUE, ); $form['description'] = array( '#type' => 'textarea', '#title' => t('Description'), '#weight' => 2, '#required' => FALSE, 39
); $form['add_users_checkbox'] = array( '#type' => 'checkbox', '#title' => t('Add additional authors'), '#weight' => 3, ); $form['users'] = array( '#title' => t('Second author'), '#type' => 'select', '#weight' => 4, '#options' => $list, '#states' => array( 'visible' => array( ':input[name="add_users_checkbox"]' => array('checked' => TRUE), ), ), ); $form['users2'] = array( '#title' => t('Third author'), '#type' => 'select', '#weight' => 5, '#options' => $list, '#states' => array( 'visible' => array( ':input[name="add_users_checkbox"]' => array('checked' => TRUE), ), ), ); $form['users3'] = array( '#title' => t('Fourth author'), '#type' => 'select', '#weight' => 6, '#options' => $list, '#states' => array( 'visible' => array( ':input[name="add_users_checkbox"]' => array('checked' => TRUE), ), ), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 7, '#submit' => array('project_form_submit'), ); return $form; }
40
The form defines a number of fields, where the title field allows the user to specify a title and the description field enables to user to add a description to the project. Furthermore a checkbox is added, which gives the possibility to add additional authors to a project. In this form the additional authors are shown using dropboxes. The variable list which was sent along, is used to generate the list of additional users. Finally a submit button calls the 'project_form_submit' function: function project_form_submit($form, &$form_state) { $uid = $form_state['values']['users']; $uid2 = $form_state['values']['users2']; $uid3 = $form_state['values']['users3']; try { //add project to projects $table = 'projects'; $project->is_new = empty($project->pid); $project->title = $form_state['values']['title']; $project->description = $form_state['values']['description']; $project->created = REQUEST_TIME; $project->changed = REQUEST_TIME; drupal_write_record($table, $project); //add logged-in user to user_project global $user; $table = 'user_project'; $user_project->is_new = empty($user_project->upid); $user_project->pid = $project->pid; $user_project->uid = $user->uid; $user_project->created = REQUEST_TIME; $user_project->changed = REQUEST_TIME; drupal_write_record($table, $user_project); //add user to user_project if ($uid != '0'){ $add_user_project->is_new = empty($add_user_project>upid); $add_user_project->pid = $project->pid; $add_user_project->uid = $uid; $add_user_project->created = REQUEST_TIME; $add_user_project->changed = REQUEST_TIME; drupal_write_record($table, $add_user_project); } //add user to user_project if ($uid2 != '0'){ $add_user_project2->is_new = empty($add_user_project2>upid); $add_user_project2->pid = $project->pid; $add_user_project2->uid = $uid2; $add_user_project2->created = REQUEST_TIME; $add_user_project2->changed = REQUEST_TIME; drupal_write_record($table, $add_user_project2); } 41
//add user to user_project if ($uid3 != '0'){ $add_user_project3->is_new = empty($add_user_project3>upid); $add_user_project3->pid = $project->pid; $add_user_project3->uid = $uid3; $add_user_project3->created = REQUEST_TIME; $add_user_project3->changed = REQUEST_TIME; drupal_write_record($table, $add_user_project3); } } catch (Exception $e) { $transaction->rollback(); watchdog_exception('projects', $e, NULL, WATCHDOG_ERROR); return FALSE; } drupal_set_message(t('Project saved.')); $form_state['redirect'] = 'projects'; } First the three uids of the selected additional authors are requested from the project_form. In the second part the data is sent to the appropriate database table. The first altered table is the projects table, which is defined using the table variable. Then a new pid is created and added to the variable project. In addition the title and the description are retrieved from the project form and added to the variable along with two UNIX-timestamps. In the final step the variable project is written to the projects table. The second table that needs to be altered is the user_project table, which links users to projects. Once again the primary key is created and stored together with the pid and the uid of the users that were selected in the project form. This is done for each of the selected values and once for the logged-in user. When all database tables have been updated, a message appears and the user is redirected to the projects page. Deleting projects
The next page which is added to the hook_menu() function is the delete page, which allows users to delete their own projects. The declaration is similar to the previous menu pages. $items['projects/delete'] = array( 'title' => 'Delete a project', 'page callback' => 'expres_del_project', 'type' => MENU_NORMAL_ITEM, 'access callback' => 'check_logged_in', 'weight' => 3, 'file' => 'expres.pages.inc', ); The expres_del_projects function, which is called through the delete page, generates the following function: 42
function expres_del_project() { global $user; $sub_url = arg(2); $current_url = 'http://' .$_SERVER['HTTP_HOST']; $url = url($path = NULL); $current_url .= $url."?q="; if (empty($sub_url)){ $result = db_query("SELECT p.pid, p.title FROM {projects} p INNER JOIN {user_project} u ON p.pid = u.pid WHERE u.uid='$user->uid'"); $list=array(); $items=array(); foreach ($result as $record) { $list[] = t("
".'@title'."", array( '@title' => $record->title, '@pid' => $record->pid, )); } $theme_args = array('items' => $list, 'type' => 'ol'); return theme('item_list', $theme_args); }else { $title = db_query("SELECT title FROM {projects} WHERE pid = '$sub_url'")->fetchField(); $pid = db_query("SELECT pid FROM {projects} WHERE pid = '$sub_url'")->fetchField(); $sure = t("Are you sure you want to delete project: ".$title."?
"); $form = drupal_render(drupal_get_form('button_projects_delete_form', $pid)); $sure.=$form; return $sure; } } Once again we get the uid of the logged in user and the current url. Normally this page is generated through the delete buttons on the view projects page, which attaches the pid of the corresponding project to the url. This function then collects the pid using the arg() function and assigns it to the variable sub_url. There is however an if-loop, which controls if there is a pid attached to the url. If there isn‟t a pid, the page generates once again a list of all projects of the logged in user. The pid is then used to collect the title of the project using fetchField(). This function is new to Drupal 7 and allows for the extraction of a single record from a database table. The drupal_get_form function two buttons are shown, one to confirm the deletion of the project and one to redirect the user.
43
function button_projects_delete_form($form, &$form_state, $pid) { $form_state['pid'] = $pid; $form['yes'] = array( '#type' => 'submit', '#value' => t('Yes'), '#weight' => 3, '#submit' => array('project_delete_confirm_submit'), ); $form['no'] = array( '#type' => 'submit', '#value' => t('No'), '#weight' => 4, '#submit' => array('del_projects_form_no'), ); return $form; } function del_projects_form_no($form, &$form_state) { $form_state['redirect'] = 'projects/'; } The “Yes” button calls the 'project_delete_confirm_submit' function, which deletes the project from the database table „projects‟. After the delete query, a message is generated and the user is redirected to the projects page. function project_delete_confirm_submit($form, &$form_state) { $num_deleted = db_delete('projects') ->condition('pid', $form_state['pid']) ->execute(); drupal_set_message(t('The project has been deleted.')); $form_state['redirect'] = 'projects'; } Editing projects
The last page concerning the projects that is hardcoded is the editing page, which allows authors to edit projects and authors. $items['projects/edit'] = array( 'title' => 'Edit a project', 'page callback' => 'expres_edit_project', 'type' => MENU_NORMAL_ITEM, 'access callback' => 'check_logged_in', 'weight' => 4, 'file' => 'expres.pages.inc', ); The 'expres_edit_project' function generates a form with a textfield to edit the title of a project and two dropboxes to add or delete authors. Using the submit button „Ok‟ the function
44
'edit_project_submit' updates the database tables „projects‟ and „user_project‟. These updates depend on the altered fields in the form function. function edit_project($form, &$form_state, $sub_url, $list, $list2){ $form_state['pid'] = $sub_url; $pid = $sub_url; $form['title'] = array( '#type' => 'textfield', '#title' => t('New title'), '#weight' => 1, '#required' => FALSE, ); $form['description'] = array( '#type' => 'textarea', '#title' => t('New description'), '#weight' => 2, '#required' => FALSE, ); $form['add_users'] = array( '#title' => t('Add author'), '#type' => 'select', '#weight' => 3, '#options' => $list2, ); $form['delete_users'] = array( '#title' => t('Delete author'), '#type' => 'select', '#weight' => 4, '#options' => $list, '#empty_option'=> t(''), ); $form['Ok'] = array( '#type' => 'submit', '#value' => t('Ok'), '#weight' => 5, '#submit' => array('edit_project_submit'), ); return $form; } Once again multiple db queries are called for, which as stated before depend on the fields that which to altered in the database. In the first update the project identifier is used as a condition to alter a title, which is collected from the form using form_state[„pid‟]. In addition form_state[] can also be used to collect values from the „edit_project‟ form. For example, when adding additional users the selected user in the dropbox is collected using $form_state['values']['add_users']. At the completion of the database queries the user is once again redirected. function edit_project_submit($form, &$form_state) { 45
if (!(empty($form_state['values']['title']))){ $update = db_update('projects') ->fields(array('title' => $form_state['values']['title'])) ->condition('pid', $form_state['pid']) ->execute(); } if (!(empty($form_state['values']['description']))){ $update = db_update('projects') ->fields(array('description' => $form_state['values']['description'])) ->condition('pid', $form_state['pid']) ->execute(); } if (!(empty($form_state['values']['add_users']))){ $update2 = db_insert('user_project') ->fields(array('pid' => $form_state['pid'], 'uid' => $form_state['values']['add_users'], 'created' => REQUEST_TIME, 'changed' => REQUEST_TIME)) ->execute(); } if (!(empty($form_state['values']['delete_users']))){ $update3 = db_delete('user_project') ->condition('uid', $form_state['values']['delete_users']) ->condition('pid', $form_state['pid']) ->execute(); } drupal_set_message(t('Project edited')); $form_state['redirect'] = 'projects'; } Managing experiments
The second part of hook_menu() concernes the management of the experiments. Like the project management pages, there is a viewing page and an editing page. However there isn‟t a page for deleting experiments, because the users aren‟t allowed to delete experiments, only projects. Another difference with the project pages is the fact that the experiment pages aren‟t shown in the menu, because the project pages have to be visited first so that the corresponding „pid‟ can be recovered. The command pages are also made invisible, because of familiar reasons. The first page is the page where the experiments assigned to a specific project are viewed. $items['projects/experiments'] = array( 'title' => 'View experiments', 'page callback' => 'expres_experiments', 'type' => MENU_NORMAL_ITEM, 'access callback' => TRUE, 'weight' => 7, 'file' => 'expres.pages.inc',
46
); Viewing experiments
Once again the function that is called when visiting the page is the page callback and the file field represents the file where the code is stored. The function starts with the collection of the pid that is transferred using the url. This variable is then used to collect the project title, description from the projects table and the eid and title of the attached experiments in the experiments table. In the last database query all the users assigned to a project are collected from the users table using the user_project table, which stores the user identifier along with the project identifier. Using a foreach loop a list is created storing all authors of a project, which is then sent to the following form function. The second loop creates a list of all experiments with the same pid as collected from the url. The list creates for each a result of the database query a link to the view experiment page and an image with a link to the editing page attached to it. function expres_experiments() { $sub_url = arg(2); $current_url = 'http://' .$_SERVER['HTTP_HOST']; $url = url($path = NULL); $current_url .= $url."?q="; $project = db_query("SELECT title FROM {projects} WHERE pid ='$sub_url'")->fetchField(); $description = db_query("SELECT description FROM {projects} WHERE pid ='$sub_url'")->fetchField(); drupal_set_title(t('View experiments (Project: '.$project.")")); $result = db_query("SELECT eid, title FROM {experiments} WHERE pid ='$sub_url'"); $result_authors = db_query("SELECT u.uid, u.name FROM {users} u INNER JOIN {user_project} up ON up.uid = u.uid WHERE up.pid = '$sub_url'"); $list_authors=array(); foreach ($result_authors as $record_authors) { $list_authors[$record_authors->uid] = t('@name', array( '@name' => $record_authors->name, )); } $theme_args_authors = array('items' => $list_authors, 'type' => 'ol'); $output_authors = theme('item_list', $theme_args_authors); $list=array(); $items=array(); foreach ($result as $record) { $list[] = t("".'@ title'."
47
 
", array( '@title' => $record->title, '@eid' => $record->eid, )); } $theme_args = array('items' => $list, 'type' => 'ol'); $output = theme('item_list', $theme_args); if (empty($list)){ $no_projects = t('No experiments added yet.
'); $form = drupal_render(drupal_get_form('view_experiments_form', $sub_url, $description, $output_authors)); return $no_projects.=$form; }else{ $form = drupal_render(drupal_get_form('view_experiments_form', $sub_url, $description, $output_authors)); $output.=$form; return $output; } } In the last part of the function the form function 'view_experiments_form' is called, and several arguments are sent along with it. The following form is rather simple code used to get two form types. The first type is „fieldset‟ for the description of a project and the listing of the authors. The second is „submit‟, which shows a button to add experiments, and redirects the user to the add experiments page. function view_experiments_form($form, &$form_state, $sub_url, $description, $output_authors) { $form_state['pid'] = $sub_url; $form['description'] = array( '#title' => t('Project description  '), '#type' => 'fieldset', '#weight' => 1, '#collapsible' => TRUE, '#collapsed' => TRUE, '#value' => $description, ); $form['authors'] = array( '#title' => t('Project authors  '), '#type' => 'fieldset', '#weight' => 2, '#collapsible' => TRUE, '#collapsed' => TRUE, '#value' => $output_authors, ); $form['submit'] = array( '#type' => 'submit', 48
'#value' => t('Add'), '#weight' => 3, '#submit' => array('add_experiments_form_submit'), ); return $form; } function add_experiments_form_submit($form, &$form_state) { $sub_url = &$form_state['pid']; $form_state['redirect'] = 'projects/experiments/add/'.$sub_url; } function edit_experiments_form_submit($form, &$form_state) { $sub_url = &$form_state['pid']; $form_state['redirect'] = 'projects/experiments/edit/'.$sub_url; } Adding experiments
With the purpose of adding experiments a page was created for adding, which is similar to the project adding page. $items['projects/experiments/add'] = array( 'title' => 'Add new experiment', 'page callback' => 'expres_add_experiment', 'access callback' => TRUE, 'weight' => 11, 'file' => 'expres.pages.inc', ); The following code describes the functions through which experiments can be added to the database, and in addition the functions through which commands can be added. function expres_add_experiment() { $sub_url = arg(3); $title = db_query("SELECT title FROM {projects} WHERE pid ='$sub_url'")->fetchField(); drupal_set_title(t('Create new experiment (Project: '.$title.')')); return drupal_get_form('experiment_form', $title, $sub_url); } This function doesn‟t do much excepts for the fact that it sets the title of the page and gets the project title of the project the experiment belongs to. Through the use of the form function called for at the end of the previous function, the user can set a title, a description of the experiment. Additionally he can select and add standard and additional commands to the database which can then be used when adding a new experiment. But first we will discuss the adding of the experiments through the form function and the database queries.
49
function experiment_form($form, &$form_state, $title, $sub_url) { global $user; $form_state['pid'] = $sub_url; $form['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#weight' => 1, '#required' => FALSE, ); $form['description'] = array( '#type' => 'textarea', '#title' => t('Description'), '#weight' => 2, '#required' => FALSE, ); $form['standard_commands'] = array( '#title' => t('Standard commands  '), '#type' => 'fieldset', '#weight' => 3, '#collapsible' => TRUE, '#collapsed' => TRUE, ); $result = db_query("SELECT title FROM {standard_commands}"); $i=0; foreach ($result as $record) { $form['standard_commands'][$i] = array( '#type' => 'checkbox', '#title' => t('@title', array('@title' => $record>title,)), '#weight' => 4, '#default_value' => 0, ); $i++; } $admin = db_query("SELECT rid FROM {users_roles} WHERE uid='$user->uid'")->fetchField(); if ($admin == 3){ $form['standard_commands']['add_standard_commands'] = array( '#type' => 'submit', '#value' => t('Add new standard command'), '#weight' => 5, '#submit' => array('expres_add_standard_commands_redirect'), ); } $form['additional_commands'] = array( '#title' => t('Additional commands  '), '#type' => 'fieldset', '#weight' => 6, '#collapsible' => TRUE, 50
'#collapsed' => TRUE, ); $result = db_query("SELECT title FROM {additional_commands} WHERE pid = '$sub_url'"); $j=100; foreach ($result as $record) { $form['additional_commands'][$j] = array( '#type' => 'checkbox', '#title' => t('@title', array('@title' => $record>title,)), '#weight' => 7, '#default_value' => 0, ); $j++; } $form['additional_commands']['add_additional_commands'] = array( '#type' => 'submit', '#value' => t('Add new additional command'), '#weight' => 8, '#submit' => array('expres_add_additional_commands_redirect'), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 9, '#submit' => array('experiment_form_submit'), ); return $form; } Once again the form state function is used to collect the pid that was sent to the function. The next to form types title and description are identical to the project adding form, which we have discussed before. Next to these two form types, two fieldsets are programmed called “Standard commands” and “Additional commands”. These fieldsets encapsulate each a dropbox containing all commands extracted from the database and a button which redirects the user to the command adding page. The redirection is once again done through a redirect function. Between the two types of commands there is however a small difference. The standard commands are not subjected to one specific project, but are general and can therefore be added to all experiments. The additional commands are on the other hand attached to a specific project and can only be added to experiments belong to a specific project. But before looking further in the commands, we will first discuss how the new experiment is added to the database. function experiment_form_submit($form, &$form_state) { try { $pid = $form_state['pid']; 51
$table = 'experiments'; $experiment->is_new = empty($experiment->eid); $experiment->pid = $pid; $experiment->title = $form_state['values']['title']; $experiment->description = $form_state['values']['description']; $experiment->created = REQUEST_TIME; $experiment->changed = REQUEST_TIME; drupal_write_record($table, $experiment); $eid = $experiment->eid; $result = db_query("SELECT title FROM {standard_commands}"); $i=0; foreach ($result as $record) { if ($form_state['values'][$i] == '1'){ $table = 'experiment_submitscript'; $exp_submitscript->is_new = empty($exp_submitscript>mid); $exp_submitscript->eid = $eid; $title = t('@title', array('@title' => $record>title,)); $command = db_query("SELECT command FROM {standard_commands} WHERE title = '$title'")->fetchField(); $exp_submitscript->title = $title; $exp_submitscript->command = $command; $exp_submitscript->created = REQUEST_TIME; $exp_submitscript->changed = REQUEST_TIME; drupal_write_record($table, $exp_submitscript); $exp_submitscript = NULL; } $i++; } $result = db_query("SELECT title FROM {additional_commands} WHERE pid = '$pid'"); $j=100; foreach ($result as $record) { if ($form_state['values'][$j] == '1'){ $table = 'experiment_submitscript'; $exp_submitscript_2->is_new = empty($exp_submitscript_2->mid); $exp_submitscript_2->eid = $eid; $title = t('@title', array('@title' => $record>title,)); $command = db_query("SELECT command FROM {additional_commands} WHERE title = '$title'")->fetchField(); $exp_submitscript_2->title = $title; $exp_submitscript_2->command = t($command); $exp_submitscript_2->created = REQUEST_TIME; $exp_submitscript_2->changed = REQUEST_TIME; drupal_write_record($table, $exp_submitscript_2); $exp_submitscript_2 = NULL; 52
} $j++; } } catch (Exception $e) { $transaction->rollback(); watchdog_exception('experiments', $e, NULL, WATCHDOG_ERROR); return FALSE; } drupal_set_message(t('Experiment saved.')); $form_state['redirect'] = 'projects/experiments/'.$pid; } The first part handles the addition of an experiment to the experiments table. For this all the different values are added to the variable experiment, where the title and the description are collected from the form. Using the drupal_write_record function the variable is then sent to the table defined in the variable table at the beginning of the function. Secondly we check if the user wants to add standard or additional commands to the experiments, by verifying which boxes have been checked in the previous form. For each checked box the if loop is activated and stores all necessary information in a variable, which is then added to the table experiment_submitscript and values in the variable are removed. This table helps to generate the submitscript for an experiment, which will be discussed later on. Next we will be looking at the addition of new standard and additional commands. For these commands two pages are created in the hook_menu() function. These are also not visible for the user in the menu, similar to the experiment management pages. The code that manages the visibility of these pages is already presented. $items['projects/standard_commands/add'] = array( 'title' => 'Add new standard command', 'page callback' => 'expres_add_standard_commands', 'type' => MENU_NORMAL_ITEM, 'access callback' => 'check_admin', 'weight' => 5, 'file' => 'expres.pages.inc', ); $items['projects/additional_commands/add'] = array( 'title' => 'Add new additional command', 'page callback' => 'expres_add_additional_commands', 'type' => MENU_NORMAL_ITEM, 'access callback' => 'check_pid', 'weight' => 6, 'file' => 'expres.pages.inc', ); The functions used for the addition of commands are discussed using the standard commands function. 53
function expres_add_standard_commands() { global $user; drupal_set_title(t('Add new standard command')); return drupal_get_form('expres_add_standard_commands_submit'); } function expres_add_standard_commands_submit($form, &$form_state) { $form['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#weight' => 1, '#required' => TRUE, ); $form['command'] = array( '#type' => 'textfield', '#title' => t('Command'), '#weight' => 2, '#required' => TRUE, ); $form['save'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 3, '#submit' => array('add_standard_commands'), ); return $form; } function add_standard_commands($form, &$form_state) { try { $table = 'standard_commands'; $standard_command->is_new = empty($standard_command>scid); $standard_command->title = $form_state['values']['title']; $standard_command->command = $form_state['values']['command']; $standard_command->created = REQUEST_TIME; $standard_command->changed = REQUEST_TIME; drupal_write_record($table, $standard_command); } catch (Exception $e) { $transaction->rollback(); watchdog_exception('standard_commands', $e, NULL, WATCHDOG_ERROR); return FALSE; } drupal_set_message(t('Command saved.')); $form_state['redirect'] = 'projects/standard_commands/add'; } 54
In the first function a title is set and the form function 'expres_add_standard_commands_submit‟ is called. This function generates a form where the user can insert a title and the command. The submit button then calls the next function 'add_standard_commands', where a simple database query inserts the new standard command in the standard_commands table. The addition of additional commands is similar to the standard commands but an additional value is added to the database table „additional_commands‟, namely the project identifier. function expres_add_additional_commands() { $sub_url = arg(3); drupal_set_title(t('Add new additional command ')); return drupal_get_form('expres_add_additional_commands_submit', $sub_url); } function expres_add_additional_commands_submit($form, &$form_state, $sub_url) { $form_state['pid'] = $sub_url; $form['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#weight' => 1, '#required' => TRUE, ); $form['command'] = array( '#type' => 'textfield', '#title' => t('Command'), '#weight' => 2, '#required' => TRUE, ); $form['save'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 3, '#submit' => array('add_additional_commands'), ); return $form; } function add_additional_commands($form, &$form_state) { try { $table = 'additional_commands'; $standard_command->is_new = empty($standard_command>acid); $standard_command->pid = $form_state['pid']; $standard_command->title = $form_state['values']['title']; $standard_command->command = $form_state['values']['command']; $standard_command->created = REQUEST_TIME; 55
$standard_command->changed = REQUEST_TIME; drupal_write_record($table, $standard_command); } catch (Exception $e) { $transaction->rollback(); watchdog_exception('additional_commands', $e, NULL, WATCHDOG_ERROR); return FALSE; } drupal_set_message(t('Command saved.')); $form_state['redirect'] = 'projects/experiments/add/'.$form_state['pid']; } Editing experiments
The editing of experiment is done in the experiments editing page, which is again programmed in the hook_menu() function in the expres.module file. $items['projects/experiments/edit'] = array( 'title' => 'Edit an experiment', 'page callback' => 'expres_edit_experiment', 'access callback' => TRUE, 'weight' => 12, 'file' => 'expres.pages.inc', ); Subsequently we will discuss the function that is used within the experiments menu. This function uses once again the project identifier which is needed to collect the right experiments. In addition the function needs the experiment identifier sent along with pid in the url. As for the project editing page, the experiment editing page is also conditioned to make sure that the eid is sent along with the url. function expres_edit_experiment() { $eid = arg(4); $pid = arg(3); $current_url = 'http://' .$_SERVER['HTTP_HOST']; $url = url($path = NULL); $current_url .= $url."?q="; if (empty($eid)){ $result = db_query("SELECT eid, title FROM {experiments} WHERE pid ='$pid'"); $list=array(); $items=array(); foreach ($result as $record) { $list[] = t("
".'@title'."", array( '@title' => $record->title, 56
'@eid' => $record->eid, )); } $theme_args = array('items' => $list, 'type' => 'ol'); return theme('item_list', $theme_args); }else { $title = db_query("SELECT title FROM {experiments} WHERE eid = '$eid'")->fetchField(); $current_title = t("Current title: ".$title."
"); $result = db_query("SELECT s.scid, s.title, s.command FROM {standard_commands} s INNER JOIN {experiment_submitscript} e ON s.command = e.command WHERE e.eid = '$eid'"); $list = array(); foreach ($result as $record) { $list[$record->scid] = t('@title', array( '@title' => $record->title, )); } $result_add = db_query("SELECT scid, title, command FROM {standard_commands} WHERE command NOT IN (SELECT command FROM {experiment_submitscript} WHERE eid = '$eid')"); $list_add=array(); foreach ($result_add as $record_add) { $list_add[$record_add->scid] = t('@title', array( '@title' => $record_add->title, )); } $result_2 = db_query("SELECT a.acid, a.pid, a.title, a.command FROM {additional_commands} a INNER JOIN {experiment_submitscript} e ON a.command = e.command WHERE e.eid = '$eid' && a.pid = '$pid'"); $list_2 = array(); foreach ($result_2 as $record_2) { $list_2[$record_2->acid] = t('@title', array( '@title' => $record_2->title, )); } $result_add_2 = db_query("SELECT acid, title, command FROM {additional_commands} WHERE pid = '$pid' && command NOT IN (SELECT command FROM {experiment_submitscript} WHERE eid = '$eid')"); $list_add_2 = array(); foreach ($result_add_2 as $record_add_2) { $list_add_2[$record_add_2->acid] = t('@title', array( '@title' => $record_add_2->title, )); } $form = drupal_render(drupal_get_form('edit_experiment_form', $eid, $list, $list_add, $list_2, $list_add_2)); 57
$current_title.=$form; return $current_title; } } When the experiment identifier is collected, the first part collects the title of the experiment from the database and shown to the user. In the next part four lists are created, which contain a listing of the standard and additional commands that aren‟t assigned to the experiment and the commands that already are assigned. These lists are then used to create dropboxes for adding and deleting commands. At the end of the function the form function 'edit_experiment_form' is called for through the drupal_get_form function with the eid and the four lists attached. function edit_experiment_form($form, &$form_state, $eid, $list, $list_add, $list_2, $list_add_2){ $form_state['eid'] = $eid; $form['title'] = array( '#type' => 'textfield', '#title' => t('New title'), '#weight' => 1, '#required' => FALSE, ); $form['description'] = array( '#type' => 'textarea', '#title' => t('New description'), '#weight' => 2, '#required' => FALSE, ); if (!((empty($list_add))&&(empty($list)))){ $form['standard_commands'] = array( '#title' => t('Edit standard commands  '), '#type' => 'fieldset', '#weight' => 3, '#collapsible' => TRUE, '#collapsed' => TRUE, ); if (!(empty($list_add))){ $form['standard_commands']['add_standard_commands'] = array( '#title' => t('Add standard command'), '#type' => 'select', '#weight' => 4, '#options' => $list_add, '#empty_option'=> t(''), ); } if (!(empty($list))){
58
$form['standard_commands']['delete_standard_commands'] = array( '#title' => t('Delete standard command'), '#type' => 'select', '#weight' => 5, '#options' => $list, '#empty_option'=> t(''), ); } } if (!((empty($list_add_2))&&(empty($list_2)))){ $form['additional_commands'] = array( '#title' => t('Edit additional commands  '), '#type' => 'fieldset', '#weight' => 6, '#collapsible' => TRUE, '#collapsed' => TRUE, ); if (!(empty($list_add_2))){ $form['additional_commands']['add_additional_commands'] = array( '#title' => t('Add additional command'), '#type' => 'select', '#weight' => 7, '#options' => $list_add_2, '#empty_option'=> t(''), ); } if (!(empty($list_2))){ $form['additional_commands']['delete_additional_commands'] = array( '#title' => t('Delete additional command'), '#type' => 'select', '#weight' => 8, '#options' => $list_2, '#empty_option'=> t(''), ); } } $form['ok'] = array( '#type' => 'submit', '#value' => t('Ok'), '#weight' => 9, '#submit' => array('edit_experiment_submit'), ); return $form; } The first field is the textfield that allows the user to edit the current title of the experiment. Next to that, two fieldsets encapsulate the standard and the additional commands. These 59
fieldsets are only shown if the two lists concerning the commands aren‟t empty. This also applies to the separate dropboxes that list the commands that can be added and deleted. When the user clicks the „Ok‟ button the function 'edit_experiment_submit' is activated. This function executes the database queries needed to change the title and description of an experiment and adds or deletes the necessary standard and additional commands in the appropriate table. At the end the user is redirected to the projects page. function edit_experiment_submit($form, &$form_state) { if (!(empty($form_state['values']['title']))){ $update = db_update('experiments') ->fields(array('title' => $form_state['values']['title'])) ->condition('eid', $form_state['eid']) ->execute(); } if (!(empty($form_state['values']['description']))){ $update = db_update('experiments') ->fields(array('description' => $form_state['values']['description'])) ->condition('eid', $form_state['eid']) ->execute(); } if (!(empty($form_state['values']['add_standard_commands']))){ $scid = $form_state['values']['add_standard_commands']; $title = db_query("SELECT title FROM {standard_commands} WHERE scid = '$scid'")->fetchField(); $command = db_query("SELECT command FROM {standard_commands} WHERE scid = '$scid'")->fetchField(); $update2 = db_insert('experiment_submitscript') ->fields(array('eid' => $form_state['eid'], 'title' => $title, 'command' => $command, 'created' => REQUEST_TIME, 'changed' => REQUEST_TIME)) ->execute(); } if (!(empty($form_state['values']['delete_standard_commands']))){ $scid = $form_state['values']['delete_standard_commands']; $command = db_query("SELECT command FROM {standard_commands} WHERE scid = '$scid'")->fetchField(); $update3 = db_delete('experiment_submitscript') ->condition('command', $command) ->condition('eid', $form_state['eid']) ->execute(); } if (!(empty($form_state['values']['add_additional_commands']))){ $acid = $form_state['values']['add_additional_commands']; $title = db_query("SELECT title FROM {additional_commands} WHERE acid = '$acid'")->fetchField();
60
$command = db_query("SELECT command FROM {additional_commands} WHERE acid = '$acid'")->fetchField(); $update2 = db_insert('experiment_submitscript') ->fields(array('eid' => $form_state['eid'], 'title' => $title, 'command' => $command, 'created' => REQUEST_TIME, 'changed' => REQUEST_TIME)) ->execute(); } if (!(empty($form_state['values']['delete_additional_commands'])) ){ $acid = $form_state['values']['delete_additional_commands']; $command = db_query("SELECT command FROM {additional_commands} WHERE acid = '$acid'")->fetchField(); $update3 = db_delete('experiment_submitscript') ->condition('command', $command) ->condition('eid', $form_state['eid']) ->execute(); } drupal_set_message(t('Experiment edited')); $form_state['redirect'] = 'projects'; } Managing a specific experiment
The management of a specific experiment is done through the use of three view pages, namely the standard view experiment page, the page which shows the submitscript of an experiment and the metadata page. As can be seen in the following code, there is an addition to the previous menu page items. The access callback allows for the pages to be accessed without logging-in and this allows for the wget statement in Linuw to be executed. However this may cause a protection problem, because of the fact that the eid of experiments can be guessed and the submitscript and metadata of experiments which aren‟t assigned to an author can be accessed. This is why these pages will be using a unique identifier of which the code will be explained later on. $items['projects/experiments/view'] = array( 'title' => 'View experiment', 'page callback' => 'expres_experiments_view', 'type' => MENU_NORMAL_ITEM, 'access callback' => TRUE, 'weight' => 8, 'file' => 'expres.pages.inc', ); $items['projects/experiments/view/submitscript'] = array( 'title' => 'View experiment submitscript', 'page callback' => 'expres_experiments_view_submitscript', 'access callback' => TRUE, 'weight' => 9, 61
'file' => 'expres.pages.inc', ); $items['projects/experiments/view/metadata'] = array( 'title' => 'View experiment metadata', 'page callback' => 'expres_experiments_view_metadata', 'access callback' => TRUE, 'weight' => 10, 'file' => 'expres.pages.inc', );
The landing page calls the 'expres_experiments_view' function which looks as follows: function expres_experiments_view() { $eid = arg(3); $current_url = 'http://' .$_SERVER['HTTP_HOST']; $url = url($path = NULL); $current_url .= $url."?q="; $title = db_query("SELECT title FROM {experiments} WHERE eid ='$eid'")->fetchField(); $description = db_query("SELECT description FROM {experiments} WHERE eid ='$eid'")->fetchField(); drupal_set_title(t('View experiment: '.$title)); $eid_check = db_query("SELECT eid FROM {experiments_uuid} WHERE eid ='$eid'")->fetchField(); if(empty($eid_check)){ $uuid = UUID::v4('1546058f-5a25-4334-85ae-e68f2a44bbaf', 'SomeRandomString'); try { $table = 'experiments_uuid'; $exp_uuid->is_new = empty($exp_uuid->euid); $exp_uuid->eid = $eid; $exp_uuid->uuid = $uuid; drupal_write_record($table, $exp_uuid); } catch (Exception $e) { $transaction->rollback(); watchdog_exception('projects', $e, NULL, WATCHDOG_ERROR); return FALSE; } } $uuid_eid = db_query("SELECT uuid FROM {experiments_uuid} WHERE eid ='$eid'")->fetchField(); $submit_script = t("
"."Submitscript of ".$title."
"); $result = db_query("SELECT rid,created,uri FROM {experiment_results} WHERE eid ='$eid'"); foreach ($result as $record) { $timestamp=$record->created; 62
$uri=$record->uri; $date = format_date($timestamp, $type = 'custom', $format = 'l jS \of F Y h:i:s A', $timezone = NULL, $langcode = NULL)."
"; $submit_script.=$date; $uri = file_create_url($uri); $experiment_results = t("
"."Results of ".$title.""); $submit_script.=$experiment_results; $experiment_metadata = t("
"."Metadata of ".$title."
", array('@rid' => $record->rid)); $submit_script.=$experiment_metadata; } $form_description = drupal_render(drupal_get_form('view_experiment_form', $description, $uuid_eid)); $submit_script.=$form_description; return $submit_script; } Once again the function starts with the collection of the experiment identifier attached to the url using the arg() function. The first 2 database queries are similar to previous queries and will therefore not be explained. The third query is used to check whether or not a unique id has been assigned to an experiment, used in the metadata and the submitscript page. When there isn‟t a uuid assigned to the experiment, one is created and stored in the experiments_uuid table along with the eid. Then the uuid is collected from the table and added to a html ling which redirects the user to the submitscript page. In the next part of the function all the uploaded results are collected from the experiment_results using the eid table and used in the foreach loop. This loop loops through each record, sets a timestamp for each record and shows the link to the results and adds a link to the experiments metadata. At the end of the function a form function is called for showing a upload button and the description of the experiment. function view_experiment_form($form, &$form_state, $description, $uuid_eid) { $form_state['uuid'] = $uuid_eid; $form['description'] = array( '#title' => t('Experiment description  '), '#type' => 'fieldset', '#weight' => 2, '#collapsible' => TRUE, '#collapsed' => TRUE, '#value' => $description, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Upload an experiment'), 63
'#weight' => 3, '#submit' => array('upload_form_submit'), ); return $form; } The submit button then calls the 'upload_form_submit' function when clicked, which redirects the user to the upload page. As stated before the uuid is attached to the link. function upload_form_submit($form, &$form_state) { $uuid = &$form_state['uuid']; $form_state['redirect'] = 'projects/experiments/upload/'.$uuid; } The page to which the user is redirected is once again added to the hook_menu() function. $items['projects/experiments/upload'] = array( 'title' => 'Upload a new experiment', 'page callback' => 'expres_upload_experiment', 'access callback' => TRUE, 'weight' => 13, 'file' => 'expres.pages.inc', ); The function generated when visiting the upload page is „expres_upload_experiment‟. function expres_upload_experiment() { $uuid = arg(3); $eid = db_query("SELECT eid FROM {experiments_uuid} WHERE uuid ='$uuid'")->fetchField(); $pid = db_query("SELECT pid FROM {experiments} WHERE eid ='$eid'")->fetchField(); $eid_title = db_query("SELECT title FROM {experiments} WHERE eid ='$eid'")->fetchField(); $pid_title = db_query("SELECT title FROM {projects} WHERE pid ='$pid'")->fetchField(); drupal_set_title(t('Upload a new file (Experiment: '.$eid_title.')')); return drupal_get_form('upload_experiment', $eid_title, $pid_title, $eid, $pid); }
64
Lijst van geraadpleegde werken Boeken Butcher, M. (2010) Drupal 7 Module Development. Birmingham: Packt Publishing Ltd. Johnson, B. & Higgins, J. (2007) ITIL and the Software Lifecycle: Practical Strategy and Design Principles. Zaltbommel: Van Haren Publishing Mohapatra, P.K.J. (2010) Software Engineering: A Lifecycle Approach. New Dehli: New Age International (P) Ltd. Sommerville, I. (2007) Software engineering. Essex: Pearson Education Ltd. Artikels Laleci, G.B., Aluc, G., Dogac, A., Sinaci, A., Kilic, O. & Tuncer, F. (2010) A semantic backend for content management systems. Knowledge-Based Systems, 23, 832-843 Liang, W., O‟Grady, P. (1998) Design with objects: an approach to object-oriented design. ComputerAided Design, 30, 943-956 Lucertini, M., Nicolò, F. & Telmon, D. (1995) Integration of benchmarking and benchmarking of integration. International Journal of Production Economics, 38 (1), 59-71 Mooney, S.D. & Baezinger, P.H. (2007) Extensible open source content management systems and frameworks: a solution for many needs of a bioinformatics group. Briefings in Bioinformatics, 9 (1), 69-74 Reilly, C.A. & Williams, J.J. (2006) The price of free software: labor, ethics, and context in distance education. Computers and Composition, 23, 68–90 Vitari, C., Ravarini, A. & Rodhain, F. (2006) An Analysis Framework for the Evaluation of Content Management Systems. Communications of the Association for Information Systems, 18, 782804
65
Elektronische bronnen About Drupal. Opgehaald van http://drupal.org/node/769 PHP Manual. Opgehaald van http://www.php.net/manual/en/index.php Schema API. Opgehaald van http://drupal.org/developing/api/schema Dhoedt, B. (2010) Software Development. Opgehaald van http://minerva.ugent.be/main/document/document.php?cidReq=E0177200_2010
66
Lijst van figuren en tabellen Figuur 1: Watervalmodel van Royce ................................................................................................. 12 Figuur 2: Watervalmodel van Boehm ................................................................................................ 13 Figuur 3: Eerste versie vormgeving ................................................................................................... 17 Figuur 4: Use-case diagram............................................................................................................... 19 Figuur 5: Klassediagram ................................................................................................................... 21 Figuur 6: Create new project ............................................................................................................. 25 Figuur 7: View projects..................................................................................................................... 26 Figuur 8: Create new experiment ...................................................................................................... 27 Figuur 9: Add new standard command .............................................................................................. 28 Figuur 10: Edit an experiment ........................................................................................................... 29 Figuur 11: Submitscript .................................................................................................................... 30 Figuur 12: Upload a new file ............................................................................................................. 30
Tabel 1: Veel gebruikte CMF's en CMS'en ..........................................................................................3
Lijst met bijlagen Bijlage A: Bespreking code Expres ................................................................................................... 37
67