Jasper Gielen is softwarearchitect bij ICT Automatisering en gedetacheerd bij Thales in Hengelo. Pepijn Noltes is softwarearchitect bij Thales en Apache Celix-committer.

28 December 2012

Bij Service-Oriented Architecture denken velen vrijwel direct aan een enterprise-gerichte, trage Soap-oplossing waarbij meerdere systemen XML uitwisselen over het internet. Het is echter ook toepasbaar op kleinere schaal en zelfs voor realtime embedded systemen. In dit artikel laten Jasper Gielen en Pepijn Noltes zien hoe Thales dit aanpakt.

Binnen de afdeling Processing van Thales in Hengelo ontwikkelen we onder meer software voor radars die hun toepassing vinden in systemen voor defensie en veiligheid. Een van de aandachtspunten is hoe we de softwarearchitectuur van de sensoren naar een volgend niveau kunnen brengen. Naast de continue zoektocht om efficiënter te kunnen ontwikkelen en nieuwe technologieën snel en adequaat te kunnen inzetten, is er de wens om de functionaliteit dynamisch herconfigureerbaar te maken. Dit maakt het mogelijk om sensoren te ontwikkelen die – in gedegradeerde vorm – blijven werken als een deel van de processinghardware beschadigd raakt. Om dit te realiseren, onderzoekt Thales het gebruik van een servicegeoriënteerde manier van programmeren.

Bij servicegeoriënteerd programmeren komt functionaliteit tot stand door een samenspel van services. Wat een service precies aanbiedt, staat beschreven in een zogeheten servicecontract (Figuur 1). Een systeem is niet langer een statische integratie van devicedrivers en softwaremodules, maar een dynamisch geheel van geselecteerde en/of beschikbare services. Doordat deze onafhankelijk van elkaar opereren, zijn ze ook los van elkaar te ontwikkelen en te testen. Daarmee is de functionaliteit eenvoudig uit te breiden, bijvoorbeeld bij veranderende klantwensen (Figuur 2).

RTEmagicC_Thales_Figuur_1.png
Figuur 1: Een servicecontract beschrijft wat een service precies aanbiedt.

Hoewel het technisch gezien niet veel uitmaakt hoe een servicecontract beschreven is, is het verstandig om dit te doen in een vorm die laagdrempelig, goed leesbaar en herkenbaar is voor de ontwikkelaars die met de services aan de slag moeten. Het liefst is zo‘n contract dus opgesteld in de programmeertaal die zij gebruiken of in een Interface Definition Language (IDL) die daar dicht tegen aanligt. Het voordeel hiervan is dat de service naadloos aansluit bij de rest van de software, zodat deze duidelijk leesbaar blijft en niet onnodig complex en slecht onderhoudbaar wordt.

Servicegeoriënteerd programmeren maakt veel meer hergebruik mogelijk. Om dit voordeel optimaal te kunnen benutten, moeten de contracten en implementaties wel aan een aantal eisen voldoen. Zo moet een service vervangbaar zijn door een andere service die is gepubliceerd met hetzelfde contract. De ontwikkeling kan zich hierdoor richten op de contracten in plaats van op de implementaties. Ook moet elke service een specifieke taak binnen het systeem op zich nemen. Dit zorgt voor beheersbare en coherente services, die goed herbruikbaar zijn. Zo‘n implementatie is bovendien makkelijk te testen. Verder moet een service autonoom functioneren, zodat hij kan omgaan met wegvallende of bijkomende services. Voorwaarde hiervoor is dat hij vindbaar is voor andere services.

 advertorial 

Sigasi Extension for Visual Studio Code

Sigasi announces the release of their VS Code Extension with rich support for SystemVerilog, Verilog, and VHDL. Our extension provides features and language support such as code navigation, project management, linting, code formatting, tooltips, outline, autocomplete, hover, and much more!

Thales_Figuur_2
Figuur 2: Een simpel navigatiesysteem zouden we kunnen opzetten door een low-level service voor een serieel device te specialiseren naar een apparaat voor positiebepaling. De implementatie van de GPS-module abstraheert de functieaanroepen op het seriële device, zodat we de navigatieservice niet hoeven aan te passen als we besluiten een Ethernet- of USB-apparaat te gebruiken.

Servicegeoriënteerd programmeren is niet alleen toepasbaar bij gedistribueerde systemen maar ook op kleinere schaal, binnen een executieproces. Dan spreken we van microservices. Het gebruik hiervan heeft een interessant effect: het maakt een nieuw ontwikkelparadigma mogelijk bij een taal die dat inherent niet ondersteunt. Zo kunnen we in principe enkel objectgeoriënteerd programmeren met talen die dit ook inherent ondersteunen. Met behulp van een serviceframework kunnen we microservicegeoriënteerd programmeren echter taalonafhankelijk toevoegen. In C, dat eigenlijk alleen procedureel programmeren ondersteunt, kunnen we zo toch een servicegeoriënteerde manier van ontwikkelen toepassen.

Niet alleen voor de softwareontwikkeling heeft servicegeoriënteerd programmeren voordelen. De aanpak kan ook veel betekenen wanneer de hardware minder betrouwbaar wordt doordat chips kleiner en complexer worden. Het is zeer aannemelijk dat embedded software in de toekomst dynamisch moet kunnen reageren op dergelijke veranderingen. Daarbij valt te denken aan systemen met meer dan honderd kernen, waarbij geen garantie meer is te geven dat elke core de gehele technische levensduur blijft functioneren.

Pijplijn

Bij Thales zien we Apache Celix als belangrijkste kandidaat om servicegeoriënteerd programmeren naar het realtime-embedded-domein te brengen. Apache Celix is een opensource (micro)serviceframework in C. Als basis voor de implementatie gebruikt het platform de Open Services Gateway Initiative-specificatie (OSGI), een open beschrijving voor dergelijke raamwerken. Op dit moment zit het in de incubatiefase bij de Apache Software Foundation, wat betekent dat het wordt klaargestoomd tot volwaardig project.

In Apache Celix is een servicecontract niets anders dan een struct met functiepointers (Figuur 3). Er is met opzet voor gekozen om alles zo dicht mogelijk bij C te houden om zo een laagdrempelige en transparante implementatie in C mogelijk te maken. De bijbehorende services zijn dynamisch: ze kunnen op willekeurige momenten verschijnen en verdwijnen. Dit laat toe om een robuust en flexibel systeem te ontwerpen dat runtime kan inspelen op interne en externe veranderingen, bijvoorbeeld in functionaliteit.

//log_service.h
#define LOG_SERVICE_NAME “log_service”
struct log_service {
  void * handler;
  void (*log)(void * handler, char * message);
};
typedef struct log_service *log_service_t;
Figuur 3: In Apache Celix is een servicecontract niets anders dan een struct met functiepointers.

Services in Apache Celix registreren we samen met een set van meta-eigenschappen (service properties), zoals de naam en de seriële-poort-ID van een serieel device (Figuur 4). Onze interesse in de bijbehorende service kunnen we kenbaar maken door deze eigenschappen te gebruiken in een filter, waarbij we de LDAP-syntax (Lightweight Directory Access Protocol) volgen. Daarnaast kunnen we met behulp van de servicetracker op de hoogte blijven van gewilde services.

Om ervoor te zorgen dat Apache Celix platformonafhankelijk en dus in een breed scala aan omgevingen inzetbaar is, maakt het framework gebruik van de Apache Portable Runtime (APR). Dit is een bibliotheek die platformafhankelijke functionaliteit zoals bestandsafhandeling, dynamische gedeelde objecten, geheugenallocatie, netwerkcommunicatie en threading aanbiedt in een platformonafhankelijke schil. Hierdoor is het mogelijk om Apache Celix te draaien op elk platform waarvoor er APR-ondersteuning is. Op dit moment zijn dat Windows, Unix/Linux, Mac OS X, Netware en OS/2.

Thales_figuur_4
Figuur 4: Services in Apache Celix registreren we samen met een set van service properties, zoals de naam en de seriële-poort-ID van een serieel device.

Doordat er een implementatie beschikbaar is van de OSGI-specificatie voor remote services, is Apache Celix ook toepasbaar op gedistribueerde systemen. Hoewel die implementatie nog in de kinderschoenen staat, kunnen we haar al wel gebruiken om te communiceren met Java-services die zijn gepubliceerd met een Java-serviceframework zoals Apache Felix. Dit heeft als voordeel dat we de embedded-ontwikkeling met behulp van remote services naadloos kunnen laten aansluiten op een hoger niveau, zelfs op de enterprisesoftware.

De eerste officiële release van Apache Celix zit in de pijplijn. Deze ondersteunt alle functionaliteit die hiervoor aan bod is gekomen: we kunnen services beschrijven, aanbieden en gebruiken. Behalve een aantal praktische tools wordt er ook een kant-en-klare voorbeeldapplicatie meegeleverd zodat geïnteresseerden direct aan de slag kunnen.

Thales_Figuur_5
Figuur 5: Binnen het door de Nederlandse regering gefinancierde project Sensor Technology Applied in Reconfigurable Systems for Sustainable Security (Stars) doet Thales onderzoek aan dynamische configuratie. Wanneer processingbord 1 in de simulatie uitvalt, verplaatst het systeem de rode en groene services naar respectievelijk bord 2 en 3.

Benchmarken

Binnen het researchproject Stars heeft Thales een prototype gerealiseerd waarbij we onder meer Apache Celix gebruiken om software voor radars en andere sensoren dynamisch te herconfigureren. Zo zijn we erin geslaagd om een systeem met een minimale downtime functioneel te houden bij uitval van een processingbord. In het prototype start de software op drie borden. Wanneer we vervolgens simuleren dat een daarvan uitvalt, verplaatst het systeem de daarop draaiende services naar de andere twee (Figuur 5). Met de servicetracker kan het die services opnieuw vinden en inzetten, waarna de applicatie weer operationeel is.

Dezelfde applicatie gaan we nu gebruiken om Apache Celix verder te benchmarken. In de praktijk blijkt dat het framework eenvoudig is te porten naar de Arm-architectuur (draaiend onder UCLinux). Ook hier zullen we in de nabije toekomst verdere benchmarking op uitvoeren.

Edited by Nieke Roos