Project document & messaging integration
Docbyte heeft een standaardoplossing voor zogenaamd document output management. In essentie staat dit product in voor de conversie van documenten van type A naar type B, rekeninghoudend met zoveel mogelijk omgevingsfactoren. Het bestaande product werd ontwikkeld als enterprise grade oplossing waarbij er met grote volumes aan documenten gewerkt wordt.
Van bovenstaand product wordt een nieuwe versie ontwikkeld. Deze nieuwe versie schakelt nog een versnelling hoger op het vlak van distributed computing. Configuraties worden op een centrale plaats beheerd en daarna verdeeld over een netwerk naar de onderliggende entiteiten. Deze entiteiten werken samen om het eigenlijk output management te volbrengen.
Om een hoge graad van flexibiliteit en ease of use te voorzien, is het mijn taak om een webtoepassing voor configuratie en administratie te ontwikkelen.
Op deze website zal ik regelmatig de vorderingen van het project plaatsen.

Tests
Posted by: Robin in Integratie on December 10th, 2009
Om de aangepaste projecten te kunnen testen, werd er een testomgeving met de vorige versie van docShifter opgezet waarbij bepaalde libraries vervangen werden door een nieuwe versie. Op die manier moesten de OpenOffice services die docShifter gebruikt niet handmatig ingesteld worden. Verder werden de vereiste libraries voor de toegang tot de databank toegevoegd.
Naast het updaten van de libraries, moesten bepaalde conguraties aangemaakt worden via de configuratieconsole. De oorspronkelijke XML-conguratiebestanden waren echter op een totaal verschillende manier opgebouwd dan de XML-bestanden die door de configuratieconsole gebruikt worden. Het configuratiebestand van de senders bevatte bijvoorbeeld verschillende types van senderconfiguraties, samen met algemene instellingen voor JMS. Op basis van dit configuratiebestand werd voor elk type van sender een nieuw configuratiebestand gemaakt met de vereiste parameters. Wat de receiverconfiguraties betreft, was het omvormen van de configuratiebestanden nog ingewikkelder. De oorspronkelijke XML-bestanden bevatten namelijk zowel informatie over de transformatie als over de output. Voor de configuratieconsole werd deze informatie onderverdeeld in configuraties voor transformatiemodules en releasemodules. In het geval van transformatiemodules bevatten deze bestanden naast een naam en een omschrijving, enkel een verwijzing naar de klassenaam van de module. Releasemodules kunnen naast deze gegevens ook nog parameters bevatten.
Lokale transformatie
Nadat de benodigde conguratiebestanden waren aangemaakt, konden de benodigde moduleconguraties via de conguratieconsole aangemaakt worden. Eerst werd er een lokale transformatie aangemaakt die bestanden in een bepaalde map op het systeem transformeerde en in een andere map plaatste. De input- en releasemodules die hiervoor gebruikt werden werken dus enkel met het lokale bestandssysteem. Er werden verschillende transformaties getest waaronder PDF en platte tekst. Via de logbestanden van de sender en de receiver kon de oorzaak van eventuele problemen opgespoord worden.
Transformatie naar Documentum
De volgende transformatie die werd getest, gebruikt een Documentum repository om de getransformeerde bestanden op te slaan. Deze repository bevond zich op een bestaande virtuele machine die gebruikt kon worden voor testdoeleinden. Het volstond dus om via de conguratieconsole de juiste conguratie aan te maken.
Uitbreiding: communicatie tussen configuratieconsole en docShifter
Posted by: Robin in Uncategorized on December 10th, 2009
De vorige versie van docShifter bood geen ondersteuning voor aanpassingen in de conguratie wanneer het systeem actief was. Telkens wanneer een nieuwe conguratie moest worden toegepast, moest de senderservice herstart worden. Om dit op te lossen werd er een communicatiemechanisme ontwikkeld tussen de back-end van de conguratieconsole en de senderservice.
Omdat de communicatie tussen de sender- en receiverservice via JMS verloopt, wordt deze technologie ook voor deze toepassing gebruikt. In tegenstelling tot JMS queues worden hier topics gebruikt. Bij een queue wordt de boodschap namelijk verwijderd nadat een consumer ze gelezen heeft. Bij topics blijft de boodschap staan zodat andere senders ze ook nog kunnen ontvangen. Het versturen van de boodschappen verloopt via de JMS publisher die werd toegevoegd aan de back-end. Bij de opstarten van de senderservice wordt deze geregistreerd bij het correcte topic.
Wanneer er via de conguratieconsole een conguratie toegevoegd, aangepast of verwijderd wordt, wordt er een vaste boodschap op een topic gezet. Alle actieve senders zijn geregistreerd bij dit topic en halen de boodschap eraf. Op dat moment worden alle taken gestopt en wordt de set met senderconguraties vernieuwd. Aangezien de receiver de nodige conguraties ophaalt op basis van de gegevens die door de sender worden doorgestuurd, was het niet nodig om hier nog verdere aanpassingen aan te doen.
Uitbreiding: webservice sender
Posted by: Robin in Uitbreidingen on December 10th, 2009
DocShifter ondersteunt een aantal verschillende senders. De meest eenvoudige en meest gebruikte sender leest bestanden op de lokale harde schijf. Als uitbreiding werd de bestaande webservice sender aangepast zodat deze ook zou samenwerken met de nieuwe versie van docShifter.
Eerst werd de Java-code van de webservice aangepast. Net zoals bij de gewone senders moeten bepaalde gegevens voor JMS uit de databank opgehaald worden. Verder werden de parameters aangepast die moeten worden meegegeven bij het aanspreken van de webservice. In de vorige versie was het nodig om naast een tekstuele waarde ook een chain ID mee te geven om de correcte conguratie op te halen. In de nieuwe versie is dit chain ID niet meer nodig. De waarde van de tekstboodschap moet overeenkomen met de parameter die via de conguratieconsole ingegeven wordt bij de conguratie van sender. Ten slotte werd de DAO aangepast zodat voor een webservice sender de juist conguratie kan opgehaald worden op basis van een parameterwaarde.
De uiteindelijke webservice werd gegenereerd via de Eclipse plug-in van Apache Axis2. Tijdens de testfase werd de gegenereerde service vervolgens in een lokale Axis2-distributie geplaatst en zowel met lokale als een Documentumreceiver getest. Voor deze test werd een speciale testklasse geschreven die gebruikmaakt van een stub van de webservice. Deze stub werd automatisch gegenereerd via de ‘Axis2 code generator‘.
Integratie met docShifter (configuratieconsole)
Posted by: Robin in Integratie on December 10th, 2009
De conguratie van docShifter werd aanvankelijk ingelezen via XML-bestanden. Door gebruik te maken van de conguratieconsole, wordt deze informatie echter opgeslagen in een databank. De klassen die verantwoordelijk zijn voor het ophalen en verwerken van deze informatie, waren op voorhand al afgezonderd in een apart project. Dit heeft de tijd die nodig was voor de integratie van de conguratieconsole wat verkort.
In tegenstelling tot de conguratieconsole wordt er in dit project geen gebruik gemaakt van het Spring framework omdat dit geen extra voordeel zou opleveren. Dit houdt echter in dat het HibernateTemplateProvider-object dat in de DAO’s van de conguratieconsole gebruikt wordt, niet beschikbaar is. De DAO’s van de conguratieconsole konden voor een groot deel hergebruikt worden. Om zo weinig mogelijk code van deze DAO’s te moeten aanpassen, werd daarom een alternatieve klasse ‘HibernateTemplateProvider’ geschreven die dezelfde functionaliteit biedt.
Om de sender te laten samenwerken met de conguratieconsole moest eerst en vooral het inlezen van de conguratie aangepast worden. Overal waar informatie uit een
XML-bestand werd ingelezen, werd de code vervangen en communicatie met de databank voorzien.
Wanneer een sender gestart wordt moeten alle beschikbare senderconguraties uit de databank gehaald worden. Elke conguratie wordt voorgesteld als een object. Afhankelijk van het type conguratie wordt er een scheduler gemaakt. Die zorgt ervoor dat op bepaalde tijdstippen, volgens een ingesteld interval, alle bronbestanden opgehaald worden om te transformeren. Daarna wordt er een bericht dat het ID van de senderconguratie bevat naar de receiverservice gestuurd. Deze receiverservice neemt het werk vanaf hier over. Deze
communicatie gebeurt via een JMS queue en verloopt asynchroon.
Verbeterde validatie in Flex (2)
Posted by: Robin in Configuratieconsole on October 29th, 2009
De aangepaste validatie van de configuratieconsole werd nog verder uitgebreid. Voor het nieuwe formulier waar globale instellingen geconfigureerd kunnen worden, werd er een nieuw validatietype “match” voorzien. Door dit validatietype voor 2 invoervelden te specifiëren, wordt de inhoud van beide velden vergeleken bij het verzenden van de gegevens. Bovendien wordt er net zoals bij het type “required” gecontroleerd of de velden ingevuld zijn.
Om deze validatie te kunnen realiseren, is het belangrijk om enkele conventies te volgen in verband met de naamgeving van de velden:
- Beide velden moeten dezelfde naam hebben, op het laatste karakter na.
- Dit laatste karakter moet 1 of 2 zijn.
- Dezelfde naam moet zowel gebruikt worden in het ID en de naam van het tekstveld, als de naam van het FormItem dat het tekstveld bevat.
Een voorbeeld:
<mx:FormItem label="JMS Password" name="jmsPassword1" required="true">
<mx:TextInput displayAsPassword="true" id="jmsPassword1" name="jmsPassword1" width="120" change="validateTextInput(event);" />
</mx:FormItem>
<mx:FormItem label="Confirm JMS Password" name="jmsPassword2" required="true">
<mx:TextInput displayAsPassword="true" id="jmsPassword2" name="jmsPassword2" width="120" change="validateTextInput(event);" />
</mx:FormItem>
Wanneer de inhoud van één van beide velden aangepast wordt, wordt het andere veld automatisch gecontroleerd.
Daarnaast werd het probleem met de positie van de labels met foutmeldingen opgelost. Door gebruik te maken van de formule ‘pt.x - target.parent.width + 2 * target.width + 4′ voor de horizontale positie, staan alle labels nu juist. De variabele ‘pt’ bevat de globale positie van het tekstveld, ‘target’ is het tekstveld dat aangepast wordt. Om de globale positie te bepalen wordt de methode ‘target.contentToGlobal(pt)’ gebruikt.
Import & export (2)
Posted by: Robin in Configuratieconsole on October 8th, 2009
Importfunctie
Omdat de geëxporteerde configuraties via een ObjectOutputStream naar een bestand weggeschreven zijn, is het eenvoudig om ze terug in te lezen om te importeren. Afhankelijk van het type object dat ingelezen wordt, moet er een andere actie uitgevoerd worden.
Bij het exporteren werden de verschillende configuratie van beneden naar boven in de hiërarchie weggeschreven. De structuur kan nu dus terug opgebouwd worden beginnend bij de diepst gelegen elementen, de moduleconfiguraties. Omdat het opslaan van configuraties via Hibernate gebeurt, moeten er op voorhand nog enkele aanpassingen gedaan worden aan de objecten. In het geval van moduleconfiguraties kunnen we de volgende gevallen onderscheiden:
| Overschrijven | ||
| Ja | Nee | |
| Moduleconfiguratie en module bestaan niet | Module en moduleconfiguratie worden toegevoegd | |
| Moduleconfiguratie bestaat niet, module wel | Moduleconfiguratie wordt toegevoegd en gelinkt aan bestaande module | Moduleconfiguratie en module worden toegevoegd en aan elkaar gelinkt |
| Moduleconfiguratie en module bestaan | Bestaande configuratie en module worden overschreven | |
Ten slotte is er nog een speciaal geval, wanneer de moduleconfiguratie reeds bestaat, maar de module niet. Aangezien het onmogelijk is om de naam van een module aan te passen via de interface, kan het enkel voorkomen dat 2 verschillende modules een configuratie hebben met dezelfde naam. In dat geval zal bij het importeren een nieuwe module met bijbehorende configuratie toegevoegd moeten worden. Net zoals in het eerste geval, moet dit zowel gebeuren wanneer overschijven aangevinkt is, als wanneer dit niet het geval is.
Om te controleren of een configuratie of module al dan niet bestaat, wordt er een query uitgevoerd op basis van de naam. Na het opslaan kunnen de ID’s van de objecten veranderd zijn ten opzichte van de oorspronkelijke ID’s. Om later de moduleconfiguraties correct te kunnen linken met de andere configuraties, wordt er een mapping gemaakt tussen de oorspronkelijke en de aangepaste moduleconfiguratie. Om ervoor te zorgen dat de objecten niet aangepast zouden worden tijdens het uitvoeren van een bepaalde functie, wordt een kopie gemaakt via een “copy constructor”. Het ID wordt ook gebruikt om te bepalen of een object toegevoegd moet worden aan de database, of dat een bestaand record aangepast moet worden. Wanneer het ID de waarde 0 heeft, wordt de functie save() opgeroepen, anders de functie update(). Dit gebeurt zowel bij modules, en moduleconfiguraties als bij sender-, receiver- en transformatieconfiguraties.
Het toevoegen van de andere types van configuraties is eenvoudiger. Bij senderconfiguraties wordt de aangepaste inputconfiguratie uit de eerder aangemaakte mapping van moduleconfiguraties gehaald. Daarna wordt de senderconfiguratie opgeslagen en opnieuw een mapping gemaakt tussen de originele en de aangepaste senderconfiguraties.
In het geval van receiverconfiguraties gebeurt ongeveer hetzelfde, met dat verschil dat een hele lijst van releaseconfiguraties aangepast moet worden. Dit gebeurt weer via de mapping van moduleconfiguraties. Ook nu wordt er een mapping gemaakt van receiverconfiguraties.
De laatste 2 mappings worden gebruikt bij het importeren van transformatieconfiguraties. Het enige dat hier gebeurt is het aanpassen van sender- en receiverconfiguraties in het object. Daarna kan de configuratie opgeslagen worden.
Tijdens het importeren wordt een teller bijgehouden. Per geïmporteerd object wordt de teller verhoogd. Wanneer na het inlezen van alle objecten de teller nog altijd op 0 staat, weten we dat het geselecteerde bestand ongeldig was en wordt de gebruiker hiervan op de hoogte gebracht.
Import & export
Posted by: Robin in Configuratieconsole on October 7th, 2009
Om de configuraties die aangemaakt werden in een testomgeving op een snelle en eenvoudige manier over te kunnen zetten naar een productieomgeving, werd mij gevraagd om nog een import- en exportfunctie toe te voegen aan de configuratieconsole. Belangrijk hierbij is dat er bij het importeren geen conflicten ontstaan. Daarom moeten bij het exporteren van configuraties tegelijk alle afhankelijke configuraties geëxporteerd worden. Verder moeten de beschikbare configuraties op een eenvoudige manier geselecteerd kunnen worden.
Exportfunctie
Om de exportfunctie zo gebruikvriendelijk mogelijk te maken, werden de verschillende configuraties in de interface onderverdeeld per type. Voor elk type worden alle configuraties getoond in een uitklapbaar venster. Hiervoor werd het WindowShade-object uit de flexlib bibliotheek gebruikt. Door gebruik te maken van de flextoolbox bibliotheek, kon op een eenvoudige manier een selectievakje voor elke configuratie gezet worden.
Het meest ingewikkelde deel van de exportfunctie is het voorkomen van conflicten. Daarom wordt er bij elke selectie van de gebruiker een functie uitgevoerd die op basis van het type van de geselecteerde configuratie alle afhankelijke configuraties gaat selecteren. Daarna worden alle selectievakjes van de afhankelijke modules uitgeschakeld, zodat het onmogelijk is om dieperliggende configuraties terug te deselecteren.
De afhankelijkheden zitten als volgt in elkaar: moduleconfiguraties zijn enkel afhankelijk van modules, sender- en receiverconfiguraties zijn afhankelijk van moduleconfiguraties. Transformatieconfiguraties zijn ten slotte afhankelijk van zowel sender- als receiverconfiguraties, die op hun beurt weer afhankelijk zijn van moduleconfiguraties.
Deze hiërarchie wordt ook gebruikt in de controlefunctie. Bij selectie van een sender- of receiverconfiguratie moet enkel de lijst van moduleconfiguraties overlopen worden. In het geval van senders moet er gecontroleerd worden of het ID van de inputconfiguratie van de geselecteerde sender overeenkomt met het ID van een bepaalde moduleconfiguratie.
De controle voor receivers is iets ingewikkelder omdat dit type naast een transformatieconfigatie ook nog een lijst van releaseconfiguraties bevat.
Bij het selecteren van een transformatieconfiguratie moeten de lijsten van sender- en receiverconfiguraties overlopen worden. Als na het vergelijken van de ID’s blijkt dat een sender- of receiverconfiguratie geselecteerd moet worden, kan de controlefunctie die in de vorige paragraaf besproken werd, uitgevoerd worden.
Bij het deselecteren mogen de selectievakjes van de afhankelijke configuraties niet zomaar uitgevinkt worden. Het is namelijk mogelijk dat er nog andere configuraties geselecteerd zijn die afhankelijk zijn van deze configuraties.
Nadat bepaald is welke set van configuraties geëxporteerd moet worden, moeten deze opgeslagen worden in een bestand. Daarom wordt de lijst eerst naar de back-end gestuurd zodat er via een ByteArrayOutputStream en een ObjectOutputStream een byte array gegenereerd kan worden om weg te schrijven naar een bestand. Deze byte array wordt teruggestuurd naar de front-end. Door de ingebouwde beveiliging van Flash 10 is het echter niet mogelijk om het bestand op dat moment direct op te slaan. De functie FileReference.save() moet namelijk gekoppeld zijn aan een event. Daarom moet de gebruiker bevestigen dat hij het bestand effectief wil opslaan.
Installatie printservice client
Posted by: Robin in Printservice on August 25th, 2009
Aangezien de clientapplicatie van de printservice door eindgebruikers gebruikt zal worden, moet er een eenvoudige installatieprocedure voorzien worden. Een zeer flexibele oplossing hiervoor is IzPack. Deze tool maakt het mogelijk om een automatische installer te genereren via een XML-configuratie. Een bijkomend voordeel voor dit project is dat de gegenereerde installer platformonafhankelijk is. De printservice zal immers voor Windows en Linux beschikbaar zijn.
Tijdens de installatie kunnen verschillende opdrachten uitgevoerd worden zoals kopiëren van bestanden, invullen van gegevens… Per opdracht kan ingesteld worden op welk platform ze uitgevoerd mag worden. Op die manier kunnen verschillende opdrachten geconfigureerd worden voor Windows en Linux. Verder is het ook mogelijk om een Java-functie aan te spreken. Dit komt goed van pas tijdens de meer ingewikkelde stappen van de installatie zoals het installeren en configureren van printers.
Omdat het onmogelijk is om de interface aan te passen na het genereren van de installer, zal er een bijkomstig XML-configuratiebestand gedistribueerd worden. Dit is nodig omdat het onmogelijk is om tijdens de installatieprocedure te controleren welke DocShifterconfiguraties er beschikbaar zijn op de server. Per configuratie zal er een printer op het werkstation geïnstalleerd worden. Uiteraard zal niet elke gebruiker alle beschikbare printers willen installeren. Daarom is er een kleine aanpassing gebeurd aan de configuratieconsole.
Bij het configureren van een transformatie kan er nu een naam voor de printer en een wachtrijnaam opgegeven worden. Deze wachtrijnaam wordt achter de schermen gebruikt om te bepalen welke actie de printserver moet uitvoeren bij het ontvangen van een taak.
Bij het downloaden van de installer krijgt de gebruiker eerst een lijst met beschikbare printers te zien waar hij de printers kan selecteren die hij wenst te installeren op zijn systeem. Op basis van deze selectie zal vervolgens een configuratiebestand gegenereerd worden, dat samen met de installer verpakt wordt in een ZIP-bestand. De selectie zal overigens ook verschillen van gebruiker tot gebruiker. Dit vormt een probleem bij het genereren van het bestand, aangezien er geen twee pakketten met dezelfde naam op de server opgeslagen kunnen worden. Om dit probleem op te lossen wordt er een achtervoegsel, gebaseerd op de datum en tijd van de aanvraag, aan de bestandsnaam toegevoegd. De gebruikte tijdsaanduiding is tot op de milliseconde nauwkeurig zodat het quasi onmogelijk is om meermaals dezelfde bestandsnaam te genereren.
Een bijkomend probleem is dat de server niet kan weten wanneer de gebruiker het bestand volledig gedownload heeft, waardoor het niet automatisch verwijderd kan worden. Ook voor dit probleem werd er een oplossing ingebouwd. Via een instelbare parameter in de serverconfiguratie kan een limiet ingesteld worden voor het bewaren van een installatiepakket. Al deze pakketten worden in dezelfde tijdelijke map opgeslagen. Wanneer een nieuw pakket gecreëerd wordt, worden alle tijdelijke bestanden overlopen en verwijderd als het verschil tussen het huidige tijdstip en het tijdstip waarop het bestand aangemaakt werd groter is dan de ingestelde parameter.
Nadat de gebruiker het installatiepakket gedownload heeft, kan hij dit uitpakken en de installer starten. Tijdens de installatie zal er eerst een map opgegeven moeten worden waar de printservice geïnstalleerd wordt. Vervolgens wordt het IP-adres van de printserver gevraagd, samen met het XML-bestand dat de te installeren printers bevat. Wanneer dit bestand niet verplaatst werd, wordt deze optie automatisch ingevuld.
Vervolgens worden de nodige bestanden gekopieerd en de installatiescripts gestart. Onder Windows wordt er via een Java-functie een batch script opgestart om de printerdriver te installeren. Daarna worden de nodige printers en poorten geïnstalleerd. Omdat het bij deze stap nodig is om het XML-bestand in te lezen, gebeurt dit ook via een oproep naar een Java-functie. Voor elke parameter dat dit bestand bevat, wordt er tweede batch script gestart waar deze parameters aan worden doorgegeven.
Update printservice client
Posted by: Robin in Printservice on August 17th, 2009
Er zijn enkele problemen opgedoken bij het installeren van de printservice client. Het eerste idee was om deze als Windows service te installeren. Het bleek echter snel dat tijdens het gebruik van de applicatie geen interactie met de gebruiker toegelaten wordt. Na een uitvoerige controle werd het duidelijk dat alle functies van de applicatie wel afgehandeld werden, maar dat de interface gewoonweg niet getoond werd. Ook het controlemechanisme werkte niet meer. Een Windows service draait immers niet onder een gewone gebruikersaccount waardoor bij het opvragen van de gebruikersnaam een ander resultaat gegenereerd werd.
De clientapplicatie werkte wel wanneer ze rechtstreeks gestart werd vanuit een .bat-bestand. Het grote nadeel hierbij is dan weer dat er voortdurend een consolevenster getoond wordt. Jammer genoeg is het niet mogelijk om dit consolevenster te verbergen, zodat deze methode ook niet bruikbaar is.
Een laaste oplossing is launch4j, een zogenaamde “Java executable wrapper”. Dit programma kan een Java-applicatie verpakken in een exe-bestand dat rechtstreeks uitvoerbaar is onder Windows. Na het instellen van enkele parameters bleek deze oplossing goed te werken. Om het distribueren van nieuwe versies van de clientapplicatie in de toekomst eenvoudig te maken, werd er een ANT buildbestand toegevoegd aan het project.