Linux + Glassfish 4.0 High availability Load Balancing Cluster – osa 1

Sain taannoin loistavan syyn perehtyä toimintavarman ja skaalautuvan järjestelmän rakentamiseen Glassfish serverin vinkkelistä – olen aiemmin rakentanut vastaavia mm. JBOSS alustalla. Tässä mitä teen ei ole mitään mullistavaa, nykyisellään löytyy paljon teknisesti jännempiäkin juttuja mm. Riak, MongoDB, Hadoop, ja pilvipalveluiden ajatusmaailmasta. Mutta tämä on yksi kätevä työkalu pakissa: miten saada Java sovelluspalvelin toimimaan katkotta yli käyttöhäiriöiden ja päivitysten, ja miten saada se skaalautumaan yli satojen yhtäaikaisten käyttäjien (satoja saa yhdelläkin serverillä vaikka mitenpäin aikaiseksi).

Perusidea on vähintäänkin tuplata kaikki: Jotta saadaan serveri vikasietoiseksi, niitä tulisi olla ainakin se kaksi (mieluiten enemmän), ja jos jotain tilaa on käytetty, se pitäisi jotenkin replikoitua. Mutta vikasietoisuus on yhtä vahva kuin heikoin lenkki: glassfish serverien replikointi ei vielä riitä. Siihen tarvitaan eteen mylly joka reitittää pyynnöt toimiville serverille, load balancer toisinsanoen. Mutta mitä jos load balancer kaatuu? No niitäkin tarvitaan kaksi, tai enemmän, siten että yhden ollessa maissa toinen ottaa sen paikan. Entäpä.. taustatietokannat? Verkko? On paljon kahdennettavia kohtia.

Tämän voi tehdä monella tapaa, mutta itseä viehätti tällainen malli: Joka serveri on virtuaalikone, jossa on Glassfish serveri, Apache Http serveri Load balancerina, ja MySQL tietokanta. Periaatteessa siis joka mylly on lähes identtinen, ja sisältää kaiken tarvittavan. Skaalautuvuutta ja vikasietoisuutta saadaan siis lisäämällä myllyjä – ainakin tiettyyn rajaan asti (Session replikointi, sen tarve ja ratkaisuperiaate vaikuttaa skaalautuvuuden skaalautuvuuteen – ja kaikki serveriresurssit eivät muutenkaan skaalaudu niin hyvin 😉

Tuossa on kuva siitä miltä tämmöinen voisi näyttää – ei ole oma mutta kuvaa niin hyvin mistä on kyse että menköön (lopussa on lähdeviittaus sivustoon josta kuva ja alkuperäiset ideat ovat peräisin):

diagram

No niin, olen jo aiemmin käsitellyt aihetta, miten asennetaan Debian alustalle yksi Glassfish instanssi – joten se tarvitaan tietysti pohjaksi. Samalla kaavalla tehdään vähintään kaksi lähes identtistä serveriä – jotka näkevät toisensa (ping toimii ristiin).

Ensimmäinen askel on poistaa paikallinen serveri ja http kuuntelijat – koska niiden tilalle tulee klusterin instanssikuuntelijat. Tämä tehdään molemmille myllyille, ja Glassfish täytyy olla käynnissä aluksi:

#run these on both debian1 and debian2 machines

$ asadmin delete-http-listener http-listener-1

$ asadmin delete-http-listener http-listener-2

$ asadmin delete-virtual-server server

Selvä pyy. Vaihdetaan seuraavaksi Glassfish tunnukseen, koska sillä serverit ajavat käskyjään, ja luodaan ssh avainparit joilla serverit voivat viestiä. Tämän voit ajaa vain node1 koneesta – ellet sitten halua Domain Admin nodea molempiin koneisiin. Huomaa että glassfish tunnuksella tulisi tässä kohtaa olla myös salasana – sama molemmissa nodeissa. Ellet ole sellaista luonut, aja passwd glassfish nyt.

Tässä esimerkissä koneiden verkkonimet ovat: debian1.mycompany.com ja debian2.mycompany.com:

#run this only on debian1 machine

sudo su --shell /bin/bash glassfish

asadmin setup-ssh --generatekey=true debian1.mycompany.com

# seuraava komento antaa virheen koska glassfish on jo asennettu kakkosnodeen, mutta 
# se myös mukavasti tarkistaa että kommunikaatio pelaa

asadmin install-node debian2.mycompany.com

Seuraava askel, luodaan kaksi hallinta-nodea Glassfishiin:

# run this on debian1 machine

asadmin create-node-ssh --nodehost localhost debian1-ssh 

asadmin create-node-ssh --nodehost debian2.mycompany.com debian2-ssh

Nämä ovat ssh nodeja, eli näiden avulla Glassfish voi yhdestä DA-serveristä käsin lähettää ssh-protokollalla komentoja kaikille klusterin nodeille.

Seuraavaksi luodaan klusteri ja kaksi serveri-instanssia siihen:

# run this on debian1 machine

asadmin create-cluster --systemproperties HTTP_SSL_LISTENER_PORT=8181:HTTP_LISTENER_PORT=8080 cluster1 

asadmin create-instance --cluster cluster1 --node debian1-ssh debian1-gf

asadmin create-instance --cluster cluster1 --node debian2-ssh debian2-gf

Jos tähän asti kaikki sujui, seuraavaksi tehdään Load Balanceriä varten AJP-palvelut. Tässä kikkaillaan vähän – ja asetetaan järjestelmämuuttujiin (system properties) instanssin nimi jota voi serverissä sitten käyttää esim. virtuaalikoneparametreissa kätevästi:

# run this on debian1 machine

asadmin create-http-listener --listenerport 8009 --listeneraddress 0.0.0.0 --defaultvs server --target cluster1 jk-connector

asadmin set configs.config.cluster1-config.network-config.network-listeners.network-listener.jk-connector.jk-enabled=true

asadmin create-jvm-options --target cluster1 "-DjvmRoute=\${AJP_INSTANCE_NAME}"

asadmin create-system-properties --target debian1-gf AJP_INSTANCE_NAME=debian1

asadmin create-system-properties --target debian2-gf AJP_INSTANCE_NAME=debian2

Seuraavaksi, piipahdetaan molemmilla koneilla vaihtamassa masterpassword – mutta siten että se tallettuu tiedostoon jolloin sitä ei koko aikaa kysellä:

# run this on debian1 machine

asadmin change-master-password --savemasterpassword true debian1-ssh

#run this on debian2 machine:

asadmin change-master-password --savemasterpassword true debian2-ssh

Ja lopulta, talletetaan myös tavallinen admin salasana tiedostoon, jotta asadmin työkalun ajo ei juutu dialogeihin:

# on debian1:

asadmin --host debian2 --port 4848 login 

#on debian2:

asadmin --host debian1 --port 4848 login

Nyt ollaan jo aika loppusuoralla. Meillä on jo ennestään init scripti joka ajaa glassfish domain serverin (ja tässä tapauksessa DAS) käyntiin, mutta kannattaa ehkä lisätä scripti joka käynnistää myös molemmissa koneissa instanssin – tai clusterin. Editoi tiedostoa etc/init.d/glassfish-inst ja pistä sinne jotain tämäntapaista:

#!/bin/sh
#
# glassfish init script for Linux 
# It only starts one instance by name. The instance needs to have
# .asadminpass and .asadmintruststore password files created
# for the user.
#
# .asadminpass is created via "asadmin login" command
# .asadmintruststore is created via 
# "asadmin change-master-password --savemasterpassword true"
### BEGIN INIT INFO
# Provides: glassfish-inst
# Required-Start: $local_fs $remote_fs $network $syslog $named
# Required-Stop: $local_fs $remote_fs $network $syslog $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# X-Interactive: true
# Short-Description: Start/stop a glassfish instance
### END INIT INFO

GLASSFISH_HOME=/opt/glassfish4
GLASSFISH_USER=glassfish
GLASSFISH_INSTANCE=debian1-gf

case $1 in

start)
 echo "Starting Glassfish local instance ${GLASSFISH_INSTANCE}..."
 su - "${GLASSFISH_USER}" -c \
 "${GLASSFISH_HOME}/bin/asadmin start-local-instance "${GLASSFISH_INSTANCE}""
 ;;

stop)
 echo "Stopping Glassfish local instance ${GLASSFISH_INSTANCE}..."
 su - "${GLASSFISH_USER}" -c \
 "$GLASSFISH_HOME/bin/asadmin stop-local-instance "${GLASSFISH_INSTANCE}""
 ;;

restart)
 echo "Restarting Glassfish local instance ${GLASSFISH_INSTANCE}..."
 su - "${GLASSFISH_USER}" -c \
 "$GLASSFISH_HOME/bin/asadmin restart-local-instance "${GLASSFISH_INSTANCE}""
 ;;

*)
 echo "usage: $0 (start|stop|restart|help)"

esac

Huom! Vaihda ylläolevassa tuo GLASSFISH_INSTANCE arvoon 1, 2, tai mitä serveriä käsitteletkään. Joka serverillä se tulee tietysti olla omansa. Jos käynnistät clusterin, se tietysti potkaisee joka instanssin käyntiin kerralla. Tätä tapaa en kuitenkaan vielä ehtinyt kokeilemaan.

Seuraavaksi pistetään tämäkin automaattikäynnistymään:

sudo chmod 755 /etc/init.d/glassfish-inst

sudo update-rc.d glassfish-inst defaults

No niin, sitten vain boottia kehiin. Serverin 1 pitäisi toimia DAS-serverinä, joten sen kautta voit käydä ihan hallintakonsolista katsomassa miltä kaikki näyttää. Kannattaa myös kokeilla asentaa joku pieni ja varmasti toimiva klusterisovellus ja testata vähän miten se asentuu kaikille instansseille, ja miten se käyttäytyy kun instanssit sammuvat ja taas käynnistyvät.

Sellainen löytyy esim. täältä: http://blogs.nologin.es/rickyepoderi/uploads/SimplebutFullGlassfishHAUsingDebian/clusterjsp.war

Pari huomiota sessioreplikoinnin vaatimuksista ja nykytilasta:

Glassfish 4.0 ei virallisesti tue HA piirteitä, mutta siellä on olemassa early access joka toimii ihan hyvin. 4.1 versiossa olisi paremmin testattuna tulossa samat piirteet. Glassfish versioissahan on aina joissain klusterituki, joissain ei, eli kannattaa olla tarkkana version kanssa.

Glassfish 4.0 tukee eri replikointitavoista vain in-memory tapaa, joka tarkoittaa että nodet heittelevät verkon yli toisilleen notifikaatioita, ja replikoivat sessiodataa. Tämä ei ole parhaiten skaalautuva malli, mutta pienille ja keskikokoisille klustereille joissa sessiotilaa ei ole valtavasti ihan ok malli. Tämä edellyttää että klusterissa on GMS palvelu päällä, ja nodet näkevät toisensa verkossa. Hyvä myös tarkistaa että konfiguraation availability service alla on rastit oikeissa laatikoissa, mutta oletuksena pitäisi olla.

gms_service_enabled

availability_service_enabled

Mutta vielä on tärkeä huomioitava asia: Asennettava sovellus tulee olla availability-yhteensopiva ja availability-moodissa. Ensimmäinen edellyttää web.xml tiedostossa distributable=true arvoa (tai ei ollenkaan web.xml tiedostoa). Toinen vaatii että availability laitetaan päälle joko asennettaessa sovellus tai sen jälkeen. Esim. kun asensin em. clusterjsp sovelluksen oletusasetuksilla, siitä jäi rasti pois ruudusta, jolloin sessiot eivät replikoituneet.

availability_enabled

Voit myös kokeilla näkevätkö serverit toisensa ajamalla molemmissa nodeissa about yhtäaikaa tämän:

asadmin validate-multicast

 

Tässä tämä tällä kertaa. Tästä lähteestä ammensin paljon ideoita ja käytännön säätöjä:

http://blogs.nologin.es/rickyepoderi/index.php?/archives/53-Simple-but-Full-Glassfish-HA-Using-Debian.html

Jos tykkäät mielummin tehdä näitä UI:n puolella, tässä hyvä tutoriaali siihen (Glassfish 3 oppaat pätevät suurimmalta osin Glassfish 4:seen):

http://javadude.wordpress.com/2011/04/25/glassfish-3-1-clustering-tutorial/

 

Android 5.0 L**** ja muuta kivaa

No niin, kaikki tästä kiinnostuneet ovatkin jo varmaan seuranneet vesi kielellä Google IO julkistuksia. En ole valitettavasti paikan päällä, eli poimin myös vaikutelmia etänä, mutta kaikenlaista mielenkiintoista osuu tutkaan:

– Seuraava Android versio 5.0 alkaa jo saamaan muotoaan. Sen nimi alkaa tietysti kirjaimella L, ja perinteiden mukaan on jälkiruoka. Key Lime Pien jälkeen ei varmaan Lime-alkuinen, oisko joku Lemon Lollipop? 😉

– Google on muuttanut vähän tyyliään tässä, aiemmin julkistukset tulivat aikalailla kun ne olivat valmiina, nyt on ennakkotietoa ja maistiaisia tarjolla kehittäjille. Hyvä!

– Luvassa on uusi design ’kieli’ – kolmiulotteisuutta vähän eri tavalla. Avaimena on syvyysvaikutelma. Android käyttöliittymät menevät uusiksi, mutta myös web sovellukset. Avainkohtia ovat tasot ja varjot ja automaattiset animaatiot niitä hyödyntäen, mutta mielenkiintoista ovat myös ’herot’, komponentit jotka voivat leijua sovellusruutujen välillä. Kokonaisuutta kutsutaan nimellä ’Material Design’ – ja sen on tarkoitus olla aiempaa värikkäämpi, havainnollisempi, ja konkreettisempi. Näyttää ja kuulostaa hauskalta.

– Googlen älyvaatteet – pääosin kellot – voivat autentikoida käyttäjän suoraan, esim. jos kello tai auto on 30cm päässä kännykästä, sen lukitus poistuu itsestään. Tämäkin aika nastaa.

– Virransäästöä luvassa – tietenkin – monin tavoin, akkukesto siis paranee taas

– Chromecast tulee entistäkin hyödyllisemmäksi – android laitteen ruudun peilausta tulossa, eli yksittäisten sovellusten sijaan voi pyöritellä mitä mieleen juolahtaa, demottu esim. videokameraruudulla jo. Suorituskyky loppututuoksessa jää nähtäväksi.

Vitosversiosta esimaistiaisia tarjolle esim. Nexus 5 tai 7 omistajille. Oma Nexus 7 taitaa saada vähän testiversiota jossain vaiheessa.. 😉 Arkikännykkäni saa odotella finaaliversiota jonkun aikaa.

Ei sen enempää vielä tällä kertaa. Tänään. 😉

Tuosta:

http://www.google.com/design/spec/material-design/introduction.html

https://www.youtube.com/watch?v=Q8TXgCzxEnw

[edit] Tuossa näkee aika hyvin Material Design ja Hero Element ideoita…

https://www.youtube.com/watch?v=97SWYiRtF0Y

Visualisoi EE riippuvuudet (CDI ja EJB)

Visuaalisena ihmisenä tykkään nähdä asioita eri vinkkeleistä ja saada sitä metriikkaa. Hiljattain heräsi projektissa mielenkiinto nähdä miten riippuvuuden olioiden ja komponenttien välillä menevät, missä kohden niitä voi yksinkertaistaa ja siistiä.

Mukavasti juuri törmäsin kirjoitukseen aiheesta ja löysin palikan joka vielä kaiken lisäksi toimii mahtavasti. Asialla taas kerran vanha kunnon Adam Bien 😉

Temppu on hyvin simppeli: Lisää tämä Maven pom.xml tiedostoon:

            <plugin>
                <groupId>de.struller-baumann</groupId>
                <artifactId>visualee</artifactId>
                <version>0.25</version>
                <configuration>
                    <outputdirectory>visualee</outputdirectory>
                </configuration>
                <executions>
                    <execution>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>visualize</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Ja tadaa! Sieltä ne riippuvuudet piirtyvät buildin ohessa, projektin alle alikansioon /visualee. Sinne tulee HTML+JavaScript+JSON paketti joka on niin paljon vaikuttavampi aidolle projektille ja livenä kuin kuvana – että kannattaa ihan kokeilla itse.

Tuossa kuitenkin maistiaisia:

http://www.struller-baumann.de/visualee/

Kuva

Pikkasen paremmin saa selkoa kun ottaa kiinni palikasta joka kiinnostaa, ja vaikka järjestelee niitä vähän ruudulla – tai käyttää hakutoimintoa.

visualee2

Vinkki: Paikallisesti käytettynä valitettavasti eivät toimi ilman virityksiä Chromessa, mutta esim. Firefox näyttää hienosti myös lokaalina omalta levyltä nämä. Työkalun sivuilla on lisätietoa näistä pikku virityksistä.

 

Lähde:

http://www.adam-bien.com/roller/abien/entry/visualize_your_javaee_dependencies_in

https://github.com/Thomas-S-B/visualee

Koodin laadun hifistelyä – Maven, AntRun, SonarQube

Hetken SonarQubea käytettyäni olen suuri fani. Kun koodaustiimi saa jatkuvasti metriikkaa tekemisistään, on helpompi tehdä asiat alusta asti oikein ja välttää teknistä velkaa. Olen jo aiemmin ollut ihastunut staattisiin lähdekoodianalyysiohjelmistohin, mutta Sonar on – puutteistaankin huolimatta – paljon laajempi ja osittain helppokäyttöisempi paketti.

Tässä pari uutta havaintoa matkan varrelta:

Sonarista saa näppärästi web service rajapinnan kautta metriikkaa ulos siitä miten homma etenee – näistä voi vuorostaan jopa päräytellä näppäriä graafeja tai radiaattoreita.

Esim: http://munsonarserveri:9000/api/timemachine?resource=1&metrics=coverage

Pajauttaa aikakoneesta koodin kattavuusmetriikkaa tämännäköiseen json muotoon:

[{"cols":[{"metric":"coverage"}],"cells":[{"d":"2014-06-04T15:42:12+0300","v":[0.0]},{"d":"2014-06-05T09:21:24+0300","v":[11.9]},{"d":"2014-06-09T10:22:23+0300","v":[12.8]},{"d":"2014-06-10T08:03:49+0300","v":[12.8]},{"d":"2014-06-11T07:36:49+0300","v":[14.1]},{"d":"2014-06-11T13:59:50+0300","v":[18.3]}]}]

Tuossapa tietysti sampleja joissa aikaleima, ja testikattavuuden prosentuaalinen määrä – toivon mukaan nouseva trendi.

Samoin irtoaa esim. tech debt mittari, LOC mittari, jne, joilla pystyy seuraamaan mitä tapahtuu. Nämä vaikka Android kännykän näytölle pyörimään tai robotti motkottamaan jos ylityksiä tapahtuu.

Toinen huomio: Javascript projektissa ei alkuun code coverage mittailut toimineet, vaikka lcov kattavuustiedostoja generoimmekin. Keksin pari heikkoutta Maven projektihässäkässä Sonarin suhteen:

– Sonarista on jokin aika sitten poistettu käytöstä parametrit joilla voi kertoa mistä junit testiraportit löytyvät. Monet tutorialit viittaavat vielä niihin, mutta ne eivät siis toimi.

– Grunt rakentelee kyllä iloisesti lcov-standardin mukaisia raportteja Karma -testeistä. Mutta ne menevät ikävästi kansioon jonka nimessä on selain ja käyttöjärjestelmä – jotka voivat vaihdella, ja joissa on välilyöntejä. Toinen ongelma oli lcov tiedoston sisältö – siellä oli suhteellisia polkuja jotka eivät olleet suhteessa Maven projektiin, vaan testikonfiguraatioiden paikkaan.

Joten muutama korjaus joita tein:

Ensinksi AntRun plug-in kopsaamaan lcov tiedosto fiksumpaan ja vakioidumpaan paikkaan – ja regexp replace fiksaamaan nuo polut:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <version>1.7</version>
  <executions>
    <execution>
      <id>copy-lcov-file-to-target</id>
      <phase>test</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <skip>${skipTests}</skip>
       <target>
         <copy todir="target" flatten="true">
           <fileset dir="target">
             <include name="surefire/PhantomJS*/lcov.info" />
           </fileset>
         </copy>
         <replaceregexp byline="true"
 file="${basedir}/target/lcov.info"
 match="SF:./app/"
 replace="SF:src/main/frontend/app/" />
       </target>
      </configuration>
    </execution>
  </executions>
</plugin>

Sitten vain sonaria varten yksi property asetus Maven pom.xml tiedostoon:

<properties>
    <sonar.javascript.lcov.reportPath>target/lcov.info</sonar.javascript.lcov.reportPath>
</properties>

Ja näin alkaa tippumaan testikattavuudesta raportteja.

Protractor alkoi myös tiputtelemaan JUnit yhteensopivia raportteja kun lisäili sen konfiguraatiotiedostoon tällaista:

 onPrepare: function() {
   require('jasmine-reporters');
   jasmine.getEnv().addReporter(
     new jasmine.JUnitXmlReporter('../../../target/surefire', true, true,'e2e-TEST-'));
 },

Siinäpä nämä tällä kertaa. Sonarin aikakone – time machine – antaa mukavaa metriikkaa siitä miten tarkkailija muuntaa tarkkailtavaa – quality is in the eye of the beholder.

timemachine

 

 

 

Java-projektin laatua paremmaksi – SonarQube

No niin, tämä ei ole varsinaisen uusi tuote, ja jotkut aiemmista asiakkaistani ovat hehkuttaneet tätä jo aiemminkin, mutta vasta nyt oma tieni vei tämän äärelle.

Olen metriikkafriikki. Tarkoittaen että minusta on mukavaa saada jotain kättä pidempää analyysiä projektin laadusta, ja pidemmälle vieden teknisestä velasta. Siitä spagettikoodi-sotkusta jota helposti kertyy kun kiireessä ja paineen alla tehdään ja mennään siitä missä aita on matalin.

Ideana ei toki ole vain paljastaa tuskaa huonosta koodista, vaan parantaa läpinäkyvyyttä ja tukea parhaita käytäntöjä. Ideaali työlooppiin liittyy testi (speksi), minimikoodi joka sen läpäisee (ruma), riittävästi iteraatioita jotta testi ja implementaatio toimivat ok, jonka jälkeen refaktorointikierros – joka usein unohdetaan kiireessä. Toisin sanoen, jos metriikkaa kerää vanhasta projektista jossa on muutama miljoona riviä, tuska on valtaisa ja refaktoroinnin määrä kohtuuton ja epärealistinen. Eli paras hetki ottaa näkyvyyttä on itseasiassa projektin alusta alkaen, ja ideana tehdä siitä kehittäjille hyvin halpa, säännöllinen, havainnollinen, helppo, ja jopa hauska (Gamifikaatio olisi tässä kova juttu – saavutuksia ja tasoja 😉

No niin, rönsyilyksi meni. Joka tapauksessa, itse kerään metriikkaa mm. Jenkinsin avulla, GitHub näyttää kivasti metriikkaa, ja olen tottunut ajamaan code coverage vimpaimia kuten Cobertura ja JaCoCo, sekä staattisen lähdekoodin analyysejä kuten FindBugs ja PMD. Mutta nyt otin käyttöön myös Sonarin joka yhdistelee näitä, ja mikä mukavinta solahtaa mukavasti Maveniin jotta jokainen koodaaja voi sen halutessaan ajaa – tai Jenkinsiin jotta saadaan säännöllisiä raportteja. Näillä on hyvä näyttää teknisen velan määrä, idea, ja totuttaa säännölliseen refaktorointiin – joka taas vaatii testikattavuutta.

SonarQube sai huomioni kahdesta syystä: Se alkoi juuri tukemaan ainakin osittain Java 8 tasoa, ja siinä on hieno JavaScript plugin. Siinä on useita hyödyllisiä maksuttomia plugineita, ja kyseessä on aluperinkin open source tuote, mutta tarvittaessa löytyy maksullista tukea ja parempia plugareita rahalla.

Tässäpä kokoonpanoa:

Testasin ensin SonarQube serveriä omalla koneella. Latailin sen osoitteesta http://www.sonarqube.org/ – ja ajoin scriptin, joka potkaisi serverin ja muistitietokannan käyntiin porttiin 9000. Tämän jälkeen ajoin Mavenissä komennon

mvn sonar:sonar

— ja raporttihan sieltä putkahti esiin serverille. Tämän jälkeen viritin serverin toimimaan pysyvämmälle palvelimelle – valitettavasti .war paketointia ei ole enää nykyisin tarjolla, ja menin siitä missä aita on matalin eli latasin suoraan linux-asennuksen ja asensin sen servicenä. Mutta sama lopputulos kuin edellä – nyt vain serveri jyllää yötäpäivää saatavilla. Pystytin myös mysql kannan ja muutin SonarQube serverin properties tiedostosta oikeat ajurit ja yhteystiedot.

Maven työasemapäässä sitten piti opettaa sonar käyttämään etäserveriä paikallisen sijasta. Tein säädöt henk koht settings.xml tiedostoon (.m2 kansion alla oman kotihakemiston alla, tämä ei mene lähdekoodihallintaan vaan on joka kehittäjällä oma) – ja se näyttää about tältä:

<profiles>
 <profile>
 <id>sonar</id>
 <activation>
 <activeByDefault>true</activeByDefault>
 </activation>
 <properties>
 <sonar.jdbc.url>
 jdbc:mysql://myserver.mycompany.com:3306/sonar?useUnicode=true&amp;characterEncoding=utf8
 </sonar.jdbc.url>
 <sonar.jdbc.username>myusernamethatisnotroot</sonar.jdbc.username>
 <sonar.jdbc.password>notrootpassword</sonar.jdbc.password>
 <sonar.host.url>
 http://myserver.mycompany.com:9000
 </sonar.host.url>
 </properties>
 </profile>
 </profiles>

Ja taas voi ajella mvn sonar:sonar komentoa kehitysasemissa – nyt vain raportit tallettuvat jaetulle palvelimelle ja mysql kantaan.

Seuraava steppi: Oletuksena sonarissa on java-plugin joka ei oikein java 8:n kanssa tule toimeen. Sen voi onneksi päivittää uusimpaan versioon ja se alkaa tulemaan vähän paremmin toimeen.

(Yhteensopivuusongelmat ovat mm. pmd ja jacoco ja findbugs kanssa, ne voi halutessaan toki disabloida. PMD ja JaCoCo ja FindBugs taas ovat Java8 kanssa ongelmissa kiitos ASM kirjaston, jonka aiemmat/nykyiset versiot eivät tajua Java 8 bytecodea. Tässä on aika sotkuinen vyyhti ja hyvin mielenkiintoista että tätä ei ole fiksattu jo ennen Java 8 julkaisua – mutta useimpia näistä tekevät harrastetyönään kehittäjät joilla on muutakin elämää)

Joka tapauksessa, Java plugarin päivityksen ohella itse tuli asennettua mm. JavaScript plugari, sekä pdf raportointiplugari. Monenmoista muutakin herkullista löytyy.

Tuossa kuvaa Sonar raportista – kaikkine karuuksineen – ennen kuin aletaan siistimään sen perusteella:

sonar raportti

Ja JavaScriptistäkin tämä sai rouskutettua esiin metriikkaa – vaikka kyseessä on aika monimuotoinen projekti – mielestäni tosin aika lepsu analyysi 😉

sonar_javascript

Mutta – metriikaa näkyviin alkumetreistä, ja säännöllisesti. Näin saadaan koodin löyhkät esiin aiemmin. Näin saadaan bugeja korjattua ennen kuin niistä tulee bugeja – ja levitetään parhaita käytäntöjä tasaisesti tiimin kesken. SonarQube näyttäisi olevan taas yksi palikka pinossa joka saa oman hyväksyntäleiman.

Paholaismainen puoleni on seuraavaksi kiinnostunut miettimään laittaisiko buildin failaamaan jos coverage report ei ole riittävällä tasolla, jos javadoc generoinnissa on virheitä tai varoituksia, tai jos koodin kompleksisuusmetriikka mättää :p

Spring 4 + Spring Boot + Jax-rs + Jersey + Jackson + JsonObject toimimaan

Sain hiukan takkua yrittäessäni konvertoida Java EE projektia toimimaan Springin päällä standardin Jax-RS rajapinnan avulla sensijaan että olisin käyttänyt Springin omia.

Tässä toimivaksi testattu dependencies-osa pom.xml tiedostosta, jossa riippuvuudet paikallaan. Pohjalla on Spring boot, joka on jo otettu parent-osion avulla mukaan (kuten aiemmassa blogissani näytin):

Huomaa että riippuvuudet joissa ei ole versionumeroa tulevat Spring boot perinnässä dependencyManagement osan kautta, esim. log4j, mysql, jne. Tässä on myös muutama extra riippuvuus JAX-RS:n ohella sekä mysql ajurit.

jersey.version property on asetettu arvoon 2.8 ylempänä properties-osiossa, jota tässä ei ole näytetty.

<dependencies>

  <!-- Let's get this started with Spring Boot for web apps -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
 
  <!-- Do not include tomcat server libs, as we package .war -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
  </dependency> 
 
  <!-- Include Spring Data, jpa, and derby for database testing -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>


  <!-- Log4j support so we can get some log output -->
  <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
  </dependency> 

  <!-- Mysql database -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
  </dependency>

  <!-- Jersey JAX-RS 2.0 support -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-jersey</artifactId>
    <version>1.0.2.BUILD-SNAPSHOT</version>
  </dependency> 

  <dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.0.4</version>
    <scope>runtime</scope>
  </dependency>

  <dependency>
    <groupId>javax.json</groupId>
    <artifactId>javax.json-api</artifactId>
    <version>1.0</version>
  </dependency>

  <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
    <version>${jersey.version}</version>
  </dependency> 

  <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-common</artifactId>
    <version>${jersey.version}</version>
  </dependency> 

  <dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>${jersey.version}</version>
  </dependency> 
 
 <dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-processing</artifactId>
    <version>${jersey.version}</version>
  </dependency> 
 
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>${jersey.version}</version>
  </dependency> 

  <dependency>
    <groupId>org.glassfish.jersey.ext</groupId>
    <artifactId>jersey-spring3</artifactId>
    <version>${jersey.version}</version>
  </dependency> 

  <!-- JAXB-to-JSON Serialization support -->
  <dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey.version}</version>
  </dependency> 
 
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.0-rc3</version>
  </dependency> 

  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.4.0-rc3</version>
  </dependency> 
 
  <!-- Using restassured for API testing -->
  <dependency>
    <groupId>com.jayway.restassured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>2.3.1</version>
    <scope>test</scope>
  </dependency>
 </dependencies>

Ylläolevassa on tuotu myös jersey-kirjastoja uudestaan vaikka osa niistä tuleekin spring-jersey ja spring-boot-jersey mukana. Mutta näin saadaan tuoreimmat versiot käyttöön ja versio helposti säädetyksi kerralla. Tässä voisi myös käytellä dependencyManagement-osiota versioiden hallintaan.