Java 9 on kymmenen kertaa nopeampaa!

Törmäsin mielenkiintoiseen ilmiöön taannoin. Valmistelin esitystä suorituskyvystä ja Java muistimallista, ja ajoin eräänlaista benchmark sovellusta Dockerin avulla eri virtuaalikoneissa. Sovelluksen ideana on sisältää aika typerästi kirjoitettua mutta varsin tavanomaista Java-koodia. Silmukoita, ehtolauseita, merkkijonojen käsittelyä, laskentaa, kokoelmien käsittelyä, ja kellottaa paljonko kaikkeen menee aikaa. Tällä voidaan myös nähdä nykyaikaisen virtuaalikoneen itseään optimoiva vaikutus – kun ajo jatkuu, nopeus yleensä kasvaa. Tässä on sovelluksen mittaustuloksia Oracle Java 6 Docker kontissa ajettuna:

Screenshot 2016-10-16 13.19.54.png

Eli, yhden kierroksen aika on n. 84 sekuntia, laskien 82 sekuntiin jahka virtuaalikone vähän ”lämpenee” eli käytännössä jit-kääntää enemmän koodia ja tekee muita tarvittavia optimointeja.

 

Tässä on OpenJDK+Java 8 ajotulokset:

Screenshot 2016-10-16 13.23.31.png

Kuten tuloksista näkyy, uudempi virtuaalikone optimoi usein tehokkaammin. Tässä kierrosajat pyörivät n. 62 sekunnin pinnassa – Java 6 verraten on irronnut noin 20 sekuntia, tai 1/4 suoritusajasta. Paras kierrosaika oli jopa 52 sekuntia. Aika hyvä tulos!

Kokeillaanpa G1 roskankeruualgoritmilla:

Screenshot 2016-10-16 13.35.12.png

Oops! Vaikka G1 on teoriassa kauneinta ja uusinta mitä roskankeruualgoritmeihin tulee, se ei ole joka ongelmaan optimaalinen ratkaisu. Suoritusajat vaihtelevat 98 ja 104 sekunnin välillä ja ovat nousemaan päin. Tällä sovelluksella ja tämän koneen muistilla tässä tuli takapakkia, huonompi suorituskyky. Varmaan tästä syystä G1 ei ole vielä oletusalgoritmina vaan pitää erikseen kytkeä päälle lisäparametrilla -XX:+UseG1GC.

Java 9 julkaistaan vasta pitkällä ensi vuonna. Siitä on kuitenkin jo prereleaseja liikkeellä, ja jopa Docker virtuaalikuva. Tämän ansiosta on lasten leikkiä ajaa sama koodi Java 9:llä. Tulokset tässä:

Screenshot 2016-10-16 13.36.26.png

WUT? Sama koodi, tekee saman asian, sama koneympäristö ja resurssit. Suoritusajat vaihtelevat 9 ja 12 sekunnin  välillä. Karkeasti ottaen noin kymmenen kertaa nopeampaa kuin useimmat muut testiajot, ja yli viisi kertaa nopeampaa kuin paras tulos tähän asti.

Jotain on muuttunut. Mitä, en tiedä vielä. Epäilen että yksi tekijä voi olla Jigsaw moduulimallit. Toinen tekijä lienee, että on taas opittu tunnistamaan joku negatiivinen koodaustapa, ja optimoimaan sen suoritus. Tulokset tuskin ovat yleispäteviä, ne pätevät lähinnä tähän tyypilliseen koodiesimerkkiin mitä käytin, ja tähän ympäristöön. Docker välissä voi myös vaikuttaa jotain, tuskin kuitenkaan paljoa. Niin tai näin, koodi otti taas kerran hurjan tehokkuushypyn. Tätä herkkua olisi luvassa ensi vuonna.

Virtuaalikoneiden ihanuus on siinä, että nautit kaikista edistysaskelista, ilman koodimuutoksiakin. IBM nimesi juuri oman open source JDK 9 versionsa JIT-kääntäjän Testarossaksi, joten veikkaisin että sieltä on myös suurta hyvyyttä tulossa.

p.s. Docker on ihana keksintö!

p.p.s. Niin on Cathode terminaalikin :p

 

Kuolema nullpointerexceptioneille: Kotlin ftw!

Lomaillessa ja sairastaessa on hyvin aikaa leikkiä jollain jolle ei ole ollut kysyntää ns oikeissa, hiellä ja tuskalla väännetyissä Wakavissa Projekteissa. Tällä kertaa tutkaan osui Kotlin, johon on ollut tarkoitus perehtyä tilaisuuden tullen.

Kotlin on tuorein lisäys JVM-perheen kieliin; Eli kuten Scala, Clojure, ja Groovy, se on ihan oma erillinen kielensä, syntaksinsa, ja filosofiansa, mutta kun se menee kääntäjän läpi, putkesta ulos tulee Java-virtuaalikoneen bytecodea – vaatii tosin minimitasoksi Java 6 myllyn.

Ajonaikaiset virheet ohjelmissa ovat nykypäivän ohjelmistokehityksessä niitä kalleimpia virheitä – koska ne löytyvät vain kattavalla testauksella, voivat vaatia hyvinkin eksoottisia tiloja ja kombinaatioita ilmentyäkseen, ja mitä myöhemmin ne löytyvät, sitä enemmän ne maksavat. Esim. käyttöönottovaiheen jälkeen löytyvä bugi pitää ensin havaita, sitten raportoida, sitten toistaa, sitten ymmärtää, sitten korjata, sitten testata korjaus, ja testata ettei korjaus rikkonut mitään muualla, jne. Tästä kertyy ihan kohtuullisesti hintaa pienille asioille. Java-kielessä on alusta alkaen ilmennyt kahta eri virhettä yli kaiken muun: ClassCastException, sekä NullPointerException. Java 5 onnistui aikanaan hävittämään edellisen lähes sukupuuttoon Generics tyypitettyjen kokoelmien myötä. Mutta NullPointer on edelleen valitettavan yleinen virhe. Ja kun se paukahtaa, se usein valuu pinossa ylöspäin, ja voi ilmentyä hyvin mielikuvituksellisin tavoin – tai voi aiheuttaa seurauksia jotka näkyvät jossain aivan muualla myöhemmin. Eli pirullisia virheitä.

Nullpointereita on jahdattu eri tavoin. Olen itse opettanut ja kirjoitellut siitä miten Java-kielellä koodatessa voi tiedostaa tämän, ja koodata fiksusti. NullPointer paholainen iskee tyypillisemmin kun metodi palauttaa kokoelman sijasta null-arvon. Eli parempi filosofia on palauttaa aina ei-null arvo, esim. tyhjä. Jos jossain oikeasti tulee vastaan niin harvinainen tapaus, että null ja tyhjä ovat eri asia ja molemmat tarpeen palauttaa, niin se poikkeus on hyvä dokumentoida ja nimetä selkeästi, jotta kutsuja osaa käsitellä arvot oikein. Scala ja Groovy hoitavat nulleja omilla tavoillaan, mutta molemmat kielet edelleen sallivat null arvoja. Java 8 esitteli uuden Optional-tyypin, josta olen myös kirjaillut, ja se tuo vähän helpotusta ongelmiin oikein käytettynä – mutta ei sekään ongelmaa poista, ja mikään ei sitä pakota käyttämään.

Joten – long story short – Kotlin kielen mainostetuin uutuuspiirre on juurikin kuolema nullpointtereille, taas uudella ja tuoreella näkökulmalla. Mutta ei mennä asioiden edelle. Kotlin on syntaksiltaan ja toiminnaltaan eniten lähellä Scala-kieltä, ja Java-koodaajillekin tuttu.

fun main(args: Array<String>) {
  print("Kuolema NULLPOINTEREILLE!")
}

Jeah, puolipisteet valinnaisia, pääohjelman voi tehdä ilman luokkaa. Itse asiassa on myös mahdollista tehdä Kotlin scriptitiedosto, joka sisältää vain pääohjelman koodin:

print("Kuolema NULLPOINTEREILLE scriptissä!")

Kotlin käännetään kotlinc-kääntäjällä, joka voi suoraan paketoida java-kirjastot mukaan. Lopputuotos voi olla .class tiedostoja, tai suoraan ajettava .jar. Kotlin voi vapaasti importoida ja kutsua Java-kirjastoja, sekä JVM sisältä että mitä hyvänsä lisäkirjastoa mitä on tehty sitten vuoden 1995.

kotlinc app.kt -include-runtime -d app.jar

Miten Kotlin sitten auttaa nullpointerien kanssa? Kotlin ei salli normaalien tyyppien asettamista null-arvoon: kääntäjä estää sen. Esim. tyyppi String vaatii aina ei-null arvon. Jos haluat asettaa null-arvon, tyypin perään tulee kysymysmerkki merkiksi, esim. String?

var name:String?
var email:String
name = null
email = null // This line does not compile at all!
print("HELLO " + name + "!")
print("Your email is " + email)

Ylläolevassa koodiesimerkissä näet molemmat käytössä. Jos halutaan siis varata oikeus käyttää null-arvoja, se pitää näkyä jo alunperin tyyppimäärityksessä. On siis varsin mahdollista käyttää null-arvoja – mutta useimmiten ne ovat vain puhdasta laiskuutta. Useimmiten kun on mielijohde palauttaa null-arvo, onkin fiksumpaa palauttaa ns tyhjä arvo, esim. tyhjä String, tyhjä List, jne, tai heittää poikkeus. Niihin harvoihin tapauksiin kun null arvo on oikeasti kätevä, se on helppo ottaa käyttöön.

Mitä muuta jännää on Kotlinissa, verrattuna Java/Scala kieliin esim? Aika paljolti paletti molempien parhaita puolia. Primitiivityypit on poistettu: Kaikki ovat oliotyyppejä. Ei ns checked exceptions poikkeuksia, kaikki ovat nykymuodin mukaan runtime exception tyyppiä, eli käsitellään kun halutaan, ei ole pakko. Nykymuodin mukaan myös kielessä on paljon älykkyyttä ja päättelyä: esim. muuttuja/vakiotyyppiä ei tarvitse määrittää jos kääntäjä sen jo osaa päätellä arvon perusteella. Erikseen löytyy val ja var avainsanat immutable/mutable käyttöä varten. Tottakai lambda expressionit pelaavat mainiosti.

Kielestä on sitten vastaavasti jätetty pois monia piirteitä, joilla Java/Scala koodaajat ampuvat itseään lahjakkaasti jalkaan, esim. static avainsanat ja osat, implicit conversions, ja rohkaisu on ratkoa ongelmia siten että koodi pysyy luettavana ja selkeänä. Toisin kuin Scala, kieli on myös rakennettu modernin Java 8 pohjalle, eli on lähempänä nykysyntaksia mm. Lambdojen ja Stream käsittelyn osalta. Itse pidän myös esim. funktioparametrien oletusarvoista, ja mahdollisuudesta asettaa parametreille arvot nimen perusteella. Tämä vähentää tarpeetonta polymorfismia – toki kohtuudella käytettynä tämäkin, muuten polymorfisuus korvautuu modaalisuudella joka taas ei ole hyvä vaihtokauppa.

2016-06-10 13.13.59

Firman Flamingo hyväksyy Kotlinin

Kotlin on tosiaan melko tuore tulokas kentällä: JetBrains niminen paja lanseerasi sen vuonna 2011, vuonna 2012 se vapautettiin Apache lisenssillä open sourceksi, ja nyt vuonna 2016 siitä on julkaistu vakaaksi laskettava versio 1.0, vuoden alusta. Sen osuus on sen verran marginaalinen ettei vielä näy esim. TIOBE indeksissä, mutta se ei toki tarkoita etteikö sitä jo kentällä käytettäisi.

Kannattaisiko siis käyttää Kotlinia seuraavaan projektiin? Omalta puoleltani annan vahvan peukutuksen. Clojure uskovaiset tuskin kokevat halua kääntyä tänne, se on edelleen oma maailmansa. Java uskovaisten kannattaisi tehdä seuraava projekti ihan millä hyvänsä modernimmalla kielellä, Java on nykymuodossaan aika rasitettu ja päällelaastaroitu sekamelska, ja Scala, Clojure, ja Kotlin ovat kaikki huimia parannuksia siihen. Scala kielen pieni haitta on se että se oli kentällä aikaisin, ja nyt sen linjaus Java 8 mukaiseksi on vähän isompi operaatio. Scalassa on myös turhankin voimallisia tapoja ampua itseään jalkaan, jotka ovat Kotlinista tahallisesti poistettuja.

Kuten Scala, myös Kotlin on hyvä alusta jossa voit toteuttaa vapaasti haluamaasi yhdistelmää funktionaalista tai olio-ohjelmointityyliä. Voit esim. aloittaa iisisti perinteisemmällä Java oliokoodilla, ja hivuttaa itseäsi kohti korkeamman tason funktioita ja immutable, arvoja. Kotlin käyttöönotto on helppoa, ja sen voi perinteiseen tapaan aloittaa vaikkapa testipuolella. Kotlin toimii myös mukavasti esim. Spring Boot+REST alustana, ja sen saumaton yhteensopivuus olemassaolevien Java-kirjastojen kanssa tuo ratkaisua mm. tietokantojen kanssa pelaamiseen.

Itse ainakin käyttäisin. Rakastuin aikanaan Scalaan, ja Kotlin on Scalalle vähän samaa kuin Scala oli Javalle. Scala on edelleen paljonkin voimallisempi työkalu, ja kypsempi myös, mutta molemmat piirteet ovat kaksiteräisiä miekkoja. Ja Java-kieltä taas kukaan ei varmaan ihan ehdottoman innoissaan halua koodata. Sen paras argumentti lienee Cobol-mainen 20 vuoden tuoma maturiteetti, se on hyvä sveitsin armeijan linkkuveitsi siellä työkalupakin pohjalla. Ehkä sen olisi kielenä jo aika kuolla pois. Mutta toki maailmalta löytyy 10 miljoonaa enemmän tai vähemmän aktiivista koodaajaa jotka sitä ymmärtävät. Digitalisoinnin tarpeiden taas laajentuessa eksponentiaalisesti sekin on hyve.

 

Tuolta lisää:

https://kotlinlang.org/

 

Android N ja Java 8

Tuloillaan on uusi versio Android käyttöjärjestemästä, tässä vaiheessa koodinimellä N tunnettu. Siinä on taas aika suuri heilutus tuloillaan alustaan, jota on jo puitu monissa ulkomaan artikkeleissa. Mutta tässä omasta näkökulmasta kiinnostavia juttuja:

Jack it to the max

Jep, kuten otsikko kertoo, nyt voi koodata täydellä Java 8 ilmaisuvoimalla. No, lähes täydellä. Käytössä on Jack-niminen työkaluketju, jolla käännetään Java 8 lähdekoodit Android .dex bytecodeksi. Tämä on kahdestakin syystä ihastuttavaa. Ensinnäkin Java 8 on ihanaa! Toisekseen tämä kertoo että Google ei ole antamassa periksi Javan osalta, ja siirtymässä johonkin uuteen. Tai ehkä onkin, mutta näyttää silti siltä, että Javalla on vielä tulevaisuutta edessään täälläkin alustalla.

https://developer.android.com/preview/j8-jack.html

https://source.android.com/source/jack.html

Joka tapauksessa, ei mene ihan perusputken mukaan, eli pieniä eroja täysiveroiseen OpenJDK ympäristöön voi tulla. Lähinnä esim. työkalustojen osalta voi tulla säätöä. Mutta näin on odotettavissa, aika iso hyppäys siirtyä Java vitostasosta kolme tasoa kerralla ylöspäin.

Saako sitä jo?

No tottakai sitä saa. Google on avannut beta-ohjelmaa, johon voi imaista sopivaan kännykkään N-version ihan OTA päivitysenä, rekisteröitymällä vain kiinnostuneeksi. Ei siis ole tarpeen viriviritellä laitettaan usb piuhalla. No sitten on, jos haluaa palata takaisinpäin. Se ei OTA:lla onnistukaan. No, ainakaan ilman että pyyhkii kaiken sisällön pois.

Ihan harmittaa ettei itsellä ole redundanttia Android vehjettä käsillä. Jahka saan firman uuden puhelimen hyppysiini, nykyinen/vanhaksi jäävä Nexus tilannee OTA päivitystä samantien. Mutta ihan työ/käyttöpuhelimeen ei kannata N versiota vetäistä, sen verran varhaisia hetkiä elellään.

https://www.google.com/android/beta

Virallisempaa releasea luvassa vuoden loppupuoliskolla.

Ikkunointia

No niin, hulluus on saavuttanut uuden tason. Aloitimme kännyköistä missä tärkein ominaisuus oli kyky soittaa. Siten päädyimme kännyköihin joissa laskentateho ja ominaisuudet tekevät niistä pieniä tietokoneita – tai rökittäväthän ne aika kevyesti aikanaan supertietokoneiksi kutsuttuja talonkokoisia yksiköitäkin. Nyt pistetään lisää pykälää – lisääntyvä teho ja näyttökoko ovat ajaneet meidät tilanteeseen jossa kännykässä voi olla tarvetta ajaa sovelluksia ikkunoissa. Ja tätä tulee Android N:ssä.

Eli jep, voidaan avata sovelluksia eri ikkunoihin, ajaa samanaikaisesti, ja muuttaa kokoa. Tämä vaatii toki sovellukselta tukea, mutta eiköhän sitä ole tulossa. Clash of Clans ja Youtube strategiavideo auki rinnakkain. Copy/Paste. Jepjep, me olemme viimein saaneet työpöytäkoneet taskuihimme, viimein on käyttöä tarpeettoman järeille moniydinprosessoreille 😉

Odota hetki, päivitän sovelluksia…….

Myös optimointi on käynyt läpi omat elinkaarensa. Ensin oli JIT käännökset, jossa sovellusta optimoitiin ajon aikana. Sitten keksittiin, että on parempi optimoida jo asentaessa, niin sovellus käynnistyy nopeammin (ART). Tästä saatiin kaikkien rakastamat Android sovelluspäivitysodottelut aina käyttöjärjestelmän päivittyessä – ja yleensä juuri silloin kun puhelinta tarvitsisi. Nyt, Android N myötä, tämä vaihe poistuu unholaan. Palataan taas JIT-malliin, nyt kun tehoa on enemmän, voidaan taas jakaa optimoinnin kuorma tasaisemmin ajon ajaksi. Tästä lisää täällä:

http://www.androidauthority.com/android-n-app-optimization-compile-679129/

Ja paljon paljon muuta. Onhan tuota tulossa, mutta näitä piirteitä on jo analysoitu hyvin muualla. Itseä kiinnostaa eniten tuo Java 8 piirre, se on kehittäjänäkökulmasta tuoretta ja virtaa tuovaa. Myös mahdollisuus osallistua aikaisin testaukseen – niinkuin nyt – on aika kova. Palaan astialle jahka saan jonkun omista laitteista N-aikaan ja vähän konkretiaa testailuun.

 

 

Java 20 vuotta

Jep, tämä on se vuosi. Vuonna 1995, toukokuussa, Sun Microsystems puski jakoon 1.0 version Javasta. Se sai huimasti sykettä ja suosiota ja nousi yhdeksi suosituimmista työkaluista. Ihan vain sen kunniaksi, hiukan muisteloita ja hajatuksia tästä.

Nillittäjät voivat huomata että vuoden 95 Java oli lähes käyttökelvotonta Alpha ja Beta versiota, ja vasta -96 saatiin vakaa 1.0 JDK. Ehkä synttäreitä voi siis juhlia uusiksi ensi vuoden tammikuussa 😉

The Duke

Vuonna 95

Tarina alkoi jo kauan ennen vuotta 95, työnimellä Oak – ja alunperin kohteena älykkäät kodinkoneet ja PDA laitteet. Vuoden 95 julkaisussa nimi muuttui Javaksi, ja fokus kiteytyi WORA periaatteeseen: Write Once, Run Anywhere. Tässä oli jotain uutta ideaa, kun ei tarvinnut tehdä natiivikäännöksiä joka alustalle softasta. Sekä lähdekoodi että binäärit olivat kaikilla tuetuilla alustoilla toimivia. Tämän mahdollisti virtuaalikonearkkitehtuuri, jota sittemmin menestyksellä kopioitiin muuallakin.

Mitä muuta meni nappiin? Yksinkertaisuus – kieli ei ollut aiempia monimutkaisempi tai monipuolisempi, vaan ohjelmoijalta abstraktoitiin pois mm. pointteriaritmetiikka ja muistinhallinta – virtuaalikone hoiti ne pinnan alla. Paradigmaksi valittiin objektiorientaatio, ja toimntaympäristöksi hajautettu ja monisäikeinen. Network is the computer.

java-duke-guitar

Kolikolla oli kääntöpuolensakin. Etenkin alkuaikojen Java oli tunnettu surkeasta suorituskyvystään: Kymmeniä kertoja C++ koodia hitaampaa. Sillä ei voinut tehdä ollenkaan kaikkea: suora pääsy virtuaalikoneen ulkopuolella käyttämään ympäristön natiiviominaisuuksia ei ollut helppoa eikä hauskaa (JNI). Appletit olivat suosituin tekniikka, pelit ja vilkkuvat bannerit, ja tietoturvaongelmat alkoivat nostamaan päätään heti kun annettiin voimaa ja valtaa asiakaspuolelle. Swing oli sinällään hieno käyttöliittymäkirjasto joka pyöri kaikkialla, mutta oli toisaalta yhtä tympeän karu ja hidas kaikkialla.

Muutama vuosi myöhemmin mentiin pykälällä eteenpäin: JIT eli Just-In-Time käännökset antoivat potkua suoritukseen, ja nopeasti sen perässä tulikin jako kolmeen: J2ME, J2EE, J2SE – eli Javaa pieniin ja suuriin ympäristöihin. Mobiililaitteiden myötä Javaa ajavien ympäristöjen määrä räjähti pilviin, ja serveripuolella tuli käyttöön standarditapoja tehdä asioita – ja ajaa samaa koodia SUN, IBM, Oracle, BEA alustoilla (Sittemmin lista on kaventunut, koska yritysostot 😉

2000-luku

2000-luvulle siirryttäessä Java alkoi näyttää vanhalta ja kankealta. Markkinoille tuli paljon uutta ja hyvää. Ruby, Rails, C# ja .NET, PHP ja JavaScriptin uusi tuleminen. Yhtäkkiä Java olikin se kankea perinnealusta joka ei ollut inspiroivaa koodata. Java oli se uusi Cobol.

Onneksi heiluri heilahti takaisinpäinkin. Siinä missä Microsoft otti huomattavasti inspiraatiota Javasta omaan .NET alustaansa ja C#-kieleen, Java 5 otti taas hienoja asioita siltä puolen ja antoi ne Java-kehittäjille. Osa päivityksistä oli kiistanalaisia ja hieman päälle laastaroituja, mutta silti, Generics, ja annotaatiot, toivat ruutia alustaan. Samalla avoin lähdekoodi saavutti Javan, ja alkoi tulemaan pilvin pimein hienoja tuotteita joiden koodi oli avointa ja käyttöönotto mutkatonta ja nopeaa. Eclipse, Tomcat, JBOSS avasivat tietä, ja saivat nopeasti lukuisia kilpailijoita.

IMG_3013

Sitten tuli turbulenssin aika, ja pari vähäisempää Java-versiota – Java 6, ja Java 7. Niiden suunnitelmat olivat kunnianhimoisia, mutta Sun Microsystems ajautui Oraclen sulauttamaksi, ja kaikkeen meni enemmän aikaa kuin arvioitiin – Java 7 suunnitellut muutokset valuivatkin eteenpäin tuleviin julkaisuihin.

Olisiko Sun Microsystemsin kirouksena ollut liiketoimintamallin puute? Java mahdollisti softan kehityksen ja ajon melkein missä vain – eikä sitonut tietyn valmistajan alustaan tai tuotteisiin. Sen käytöstä ei hurjia tuottoja tippunut eikä se sitonut kotiinpäin asiakkaita. Siitä tuli liiankin avointa ja vapaata.

Fast forward to Now

Nyt eletään vuotta 2015 – ja Oraclen valtakautta, kuudetta vuotta. Käytössä on Java 8 ja ysiversiota rakennetaan jo. Java 8 otti paljon vaikutteita erinomaisen Scala-kielen pohjalta, ja muualtakin, ja Lambat ja Streamit ja parannetut päivämääräkirjastot maistuvat kieltämättä hyvältä. Kieli on onnistunut uudistumaan mukavasti vaikka on jo ajat sitten saavuttanut täysi-ikäisyyden. Se on pysynyt markkinoilla validina. Mikä vielä kiehtovampaa, virtuaalikonearkkitehtuuri on osoittanut hyötynsä, ja Java-kielen rinnalla voi tuottaa toimivia ratkaisuja mm. Scala, Groovy, tai Clojure-kielellä – joissa kaikissa on omat vahvuutensa. Uusia Javantappajia ei ole näköpiirissä – ellei noita edellämainittuja kieliä lasketa. Java-koodaajia on maailmanlaajuisesti yli 10 miljoonaa.

Uuden maailman ilmiöitä ovat mainitut Lambdat, streamit, niiden ohella funktionaalinen ohjelmointi, ja rohkea yhdistäminen Javascript-raskaisiin käyttöliittymiin – Angular, React, Aurelia. Staattisen tyypityksen voi kyseenalaistaa esim. Clojurella – tai tiputtaa koodin määrää 90% melkein millä vain noista edellämainituista virtuaalikonekielistä. Java toimii kaikkialla missä ennenkin – ja monessa uudessa paikassa. Androidin myötä se valloitti mobiililaitteet rytinällä – ja nyt on IoT valloitus kovassa käynnissä. Eli vahvasti mennään taas.

IMG_8068

Ainoa ongelma on se kun tajuaa koodanneensa Javaa alkuajoista asti. Sehän tuntuu kuin olisi saanut alkunsa eilen? Samaa hommaa tehdään siis edelleen – vain tukkaa on vähemmän. Olisiko aika jollekin uudelle ja virkistävälle kielelle? 😉

Java 8 Optional – oikea käyttö

Olen käytellyt Java 8 versiota tuotannossa jo useammassa paikassa yli vuoden verran, mutta Optional luokasta en ole kirjoitellut – enkä suuremmin käyttänyt. Olen kuitenkin suuri NullPointerException:ien vihaaja (emmekö me kaikki) ja olen aiemmin vähennellyt niitä lähinnä hyvillä paluuarvo ja parametrikäytännöillä. Tämähän on yleisimpiä ja viheliäisimmin metsästettäviä poikkeuksia Javassa – kiitos poikkeuksien kuplimisen.

Syy miksi en ole kirjoitellut tai käytellyt Optionalia vielä on että esimerkit joita olen nähnyt sen käytöstä ovat olleet surkeita. Kun Javan päälle laastarilappu-liimataan uusia piirteitä, käy usein niin että lääke on sivuvaikutuksiltaan pahempi kuin alkuperäinen sairaus. Ja Optional-paluuarvon tarkistaminen if-lauseilla on juuri sitä. Hyi!

Nyt näin kuitenkin ihan virkistävän uuden blogipostauksen jossa muistuteltiin muistakin tavoista. Teen myöhästyneen uudenvuodenlupauksen testailla näitä itsekin, ja katsoa tykästynkö. Ideana on korvata Optional-arvon tarkistus ehtolauseessa sen omilla funktioilla ja ominaisuuksilla, ja näin saada koodista luettavampaa silti säilyttäen fiksumpi null pointer käsittely.

Ytimessään idea on tässä:

Optional<String> result = service.find("id");
final String value = result.orElseGet(() -> "<absent>").trim();

Tämä on jo itselle ihan sopiva tapa, pystyn lukemaan sen. Artikkelin kirjoittajalla oli toinenkin idea, joka koski Optional käyttöä kokoelmana, näin:

Optional<String> result = service.find("id");
String value = result.map(String::trim).orElse("<absent>");
Tästä en ole ihan varma, jotenkin häiritsee ajatus että vedetään collections apit hatusta mukaan, mutta kiitokset luettavuudesta saa tämäkin.
Artikkelin kirjoittajalla oli pari muutakin hyvää pointtia, joten en ala kopioimaan niitä tähän vaan pidetään tätä artikkelia teaserinä. Jos mielenkiinto heräsi, kipin kapin lukemaan alkuperäinen artikkeli tuosta alta 😉

Ja artikkelin lähde:

https://www.voxxed.com/blog/2015/02/defence-java-8s-optional-use/

Java 8 + Glassfish 4 asennus Debian Linuxiin – osa 2

Viimeksi asenneltiin Debianiin glassfishiä. Tässä pari edistynyttä niksiä:

32-bit kirjastot 64-bit debianiin

64-bit debian ei välttämättä suostu ajelemaan pkg työkalua jolla voi päivitykset tehdä – se valittaa ia32-libs paketista ja pythonista. Ongelma: kun yrität asentaa paketin, se valittaa riippuvuuksista joita ei olekaan. Ratkaisu tässä:

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libjpeg62:i386
sudo apt-get install ia32-libs

Nice.

Glassfish asennuksen päivittäminen ajan tasalle.

Nyt voit päivitellä lasikalan uusimpiin kirjastoihin pkg työkalulla esim. näin:

#stop Glassfish
sudo service GlassFish_domain1 stop

# Switch to being user 'glassfish'
sudo su --shell /bin/bash glassfish 

/opt/glassfish4/bin/pkg -R /opt/glassfish4 list
/opt/glassfish4/bin/pkg -R /opt/glassfish4 image-update -v

exit # Revert to being old caffeine-deprived yourself

Muista ajaa kaikki tiedostoja luovat komennot kuten päivitykset ja käynnistykset glassfish-tunnuksella. Jos teet jotain muulla, voit korjata tilanteen päivittelemällä omistajuudet taas glassfish-kansioon ja/tai poistamalla esim. tilapäistiedostot ja cachet. Näin saat omistajuudet kuntoon:

sudo chown glassfish:glassfish -R /opt/glassfish4

 

Oletuksena zip-versio Glassfish ei omaa etähallintaa ja sen admin-salasana on tyhjä, ja master-salasana ’changeit’ – eli ei kovin käyttökelpoinen eikä turvallinen. Korjataanpa nämä.

Glassfish työkalut polkuun

Jatko-operaatioita ajatellen on kätevää lisätä Glassfish bin kansio polkuun, jotta pääset työkaluihin suoraan käsiksi. Tässä vinkit siihen:

#run these as glassfish to generate right ownerships for files
sudo su --shell /bin/bash glassfish

#These will help running the tools:
cd ~
nano .bashrc

#Set up environment for user 'glassfish': edit .bashrc and add this to end:

export PATH="${PATH}":/opt/glassfish4/glassfish/bin

# save file in editor

Testaa voitko ajaa komennon: asadmin. Ellei, kirjaudu ulos ja sisään.

Glassfish master password

Master password on tosiaan oletuksena: changeit – joten muutetaanpa se. Valitettava seuraus on, että muutos päivittää myös avain-ja sertifikaattitiedostoja, joten on taas oltava omistajuuksien kanssa tarkkana. Tässä ohjeistusta:

#if you're glassfish user, exit back to your normal user:
exit

#make sure glassfish is stopped
sudo service GlassFish_domain1 stop

#run these as glassfish to generate right ownerships for files
sudo su --shell /bin/bash glassfish

#Backup default passwords, if you got already master-password file, backup it too:
cd /opt/glassfish4/glassfish

tar cf passwords.orig.tar domains/domain1/config/domain-passwords domains/domain1/config/keystore.jks domains/domain1/config/cacerts.jks

Tässä kohtaa on olemassa varmuuskopio passwords.orig.tar josta löytyy alkuperäiset tiedostot. Nyt muutetaan niitä:

Change master password
asadmin change-master-password --savemasterpassword=true domain1
# Enter the current master password> [By default this is 'changeit']
# Enter the new master password> [e.g. 'Y0uW1llN3v3rGu3ssTh1sL33tP4ssw0rd!']
# Enter the new master password again>
# After entering the new master password twice, there is a pause of several
# seconds. Then you will find new versions of 'master-password'
# 'domain-passwords' 'keystore.jks' and 'cacerts.jks'.

Sitten kokeillaan toimiiko homma – nämä komennot kysyvät salasanaa, anna siihen valitsemasi master password.

# Your chosen master password should unlock both keystores, and reveal
# two certificates in keystore.jks, and many additional ones in cacerts.jks.
keytool -list -v -keystore domains/domain1/config/keystore.jks 
keytool -list -v -keystore domains/domain1/config/cacerts.jks

Ja jos meni jotain pieleen, aina on varmuuskopiot. Toivottavasti ne menivät oikein alunperin, kai tarkistit ne? 😉 Jos kaikki ok, näin voit palauttaa tarvittaessa alkuperäiset tiedostot jos jotain meni pahasti pieleen:

#if you mess up, you can return the backups by going to /opt/glassfish4/glassfish and running: tar -xvf passwords.orig.tar

 Admin-salasana ja etähallinnan aktivointi

Oletuksena tosiaan admin-salasana on tyhjä, ja etähallinta disabloituna. Näin saat korjattua nämä puutteet:

#exit to normal account, sudo start server - it needs to be running
exit
sudo service GlassFish_domain1 start
sudo su --shell /bin/bash glassfish

# enable remote administration for glassfish 

asadmin enable-secure-admin

# ja tässä kohtaa syytä buutata taas palvelin jotta asetukset
# astuvat voimaan

exit
sudo service GlassFish_domain1 restart
sudo su --shell /bin/bash glassfish

Nyt on tilaisuus tallettaa nämä tiedot paikallisesti, siten että linux-tunnuksiltasi ei salasanaa kysellä:

########Store admin password, to enable automatic login to localhost:4848
asadmin login
# Enter admin user name [Enter to accept default]> [Just press Enter]
# Enter admin password> [e.g. whatever you selected earlier]
# Login information relevant to admin user name [admin] for host [localhost] and admin port [4848] stored at [/home/glassfish/.gfclient/pass] successfully.
# Make sure that this file remains protected. Information stored in this file will be used by administration commands to manage associated domain.
# Command login executed successfully.

Eli, tämän tiedoston voit kopioida haluamiesi linux-tunnusten kotihakemiston alle, .gfclient/pass kansioon. Sen oikeudet voit muuttaa niin että vain user omaa oikeudet päästä tähän käsiksi. Muista säätää myös omistajuus oikein, eli omistajaksi ko tunnus.

Voit myös tuikata admin-konsolin vain https-protokollalle:

#Enable https for remote access to admin console
# Requests to http://xxx:4848 are redirected to https://xxx:4848

asadmin set server-config.network-config.protocols.protocol.admin-listener.security-enabled=true

Glassfish käyttämään portteja 80 ja 443 – ilman root oikeuksia

Jos haluat Glassfishin operoivan porteissa 80 ja 443 – mutta et halua ajaa sitä root tunnuksin jotka normaalisti vaaditaan ko porttien käyttöön  – voit tehdä /etc/init.d/GlassFish_domain1 tiedoston loppuun seuraavat reititykset – näin nämä ajetaan root tunnarilla, mutta itse glassfish normaalisti glassfish tunnarilla – ja portit 80 ja 443 ovat käytössä.

iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8181

 Sertifikaatit uusiksi

Glassfish oletussertifikaatit ovat tasan samat mitä jokainen käyttää – ei kovin turvallista. Tässä ohjeita miten voit tehdä uudet avaimet omaan käyttöön:

# Ensure that you are running as user 'glassfish'!!
# Ensure GlassFish is stopped

#Inspect keystore.jks
cd /opt/glassfish4/glassfish/domains/domain1/config/
keytool -list -keystore keystore.jks -storepass [whateverismymasterpassword]

#Update keystore.jks

keytool -delete -alias s1as -keystore keystore.jks -storepass [whateverismymasterpassword]

keytool -delete -alias glassfish-instance -keystore keystore.jks -storepass [whateverismymasterpassword]

keytool -genkeypair -alias s1as -dname "CN=myservername,OU=myunit,O=MyOrganization,L=MyTown,C=FI" -keyalg RSA -keysize 2048 -validity 3650 -keystore keystore.jks -keypass [whateverismymasterpassword] -storepass [whateverismymasterpassword]

keytool -genkeypair -alias glassfish-instance -dname "CN=myservername,OU=myunit,O=MyOrganization,L=MyTown,C=FI" -keyalg RSA -keysize 2048 -validity 3650 -keystore keystore.jks -keypass [whateverismymasterpassword] -storepass [whateverismymasterpassword]

#Check keystore.jks

keytool -list -keystore keystore.jks -storepass [whateverismymasterpassword]

#Export certificates from keystore.jks

keytool -exportcert -alias s1as -file s1as.cert -keystore keystore.jks -storepass [whateverismymasterpassword]

keytool -exportcert -alias glassfish-instance -file glassfish-instance.cert -keystore keystore.jks -storepass [whateverismymasterpassword]

#Update cacerts.jks

keytool -delete -alias s1as -keystore cacerts.jks -storepass [whateverismymasterpassword]

keytool -delete -alias glassfish-instance -keystore cacerts.jks -storepass [whateverismymasterpassword]

keytool -importcert -alias s1as -file s1as.cert -keystore cacerts.jks -storepass [whateverismymasterpassword]

#Trust this certificate? [no]: [Enter 'yes']

keytool -importcert -alias glassfish-instance -file glassfish-instance.cert -keystore cacerts.jks -storepass [whateverismymasterpassword]

#Trust this certificate? [no]: [Enter 'yes']

#Check cacerts.jks and tidy up

keytool -list -keystore cacerts.jks -storepass [whateverismymasterpassword]

rm s1as.cert glassfish-instance.cert

exit

Done! Nyt on uudet ja omat avaimet serverillä, ja aiemman vaiheen ansiosta uudella master salasanalla suojattuna. Tässä voi välivaiheena allekirjoituttaa sertifikaattinsa jollain virallisella taholla jos haluaa tuotantokäyttöön sopivan vimpaimen.

Serveriheaderien obfuskointi – äläpä kerro enempää!

Yksi oma lempiaiheeni tietoturvassa on ollut suojata systeemeitä siten että ne eivät kerro tarpeettoman paljon itsestään .- esim. header joka sanoo: X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7) – suorastaan kirkuu googlettamaan seuraavaksi haavoittuvuuksia, oletustunnuksia, ja täsmähyökkäysohjelmia. Mitä vähemmän paljastaa tietoa ulospäin sen vaikeampaa on heti tietää mitä hyökkäyksiä soveltaa. Vielä kierompaa on näyttää misinformaatiota – esim. ajaa IIS palvelinta joka väittää olevansa Glassfish tai Glassfishiä joka väittää olevansa Websphere jne.

Tässä komennot joilla voit tukahduttaa näitä headereita. Huom! Ne muuttavat domain1/config/domain.xml tiedostoa, joten syytä taas olla glassfish tunnuksena sisässä (komento whoami kertoo mikä on tunnuksesi). Glassfish serverin tulee olla päällä.

#start glassfish if it's not running
sudo service GlassFish_domain1 start

#Ensure that you are running as user 'glassfish'!!
sudo su --shell /bin/bash glassfish

#Check HTTP headers
# Check HTTP response headers (as shown below) to make sure that there are
# clues as to the server or its version. Look for any mention of
# 'GlassFish', 'X-Powered-By', etc. If necessary:

asadmin create-jvm-options -Dproduct.name=

asadmin set server.network-config.protocols.protocol.http-listener-1.http.xpowered-by=false

asadmin set server.network-config.protocols.protocol.http-listener-2.http.xpowered-by=false

asadmin set server.network-config.protocols.protocol.admin-listener.http.xpowered-by=false

Samalla voit myös tsekata virhesivut, esim. 404 sivua ei löydy kertoo usein paljonkin serveristä. Se on muutenkin hyvä ottaa omaan haltuun. Voit tehdä tämän toki sovelluskohtaisenakin, mutta tässä on serverikohtainen asetus:

asadmin set server.http-service.virtual-server.server.property.send-error_1="code=404 path=/opt/glassfish4/glassfish/globalhtml/404.html reason=Resource_not_found"

Tämä menee domain.xml:ään – jota toki voi käsinkin muokata. Muillekin virheilmoituksille voi tehdä vastaavia. Saatat myös haluta disabloida/poistaa/vaihtaa juuri-kontekstin oletussivun ja sovelluksen.

Lopuksi tietysti buutataan mylly

#Restart to take effect

exit

sudo service GlassFish_domain1 restart

Virtuaalikoneen säädöt ja muisti

Virtuaalikoneen tuunaus on ihan oma taiteenlajinsa – sitä voi harrastaa web-admin konsolista, tai domain.xml tiedostoa editoimalla, mutta onnistuu se komentoriviltäkin:

#List current JVM options

asadmin list-jvm-options

# Now update some important JVM settings. 
# Of course use memory as you need to, so if you like 64GB max heap, go for it!

asadmin delete-jvm-options -Xmx512m
asadmin create-jvm-options -Xmx2048m
asadmin create-jvm-options -Xms1024m

# and run with -client or -server optimizations
# -client boots up faster, server optimizes tighter on longer run
# -client is now the default, so if you like -server:

asadmin delete-jvm-options -client
asadmin create-jvm-options -server

Siinä kaikki tällä erää. Moderni sovelluspalvelin on sillä tavalla kiehtova paketti että se sisältää hurjasti piirteitä, palveluita, ja yksityiskohtia. Monet näistä periaatteista pätevät hyvinkin muihinkin servereihin, kuten Tomcat ja JBOSS, ja miksei myös WebSphere/Weblogic. Toivottavasti näistä on apua.

 

Oracle Java 8 Debianiin

Jep jep, lisenssiyhteensopivuusongelmista johtuen Oraclen virallinen Java 8 on hieman mutkatonta hankalampaa saada Debianiin. Samoin Java 7. Vaihtoehto on toki asentaa OpenJDK. Mutta sattuneesta syystä törmäsin artikkeliin jossa neuvotaan miten myös Oracle Java 8 on asennettavissa – sekä JRE että JDK.

Jippo on tässä:

su -
echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list
echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EEA14886
apt-get update
apt-get install oracle-java8-installer
exit

Jep, ei sen kummempaa.Tietysti voit myös pistää sudo komennon joka komentosarjan alkuun.

Jippo on siinä että repositorystä ei löydy varsinaisesti Java 8 versiota – vaan vain installer. Kun sen asentaa ja ajaa, tulee lisenssiehtojen hyväksyntädialogi. Ja sitten tippuu varsinainen Java.

Ja tietysti tarkistetaan mikä Java on kyseessä komennolla:

java -version

Tähän asennukseen sisältyy tietysti myös automaattiset päivitykset.

Vinkin lähde:

http://www.webupd8.org/2014/03/how-to-install-oracle-java-8-in-debian.html