ABONAMENTE VIDEO REDACȚIA
RO
EN
×
▼ LISTĂ EDIȚII ▼
Numărul 23
Abonament PDF

Procesoare de șabloane pentru dezvoltare web în Java

Dănuţ Chindriş
Java Developer
@Elektrobit Automotive
PROGRAMARE

În multe dintre proiectele informatice întâlnite avem de-a face cu situaţii în care trebuie să procesăm text, să generăm rapoarte, scripturi sau cod sursă. Adeseori, aceste probleme pot fi rezolvate cu ajutorul unor unelte numite procesoare de șabloane. Totuși, cel mai des întâlnit scenariu pentru utilizarea procesoarelor de şabloane este acela al dezvoltării de aplicaţii web, unde s-a observat nevoia separării logicii aplicaţiei de prezentare.

În cazul aplicaţiilor web dezvoltate cu tehnologii Java, standardul pentru partea de prezentare a fost mult timp JavaServer Pages, care are trăsăturile unui procesor de șabloane. Marele neajuns al acestei tehnologii este posibilitatea inserării de business logic în codul de prezentare. Astfel, avem posibilitatea să inserăm în documentul JSP scriptlets sau chiar blocuri de cod Java. Deși acest lucru ne poate ajuta în anumite situații, codul devine în mod rapid mai complex și greu de întreținut. Mai mult decât atât, această practică încalcă principiul design pattern-ului MVC.

Din cauza neajunsurilor de acest gen, JSP a pierdut teren semnificativ în favoarea altor procesoare de şabloane, care sunt folosite în tot mai multe proiecte, sporind productivitatea dezvoltatorilor şi calitatea produselor. Proiectele despre care vom discuta ne ajută să creăm cu ușurință conținut dinamic, combinând șabloanele cu modelul de date, pentru a produce documente rezultat. Șabloanele sunt scrise într-un limbaj de templating, iar documentele rezultate pot reprezenta orice fel de text formatat.

Pe lângă procesoarele deja consacrate, cum ar fi Apache Velocity sau FreeMarker, în ultimii ani a fost lansată o varietate de noi produse de acest gen, care oferă funcţionalităţi diverse. În continuarea acestui articol vom analiza patru produse disponibile gratuit pentru uz comercial, încercând să realizăm o comparaţie a acestora.

Spring MVC şi procesoarele de şabloane

Când ne gândim la dezvoltarea unei aplicaţii web cu ajutorul tehnologiilor Java, unul dintre primele lucruri pe care le facem este să alegem un framework MVC. Practica ne-a arătat că Spring MVC este unul dintre cele mai populare framework-uri web, iar în acest articol vom analiza utilizarea procesoarelor de şabloane din perspectiva integrării cu acesta. Pentru a ilustra anumite trăsături ale fiecărui procesor prezentat, vom dezvolta o aplicaţie web simplă, ce va fi compusă din două pagini: una care afișează o listă de produse și alta care afișează detaliile unui produs.

Apache Velocity

Velocity (http://velocity.apache.org/) este un proiect distribuit sub licenţă Apache Software License, care se bucură de o mare popularitate printre dezvoltatorii de aplicaţii Java. Deşi este utilizat de cele mai multe ori în context web, nu suntem limitaţi să folosim produsul doar pentru acest tip de proiecte. Poate fi utilizat fie ca un utilitar de sine stătător pentru generare de cod sursă şi rapoarte, fie ca o componentă integrată în alte sisteme.

Asemeni altor procesoare de şabloane, Velocity a fost proiectat astfel încât designerii web să poată lucra în paralel cu programatorii Java. Astfel, Velocity ne ajută să despărțim codul Java de codul paginilor web, oferind o alternativă viabilă tehnologiei JSP.

Velocity Template Language

Apache Velocity se bucură de un limbaj de scripting propriu, numit Velocity Template Language (VTL), care este puternic şi flexibil. Autorii Velocity anunţă cu mândrie că flexibilitatea produsului lor este limitată doar de creativitatea utilizatorului. VTL a fost creat cu scopul de a oferi cea mai simplă şi curată cale pentru a încorpora conţinut dinamic într-o pagină web.

Velocity foloseşte referinţe pentru a îngloba conţinut dinamic în paginile web, iar unul dintre tipurile de referinţe este reprezentat de către variabile. Acestea pot referi obiecte definite în codul Java sau pot primi valori chiar în interiorul paginii web, prin intermediul unei declaraţii VTL. O astfel de instrucţiune începe cu un caracter #, după cum putem observa în exemplul următor:

#set( $magazineUrl = "http://www.todaysoftmag.com/" )

Integrarea cu Spring MVC

Spring MVC are suport nativ pentru procesorul de șabloane despre care discutăm, și în consecință integrarea acestora este un proces simplu. Presupunând că folosim Maven pentru crearea proiectului, alegem arhetipul maven-archetype-webapp din grupul org.apache.maven.archetypes. Fără a enumera toate dependințele Maven necesare, menționăm totuși că avem nevoie de artefactele velocity și velocity-tools din grupul org.apache.velocity. Codul sursă al proiectului exemplu poate fi descărcat de la următoarea adresă: https://springvelocity.googlecode.com/svn/trunk.

După ce am declarat în web.xml servlet-ul DispatcherServlet care va gestiona toate request-urile și am definit fișierul servlet-context.xml cu toate elementele specifice Spring, putem declara bean-urile pentru lucrul cu Velocity. În primul rând, avem nevoie de un bean cu id-ul velocityConfig, căruia îi vom transfera calea relativă la care se vor găsi șabloanele pentru paginile aplicației:

Apoi, declarăm un view resolver, care primește mai multe proprietăți. Clasa care va determina tipul acestui bean trebuie să implementeze interfața ViewResolver și are ca principal rol găsirea view-urilor după nume. Cea mai interesantă proprietate a acestui bean este layoutUrl. Aceasta reprezintă numele șablonului care va stabili layout-ul general:

De asemenea, Velocity are capacitatea de a face caching șabloanelor folosite, lucru specificat prin proprietatea cache.

Acum că am configurat aplicația astfel încât partea de vizualizare să fie reprezentată prin șabloane Velocity, putem să vedem cum arată aceste șabloane. Partea cea mai interesantă a șablonului care determină layout-ul general este prezența variabilei speciale $screen_content. Aceasta va conține la runtime rezultatul procesării șablonului corespunzător view-ului returnat de controller-ul Spring MVC. În cazul aplicației noastre există un singur controller, care poate returna fie view-ul list, fie view-ul details. Șablonul corespunzător view-ului list este list.vm și are următorul conținut:

În blocul de mai sus observăm cum iterăm o colecție și cum accesăm proprietățile obiectelor din model cu ajutorul VTL.

Avantaje și dezavantaje

Fiind unul dintre cele mai cunoscute proiecte în materie de template processing, Velocity beneficiază de susținerea unei comunități bine stabilite. De asemenea, documentația de pe site-ul oficial este generoasă și există multe articole, care răspund la diverse întrebări. În plus, în decursul timpului au fost publicate câteva cărți dedicate proiectului Apache Velocity. Dacă aceste resurse nu sunt de ajuns, există un mailing list cu o arhivă bogată, la care ne putem abona.

Există o varietate de aspecte care ne pot convinge să utilizăm acest produs în următorul nostru proiect: Velocity este un procesor robust, flexibil şi bogat în funcţionalităţi. Există dezvoltatori care afirmă că acesta ar fi cel mai puternic tool de acest tip de pe piaţă.

Un alt plus al acestui proiect este faptul că, pe lângă Velocity Engine, are în componență o serie de subproiecte: Tools (unelte și elemente de infrastructură, folositoare pentru dezvoltarea de aplicații web și nu numai), Anakia (transformare de documente XML), Texen (generare de text), DocBook Framework (creare de documentație), DVSL (Declarative Velocity Style Language - transformări XML).

Când vine vorba despre suport pentru IDE-uri, Velocity beneficiază de o serie de plugin-uri dezvoltate de membri ai comunităţii. Aceste plugin-uri sunt dedicate unor IDE-uri precum Eclipse, NetBeans, IntelliJ IDEA, ca să le amintim doar pe cele mai populare. Multe dintre acestea oferă evidenţierea sintaxei şi chiar autocompletion. La dezvoltarea exemplului prezentat în acest articol am folosit Velocity Edit pentru Eclipse.

Așa cum am arătat într-un paragraf anterior, integrarea cu Spring MVC este facilă. De asemenea, distribuţia Spring MVC conţine o bibliotecă de macro-uri pentru binding support şi form handling, unelte valoroase pentru dezvoltarea de aplicații web.

Deși este cel mai popular template engine în universul Java, Apache Velocity nu a mai beneficiat de niciun release din noiembrie 2010, când s-a lansat versiunea 1.7 a nucleului proiectului. Proiectul este încă activ, însă comunitatea pare a fi mulțumită cu funcționalitățile deja implementate și încă nu există un release planificat.

Velocity este un proiect la care s-a contribuit intens, devenind un produs complex, intimidant pentru noii utilizatori. Sintaxa este oarecum greoaie, iar scrierea de template-uri fără ajutorul unui IDE care să suporte sintaxa VTL poate fi un coşmar.

FreeMarker

FreeMarker este un produs matur, distribuit sub licenţă BSD. Asemănător proiectului Apache Velocity, FreeMarker oferă funcţionalităţi complexe care vin în întâmpinarea nevoilor dezvoltatorilor de aplicaţii web. Acesta a fost proiectat pentru generarea eficientă a paginilor HTML, însă posibilităţile utilizării tool-ului nu se opresc aici. Aşa cum afirmă creatorii proiectului, acesta este un produs software generic pentru generarea de text, aceasta însemnând orice de la HTML la cod sursă.

FreeMarker Template Language

Pentru descrierea şabloanelor, FreeMarker ne pune la dispoziţie un limbaj puternic de templating, numit FreeMarker Template Language. FTL ne permite definirea de expresii, funcţii şi macro-uri în cadrul şabloanelor pe care le scriem. De asemenea, ne este pusă la dispoziţie o bibliotecă bogată cu directive predefinite, care ne dau posibilitatea să iterăm colecţii de date, să includem alte şabloane şi multe altele. În continuare, prezentăm un exemplu de apel al unei directive FTL, care asignează o valoare unei variable:

<#assign magazineUrl = "http://www.todaysoftmag.com/">

Observăm că în limbajul de templating specific FreeMarker, directivele predefinite se apelează folosind sintaxa <#numedirectiva parametri>, iar macro-urile se apelează cu ajutorul sintaxei <@macro parametri>. Expresiile se scriu astfel: ${expresie}.

Integrarea cu Spring MVC

La fel ca în cazul Apache Velocity, FreeMarker beneficiază de suport pentru integrarea cu Spring MVC chiar din partea creatorilor framework-ului web. Astfel, distribuția Spring MVC ne oferă o implementare de ViewResolver, dar şi o bibliotecă cu macro-uri pentru binding support şi form handling.

Folosind aceeași modalitate pentru a crea o aplicație Spring MVC + FreeMarker ca în cazul Apache Velocity, remarcăm că singurele modificări pe care trebuie să le efectuăm sunt în fișierul de configurare Spring și în șabloane. De fapt, vom vedea că acest lucru este valabil și atunci când ne vom ocupa de proiectele Thymeleaf și Rythm. De asemenea, trebuie să remarcăm că avem nevoie să declarăm în fișierul de configurare Maven dependința freemarker din grupul org.freemarker. Codul sursă al proiectului exemplu poate fi descărcat de la următoarea adresă: https://springfreemarker.googlecode.com/svn/trunk.

În servlet-context.xml înlocuim bean-ul de configurare și bean-ul cu rol de view resolver. Cel mai interesant aspect al acestor elemente XML este proprietatea cu cheia auto_import, care ne permite să importăm în toate fișierele noastre FTL macro-urile definite în fișierul spring.ftl, oferit de către distribuția Spring MVC. Acestea sunt accesibile prin intermediul alias-ului spring:

/spring.ftl as spring

Șablonul corepunzător view-ului list este reprezentat de fișierul list.ftl. Partea notabilă a acestuia este prezentată în continuare:

<#include "header.ftl" />

Products

<#include "footer.ftl" />

În acest template observăm cum se poate include conținutul altui șablon, cum putem itera o colecție de obiecte și cum scriem o expresie FTL.

Avantaje și dezavantaje

Proiectul FreeMarker se bucură de o documentație cuprinzătoare, site-ul oficial oferind un manual bogat, din care atât programatorii, cât și designerii pot extrage multă informație utilă. De asemenea, există un mailing list pentru discuții, însă utilizatorii sunt încurajați să ceară ajutor pe Stack Overflow, punând întrebări marcate cu tag-ul "freemarker". Deși FreeMarker este un template engine popular, până în prezent s-a publicat o singură carte dedicată acestuia.

FreeMarker oferă un limbaj de templating complet și relativ ușor de înțeles. Se poate spune că acest procesor de șabloane se bate de la egal la egal cu Velocity, fiind un produs matur, gata să fie integrat în proiecte enterprise. Merită menționat că, asemeni proiectului prezentat anterior, FreeMarker oferă mecanisme de caching al șabloanelor.

Pe pagina oficială există o listă cu o serie de plugin-uri pentru diverse medii de programare. Pentru exemplul prezentat în acest articol am folosit plugin-ul care face parte din JBoss Tools Project pentru Eclipse. Acesta oferă evidențierea sintaxei, indicatori pentru erorile de sintaxă, code completion pentru numele de macro-uri și de proprietăți ale bean-urilor. Trebuie să remarcăm că plugin-urile disponibile pentru FreeMarker nu sunt la fel de puternice precum cele scrise pentru Apache Velocity. De fapt, plugin-ul dedicat NetBeans nu pare să funcționeze pentru versiunea 7 a acestuia, deși pe site este indicat că suportă versiunile mai mari sau egale cu 6.

La fel ca în cazul Apache Velocity, FreeMarker se integrează ușor cu Spring MVC. Așa cum am văzut într-o secțiune anterioară, Spring MVC oferă atât o implementare pentru ViewResolver, cât şi o bibliotecă cu macro-uri pentru binding support şi form handling.

Proiectul este destul de activ, cea mai recentă versiune fiind 2.3.20, publicată în iunie 2013.

Am văzut că proiectul prezintă cam aceleași plusuri precum procesorul de șabloane prezentat înaintea lui și putem spune că și la capitolul minusuri se aseamănă. Fiind un proiect la care se lucrează de ani buni, a devenit complex, apărând uneori ca dificil de stăpânit pentru noii utilizatori.

Thymeleaf

Thymeleaf este o bibliotecă Java distribuită sub versiunea 2.0 a licenței Apache, având ca scop principal crearea de șabloane într-un mod elegant. Cel mai potrivit use case pentru Thymeleaf este generarea de documente XHTML / HTML5 în context web. Totuși, acest tool poate fi folosit și în medii offline, fiind capabil să proceseze documente XML.

Creatorii Thymeleaf ne oferă un modul pentru integrarea cu Spring MVC, care ne dă posibilitatea să folosim acest produs pentru stratul de vizualizare al aplicațiilor noastre web, fiind astfel un substituent pentru JSP. Thymeleaf este bazat pe seturi de trăsături numite dialecte. Distribuția standard vine cu dialectele Standard și SpringStandard, care ne permit să creăm așa-numite natural templates. Acestea pot fi afișate corect de către browser, chiar dacă le accesăm ca fișiere statice. Astfel, aceste documente pot fi privite ca niște prototipuri. Dacă avem nevoie de alte funcționalități decât cele predefinite, Thymeleaf ne dă posibilitatea să ne creăm propriile noastre dialecte. Un dialect oferă funcționalități cum ar fi evaluarea expresiilor sau iterarea colecțiilor.

Nucleul Thymeleaf este construit în jurul unui motor de procesare DOM, care este o implementare proprie, de înaltă performanță. Cu ajutorul acestui mecanism realizează o reprezentare a șabloanelor în memorie, iar apoi efectuează procesări pe baza configurației curente și a setului de date pus la dispozițe, traversând nodurile.

Standard Dialect și SpringStandard Dialect

Aceste două dialecte au aceeași sintaxă, marea diferență între ele fiind așa-numitul expression language folosit. Dacă dialectul Standard folosește OGNL, StandardSpring are integrat Spring Expression Language. De asemenea, dialectul SpringStandard are o serie de mici adaptări pentru a utiliza mai bine anumite funcționalități oferite de Spring. Notația pe care o folosește Thymeleaf în șabloanele sale poate fi observată în exemplul următor:

Today Software Magazine

Atunci când șablonul de mai sus este procesat cu Thymeleaf, acesta evaluează expresiile reprezentate ca valori ale atributelor situate în spațiul de nume th și înlocuiește valorile atributelor clasice HTML cu rezultatul procesării.

Pentru a putea beneficia de validarea documentului, trebuie să declarăm spațiul de nume astfel:

Integrarea cu Spring MVC

Așa cum am menționat, Thymeleaf ne oferă un modul pentru integrarea cu Spring MVC, disponibil atât pentru Spring 3 cât și pentru Spring 4. Pentru a beneficia de acesta, pentru exemplul nostru am adăugat în pom.xml dependința thymeleaf-spring3 din grupul org.thymeleaf. Codul sursă al proiectului exemplu poate fi descărcat de la următoarea adresă: https://springthymeleaf.googlecode.com/svn/trunk.

Avantaje și dezavantaje

Thymeleaf este un proiect care atrage tot mai mulți utilizatori, dar și programatori care contribuie la dezvoltarea acestuia. Site-ul oficial ne oferă o varietate de resurse pentru a ne familiariza cu acest produs. Mai mult decât atât, documentația existentă ne prezintă și cum putem extinde Thymeleaf cu propriile noastre dialecte. Pe lângă aceste tutoriale, avem la dispoziție articole pe diverse teme, un forum pentru utilizatori și un tutorial interactiv. Deși la momentul scrierii acestui articol nu există cărți dedicate acestui proiect, putem găsi numeroase articole despre Thymeleaf. De asemenea, avem la dispoziție și documentațiile Javadoc pentru API-urile thymeleaf și thymeleaf-spring.

Acest procesor de șabloane vine cu o filosofie diferită față de de Velocity și FreeMarker, lucru ce se poate observa și în sintaxa dialectelor Standard și SpringStandard. Thymeleaf pune mare accent pe conceptul de natural templating, care oferă posibilitatea creării de prototipuri statice.

O dată cu lansarea versiunii 2.0 a motorului Thymeleaf, mecanismul de procesare a șabloanelor a fost înlocuit, sporind performanțele acestuia. De asemenea, există și un sistem de caching al șabloanelor.

În ce privește integrarea cu mediile de programare, există un plugin pentru Eclipse care oferă autocompletion. Din păcate, nu există suport și pentru alte IDE-uri.

Asemeni proiectelor despre care am discutat până acum, integrarea cu Spring MVC este ușor de obținut, întrucât autorii Thymeleaf au creat un modul special pentru aceasta.

Proiectul beneficiază de lansări frecvente, versiunea curentă fiind 2.12.RELEASE. Aceasta este disponibilă publicului din decembrie 2013.

Thymeleaf oferă o gamă largă de funcționalități, însă testele arată că procesarea șabloanelor este mai lentă decât în cazul unora dintre competitorii săi.

Rythm

Rythm este un procesor de șabloane pentru aplicații Java distribuit sub licență Apache, versiunea 2.0, descris de autorul său ca fiind un produs cu scop general, ușor de folosit și foarte rapid. Asemeni altor procesoare de șabloane, putem procesa cu ajutorul acestuia documente HTML, XML, scripturi SQL, cod sursă, email-uri sau orice alt text formatat. Rythm a fost inspirat din proiectul .Net Razor, datorită sintaxei sale simple și elegante.

În aceiași termeni laudativi, autorul pretinde că preocuparea numărul unu a proiectului este experiența utilizator. De la API până la sintaxa șabloanelor, produsul este caracterizat prin simplitate. De asemenea, produsul a fost proiectat astfel încât utilizarea acestuia să fie cât mai facilă pentru programatorii Java.

Sintaxa procesorului de șabloane

Rythm folosește caracterul special @ pentru a introduce toate elementele de sintaxă. Acest lucru este exemplificat în blocul de cod prezentat în continuare:

@for (product: products) {
  • @product.getName()
  • }

    Pentru a putea utiliza în template obiecte adăugate modelului de date în controller-ul Spring, trebuie să folosim următoarea notație:

    @args java.util.List products

    Integrarea cu Spring MVC

    Pentru integrarea cu Spring MVC avem la dispoziție o bibliotecă de clase third-party, disponibilă ca artefact Maven sub id-ul spring-webmvc-rythm și grupul com.ctlok. Având această dependință în proiect, putem declara bean-urile necesare în servlet-config.xml. Una dintre proprietățile bean-ului rythmConfigurator este mode, cu ajutorul căreia putem specifica în ce mod rulăm aplicația: dev sau prod. Codul sursă al proiectului exemplu poate fi descărcat de la următoarea adresă: https://springrythm.googlecode.com/svn/trunk.

    Avantaje și dezavantaje

    Spre deosebire de Velocity și FreeMarker, Rythm procesează șabloanele, transformându-le în bytecode Java. Datorită acestui lucru, la runtime, procesarea acestora este foarte rapidă, plasând acest proiect alături de cele mai rapide procesoare de șabloane din universul Java.

    Deși nu este la fel de vastă precum a celorlalte produse prezentate, documentația proiectului este cuprinzătoare, permițându-ne să deprindem abilitățile necesare dezvoltării de aplicații web cu ajutorul Rythm Template Engine. Pe site-ul proiectului există o serie de tutoriale, atât pentru programatori, cât și pentru webmaster-i, iar cu ajutorul instanței Fiddle dedicate putem scrie șabloane Rythm și vedea rezultatul imediat. Fiind un proiect relativ tânăr, comunitatea din jurul lui nu este încă dezvoltată.

    Rythm poate opera în două moduri: dev (development) și prod (production). Astfel, în modul dev șabloanele sunt reîncărcate de fiecare dată când sunt modificate, pentru a scurta timpul de dezvoltare; pe de altă parte, în modul prod acestea sunt încărcate o singură dată, pentru sporirea performanței.

    Unul dintre minusurile proiectului Rythm este faptul că momentan nu oferă niciun plugin pentru medii integrate de dezvoltare. Astfel, deși sintaxa acestuia este cât se poate de prietenoasă, nu avem asistență din partea IDE-ului preferat pentru scrierea șabloanelor, un aspect important pentru mulți dezvoltatori.

    Rythm permite inserarea de cod Java în cadrul unui șablon, acesta fiind unul dintre aspectele care ne-au îndemnat să renunțăm la JSP în favoarea altor procesoare de șabloane. Așadar, vedem acest lucru ca pe un minus al proiectului.

    Performanțe

    Există prea puține teste relevante pentru determinarea performanței procesoarelor de șabloane prezentate în acest articol, însă în continuare vom prezenta rezultatele unor astfel de studii. Folosind tool-ul de benchmarking disponibil la adresa https://github.com/greenlaw110/template-engine-benchmarks am obținut următoarele rezultate pentru 10000 de request-uri:

    • Velocity: 3.8 secunde,
    • FreeMarker: 4.8 secunde,
    • Thymeleaf: 43.2 secunde,
    • Rythm: 3 secunde.

    Un alt test (disponibil la adresa http://www.slideshare.net/jreijn/comparing-templateenginesjvm), în care Rythm nu a fost inclus, arată că Velocity și FreeMarker au avut performanțe aproape identice, în timp ce Thymeleaf a fost, din nou, printre cele mai lente procesoare.

    Astfel, Rythm pare a fi cel mai rapid template engine dintre cele despre care am discutat în acest articol, Velocity și FreeMarker își dispută locurile al doilea și al treilea, în timp ce Thymeleaf a obținut cel mai slab timp.

    Concluzii

    Deși am văzut că proiectele prezentate ne pun la dispoziție funcționalități similare, în urma acestei discuții putem trage câteva concluzii. Atât Velocity, cât și FreeMarker sunt produse consacrate, care și-au dovedit valoarea în multe proiecte de succes, oferind performanță decentă. Pe de altă parte, Thymeleaf și Rythm sunt proiecte mai tinere, care vin cu o filosofie nouă, adaptată trendurilor în dezvoltarea web. Spre exemplu, Thymeleaf excelează la capitolul natural templating, în timp ce Rythm oferă o sintaxă curată, ușor de înțeles atât pentru programatori, cât și pentru webmaster-i. Putem concluziona că alegerea unui template engine depinde, în primul rând, de proiectul pentru care avem nevoie de acesta, fiecare dintre procesoarele despre care am discutat meritând să fie luat în considerare.

    LANSAREA NUMĂRULUI 89

    Prezentări articole și
    Panel: Programming

    Joi, 21 Noiembrie, ora 18:00
    Liberty Technology Park

    Înregistrează-te

    Facebook Meetup

    Sponsori

    • comply advantage
    • ntt data
    • 3PillarGlobal
    • Betfair
    • Telenav
    • Accenture
    • Siemens
    • Bosch
    • FlowTraders
    • MHP
    • Connatix
    • UIPatj
    • MetroSystems
    • Globant
    • Colors in projects