Tuesday, January 20, 2015

Atlassian JIRA REST API

(Publicat în revista Today Software Magazine, Numărul 30, Decembrie 2014: http://www.todaysoftmag.ro/article/1186/atlassian-jira-rest-api)

Nu cred că este o coincidenţă faptul că Atlassian JIRA este tool-ul folosit pentruissue tracking în toate proiectele la care am luat parte până acum. Deşi există destul de multe produse de genul acesta pe piaţă, JIRA este unul dintre numele recunoscute de majoritatea actorilor implicaţi în proiecte informatice. Alături de alte titluri sonore precum Bugzilla sau Redmine, JIRA iese în evidenţă prin setul complet de funcţionalităţi, calitate, uşurinţa utilizării, dar şi prin extensibilitatea sa.
Atlassian JIRA a fost conceput ca un produs flexibil, uşor extensibil prin intermediul plugin-urilor. De asemenea, sistemul comunică cu lumea exterioară printr-o interfaţă REST, prin intermediul căreia clienţii platformei pot efectua diverse operaţii. În rândurile care urmează ne vom concentra atenţia asupra trăsăturilor acestui API, discutând câteva use case-uri clasice, cum ar fi căutarea unui issue sau adăugarea unui comentariu. De asemenea, vom petrece puţin timp uitându-ne atât la clientul Java pus la dispoziţie de Atlassian, cât şi la implementarea unui client REST utilizând Jersey, implementarea de referinţă de la Oracle.

JIRA REST Java Client

Atlassian ne pune la dispoziţie o bibliotecă de clase menită să ne înlesnească lucrul cu API-ul REST, aceasta numindu-se sugestiv JIRA REST Java Client. Această bibliotecă expune la rândul său un API aproape complet pentru operațiile pe care le putem face într-un proiect JIRA. Spre exemplu, prin intermediul acestui client avem posibilitatea să găsim un anume proiect după cheie, să creăm tichete, să le ştergem, să adăugăm atașamente, să adăugăm worklog-uri și multe altele.
Metodele pe care le avem la dispoziție sunt grupate în mai multe clase, în funcție de obiectul business despre care este vorba. De exemplu, putem apela metodele ce țin de administrarea issue-urilor doar după ce obținem un obiect de tip IssueRestClient. Înainte de aceasta, avem nevoie de un obiect de tip JiraRestClient, creat prin intermediul unei implementări asincrone a interfeței JiraRestClientFactory.
Detaliile menționate mai sus pot fi observate în clasa JiraClient care face parte din proiectul demonstrativ ce însoțește acest articol. Proiectul poate fi descărcat de la adresa menționată în secțiunea Resurse. Trebuie să observăm faptul că acest proiect Java are scop didactic, codul sursă fiind unul minimal, care nu urmăreşte să respecte bunele practici.
Să presupunem că dorim să obținem cu ajutorul bibliotecii JRJC un obiect de tip Issue, ce modelează detaliile unui tichet JIRA. Acum că avem la dispoziție un obiect de tip JiraRestClient putem scrie următoarele:

Promise promise = jiraRestClient.getIssueClient().getIssue("JRA-9");
Issue issue = promise.claim();

Observăm că metoda getIssue(String issueKey) returnează un obiect de tip Promise, motiv pentru care, pentru a obține instanța Issue trebuie să apelăm metoda claim(). În aceeași manieră trebuie să procedăm și pentru obținerea altor obiecte, cum ar fi proiecte, worklogs etc. .
Unul dintre avantajele utilizării acestei biblioteci îl reprezintă faptul că nu trebuie să ne preocupăm de subtilitățile lucrului cu servicii REST. În fond, până în acest moment pentru noi a fost transparent faptul că avem de-a face cu un API REST. Pentru a ne face o părere mai clară despre ce înseamnă JIRA REST API, trebuie să realizăm propria noastră implementare a unui client REST, lucru pe care îl vom face utilizând Jersey.

Client REST cu Jersey

Jersey ne oferă un mod simplu și rapid de a crea un client REST, aspect pe care îl ilustrăm în continuare:

String auth = new String(Base64.encode(USERNAME + ":" + PASSWORD));
Client client = Client.create();
WebResource webResource = client.resource(JIRA_SERVER + REST_PATH + query);
Builder builder = webResource.header("Authorization", "Basic " + auth)
    .type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);

Revenind la scenariul în care dorim să regăsim un tichet pe baza cheii, presupunem că parametrul query conține o cale de genul issue/JRA-9, unde JRA-9este cheia tichetului. Pentru a obține obiectul Issue apelăm metoda get(), care corespunde metodei HTTP GET.

ClientResponse clientResponse = builder.get(ClientResponse.class);

În acest moment putem obține obiectul JSON serializat, sub forma unui String:

String json = clientResponse.getEntity(String.class);

Acest String poate fi apoi deserializat într-un bean creat de noi cu ajutorul bibliotecii Jackson, care ne pune la dispoziție diverse unelte de lucru cu JSON. Acest scenariu este unul dintre cele mai simple, însă lucrurile devin mai complicate atunci când trebuie să creăm un worklog, spre exemplu. În acest caz, mai întâi trebuie să creăm un bean cu ajutorul căruia să modelăm un worklog și să populăm o instanță cu informațiile pe care dorim să le salvăm. Apoi trebuie să serializăm acest obiect sub forma unui String și să-l transmitem serviciului REST după modelul de mai sus, însă folosind metoda HTTP POST de data aceasta. Răspunsul serviciului va conține obiectul salvat sub formă serializată, îmbogățit cu noi informații, cum ar fi id-ul worklog-ului.

Concluzii

JIRA REST API este o interfață către lumea exterioară care are o valoare business incontestabilă. Acest API oferă organizațiilor posibilitatea să integreze cu ușurință tool-ul în ecosistemul propriu, pentru a defini procese dintre cele mai creative și complexe. Totuși, se poate observa că JIRA REST API nu acoperă în totalitate scenariile de utilizare JIRA. Unul dintre aspectele pentru care utilizatorii așteaptă o rezolvare îl reprezintă imposibilitatea de a lucra cu filtrele salvate. Există și un tichet pe acest subiect (JRA-36045), care încă este deschis.
Pe de altă parte, trebuie să menționăm că API-ul REST vine cu funcționalități importante, cum ar fi posibilitatea de a regăsi câmpurile custom și valorile acestora, operație pe care nu o puteam face cu API-ul SOAP.
JIRA REST API a ajuns la versiunea a doua şi, chiar dacă există loc de îmbunătăţiri, putem spune că este un produs matur, care vine cu funcţionalităţi importante față de predecesorul său.

Resurse

  1. https://jira-rest-client-ro-leje.googlecode.com/svn/trunk
  2. https://docs.atlassian.com/jira/REST/latest/
  3. http://www.j-tricks.com/tutorials/java-rest-client-for-jira-using-jersey
  4. http://www.baeldung.com/jackson-ignore-null-fields

Internet of Things în universul Java

(Publicat în revista Today Software Magazine, Numărul 31, Ianuarie 2015: http://www.todaysoftmag.ro/article/1244/internet-of-things-in-universul-java)

Experții din domeniul IT au numit 2014 "anul Internet of Things ", acesta fiind unul dintre cele mai fierbinți subiecte ale anului care tocmai s-a încheiat. Titlul atribuit nu este deloc surprinzător dacă luăm în considerare faptul că site-uri importante precum dzone.comjaxenter.com sau oracle.com au publicat câteva articole pe săptămână despre tehnologiile din sfera Internet of Things, iar blogger-ii nu au scăpat nicio ocazie să posteze despre ultimele lor proiecte IoT. Nici editurile nu au fost mai prejos, în 2014 fiind publicate zeci de titluri, multe altele așteptând să vadă lumina tiparului anul acesta.
Toate acestea s-au întâmplat în contextul lansării unei multitudini de noi gadgeturi sau dispozitive inteligente, dar și a numeroase platforme software sau implementări ale unor protocoale mai mult sau mai puțin cunoscute. Mulți împătimiți ai tehnologiei au auzit de produse populare, lansate în ultimii ani, precum Philips Hue sau Nest, însă începând cu 2014 e nevoie de un efort activ să putem ține pasul cu frecvența apariției de noi dispozitive, cum ar fi Sen.se Mother, Fitbit Charge sau SkyBell. IoT influențează din ce în ce mai mult domeniile din viața de zi cu zi, precum sănătatea cu dispozitive care monitorizează pacienții, îngrijire la domiciliu, prin gadgeturi pentru un stil de viață sănătos, transporturi, cu autovehicule conectate, automatizarea locuințelor, industrie etc. .
Înainte de a discuta despre modalitățile prin care comunitatea Java își poate face auzită vocea în sfera Internet of Things, suntem datori să descriem pe scurt ce înseamnă mai exact IoT.

Definiții

Internet of Things sau, pe scurt, IoT este un concept dezbătut din ce în ce mai mult în ultimii ani, dar semnificația sintagmei nu este întotdeauna pe deplin înțeleasă. CASAGRAS (Coordination and support action for global RFID-related activities and standardisation) ne dă o definiție destul de abstractă, care spune despre IoT următoarele: este "o infrastructură de rețea globală, care conectează obiectele fizice și virtuale prin intermediul exploatării capturii de date și a capacității de comunicare. Această infrastructură include dezvoltările existente și viitoare ale rețelelor și ale Internet-ului. Aceasta va pune la dispoziție modalități de identificare a obiectelor, senzori și capacitatea de conectare ca bază pentru dezvoltarea de servicii sau aplicații independente și cooperante. Acestea vor fi caracterizate printr-un grad înalt de autonomie pentru captura de date, transferul evenimentelor, conectivitatea în rețea și interoperabilitate" [1].
Definiția oferită de Stephen Haller de la SAP Research ne ajută să ne creăm o imagine mai concretă asupra Internet of Things, despre care spune că este "o lume unde obiectele fizice sunt integrate omogen în rețeaua informațională și unde aceste obiecte fizice pot deveni participanți activi în procesele business. Serviciile sunt gata să interacționeze cu aceste obiecte inteligente prin intermediul Internet-ului, să interogheze și să-și schimbe starea și orice informație asociată cu ele, luând în considerare securitatea și chestiunile ce țin de intimitate"[2].
O altă explicație este dată de Oracle, care afirmă că "Internet of Things se referă la colectarea și gestionarea cantităților masive de date provenite de la rețelele - aflate într-o rapidă expansiune - de dispozitive și senzori, procesarea acestor date și apoi partajarea lor cu alte obiecte conectate"[3]. Pentru a ne da seama care este ordinul de mărime al acestor cantități de date, ne putem uita la exemplul echipei de navigație Oracle Team USA, care lucrează cu ambarcațiuni echipate fiecare cu câte 300 de senzori, meniți să furnizeze informații despre o mulțime de parametri, cum ar fi eficacitatea reglajelor pânzelor, tăria și stabilitatea carenei sau tensiunea din catarg. Acești senzori măsoară 3000 de variabile de 10 ori pe secundă, producând 500 GB de date neprelucrate pe zi. Un alt aspect interesant este faptul că în prezent doar 11% din volumul total de date este generat de dispozitive, dar IDC estimează că până în 2020 procentul va crește la 40%[4].
Acest titlu descriptiv, care încearcă să surprindă esența următorului mare trend în IT, reprezintă în principiu efortul de a regândi relația noastră cu obiectele pe care le folosim în fiecare zi, dar și a obiectelor între ele. Conform experților, IT-ul se va îndrepta puternic în această direcție. Ca dovadă, mai multe nume sonore ale tehnologiei secolului al XXI-lea, precum Cisco sau Bosch, au întreprins studii pe această temă, ajungând la concluzia că proiectele din sfera IoT vor depăși valoarea economică de 15 trilioane de dolari, până în 2020[5]. De asemenea, analiștii de la Cisco afirmă că în 2010 existau peste 12.5 miliarde de obiecte conectate la Internet și estimează că vor exista aproximativ 25 miliarde de "lucruri" inteligente, conectate la Internet, până la finalul anului 2015. Pentru anul 2020, previziunea lor este de 50 de miliarde de "lucruri"[6].

Oracle și Java Embedded

În acest context intră în scenă Java, atât ca platformă ce are la bază Java Virtual Machine, cât și ca limbaj de programare, cu o comunitate de peste 9 milioane de utilizatori. Facem această distincție între platformă și limbaj[7] întrucât un dispozitiv care rulează JVM nu este limitat la execuția de aplicații Java; acestea pot fi, în anumite condiții, aplicații scrise cu ajutorul Scala, Clojure etc. . În trecut, programarea dispozitivelor embedded se făcea preponderent în limbaje de nivel scăzut, precum C sau limbaj de asamblare.
În acest articol vom încerca să ne facem o părere despre soluțiile propuse de Oracle pentru IoT, companie a cărei implementare a platformei Java se bucură de cea mai mare popularitate printre programatori. Totuși, în articolele viitoare vom privi mai îndeaproape și caracteristicile altor proiecte Java pentru IoT, cum ar fi cele din stiva dezvoltată de Eclipse Foundation.
În ultimii ani, Oracle a investit masiv într-o linie de produse denumite sugestiv Java Embedded, lucru ce oferă posibilitatea programatorilor Java să scrie aplicații pentru astfel de dispozitive, de la smart card-uri și module wireless, până la single board computer-e (SBC), cum ar fi Raspberry PI. Platformele Java Embedded sunt principalul lucru pe care Oracle îl oferă dezvoltatorilor embedded și prin intermediul căruia contribuie la influența pe care o are Java în sfera Internet of Things.
Viziunea Oracle pentru Java 8 a fost să lanseze, pe lângă Standard Edition (SE), încă două variante importante ale platformei, mai exact Oracle Java ME Embedded 8 și Oracle Java SE Embedded 8, la care se adaugă Java Embedded Suite. Henrik Ståhl, vicepreședinte peste product management pentru Java și IoT la Oracle, afirmă în ediția noiembrie/decembrie 2014 a revistei Oracle Java Magazine că, prin lansarea acestor variante ale platformei au "făcut disponibile pe platforme embedded, care au doar câteva sute de KB de memorie, feature-urile cu care programatorii sunt obișnuiți în Java SE"[8].


Fig. 1 Privire de ansamblu asupra platformei Oracle Java ME Embedded 8[9]

Prin lansarea noii versiuni a distribuțiilor amintite mai sus, Oracle a încercat să le aducă la un grad cât mai înalt de compatibilitate una cu cealaltă și, în același timp, să le alinieze la Java SE 8. Pentru aceasta, s-a introdus conceptul de Compact Profiles, dezvoltatorii putând alege între setul complet de API-uri Java SE și alte trei subseturi care au la dispoziție doar acele API-uri care sunt necesare pentru use case-urile relevante. Un astfel de use case poate fi rularea unei stive OSGi (Open Service Gateway initiative). Așa cum vom vedea într-un articol viitor, OSGi joacă un rol important în cadrul eforturilor făcute de Eclipse Foundation pentru implementarea unei stive complete IoT, numită Open IoT Stack for Java.
Începând cu Java 8, versiune lansată în prima parte a anului 2014, am văzut că Oracle face eforturi considerabile pentru a aduce la zi varianta Micro Edition (ME) a platformei, lucru ce confirmă implicarea corporației în războiul soluțiilor IoT. Printre îmbunătățirile aduse platformei se numără eficientizarea procesului dedeployment pe dispozitive de dimensiuni mici, cum ar fi senzorii inteligenți saugateway-urile embedded. De asemenea, API-urile au fost actualizate pentru a răspunde nevoilor de programare a dispozitivelor țintă. Prin această nouă versiune Java ME, platforma are mult mai multe lucruri în comun cu Java SE, însă funcționalități precum reflection sau expresiile lambda urmează să fie adăugate. Acest aspect este important, întrucât în felul acesta, orice programator Java se va putea implica în proiecte embedded într-un timp scurt, fără a face eforturi considerabile. În 2015, Henrik Ståhl anunță că unii producători de hardwareplănuiesc să integreze Java ME în dispozitivele lor, ceea ce va conduce la o mai mare rată de adopție a platformei.
Componentele construite cu soluțiile embedded despre care discutăm, livrate într-un context IoT, dau acces aplicațiilor business la resursele instalate în mediul înconjurător, atât pentru a primi input de la acestea cât și pentru a lansa comenzi. Un astfel de use case este orchestrarea sistemelor eterogene de control a temperaturii și a iluminării într-o clădire. Observăm că abilitatea Java ME de a controla echipamente cum ar fi senzori, valve sau servo-motoare, reprezintă unul dintre aspectele fundamentale ale obținerii unei infrastructuri IoT.
Privind lucrurile de la o oarecare distanță, putem observa că arhitectura Java ne permite să creăm aplicații pe verticală, după cum a arătat și Maulin Patel, liderul în soluții de procesare embedded de la Freescale[8]. Întâi colectăm datele de la obiectele inteligente cu Java ME, apoi trecem la Java SE pentru servicii de gateway, iar în final executăm gestiunea și procesarea datelor cu Java EE, în cloud.
Aproape de fiecare dată când se vorbește despre IoT, se aduce în discuție problema securității. Într-un mediu eterogen și deschis precum este o infrastructură Internet of Things, securitatea este esențială, dar greu de obținut. Este de ajuns ca un atacator să aibă acces la una dintre componentele soluției IoT pentru a fi capabil să exploateze posibilele breșe în sistemul defensiv al acesteia. Spre exemplu, în cazul contoarelor inteligente de utilități, cel mai interesat de compromiterea acestor unități poate fi chiar proprietarul locuinței în care au fost instalate. Astfel, potențialul atacator are chiar și acces fizic la echipament, lucru ce ridică întrebări cu privire la nivelele la care trebuie implementate mecanisme de securitate. Acum că am remarcat seriozitatea acestei chestiuni, putem veni cu o veste bună pentru dezvoltatorii IoT din universul Java, întrucât această platformă asigură securitatea datelor pe întreaga verticalitate a sistemului implementat. Securitatea este o caracteristică înglobată în arhitectura platformei, fiind dezvoltată și actualizată constant, cu fiecare nouă versiune. Vom reveni cu detalii referitoare la securitatea oferită de Java ME 8 într-unul dintre paragrafele următoare, când vom discuta câteva caracteristici tehnice ale platformei.

Java ME Embedded 8

Platforma dedicată dispozitivelor cu cele mai puține resurse, cum ar fi cardurile, se numește sugestiv, Java Card. Totuși, primul produs din familia Oracle care aduce cu adevărat o contribuție importantă în spațiul IoT este Java ME Embedded 8. Prin urmare, în continuare ne vom concentra atenția asupra acestuia. Înainte de a ne uita la câteva detalii, trebuie să menționăm Java ME Embedded constă din două versiuni: Java ME Embedded și Java ME Embedded Client.
Java ME Embedded 8 este o platformă ce poate fi folosită de către dispozitive care au mai puțin de 1 MB de memorie. Astfel, este potrivită pentru "obiecte inteligente" fără interfață grafică, care au timp îndelungat de funcționare și resurse limitate.
Așa cum putem vedea în Figura 1, la baza Java ME Embedded 8 stă mașina virtuală, pe care o găsim sub denumirea Connected Limited Device Configuration sau, pe scurt, CLDC 8. Această componentă reprezintă un sub-set al Java SE 8, dedicat dispozitivelor embedded. După cum am menționat mai sus, o dată cu versiunea 8, CLDC reprezintă un prim pas spre o mai bună aliniere cu Java Standard Edition și totodată un important salt de la CLDC 1.1.1. Așadar, avem la dispoziție adnotații,generics și multe alte caracteristici Java, familiare tuturor dezvoltatorilor. Deși s-a realizat o evoluție foarte importantă prin lansarea CLDC 8, s-a reușit menținerea compatibilității binarelor cu versiunea anterioară.
Deasupra fundației pe care o reprezintă CLDC 8 stau mai multe componente definitorii pentru platformă. Una dintre ele este Generic Connection Framework 8(GCF 8). Așa cum se poate intui, această componentă gestionează problemele de conectivitate. Acest framework este necesar întrucât în spațiul embeddedposibilitățile de conectare sunt multiple, iar dispozitivele pe care rulează aplicația noastră au interfețe variate de comunicare cu lumea exterioară. Unele pot avea capacitate de conectare prin Wi-Fi, altele de tip cellular, Bluetooth sau prin cablu. De asemenea, pentru un control optimizat al conectivității GCF 8 expune AccessPoint API. Totodată, GCF 8 vine cu suport pentru IPv6, scăpând dezvoltatorii Java ME Embedded 8 de emoțiile epuizării adreselor IPv4.
Revenind la subiectul securității în lumea Internet of Things, putem da câteva detalii despre modul în care GCF 8 rezolvă această problemă. Java ME Embedded 8 vine echipat cu implementări ale celor mai noi standarde în materie de securitate, printre care se numără Transport Layer Security 1.2 și Datagram Transport Layer Security 1.2. Astfel, Oracle îi asigură pe utilizatorii platformei de faptul că aceasta oferă "cele mai înalte nivele de criptare la nivel de rețea și autentificare" [9].
Un alt bloc constructiv al Java ME 8 este Micro Edition Embedded Profile 8 (MEEP 8). Această componentă este responsabilă cu definirea modelului, a containerului în care rulează aplicația, în general cu ciclul de viață al acesteia. Prin intermediul MEEP 8 putem partaja cod între aplicații, putem actualiza componente în sistem sau aplica patch-uri aplicației. Partajarea bibliotecilor - denumite sugestiv, LIBlets - se face tot prin intermediul MEEP 8, contribuind la minimizarea necesarului de memorie și la modularizarea aplicațiilor. În plus, MEEP 8 oferă aplicațiilor posibilitatea de a comunica între ele atât sincron (Inter-MIDlet Communication sau IMC), cât și asincron, printr-un sistem de mesagerie bazat pe evenimente.
Securitatea este un subiect important și pentru MEEP 8, deoarece se pot defini politici de securitate pentru autentificare și autorizare, în funcție de situația specifică. Astfel, încărcarea codului și execuția lui se realizează într-un mediu securizat, întrucât fiecare componentă este asociată unui client, având permisiuni specifice. Acestea trebuie verificate la fiecare încercare de acces.
O componentă de o importanță crucială pentru Java ME Embedded 8 este Device Access API, care oferă aplicațiilor acces la dispozitive periferice, cum ar fi senzori, comutatoare sau LED-uri. Această componentă exista și în versiunile anterioare, însă acum vine cu funcționalități noi, printre care late binding, care permite adăugarea de noi periferice, fără a fi necesară modificarea API-ului.
Alături de aceste blocuri constructive, Java ME Embedded 8 vine cu o multitudine de API-uri, precum cel pentru servicii web sau localizare.
Având toate aceste componente Java ME Embedded la dispoziție, este la îndemâna noastră, a dezvoltatorilor, să construim aplicații embedded, contribuind la spațiulInternet of Things.
În ajutorul nostru vine Java ME SDK 8, un toolkit complet creat pentru a întâmpina orice nevoie avem în procesul creării și întreținerii unei aplicații. Acest SDK oferă inclusiv un mediu de emulare, având posibilitatea să ne testăm aplicațiile chiar dacă dispozitivele pe care vor fi distribuite nu sunt disponibile în timpul dezvoltării. De asemenea, putem face debugging atât în modul de emulare, cât și atunci când aplicația rulează pe dispozitiv. Pentru a întregi acest set de unelte, Oracle oferă plugin-uri pentru Netbeans IDE și Eclipse IDE, care încorporează toate funcționalitățile SDK-ului. Vom discuta mai multe detalii și vom exemplifica modul de utilizare al Java ME SDK 8 într-unul dintre articolele viitoare.
Java ME Embedded Client este o implementare CDC (Connected Device Configuration) care, în principiu, este configurația destinată dispozitivelor mobile cu ceva mai multe resurse, cum ar fi smartphone-urile. Pentru Java ME Embedded Client, această configurație a fost restrânsă și optimizată, pentru a se potrivi sistemelor embedded de categorie joasă înspre medie. Deși amprenta acestei configurații este redusă, oferă mare parte din limbajul Java. Astfel, Java ME Embedded Client este destinată obiectelor inteligente cu mai puțin de 10 MB de memorie și fără interfață grafică.

Concluzii

Industria IT autohtonă nu este străină de spațiul Internet of Things, începând să fie lansate produse Made in Romania, precum Pocketo sau Tintag. De asemenea, există companii în România, implicate în proiecte care se integrează în paradigma IoT. De exemplu, regăsim astfel de proiecte la Brașov în domeniul automotive, cu al său concept de connected car . Un alt lucru îmbucurător este faptul că au început să se organizeze evenimente despre IoT, unul dintre acestea fiind ALT Festival, care a avut loc în noiembrie 2014, la Brașov.
Un obiectiv important pentru Oracle în ultima perioadă este afirmarea platformei Java în lupta care se dă între soluțiile IoT. Mai mult decât atât, corporația și-a exprimat dorința de a câștiga această bătălie, astfel încât Java să devină alegerea majorității specialiștilor implicați în astfel de proiecte. Totuși, răspunsul a venit rapid din partea oponenților, existând multe voci care și-au exprimat scepticismul cu privire la potrivirea platformei în sfera IoT. Există multe argumente, atât pro, cât și contra acestei idei, însă un lucru e cert: Java a străbătut un drum lung pentru a ajunge la gradul actual de maturitate, diversitate și aplicabilitate. Eforturile din ultimii ani au dat naștere unei noi familii de produse, care se dovedesc promițătoare și, mai mult, încep să-și dovedească valoarea în cadrul proiectelor reale IoT. Vom vedea clar acest lucru în articolul viitor, când vom atinge, prin exemple concrete, partea practică a platformei Java ME Embedded 8.

Resurse

[1] CASAGRAS, RFID and the Inclusive Model for the Internet of Things
[2] Stephen Haller, Internet of Things: An Integral Part of the Future Internet, SAP Research, 2009
[3] "The Internet of Things: Manage the Complexity, Seize the Opportunity", Oracle Corporation, 2014
[4] IDC Digital Universe Study, sponsored by EMC, December 2012
[5] Dzone Research, 2014 Guide to Internet of Things
[7] Benjamin Evans, Martijn Verburg, The Well-Grounded Java Developer, Manning, 2013
[8] "Java Development for the Internet of Things", Oracle Java Magazine, November/December 2014 Issue

Friday, November 14, 2014

Eclipse SWT: Cum se poate seta poziția caracterului "caret" într-un widget Text

Astăzi lucram cu un widget Text (org.eclipse.swt.widgets.Text) și am avut nevoie să setez manual poziția caret-ului după un apel al metodei setText().
Am descoperit în Javadoc metoda getCaretPosition(), care returnează un int, însă API-ul nu oferă și o metodă setCaretPosition().
Căutând pe Internet soluții la problema mea, am găsit post-uri despre cum se poate muta caret-ul la sfârșitul textului, folosind metoda setSelection(int start):

textWidget.setSelection(textWidget.getText().length());

unde textWidget este o instanță a clasei Text. Pentru mai multe detalii, vezi post-ul de pe StackOverflow.
De asemenea, API-ul ofera o variantă overloaded a metodei setSelection(int start), sub forma setSelection(int start, int end), indecșii start și end corespunzând poziției caret-ului.
Astfel, am scris următoarea soluție:

int caretPosition = textWidget.getCaretPosition();
textWidget.setText( newValue );
textWidget.setSelection( caretPosition, caretPosition );

Prin acest truc am setat poziția caret-ului la valoarea anterioară apelului metodei setText(), stabilind o selecție vidă.
Încă nu mi-e clar dacă simplul fapt că am fost nevoit să resetez manual poziția caret-ului indică un design defectuos sau nu, dar sper să revin cu un răspuns.

Tuesday, October 21, 2014

Ștergerea elementelor unei liste în timpul iterării

Începând cu Java 1.5, avem la dispoziție forma for-each a clasicului ciclu for. Aceasta ne ajută să iterăm rapid o colecție, astfel:

for (String element : list) {
   System.out.println(element);
}

unde variabila list a fost declarată și inițializată astfel:

List<String> list = new ArrayList<>() { {
      add("Luni");
      add("Marti");
      add("Miercuri");
      add("Party");
      add("Joi");
      add("Vineri");
   }
};

ACTUALIZARE: Se pare că varianta aceasta de adăugare a elementelor e un anti-pattern, deci nu e bine să o folosim. Detalii aici:
http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

O problemă devenită deja clasică este ștergerea de elemente în timpul iterării. Dacă în interiorul ciclului for scriem ceva de genul:

for (String element : list) {
   if (element.equals("Party")) {
      list.remove(element);
   }
}

se aruncă la runtime o excepție java.util.ConcurrentModificationException.
Nu putem folosi forma for-each a ciclului for pentru a șterge elemente în timpul iterării, dar avem la dispoziție interfața java.util.Iterator, care expune metoda remove(). Aceasta se dovedește a fi exact ce avem nevoie:

for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
   if (iterator.next().equals("Party")) {
      iterator.remove();
   }
}


Metoda remove() șterge ultimul element returnat de metoda next(), declarată în interfața Iterator. Totuși, trebuie să ținem cont de faptul că această operație este opțională, după cum se menționează în Javadoc. În concluzie, atunci când folosim iteratori putem atât să iterăm colecția, cât și să ștergem elementele acesteia.

Monday, October 20, 2014

Adăugarea rapidă a unor elemente într-o listă nouă

Am întâlnit unele situații în care am avut nevoie rapid de o listă (java.util.List) căreia să-i adaug, la fel de rapid, câteva elemente. Primul lucru ce îmi venea în minte era să creez o astfel de listă, căreia să-i adaug apoi, rând pe rând elemente, apelând metoda add() astfel:

List<String> list = new ArrayList<>();
list.add("Luni");
list.add("Marti");
list.add("Miercuri");
list.add("Joi");
list.add("Vineri");

O modalitate destul de enervantă și ineficientă, nu?
La un moment dat însă, am găsit o variantă ceva mai elegantă, care se folosește de clase interne, anonime:

List<String> list = new ArrayList<>() { {
      add("Luni");
      add("Marti");
      add("Miercuri");
      add("Joi");
      add("Vineri");
   }
};

ACTUALIZARE: Se pare că varianta aceasta e un anti-pattern, deci nu e bine să o folosim. Detalii aici:
http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

În plus, un coleg de muncă mi-a atras atenția că există o variantă și mai rapidă:

List<String> list = Arrays.asList("Luni", "Marti", "Miercuri", "Joi", "Vineri");

Acest ultim exemplu este discutat pe StackOverflow, la următoarea adresă:


Răspunsul acceptat menționează, de asemenea, și faptul că această modalitate nu permite adăugarea de noi elemente acelei liste, întrucât este ”fixed-size”, după cum spune și documentația:



Friday, March 7, 2014

Decizii

Deschizi încet o ușă,
Ea scârțâie ușor.
Pe mân-ai o mănușă.
Urmezi un coridor.

Ridici și-aprinzi o torță,
Poteca se desparte.
Picioarele n-au forță,
Cu gândul ești departe.

În piept simți un răsunet,
O voce cum te cheamă.
Ai vrea să-i poți răspunde,
Ai vrea, dar 'ți-este teamă.

Thursday, March 6, 2014

Dincolo de perdea

Dincolo de perdea un țipăt se-aude,
Dincolo de perdea sunt lucruri mărunte.
Dincolo de perdea sunt ferestrele ude,
Dincolo de perdea vrei apa să se zvânte.

Dincolo de perdea  ai gânduri profunde,
Dincolo de perdea rugina pătrunde.
Dincolo de perdea lumina surâde,
Dincolo de perdea, nu te mai ascunde.

Wednesday, December 18, 2013

2. MARIUS

               Pe măsură ce mă apropiam de centrul orașului, acolo unde era situată mica terasă la care mă întâlneam cu Marius de obicei, străzile erau din ce în ce mai aglomerate. Pe lângă faptul că drumul în sine era extrem de îngust, se mai găsea câte-un ”deștept” să-și parcheze mașina de teren ”pe avarii” fix în dreptul magazinului în care avea treabă. Nu puține au fost ocaziile în care oglinzile laterale ale limuzinei mele aproape că s-au cunoscut într-un mod intim cu cele ale mașinii ”deșteptului”, lucru care a făcut să-mi sporească starea de iritare. Obișnuiam să le spun câteva vorbe dulci, şuierate printre dinţi, șoferilor care își lăsau mașina ”pe avarii” în locuri în care îi încurcau pe alții, dar în momentul acela mi-am dat seama că făceam același lucru. Surprins de mine însumi, pentru o clipă am crezut că am înţeles ceva; am încercat neplăcutul sentiment că fusesem programat să mă conformez societății în care trăiesc. Brusc, mi-am scuturat corpul, ca și când încercam să înlătur o greutate ce-mi stătea pe umeri, și mi-am zis: ”gândești prea mult”.
Terasa era pe o străduță lăturalnică, pavată cu piatră cubică, unde numai pietonii aveau acces. Pereții înalți ai clădirilor ce vegheau asupra culoarului cenușiu de piatră împiedicau razele soarelui să ajungă la nivelul solului mai mult de câteva ore pe zi. În acele momente mă bucura acest lucru deoarece, pe măsură ce soarele se ridica pe bolta cerească, atmosfera era din ce în ce mai înăbușitoare; o zi de vară autentică.
Ajunsesem mai devreme, așa că am comandat un espresso pentru a-mi face așteptarea mai puțin plictisitoare și ceva mai aromată. Unul dintre motivele pentru care frecventam această terasă era cafeaua pe care o puteam comanda aici. La o altă masă stătea un grup de liceeni care păreau să nu aibă chef de școală și profitau de vremea frumoasă și WiFi-ul gratuit.
În sfârșit, Marius se apropie și se așeză pe scaunul din fața mea, însă răspunsul meu la salutul lui fu absent, ceea ce-l determină să mă întrebe puțin suspicios:
- Eşti OK?
- Da... cred. De ce mă întrebi?
- Arăți de parcă ai fi pe altă lume.
- Asta pentru că sunt din altă lume, i-am răspuns privindu-l serios pentru o clipă, iar mai apoi rânjind ștrengărește. O umbră trecu peste chipul lui Marius, apoi zâmbi şi el, părând că intră în jocul meu.
Adevărul era că într-adevăr, mintea mea era preocupată cu altceva în momentul în care Marius se așezase la masa la care mă aflam. La puțin timp după ce ajunsesem la terasă, un Alfa Romeo de culoare neagră se oprise la câțiva zeci de metri distanță, atât cât i-au permis stâlpii ce blocau accesul pe drumul pietonal să se apropie. Deși autoturismul era parțial acoperit de umbră, am putut distinge pe locul șoferului figura unui bărbat brunet, care purta ochelari de soare de aviator și se uita în direcția mea. Mașina, figura nebărbierită și cu trăsături dure îmi păreau cunoscute, iar mintea mea a început să caute frenetic amintiri, imagini, care să-mi răspundă la întrebarea: de unde? Acela era momentul în care Marius şi-a făcut apariția și mi-a întrerupt gândurile.
Cu Marius mă cunoșteam din prima zi de muncă și, chiar dacă nu lucram în același departament și nu ne întâlneam prea des în timpul programului, ne-am împrietenit la scurt timp după mutarea mea în acest oraș. Era politica firmei ca noii veniți să fie primiți călduros, iar Marius se oferise să îmi arate împrejurimile. Din acea seară, care începuse cu schimbul standard de întrebări despre vreme și sporturile preferate, am făcut o tradiție să petrecem serile de vineri la terasa unde ne aflam și acum. Pe timpul iernii localul își restrângea activitatea în interiorul clădirii, care era de fapt o încăpătoare sală, decorată rustic și dominată de un șemineu bine hrănit cu lemn uscat, plăcut mirositor.
Colegul meu era un tip despre care încă nu puteam să spun că l-am descifrat. Știam ce hobby-uri are, ce îi place să mănânce și ce nu, ce haine are în dulap, dar nu reușisem încă să trec dincolo de privirea aceea hotărâtă, cu nuanțe de verde și maroniu, care îmi lăsa impresia că ascunde ceva interesant. Singurul lucru cu adevărat important pe care-l observasem la el era inexplicabila putere de a convinge şi de a-şi aduna oameni în jurul lui, mai ales persoane de sex feminin. Invidioşii se grăbeau să tragă concluzia că totul se datorează fizicului său armonios proporţionat şi feţei lui de model Calvin Klein. Era genul ăla de bărbat pentru care exerciţiile fizice la sală nu mai reprezentau de mult o provocare; însă el nu făcea asta cu scopul de a deveni o conservă de muşchi, ci pur şi simplu avea nevoie să-şi consume energia cumva. Aşa cum sunt unii oameni care la micul dejun ar servi o pernă moale, care pur şi simplu au la dispoziţie tot atâta energie cât se găseşte într-o baterie 777, tot aşa există oameni care s-ar urca şi pe pereţi, numai să facă ceva.
Marius arăta bine, dar cu toţii ştim deja că nu asta e cheia masculinităţii. Altceva îl făcea pe Marius să pozeze – pe bună dreptate – în bărbatul irezistibil. Ştia cum să se comporte cu o femeie. Dacă era într-un local şi voia să intre în vorbă cu o necunoscută, ştia cum s-o abordeze. Întotdeauna mergea la sigur, nu am văzut nicio situaţie în care Marius să fie flituit. Uneori puteam să jur că Marius are cumva încorporat un radar Doppler care îi transmitea tot ce avea nevoie să ştie despre cea cu care urma să intre în vorbă. Când ne plictiseam de cafeneaua în care ne întâlneam vineri seara, dar totuşi aveam chef să mai socializăm şi nu voiam să mergem acasă, găseam un bar ori un club în care uitam de timp, de responsabilităţi şi de tot ce se numeşte realitate. Se întâmpla uneori, stând noi la bar, că Marius zărea o femeie extrem de atrăgătoare, care părea să nu aibă pe moment companie.
- Pune mâna şi notează, îmi zicea el, ridicându-se elegant şi păşind hotărât spre ea. Era genul ăla de femeie care era sătulă de textele fumate ale majorităţii băieţilor în corp de bărbat ce şi-au compus poezia, au repetat-o temeinic, iar acum îşi încercau norocul recitând-o răguşit, căutând inspiraţie în decolteul ei. Nu şi în cazul lui Marius; el ştia exact de ce are nevoie acea femeie; de un bărbat care să nu fie intimidat de frumuseţea ei, care să poată purta cu ea o discuţie interesantă, ce nu ar plictisi-o în primele trei minute; care să o facă să râdă pe bune, ca şi când spiriduşul ăla irlandez ar gâdili-o la tălpi; şi toate porcăriile alea pe care majoritatea dintre noi oricum nu le înţelegem şi nu le putem şti, pentru că dacă era altfel, Marius nu ar mai fi aşa meseriaş. Aşa vedeam eu lucrurile prin sticla paharului de cocktail, în timp ce mă uitam în jur plictisit, dându-mi seama că pierdusem compania lui Marius pentru seara respectivă.
În timp ce sorbeam din cafea şi o plimbam prin gură preţ de câteva secunde, ca să-i pot savura cât mai mult aroma, încercam să mă concentrez la ceea ce-mi spunea Marius. În ciuda eforturilor mele de a nu da atenţie gândurilor întunecate despre lucrurile ce mi s-au petrecut în dimineaţa asta, o dată la câteva zeci de secunde mă surprindeam gândindu-mă tot acolo. Era ca o frântură dintr-o manea pe care ai auzit-o urlând într-un BMW când aşteptai la semafor, şi pe care nu mai reuşeşti să ţi-o scoţi din cap... „tot la mine vine banu, eu sunt căpitanu’…”.
Din tot ce îmi spusese Marius până în acel moment nu prinsesem decât „propunere”, „încredere” şi „secret”.
- Ce zici, pot să am încredere în tine? au fost vorbele lui, care mă treziră din reveria mea.
- Absolut, vreau să aud ce ai să-mi dezvălui.

Wednesday, May 22, 2013

1. DIMINEAŢA

Am auzit pe cineva spunând odată că omul e singura creaţie de pe pământ a lui Dumnezeu care poate gândi abstract. Poate că m-am gândit o dată sau de două ori la asta, dar n-am zăbovit prea mult asupra acestui gând niciodată. Nu eram genul care să se framânte excesiv pe o temă pe care, oricum, nu o voi înţelege pe deplin. Dar în dimineaţa asta stăteam pur şi simplu în pat cu ochii aţintiţi în tavan, fără să mă uit la ceva anume. Nu mă obosisem să mă ridic pentru a da la o parte jaluzelele, nu mă îndemna nimic să fac asta. Intensitatea luminii care intra în cameră îmi dădea de înţeles că afară ori e înnorat, ori e ceaţă. În ultimele două săptămâni plouase aproape în fiecare zi, aşa că am votat rapid pentru un cer înnorat. Mi-am amintit o poantă ce-o auzisem zilele trecute cu privire la vremea care numai a vară nu semăna şi am zâmbit, uşor amuzat.
Am uitat repede gluma, pentru că în dimineaţa asta nu puteam să mă concentrez mai mult de câteva secunde asupra unui gând. Era ca în acele zile când îmi aminteam în faţa oglinzii că trebuie sa fac ceva important înainte de a pleca la servici, dar uitam complet de acel lucru cu mult înainte să-mi termin de periat dinţii.
M-am întors alene într-o parte şi am căscat plictisit. Azi nu trebuia să merg la servici; era sâmbătă şi, pe deasupra, mă aşteptau două săptămâni de concediu. Nu-mi propusesem să fac mare lucru azi, simţeam nevoia să-mi iau o zi liberă de la orice activitate după o lungă perioadă de stres şi muncă susţinută. Totuşi, aveam un sentiment ciudat. Mă dezobişnuisem să stau fără a face ceva constructiv. “Până la urmă, trebuie să recunosc că e bună şi rutina la ceva. Lipsa asta de ocupaţie mă omoară. Ridică-te din pat!” Am ascultat supus vocea din capul meu şi am dat la o parte cearşaful, ridicându-mă în acelaşi timp. M-am îndreptat instinctiv spre fereastră şi am tras perdeaua de umbră. M-am oprit în faţa uşii de sticlă care cobora de la tavan până la podea.
Camera era separată de balcon printr-un perete de sticlă, care îmi oferea o vedere largă la munţii împăduriţi care răsăreau în faţă la câteva sute de metri. Blocul de apartamente era construit pe coasta unui deal abrupt, care se afla la marginea unui masiv muntos. Între acesta şi munţii pe care-i admiram acum era un culoar adânc, împânzit de străzi întortocheate, cu imobile plantate iscusit în locuri greu accesibile sau chiar ciudate. Mintea mea de muritor de rând nu înţelegea cum au reusit acei ingineri să planteze locuinţe în asemenea locuri.
Am răsucit mânerul şi am deschis larg uşa, când o adiere uşoară de aer rece mă învălui imediat. Cu coada ochiului am observat cum se înfiora perdeaua de mătase de la cealaltă fereastră sub influenţa curentului care străbătea acum camera. Mi-am îndreptat din nou privirea înainte şi am ridicat uşor capul. Norii coborâseră în dimineaţa aceasta mai mult ca de obicei şi acopereau vârful muntelui din faţa mea cu o pătură pufoasă de culoare gri închis.
Mă mutasem în acest oraş de la câteva sute de kilometri distanţă când compania la care lucram avea nevoie la această filială de încă un om în echipă pentru un proiect de cercetare. Apartamentul îl închiriasem de câteva luni, dar mi-am dat seama că până acum n-am observat cu adevărat panorama ce se deschidea dincolo de fereastră.
Programul zilnic mă acaparase atât de mult încât, până acum, nu cunoşteam din acest oraş pitoresc de munte decât străzile pe care trebuia să le străbat cu maşina în grabă, pentru a ajunge la laborator înainte de ora şapte. Fiecare zi era încărcată şi stăteam peste program mult după ce un ceas mare de perete ne dădea de ştire că a fost ora şase. Doar cand ieşeam din laboratorul luminat puternic de tuburi cu neon, realizam că seara acapara totul în jur cu repeziciune. “Ei bine, a mai trecut o zi”, spuneam cu voce scăzută, ca pentru mine. După ce schimbam câteva vorbe cu colegii care încă mai erau acolo la acea oră, ne îndreptam împreună spre parcare. Fasciculul de lumină provenită de la faruri se despărţea când maşinile se îndreptau fiecare în direcţii diferite.
Nici viaţa socială nu-mi era strălucită. Eram înconjurat toată ziua de nişte oameni inteligenţi care păreau interesanţi, fiecare în felul lui, însă mi-am dat seama că nu-i cunoşteam cu adevărat. Oare ce se ascunde, de fapt, în spatele acelei feţe tot timpul zâmbitoare? Dar celălalt, să fie oare atât de superficial? Sau se ascunde de ceva mai adânc în viaţa lui? Aş fi putut să-mi amintesc chipul fiecărei persoane pe care o cunosc din acest oraş şi să-mi pun întrebări despre aceasta.
Am clipit de câteva ori, concentrându-mă din nou asupra imaginii predominant verde din faţa mea. Am făcut rapid un plan, care să mă ţină ocupat toată ziua.
Am sărit sub duş şi preţ de câteva minute doar am stat sub jetul fierbinte, fiind rezemat de peretele acoperit cu o faianţă de culoare crem, ornamentată cu motive florale. Aşa rezemat cum stăteam, desenam cu degetul pe faianţa aburită, urmărind liniile imaginate de designer. Întorcându-mă în sufragerie, am apucat din mers telecomanda şi am deschis televizorul pe un canal unde se difuzau ştiri. “Grozav”, mi-am zis, “iar a crescut Euro”. Am dat sonorul mai tare decât de obicei pentru a auzi din bucătărie. Deschizând frigiderul, am ridicat o sprânceană a dezgust. “Ia să vedem, ce-avem azi la micul dejun? Cereale sau… cereale? Eşti un bucătar desăvârşit” mi-am zis cu sarcasm. Am turnat nişte suc de portocale într-un bol şi am adăugat cereale, după care m-am îndreptat spre sufragerie, de unde se auzea televizorul care era deschis. Începuse rubrica meteo. Se părea că azi urma să iasă soarele, în cele din urmă. “Aşa mai vii de-acasă” am zis eu cu voce tare.
Am aruncat repede nişte haine lejere pe mine şi am ieşit din casă. Ca să ajung la maşina parcată la marginea străzii ce se vedea de la balcon, trebuia să traversez o curte ca o mică platformă acoperită cu gazon şi apoi să cobor câteva zeci de scări abrupte. În dreapta era pe două nivele, mica grădină cu flori a familiei Gruia. Coborând scările, am salutat-o pe vecina mea, care curăţa o tufă de trandafiri superbi.
-    Bună dimineaţa, doamnă Gruia!
-    Bună dimineaţa, Tudor!
-    În sfârşit vom avea o zi însorită, am remarcat eu continuându-mi drumul.
Doamna Gruia răspunse tot ceva legat de vreme. „Discuţia clasică între vecini” m-am gândit eu involuntar.
Hainele cu care eram îmbrăcat şi încălţămintea comodă îmi permiteau să fac mişcări mai ample, aşa că nu mă deranja să cobor câte două-trei scări deodată. În câteva secunde eram lângă maşina pe care o parcasem lângă trotuar. Şoseaua era îngustă, aşa că strada era cu sens unic, care te obliga să urci spre cartierul vechi al oraşului. Maşinile riveranilor erau parcate pe marginea stângă a şoselei, din lipsă de opţiuni; coasta abruptă a dealului pe care erau cocoţate locuinţele nu permitea şi construirea de garaje. M-am aşezat pe scaunul şoferului, apoi am răsucit cheia în contact, ascultând cu satisfacţie cum torcea motorul de 5 litri al Audi-ului. De când lucram în această companie banii nu mai erau o problemă, aşa că am profitat din plin de beneficiile materiale. Am demarat cu gândul ca prima oprire să fie la magazinul de pâine. Maşina, masivă de altfel, urca graţios pe străduţele înguste şi întortocheate, scânteind când soarele, care în sfârşit se arătase de după perdeaua de nori, reuşea să arunce câteva raze printre crengile brazilor de pe culmea dealului.
După câteva minute plăcute de condus pe străzile cartierului vechi, înaintea mea s-a deschis o piaţă destul de largă care se umplea din când în când cu oameni, la diverse evenimente urbane. Piaţa avea forma unui patrulater, pe fiecare latură aflându-se o înşiruire de clădiri vechi.
Am coborât din maşină şi am zăbovit cu privirea asupra unei clădiri masive în formă de L, a cărei faţadă îţi dădea impresia că aparţinuse unei familii de nobili iubitori de artă. Casa avea trei nivele, dar şi acoperişul avea înălţimea unui etaj. La cotul care descria litera L, acoperişul era despărţit, făcând loc unei încăperi ridicată deasupra celorlalte trei nivele. Faţada acestei încăperi privilegiate era decorată cu un balcon cu balustradă semi-rotundă, accesul în acesta fiind posibil prin trei uşi înalte de sticlă, având partea de sus boltită. Balcoanele etajelor inferioare erau mai mari, dispunerea lor amintindu-mi de problema turnurilor din Hanoi. Toate ferestrele erau mari, dintr-un lemn de culoare maro închis, de esenţă tare; chiar dacă nu mă pricep la tâmplărie, mi-am dat seama că au fost lucrate cu grijă. La primul etaj se vedeau din stradă lădiţe lungi pline cu flori. Muşcatele erau înflorite şi se revărsau peste balustradă cu inflorescenţele lor de un roşu provocator.
În plan secund se înălţa o clădire impunătoare de biserică. Avea două turnuri, cel estic dominându-l pe cel vestic. Ambele erau ascuţite şi îţi lăsau impresia că zgâriau văzduhul şi dacă norii s-ar fi lăsat îndeajuns de jos, înţepătura acoperişului de tablă neagră i-ar fi desumflat ca pe nişte baloane cu aer cald. În curtea bisericii se intra printr-un portal de piatră nu prea bogat ornamentat, dar cu un aer solemn. De o parte şi de alta a portalului erau arborate două drapele ale României, pe care le-am salutat cu mândrie în timp ce treceam de porţile din fier forjat. Nu aveam de ce să mă grăbesc să fac cumpărăturile, aşa că am ales să fac o scurtă plimbare pe aleile din curtea lăcaşului de cult. Aleea principală era pavată cu piatră cubică perfect aranjată, deşi părea să fie acolo de câteva decenii bune. În stânga mea, un grup de turişti s-au oprit în faţa unei clădiri cu aceeaşi arhitectură care te anunţa că e veche şi a văzut mult din istoria poporului român, în desfăşurare. După câteva minute de mers într-un ritm domol am văzut în faţa mea acelaşi portal prin care intrasem. Înconjurasem curtea fără să-mi dau seama când am făcut asta, fiind cufundat în gânduri. Ceva ciudat mi-a atras atenţia şi am revenit brusc la realitate. Pe partea dreaptă a aleii erau înşirate câteva morminte de marmură neagră. Numele scrise pe pietrele funerare îmi erau cunoscute. Totuşi, mi se părea ciudată asocierea dintre biserică, unde se presupunea că oamenii trebuiau să găsească viaţă, şi mormintele, care reprezentau moartea. Am ieşit, încercând să-mi izolez în minte sentimentul neplăcut care mă cuprinsese.
Jucându-mă cu cheile pe degetul arătător, am intrat în magazinul de pâine, mai mult ghidat de miros decât de explicaţia firmei care era atârnată deasupra intrării. De după tejghea mă întâmpină cu un zâmbet cald o doamnă plinuţă, mai în vârstă, pe care o recunoşteam deoarece mai făcusem cumpărături aici de câteva ori. Mirosul de pâine proaspătă îmi dădea o senzaţie de foame, deşi mâncasem cu mai puţin de o oră în urmă. Mirosul era familiar şi îmi amintea de anii copilăriei când eram în orăşelul natal şi mă trimiteau părinţii să cumpăr pâine de la un magazin asemănător. De mai bine de cinci ani mă tot mutam dintr-un oraş în altul, după cum era nevoie în companie, şi îmi lipsea stabilitatea, sentimentul acela de siguranţă, că toate lucrurile familiare, care ajung să-ţi fie dragi până la urmă, vor fi acolo tot timpul pentru tine.
-    Te servesc cu ceva, drăguţă? s-a auzit vocea caldă a doamnei de după tejghea.
-    Poftiţi? am răspuns eu nedumerit, scuturând uşor capul ca şi când mă trezeam dintr-un somn profund.
-    Avem franzelă proaspătă. Încă e caldă, uite.
Îmi întinse o franzelă bine rumenită să o verific. Am presat uşor coaja crocantă între degetul mare şi arătător şi mi-am ridicat privirea mulţumită:
-    M-aţi convins, iau două din acestea şi o legătură de covrigi. Să fie cu sare, nu mă dau în vânt după cei cu mac.
În timp ce vânzătoarea punea produsele într-o pungă mare de hârtie maro, mi-am verificat cu palma buzunarul de la spate, acolo unde ţineam de obicei portofelul. Am făcut o grimasă când mi-am dat seama că îl uitasem în maşină. M-am întors spre vânzătoare să-i explic situaţia:
-    Ah, mi-am uitat portofelul în maşină. Mă întorc într-un minut.
Maşina era parcată la câţiva zeci de metri de magazin, suficient de aproape cât să observ privirea alertă a vlăjganului care dădea târcoale automobilului. Când mă văzu că ies, s-a uitat cu ură spre mine şi a tras un şut portierei aşa, ca să văd eu. Am început să alerg spre el nervos, cu o viteză pe care nu credeam că mai sunt în stare să o ating. Însă nici el nu era mai prejos, strecurându-se cu uşurinţă printre maşinile parcate şi apoi printre oamenii surprinşi de ceea ce vedeau. Mişcările lui îmi aminteau de concursurile de parkour pe care le urmăream cu ani în urmă la televizor. În cele din urmă am scăpat de pietoni şi am intrat pe o porţiune dreaptă unde mi-am dat seama că sunt mai rapid decât el. Simţeam cum mi se zbate inima în piept şi tâmplele îmi zvâcneau dureros. „Probabil de la efortul brusc, fără să mă fi încălzit înainte”, mă gândeam încercând să mă concentrez la mişcările lui.
Îl urmam la vreo zece metri distanţă, când a cotit brusc la stânga şi a intrat pe o străduţă pietonală, umbrită de un zid înalt care probabil aparţinea vechii cetăţi. Din loc în loc se vedeau intrânduri, chiar dedesubtul micului acoperiş de ţiglă care proteja întreaga lungime a zidului, de unde gărzile puteau supraveghea tot ce mişcă în exteriorul cetăţii. Modelul ţiglei avea un efect ameţitor în timp ce alergam nebuneşte, aşa că am întors privirea şi m-am concentrat asupra ţintei mele.
După câteva zeci de metri pe străduţa asta întunecoasă am văzut patru siluete care ies din umbră în faţa celui pe care-l urmăream. Când a trecut de ei, s-a oprit brusc. Am făcut la fel, dându-mi seama că erau împreună. Între mine şi grupul care stătea nemişcat cu faţa spre mine, erau vreo douăzeci de metri acum. Un gând mi-a fulgerat prin minte: „Vânătorul devine vânat, în cele din urmă.” Locul în care eram era pustiu, însă nu intrasem suficient de mult încât să nu pot bate în retragere. Am început să păşesc rigid în spate, în timp ce aveam ochii aţintiţi asupra celui care stătea în faţa celorlalţi. Grupul era nemişcat. În timp ce mă retrăgeam, îmi calculam fiecare mişcare, concentrându-mă la maximum, ştiind că pericolul încă nu a trecut, deşi cei din faţa mea nu trădau vreo intenţie de a ataca.
Când am ieşit în strada aglomerată, am răsuflat uşurat şi am simţit ceva rece pe faţă. Mi-am atins fruntea cu degetele şi am înţeles că faţa îmi era inundată de sudoare. Inima încă îmi bătea puternic, însă respiraţia devenea din ce în ce mai regulată, pe măsură ce mă îndreptam spre piaţa unde lăsasem maşina. Încercam să mă liniştesc, dar ceva îmi spunea să fiu alert în continuare. Cine ştie ce se ascunde în mulţime. O lamă ascuţită nu are nevoie decât de o fracţiune de secundă şi trece uşor neobservată.
Când am ajuns la maşină, am verificat cu atenţie portiera. Din fericire, adidasul puştiului nu a lăsat nicio zgârietură sau adâncitură în tablă. Doar lustrul era puţin şters. Mi-am amintit de franzelele mele, aşa că am luat portofelul din torpedou şi m-am întors la magazinul de pâine.
-    Ah, credeam că nu te mai întorci, drăguţă! spuse vânzătoarea cea amabilă.
-    Pentru o clipă, la fel am crezut şi eu.
-    Nu înţeleg, replică doamna plinuţă cu ochii mari de uimire.
-    Nici eu, am răspuns eu scurt, dându-i de înţeles că nu vreau să vorbesc despre asta.
-    Vai de mine, arăţi de parcă te-a alergat ursul!
N-am răspuns nimic.
Am plătit pentru ceea ce vânzătoarea pusese în punga de hârtie cu cincisprezece minute în urmă, am mulţumit şi m-am îndreptat spre ieşire.
-    Să ai o zi bună, drăguţă! am auzit-o pe doamna cea plinuţă urându-mi în timp ce ieşeam.
Am mulţumit cât de cald am putut şi am ieşit cu o grimasă pe faţă, întrebându-mă de ce mi se tot adresează cu „drăguţă”.
Mă îndreptam îngândurat spre maşină rupând din colţul uneia dintre franzele. Gustul proaspăt al franzelei mă făcea să mă simt mai bine. Dar nu puteam să mă desprind de un gând: „Oare ce-o fi însemnând chestia asta?” Deodată mă străfulgeră o idee: „Ei nu erau interesaţi de maşină, ci de mine!”

Înainte să apuc să deschid portiera, am simţit telefonul vibrând în buzunarul pantalonilor. M-am grăbit să pun pachetul pe scaunul din dreapta şi am luat telefonul în mână. Era Marius, un coleg din echipa de la laborator.
-    Salut! Se auzi vocea lui Marius în receptorul telefonului.
-    Salut, Marius. Ce surpriză! Sper că totul e în regulă la laborator.
Niciunul dintre colegi nu mă sunase până acum, decât în interes de serviciu.
-    A, stai liniştit, nu de asta te-am sunat, veni răspunsul lui rapid. Voiam doar să te chem la o cafea la terasa obişnuită. Am să-ţi spun ceva.
-    Bine, spun eu. Ne vedem acolo într-un sfert de oră.
-    Perfect, confirmă Marius.
    Am pornit motorul şi am demarat. Coborând pe o stradă dreaptă şi îngustă, m-am surprins gândind cu voce tare. „Ce dimineaţă ciudată.”