JavaOne 2014 käynnissä

Jep, JavaOne 2014 on taas käynnissä San Franciscossa. En ole tänä vuonna itse paikan päällä, mutta aika on merkattuna kalenteriin ja seuraan mielenkiinnolla etänä.

Missä mennään tällä hetkellä on Java 8 SE käyttöönotto Lambdoineen kaikkineen, ja ME 8 on myös julkaistu, ja EE 8 työn alla seuraavaksi. Olen blogaillut aiemmin jo Javan seuraavista askelista, Java SE 9 tulee ehkä viimein näyttämään mitä Project Jigsaw – Javan modulaarisuusjärjestelmä tarkoittaa. Se ei ole lopulta erityisen seksikäs aihe, mutta se on tärkeä. Javasta on vuosien saatossa tullut aikamoinen bloat, turvoke 😉 Ajatus modulaarisemmasta Javasta on hyvä skaalatessa pienempään päin, ja Mavenin suosio näyttää että moduulien avulla skaalaus ylöspäin on myös tärkeää. Jos viimein saadaan Javaan tukea myös moduulien versioiden huomioimiseen ihan ydintasolla, paketista tulee aika kova. Brian Goetz valitettavasti komennettiin alas lavalta kesken Java 10 mallailun 😉

Jigsaw projektissa on hyvä huomata kaksi vaihetta. Vaihe 1 on purkaa Javan hurja ristiinviittaus-spaghetti pakettien välillä ja saada Javan parikymmentämegaisesta ytimestä aidosti modulaarisempi. Tätähän aloitettiin jo joskus Java 6u10 aikoihin nimellä kernel. Toinen askel on sitten alkaa käyttämään tätä moduulijärjestelmää omien ohjelmistojen kehitykseen yhtälailla, Mavenin tapaan. Tarkoituksena ei näillä näkymin ole kuitenkaan korvata Maveniä repository-puolella, lähinnä moduulien riippuvuuksien julistuksessa. Riippuvuudethan sitten voivat olla paikallisia tai verkon yli noudettavia.

Vaikka on mukava tarkkailla mitä tulevaisuus tuo mukanaan, Java 9 on vielä aika kaukaista. Tämä vuosi 2014 on edelleen Java version 8 ramp-up aikaa: Lambdoissa, rajapintojen oletusmetodeissa, ja kokoelmakirjastojen uusissa stream-piirteissä on sulateltavaa runsaasti ja harva niitä vielä arjessa käyttää. Sertifiointi Java 8:lle on tätä kirjoittaessa vasta beta-tasossa, ja sekin mielenkiintoisella tavalla uusittu.

Tuolla tech keynote joka on klassisesti ollut kiinnostava avaus koko tapahtumalle:

http://medianetwork.oracle.com/video/player/3811045975001

Goetz saa kyytiä kohdassa 34:27 alkaen 😉

Mainokset

Glassfish 4.1, JAX-RS, Jersey, ja Jackson JSON-serializer

Jep, päivitin vähän servereitä Glassfish 4.1 versioon, ja vastaan tuli mielenkiintoinen bugi: JAX-RS palvelut lakkasivat toimimasta ja antoivat sensijaan kaikenlaisia herjoja, niistä ehkä mielenkiintoisin:

Severe: Error occurred when processing a response created from an already mapped exception.
Warning: StandardWrapperValve[com.qpr.entice.common.ApplicationConfig]: Servlet.service() for servlet com.mycompany.jaadajaada.ApplicationConfig threw exception
java.lang.ClassNotFoundException: com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector not found by com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider [129]

Glassfish käyttää oletuksena Moxya JSON serialisointiin, mutta itse käytän Jacksonia suorituskyvyn ja ominaisuuksien johdosta. Mielenkiintoista kyllä Glassfish toimitetaan osittaisin Jackson kirjastoin joten sen käyttöönotto on niinkin helppoa kuin aktivoida se config tiedostossa, tähän tapaan:

import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("rest")
public class ApplicationConfig extends ResourceConfig {

  public ApplicationConfig() {
    packages(true,
       "com.mycompany.jaadajaada",
       "com.wordnik.swagger.jersey.listing");
    register(JacksonFeature.class);
  }
}

Eli rekisteröidään JacksonFeature – ja samantien käytössä on Jackson kirjastot. Aiemmassa Glassfish 4.0:ssa tämä pelasi hienosti – mutta 4.1 antaa ylläolevaa virheilmoitusta. Kokeilin myös jättää JacksonFeaturen pois ja testata pelkkää Moxya mutta sieltä tuli ihan omat herjansa. (Tuossa muuten näkyy myös Swagger joka automaattisesti dokumentoi REST APIt – ja käyttää Jackson kirjastoja)

Mielenkiintoista virheilmoituksessa on, että se viittaa puuttuvaan tiedostoon joka itselläkin oli kirjastopoluissa – mutta käy ilmi kaksi asiaa: se pitää olla Glassfishin alla, ja sen pitää olla oikea versio. Tiedosto joka uupuu on jackson-module-jaxb-annotations-2.3.2.jar, sen pitäisi olla glassfishin alla kansiossa modules, ja tosiaan versionumero 2.3.2, ei uusin. Tämän päälle kun putsaa osgi-cachen ja buuttaa serverin, saa taas REST JSON palvelut takaisin. 😉

Eli aika spesifi pulma. Aika noloa että Glassfishistä on hiljalleen turvonnut kohtuullisen monoliittinen mötikkä jossa on paljon kirjastoriippuvuuksia joita oma sovellus ei pysty helposti ylikirjoittamaan. JBOSS muistuu mieleen äärimmäisen modularisuutensa ansiosta, mutta muistelen kyllä sielläkin olleen aina uuden julkaisun kohdalla kirjastohaasteita. Mutta siellä on esim. web services implementaatio mukavan helposti vaihdettavissa.

Mutta, minä taidan digressoida 😉 Tässä joka tapauksessa virheilmoitus, ja korjaus, ja tuossa linkkiä keskusteluun samasta pulmasta:

https://java.net/jira/browse/GLASSFISH-21141

Teoriassa on mahdollista tehdä korjaus siistimminkin, autodeploy/bundles kansioon asennettavana paikkana joka ei muuta serverin toimintaa, mutta itse en saanut sitä vaihtoehtoa toimimaan.

Netbeans 8.0.1 ja JavaScript, Angular, Require, Grunt,…

Netbeans 8 on ollut kaikista kehutuista ominaisuuksistaan huolimatta Javascript käytössä lähinnä glorifioitu tekstieditori. Tarkoittaen, että ominaisuudet vaativat toimiakseen tietyn HTML5 tyyppisen projektin, esim. Maven tai web projektit eivät kelpaa, saati sitten freeform kansiot. Sen kanssa on pärjäilty tähän asti, lähinnä Maven-tuen ja Git-tuen hyvän integraation vuoksi.

Nyt tuli kuitenkin putkesta ulos 8.0.1 päivitys, ja siinä on pieniä parannuksia tälle kentälle. Jatkossakin on vielä varaa paljon parantaa – mutta jokainen askel eteenpäin on hyvästä.

Yksi päivityksistä on parempi tuki require-moduulihallinnalle. Se löytyy nyt myös Maven projektin asetuksista:

RequireJS kirjastot

Kuten dialogista näkee, voi halutessaan määritellä polkuja myös manuaalisesti jotta moduulit löytyvät – rasti ruudussa pitäisi kuitenkin pitkälti riittää. Kun moduulit löytyvät, monet intellisense/content assist mahdollisuudet paranevat:

Content assit for require paths

Intellisense

Tosiaan kaukana ollaan vielä täydellisyydestä, parannettavaa on vielä. Intellisense on paranemaan päin mutta esim. angular templateiden ymmärtäminen aivan alkutekijöissä: nykyisellään niistä tulee lukemattomia html5 sääntömotkotuksia mm. attribuuteista ilman arvoja tai siitä mikä elementti voi olla missäkin kohtaa. Useimmat niistä ovat vääriä hälyytyksiä, mutta niiden sekaan häviävät sitten merkityksellisetkin.

Tosiaan editoripuolella suosittu vaihtoehtohan on Webstorm, itse en siitä niin innostunut koska kaupallinen ja koska Maven projektituki edelleen ainakin omalle logiikalle kehno. Muita hyviä keveämpiä open source editoreita ovat mm. Brackets, sekä Sublime. Mukavasti grunt/mavenillä rakennetussa projektissa on kivaa se että voi käyttää mitä editoria haluaa, kunhan koodin muotoiluasetukset ovat yhtenevät. Brackets tuli blogin lukijavinkkinä, ja olen siihen tykästynyt.

Klusteri-uniikit id-arvot Java EE/EJB/JPA

Uniikkien avainten kuten Primary Key-arvojen generointi on hauska juttu. Siihen on tarve lähes joka projektissa, ja siihen on lukemattomia eri tapoja. Yksi hurjimmista on laavalampun kuvioiden käyttö satunnaisluvun generointiin – mutta konservatiivisemmalta puolen löytyy mm. sequence, identity keinot jotka ovat kantakohtaisia. Korkeamman tason abstraktiot kuten JPA abstraktoivat halutessaan myös tämän: GeneratedValue-annotaatio antaa kannan päättää mikä kolmesta id-generointitavasta on fiksuin.

Tähän tulee kuitenkin vähän pykälää lisää jos ei voida syystä tai toisesta käyttää JPA generointia. Kenties halutaan ottaa itse avaimen generointi hallintaan koska siihen liittyy erityissääntöjä. Kenties on tarpeen generoida identity-kentän ohella toinen, uniikki avain joka ei kuitenkaan ole primary key. Pikkasen lisää haastetasoa saadaan jos homma pitää vielä tehdä klusterissa – silloin mikään muistinvarainen ratkaisu ei piisaa – ellei muistia synkronoida verkon yli sopivalla tapaa.

JPA:sta ja Hibernatesta löytyy kyllä valmiina generaattoreita, mutta ainakin JPA standardipuolella pääsy niiden mekanismeihin erillään primary key autogeneroinnista on heikko.Mitä? Minä olen ainakin uniikki!

Joten tähän vähän omia mietelmiäni ja koodia siirrettävästä geneerisestä klusteriystävällisestä primary key generoinnista. Tämä on iteraatio 1 joten päättelyssä ja toteutuksessa voi olla aukkoja, mutta päätin silti paljastaa itseni maailmalle – yksi mukava juttu blogeissa on että niitä voi kommentoida ja palaute on tässäkin tervetullutta jos jokin pistää silmään.

Ensiksi tarvitaan taulu kantaan, josta voi saada niitä arvoja. Sen voi hoitaa esim. JPA Entity Objectilla tähän tapaan:

 

@Entity
public class GenTableEntity implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  private String tableName;
  private Long lastId;

  public String getTableName() {
    return tableName;
  }

  public void setTableName(String tableName) {
    this.tableName = tableName;
  }

  public Long getLastId() {
    return lastId;
  }

  public void setLastId(Long lastUsed) {
    this.lastId = lastId;
  }
}

Tästä esimerkistä jätetty pois Javan rakkaat equals, hashCode ja toString toteukset sekä muut hienosäädöt. Kyseessä on siis taulu jossa on String primary key, ja Long arvo jota voidaan (transaktiossa) paukutella.

Seuraava elementti: Singleton, joka pitää yllä id listaa, ja imaisee tarvittaessa serveriltä lisää.

@Singleton
public class UniqueIdGeneratorSingleton {

  private long ceiling; 
  private long current; 
  private static final long RANGE = 1000; 
  private static final String SEQUENCE_NAME = "myitem";

  @PersistenceContext
  private EntityManager entityManager;

  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  public long getUniqueId() {
    if (ceiling == 0 || current > ceiling) {
     GenTableEntity entity = entityManager.find(GenTableEntity.class,
        SEQUENCE_NAME, LockModeType.PESSIMISTIC_WRITE);
      if (entity == null) {
        entity = new GenTableEntity();
        entity.setTableName(SEQUENCE_NAME);
        entity.setLastId(0L); // Reserve space
        entityManager.persist(entity);
      }
      current = entity.getLastId() + 1;
      ceiling = entity.getLastId() + RANGE; 
      entity.getLastId(ceiling); 
    }
    return current++;
 }
}

Mitä täällä tapahtuu? Kyseessä on generaattori-EJB joka hakee ja tallettaa kantaan mihin lukemaan asti on id:t käytössä. Tässä on optimointijippo: kannasta ei haeta yksi id kerrallaan, vaan tässä koodissa tuhannen erissä. Yhtälailla erä voi olla sata, tai kymmenentuhatta. Ceiling-arvo ja kannassa oleva lastId arvo pitävät kirjaa mihin asti id avaruutta on varattu. Singleton jakelee ensin omasta jäsenmuuttuja-avaruudestaan kaikki arvot, ja kun ne loppuvat, haetaan kannasta seuraava tuhannen viipale.

Koska kyseessä on Singleton bean, metodiin pääsee yksi säie kerrallaan – serverissä. Klusterissa voi kuitenkin olla useampi serveri, joissa voi käydä niin huonosti että jokaisessa ajetaan juuri samaa riviä samasta singleton-koodista. Siksi tässä on päällä vielä transaktiot, ja pessimistinen lukulukko. Kun yksi säie on lukenut rivin kannasta, se lukitaan ja seuraavan kerran siihen pääsee käsiksi vasta transaktion päätyttyä  -kun arvoa on onnistuneesti muutettu.

Huom. tässä mallissa SEQUENCE_NAME on kovakoodattu arvoon ’myitem’ – joten kaikki generoitavat id:t ovat osa samaa, suurta, globaalia arvoavaruutta. Tätä voi muokata helposti siten että parametrina annetaan taulunimi, silloin joutuu tosin id-cachen rakentamaan Map-muotoiseksi.

Testailin tätä hieman eri kanteilta. Suorituskyky riippuu hyvin paljon range-arvosta. Id-generointi ilman kantaosumaa on muutamia millisekunteja, kannan kanssa jutellessa niitä alkaa palamaan satakertaisesti. Range arvona tuhat on aika mukava, turhan suuret range arvot voivat syödä avaruutta turhankin nopeasti, etenkin jos servereitä tiheään buuttaillaan, päivitellään, tai ne kaatuilevat useita kertoja päivässä (No jos niin käy, tämä on pienimpiä ongelmista).

Tätä on tietysti kiva testata myös rinnakkaisesti. Testausta helpottaa kovasti jos tässä on esim. REST api edes hetkellisesti päällä. Testasin tätä restassured + java concurrency kirjastolla esim. näin:

 

@Test
public void getUniqueIdShouldReturnTwentyUniqueValuesWithParallelExecution() throws Exception {

 final int setSize = 2000;

 Callable<Set<Long>> c = new Callable() {
    @Override
    public Set<Long> call() throws Exception {
      Set<Long> idSet = new HashSet<>();
      for (int i = 0; i < setSize; i++) {
        idSet.add(fetchUniqueId());
      }
      return idSet;
    }
  };

  Set<Long> masterSet = new HashSet<>();

  Future<Set<Long>>[] futures = new Future[10];

  for (int i = 0; i < 10; i++) {
    futures[i] = Executors.newCachedThreadPool().submit(c);
  }

  for (int i = 0; i < futures.length; i++) {
    Set<Long> keys = futures[i].get();
    masterSet.addAll(keys);
  }

   // Set only accepts unique values, duplicates are not added
   // as long as equals() and hashcode() are implemented properly
   assertEquals(setSize * 10, masterSet.size());
}

private Long fetchUniqueId() {
  Response response = given()
    .when()
    .get("version/uniqueid")
    .then()
    .statusCode(200)
    .extract().response();
  
    Long id1 = response.jsonPath().getLong("id");
    return id1;
}

Eli ihan mukavasti tuo toimii, hyvä niksi hihassa. Aika armottomasti yritin tätä paukutella nurin mutta tarpeettomankin vakaasti pelittää. En löytänyt taas pikaisella googletuksella suoranaisesti tällaista mistään, joten kirjoittelin itselleni muistiin.

Mutta palautetta tulemaan jos tulee jotain omia ajatuksia mieleen! Tämä on taas semmoinen juttu attä aivan varmasti joku jossain on jo paremmin tehnyt. Toisaalta 90% JPA käyttäjistä ei asiaa koskaan mietikään koska @GeneratedValue. :=)

 

 

 

 

 

Grunt, Protractor, ja Istanbul kattavuusraportit e2e-testeille

Tuli ajankohtaiseksi pohtia voiko API ja E2E testeistä saada koodikattavuusanalyysejä. Käy ilmi, että Angular-alustalla Protractor ajoista voi. Yritin ensin helppoa reittiä valmiin grunt-protractor-coverage plug-inin kanssa, mutta törmäsin toistuvasti kahteen ärsyttävään virheeseen joista ei löytynyt lisätietoa ja jotka eivät ratkeeneet. Joten löysin ratkaisun joka on vielä yksinkertaisemmista paloista koottu: Instanbul moduuli ja vähän magiaa.

Istanbulille on tehty monia Grunt-plugineita, itse päädyin käyttämään perusmallia taichi.

https://github.com/taichi/grunt-istanbul

Plugarin asennus ja lataus on ihan normikamaa. Tärkeät taskimäärittelyt ovat instrument, ja makeReport.

Instrument tähän tapaan:

    instrument: {
      files: 'app/*.js',
      options: {
        lazy: true,
        basePath: 'test/coverage/instrument/'
      }
    }

Tuossa app/*.js on kansio jossa koodit muhivat, ja test/coverage/instrument on kansio johon instrumentoidut versiot koodista kopioituvat. Tämä prosessi muuttaa koodien rakennetta rajusti joten todella syytä pitää erillisiä kopioita, ja suojata omat lähdekoodit.

Tämän magian kannalta on hyvä lisätä vielä coverageVariable muuttuja, eli lopullinen ratkaisu tässä:

    instrument: {
      files: 'app/*.js',
      options: {
        lazy: true,
        coverageVariable: '__coverage__',
        basePath: 'test/coverage/instrument/'
      }
    }

Näin kun tätä instrumentoitua koodia ajetaan, kutsut päivitetään tähän globaaliin coverage muuttujaan – jonka me voimme napata (oletusnimi on aika härpäke aikaleimoineen, siksi määrittelemme sen uudelleen).

Tämän ohella on syytä clean-taskilla putsata ensin coverage kansio, sitten copy-taskilla siirtää kaikki ei-javascript tauhkat joita e2e testaukseen tarvitaan, sisältäen esim. html, kuvatiedostot, tyylisivut, jne – tietysti valmiiksi prosessoituna e2e-käyttöön kelvollisina. Tässä esimerkki copy-taskin sisällöstä:

coverageE2E: {
 files: [
 {expand: true, cwd: './dist/lib', src: '**/*.*', dest: 'coverageE2E/lib'},
 {expand: true, cwd: './dist/', src: '**/*.html', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.png', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.jpg', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.gif', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.ico', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.svg', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.css', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.css', dest: 'coverageE2E'},
 {expand: true, cwd: './dist/fonts', src: '*.*', dest: 'coverageE2E/fonts'},
 {expand: true, cwd: './dist/lib', src: '*.*', dest: 'coverageE2E/lib'},
 {expand: true, cwd: './WEB-INF', src: '*.*', dest: 'coverageE2E/WEB-INF'},
 // Here, extra copy operation since istanbul puts instrumented code in a subdir to a wrong path
 {expand: true, cwd: './coverageE2E/dist', src: '**/*.*', dest: './coverageE2E'}
 ]
 }

Nyt kun asiaa oikein ääneen mietin, niin kenties tätäkin voisi yleistää, esim. kopioi kaikki ei- .js päätteiset tiedostot?

Nykyisellään Istanbul instrumentointi pakottaa kohdekansioon hakemistorakenteen missä lähdekansio on – joka ei ole aina haluttua. En löytänyt pluginista säätöjä, joten tuossa copy taskissa kopioidaan dist-kansion sisältö tasoa ylemmäs, jotta se on rakenteessa jota itse käytän myös testeihin ja tuotantoon.

Seuraavaksi tulee se dirty trick: Napataan kerätty __coverage__ muuttuja ja kirjoitellaan se tiedostoon, jahka kaikki coverage on kerätty. Tämä on aivan varmasti tehtävissä nätimminkin – mutta tässä on esimerkkinä protractor-taskin onComplete-funktio joka ajetaan sen lopuksi:

onComplete: function() {
  // Let's write code coverage analysis to a file!
  browser.driver.executeScript("return __coverage__;").then(function(val) {
  fs.writeFileSync("coverageE2E/coverage.json", JSON.stringify(val));
  });
}

Lopuksi analysoidaan coverage.json tiedosto makeReport-taskilla:

module.exports = {
 src: 'coverageE2E/coverage.json',
 options: {
 type: 'lcov',
 dir: '../../../target/e2ecoverage',
 print: 'detail'
 }
};

Ja tässä kooste koko e2e_coverage taskista:

 

 

module.exports = function(grunt) {
 grunt.registerTask('e2e_coverage', [
   'dev', // First do normal build to /dist folder
   'clean:coverageE2E', // clean away old instrumented code
   'instrument', // Instrument all javascript files to instrumented folder using Istanbul
   'copy:coverageE2E', // Copy all non-javascript resources from dist to instrumented code
   'express:coverageE2E', // Run express server using instrumented folder, not dist folder
   'protractor:coverage', // Run protractor tests using instrumented folder
   'makeReport' // Use Istanbul reporting
  ]);
};

Eli tiiviisti: Käännä, putsaa vanhat pois, instrumentoi koodi Istanbulilla, kopioi html:t, tyylisivut ja kuvat sinne sekaan, aja serveri ja protractor testit instrumentoidun koodin kansiosta, ja rakenna raportti tuotoksista, taas Istanbul-pluginilla.

Nyt – tätä olisi mukavaa analysoida Sonarissa, mutta näyttäisi että siellä on Javascript-pluginissa paikka vain yhdelle lcov tiedostolle…

Huom. myös – tuon coverage tiedon keruuvaiheen voisi tehdä elegantimminkin grunt-protractor-coverage pluginilla, löytyy täältä:

https://www.npmjs.org/package/grunt-protractor-coverage

Omissa kokeiluissa en kuitenkaan saanut tuota toimimaan, se antoi kahta eri virhettä – voi johtua käytössä olevista kirjastokombinaatioista, kansiorakenteista, tms, mutta en viitsinyt haaskata siihen enempää aikaa.