Links

  • 1. Sogeti
  • 2. JBoss
  • 3. IBM
  • 4. Oracle
  • 5. SpringSource
  • 6. NL-JUG
  • 7. Java

Archives

Syndication  RSS 2.0

RSS 1.0
RSS 2.0

Bookmark this site

Add 'JCN Blog' site to delicious  Add 'JCN Blog' site to technorati  Add 'JCN Blog' site to digg  Add 'JCN Blog' site to dzone

Posted by Martijn Cremer at 11:29 on Tuesday 29 October    Add 'Are you a Master of Java?' site to delicious  Add 'Are you a Master of Java?' site to technorati  Add 'Are you a Master of Java?' site to digg  Add 'Are you a Master of Java?' site to dzone

Met enige trots delen we vanuit Sogeti Nederland & de NLJUG dat de Masters of Java terug is van weggeweest! We willen jou uitdagen om samen met een andere Javaan mee te doen met deze ‘funprogging contest’.

Masters of Java is een programmeerwedstrijd met verschillende grappige of interessante opdrachten die je binnen dertig minuten op moet lossen. Met iedere seconde die je overhoudt, scoor je een punt. Het team dat aan het einde van het event de meeste punten heeft, mag zich ‘Master of Java 2013′ noemen. Natuurlijk zijn daarbij mooie prijzen te winnen.

En hoewel het evenement inderdaad bedoeld is als ‘funprogging contest’, betekent dat niet dat iedereen het slechts voor het plezier meedoet. Integendeel: in het verleden heeft er al vaak een verhitte strijd plaatsgevonden tussen de deelnemers. Ook dit jaar hopen we de passie die wij als Javanen hebben daar te zien uitspatten.

 Je kunt je hier inschrijven!

Posted by Milo van der Zee at 15:14 on Friday 18 October    Add 'Memory leak investigation' site to delicious  Add 'Memory leak investigation' site to technorati  Add 'Memory leak investigation' site to digg  Add 'Memory leak investigation' site to dzone

We all know the hassle of investigating memory leaks in Java. Tools like jConsole and jVisualVM help a lot. Especially one function I found out about recently is very useful.

In jVisualVM it is possible to walk through a heapdump and find out about the ‘Nearest GC root’ of an object. What I find extremely helpful is that it is possible to right-click on the GC-root and then select ‘Show in Threads’. This results in heavy cpu usage and after a while in a page showing the stacktrace leading to this GC-root. Now you know exactly which methods and which objects result in this object and so are a huge step in the direction of solving the memory leak. Saved my day.

Posted by Eric Gunnewegh at 9:14 on Tuesday 20 August    Add 'JMS 2.0' site to delicious  Add 'JMS 2.0' site to technorati  Add 'JMS 2.0' site to digg  Add 'JMS 2.0' site to dzone

Inleiding

Eén van de vernieuwde API’s in JEE7 is JMS 2.0. De JMS API is lang stabiel gebleven na de release van JMS 1.1 in 2002. Sinds JavaEE 1.4 maakt JMS 1.1 onderdeel uit van het Java EE platform. Twee zaken die opvallen in de nieuwe JMS API zijn het vereenvoudigde programmeermodel en het gebruik van de nieuwe features die het Java SE platform inmiddels biedt met Java SE 7. Daarnaast zijn er aan de JMS API ook een aantal nieuwe features toegevoegd.

Vereenvoudigd programmeermodel

In figuur 1 is het klassieke JMS programmeermodel weergegeven dat bestaat sinds 2002.

 

JMS 1.1

Figuur 1: Het klassieke JMS 1.1 programmeermodel

In JMS 2.0 is dit programmeermodel vereenvoudigd met de introductie van de JMSContext, zoals weergegeven in figuur 2. De JMSContext combineert de Connection en Session objecten in één object. Daarnaast bevat de nieuwe API de nieuwe JMSConsumer en JMSProducer objecten. De klassieke API wordt overigens niet vervangen door de nieuwe API. Beide API’s blijven naast elkaar bestaan. Wat dit vereenvoudigd programmeermodel betekent voor de Java code, laat zich goed illustreren door codefragment 1.

JMS 2.0

Figuur 2: Het vereenvoudigde JMS 2.0 programmeermodel

   @Resource(lookup = “java:comp/DefaultJMSConnectionFactory”)
   private static ConnectionFactory connectionFactory;

   @Resource(lookup = “jms/TestQueue”)
   private static Queue queue;

   String message = “Een test message”;
   try (JMSContext context = connectionFactory.createContext();) {
      context.createProducer().
         setDeliveryMode(DeliveryMode.NON_PERSISTENT).
         setPriority(9).
         setTimeToLive(10000).
         send(queue, message);
   } catch (JMSRuntimeException e) {
      System.out.println(e);
   }

Codefragment 1: Het versturen van een message

Codefragment 1 laat zien hoe je met de vernieuwde JMS API op vereenvoudigde manier een bericht kunt sturen. Vergeleken met de klassieke API vallen een aantal zaken op.

  1. Een Producer creëren gaat sneller via een JMSContext dan in het oude model via achtereenvolgens een Connection en een Session.
  2. Er hoeft niet eerst een TextMessage gecreëerd te worden. De Producer accepteert ook een String.
  3. Het creëren van JMSContext gebeurt in een try-with-resources block, een nieuw feature van het Java SE7 platform. De JMSContext interface extends de AutoCloseable interface, zodat bij het afsluiten van het try-with-resources block automatisch de close() methode wordt aangeroepen.
  4. Bij het creëren van de JMSProducer kan method chaining gebruikt worden voor het zetten van de diverse opties. In JMS 2.0 hebben de diverse setters voor het zetten van opties, headers en properties de JMSProducer als return value, wat method chaining mogelijk maakt.

Ook het ontvangen van berichten is vereenvoudigd. Zie ter illustratie het volgende codevoorbeeld waarbij het niet nodig is om een Message om te zetten naar een TextMessage om hier vervolgens de body uit op te vragen.

   String msg = context.createConsumer(queue).receiveBody(String.class, 1000);

Injectie van JMSContext

In een servlet of EJB is het mogelijk om direct de JMSContext te injecteren, in plaats van deze aan te maken via een geïnjecteerde ConnectionFactory.

   @Inject
   @JMSConnectionFactory(“jms/MyConnectionFactory”)
   private JMSContext context;

Wanneer gebruik gemaakt wordt van de default ConnectionFactory, kan de @JMSConnectionFactory achterwege gelaten worden.

sessionMode

De introductie van de sessionMode biedt de ontwikkelaar een duidelijker keuze in het gebruik van een transactionele sessie of een acknowledge mode. In de klassieke JMS API bevat het Connection object de volgende methode die de ontwikkelaar op het verkeerde been kan zetten.

   Session createSession(boolean transacted, int acknowledgeMode) throws JMSException;

Het probleem met deze methode is dat niet alle combinaties valide zijn. Bij een transactionele sessie (transacted=true) vindt een acknowledgement automatisch plaats na een commit. In deze situatie heeft het geen zin om een acknowledgeMode op te geven. Andersom geldt ook dat een acknowledgeMode alleen betekenis heeft bij transacted=false.

De vernieuwde JMS API biedt meer duidelijkheid met de volgende methode in het Connection object

   Session createSession(int sessionMode) throws JMSException;

of de volgende methode in het ConnectionFactory of JMSContext object.

   JMSContext createContext(int sessionMode);

De sessionMode kan één van de volgende waarden hebben, waardoor de ontwikkelaar moet kiezen tussen een transactionele sessie of een acknowledgement mode.

   Session.SESSION_TRANSACTED
   Session.CLIENT_ACKNOWLEDGE
   Session.AUTO_ACKNOWLEDGE
   Session.DUPS_OK_ACKNOWLEDGE
   Session.TRANSACTED

Hoewel dit een stuk duidelijker is dan in de klassieke JMS API, geldt ook hier dat niet elke waarde in alle situaties geldig is. Bijvoorbeeld, als de methode wordt aangeroepen in een Web of EJB container in een actieve transactionele JTA context, wordt de sessionMode genegeerd. Voor de details wordt verwezen naar de Javadoc, die met betrekking tot dit onderwerp in JMS 2.0 ook een stuk uitgebreider is geworden, zie http://docs.oracle.com/javaee/7/api/javax/jms/Connection.html#createSession(int).

Shared subsriptions

Eén van de nieuwe features in de JMS 2.0 API zijn de shared subscriptions op topics. Voor wat betreft topics waren er voorheen twee varianten, durable en non-durable topics, die beiden alleen unshared subscriptions ondersteunden. In JMS 2.0 kunnen subscriptions ook shared zijn.

In de JMS 1.1 API konden meerdere consumers een eigen subscription hebben op hetzelfde topic. Elke consumer met een eigen subscription (unshared subscription) ontving dan elk bericht dat op het topic gepubliceerd werd. Pas in JMS 2.0 is het mogelijk dat meerdere consumers een subscription kunnen delen (shared subscription). De berichten die op een topic met een shared subscription gepubliceerd worden, worden door de JMS provider verdeeld over de consumers die bij de shared subscription horen, waarmee het mogelijk wordt berichten parallel af te handelen in meerdere threads.

Exception handling

In de JMS 2.0 API wordt de unchecked JMSRuntimeException gebruikt in plaats van de checked JMSException, zie bijvoorbeeld ook codefragment 1. Dit betekent dat de aanroeper van de methodes in de JMS 2.0 API niet verplicht is deze Exception af te vangen.

Zie ter illustratie ook de createTextMessage() methode in respectievelijk de objecten Session en JMSContext.

   //klassieke API
   TextMessage createTextMessage() throws JMSException;

   //JMS 2.0
   TextMessage createTextMessage();

Wat ook een verbetering is in de JMS 2.0 API is dat de JMSRuntimeException nu ook een constructor heeft met een Throwable als argument. Bij de klassieke JMSExcepion ontbrak een dergelijke contstructor. In plaats daarvan heeft de JMSExcepion een linkedException, die in de praktijk vaak over het hoofd wordt gezien.

Aan de slag met JMS 2.0

Voor wie zelf wil ontdekken wat JMS 2.0 nog meer te bieden heeft, kan snel aan de slag met GlassFish en de JEE 7 SDK. De downloads bevatten diverse examples. Wie gebruik maakt van de built-in JMS Provider van GlassFish, is QBrowser een handige tool voor het bekijken van queues, topics en berichten.

http://www.oracle.com/technetwork/java/javaee/downloads/index.html
http://sourceforge.net/projects/qbrowserv2/
http://docs.oracle.com/javaee/7/tutorial/doc/partmessaging.htm#GFIRP3
https://jms-spec.java.net/2.0/apidocs/

Posted by Erwin De Gier at 8:30 on Tuesday 2 July    Add 'Websockets in Java EE 7' site to delicious  Add 'Websockets in Java EE 7' site to technorati  Add 'Websockets in Java EE 7' site to digg  Add 'Websockets in Java EE 7' site to dzone

Een van de nieuwe standaarden in Java Enterprise Edition 7 is de API voor het gebruik van websockets. Websockets zijn onderdeel van de HTML5 specificatie en maken het mogelijk een TCP verbinding op te zetten van een browser naar een server. Het is een bidirectioneel kanaal dat full-duplex gebruikt kan worden. Dit heeft veel voordelen boven technieken als polling of long-polling over HTTP. De bericht overhead is lager en de performance daardoor veel beter. Daarnaast is de API gestandaardiseerd (http://www.w3.org/TR/websockets/ ). Websockets kunnen bijvoorbeeld gebruikt worden als er requirements zijn om realtime data heen en weer te sturen of in het geval van push berichten.

Een websocket verbinding wordt geïnitialiseerd over HTTP. Deze wordt vervolgens geüpgrade naar een websocket verbinding. Een websocket url begint in plaats van met http met ws, bijvoorbeeld: ws://localhost:8080/websockets/echo. Dit upgraden gebeurt tijdens de websocket handshake. 
Met Java EE 7 is er nu ook een standaard API voor de het realiseren van de server kant van de websockets verbinding. We beginnen met de project dependencies. Aangezien de websockets API onderdeel is van Java EE 7 hebben we maar één dependency nodig, die ook nog eens “provided” is en dus niet meegepackaged wordt in de uiteindelijke war file:

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

Een websocket bean configureren we doormiddel van annotaties:

import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(“/echo”  )
public class  EchoBean {

         @OnMessage
         public String echo(String message) {
                return message +  ” (from your server)”  ;
       }

}

De @ServerEndpoint annotatie mapt deze bean op een url, in dit geval /echo. De @OnMessage annotatie wordt door de container aangeroepen op het moment dat er een bericht wordt ontvangen. Als je op internet zoekt op Java websockets vindt je ook voorbeelden die gebruik maken van de annotaties @WebSocket en @WebSocketMessage. Dit zijn Glassfish specifieke annotaties en zijn dus geen onderdeel van de Java EE 7 API !

Naast de @OnMessage zijn er nog twee annotaties, @OnOpen en @OnClose. Deze worden gebruikt om acties te definiëren bij het openen en het sluiten van een websocket verbinding. Voorbeeld:

@Singleton
@ServerEndpoint(“/chatsocket”  )
public class  ChatBean {

         private Set<Session>  clients  =  new HashSet<>();

         @OnOpen
         public void onSocketOpened(Session session) throws  IOException {
                clients .add(session);
       }

         @OnClose
         public void onSocketClosed(Session session)  throws  IOException {
                clients .remove(session);
       }

         @OnMessage
         public void onReceivedFrame(Session session,
                                   String message)  throws  IOException {
                for(Session client : clients ){
                      client.getAsyncRemote().
                      sendText(session.getId()+  “: “ +message);
              }
       }
}

Dit voorbeeld illustreert een simpele chatbox implementatie. De ChatBean is geannoteerd met de EJB annotatie @Singleton, waardoor er maar één instantie van deze EJB bestaat zodat we alle websocket sessies kunnen bewaren. De methode onSocketOpened is geannoteerd met @OnOpen. Deze methode wordt aangeroepen als de websocket verbinding tot stand is gebracht. De optionele methode parameter Session representeert een websocket sessie. Deze sessie wordt opgeslagen in een Set, zodat we later alle chatberichten naar alle sessies kunnen sturen.
De methode onSocketClosed is geannoteerd met de annotatie @OnClose, deze wordt aangeroepen bij het sluiten van de WebSocket verbinding. Hier verwijderen we de sessie uit de Set.
In de methode geannoteerd met @OnMessage versturen we het binnengekomen bericht naar alle websocket clients.

Om het voorbeeld compleet te maken hebben we nog een client nodig:

<html>
<body>
        <div style=” text-align: center ;”>
               <form action= “”>
                     text:
                      <input id= “textID” name =“message” value= “Hello WebSocket!”
                                                      type=“text”>
                      <input onclick= “send_echo()” value =“send” type=“button”>< br>
               </form>
        </div>
        <div id= “output”></div >
        <script language=“javascript” type=“text/javascript”>
               var wsUri = “ws://localhost:8080/websockets/chatsocket” ;
               var websocket = new WebSocket(wsUri);
              websocket.onopen = function(evt) {
                     onOpen(evt)
              };
              websocket.onmessage = function(evt) {
                     onMessage(evt)
              };
              websocket.onerror = function(evt) {
                     onError(evt)
              };

               function init() {
                     output = document.getElementById( “output”);
              }

               function send_echo() {
                     websocket.send(textID.value);
                      //writeToScreen(“SENT: ” + textID.value);
              }

               function onOpen(evt) {
                     writeToScreen( “CONNECTED”);
              }

               function onMessage(evt) {
                     writeToScreen(evt.data);
              }

               function onError(evt) {
                     writeToScreen( ‘<span style=”color: red;”>ERROR:</span> ‘
                                                 + evt.data);
              }

               function writeToScreen(message) {
                      var pre = document.createElement(“p” );
                     pre.style.wordWrap = “break-word”;
                     pre.innerHTML = message;
                     output.appendChild(pre);
              }

              window.addEventListener( “load”, init, false );
        </script>
</body>
</html>
 
In Javascript wordt er een WebSocket object instantie gemaakt op basis van een url. Op dit websocket object zijn methodes beschikbaar voor het versturen van berichten en het registreren van methodes die aangeroepen moeten worden bij de onOpen,onMessage , onClose en onError events.
In dit voorbeeld is het mogelijk om een tekst te versturen naar de server met behulp van websocket.send(String text), deze wordt vervolgens bij alle aangemelde clients op het scherm geschreven (onMessage(event)).

Het volledige voorbeeld is te downloaden van https://bitbucket.org/erwindeg/jee7-websockets-demo. Met mvn clean install kan de war file worden gemaakt. Deze kan gedeployed worden op een Java EE 7 gecertificeerde applicatieserver, bijvoorbeeld Glassfish 4. Na deployment is de chat applicatie beschikbaar op http://localhost:8080/websockets/.
Open 2 browser sessies en navigeer naar http://localhost:8080/websockets/. Als op in de ene sessie tekst verstuurd wordt naar de applicatie, dan verschijnt deze tekst in beide browsers op het scherm.
De browser moet wel ondersteuning bieden voor websockets. Dit voorbeeld is getest op Chrome (versie 27) en Firefox (versie 15).

 

Posted by Jaap Coomans at 16:01 on Sunday 30 June    Add 'Java EE 7' site to delicious  Add 'Java EE 7' site to technorati  Add 'Java EE 7' site to digg  Add 'Java EE 7' site to dzone

Op 28 mei is de definitieve versie van de Java EE 7 specificatie (JSR 342) gereleased. Niet lang daarna volgde op 12 juni de reference implementation GlassFish 4. Dat betekent dus dat we flink aan de slag kunnen om alle nieuwe speeltjes in het echt uit te gaan proberen. Om je daarbij op weg te helpen gaan we de komende weken in een serie blogs de meest interessante nieuwe aspecten van Java EE 7 behandelen. In dit eerste deel van de reeks volstaan we met een overzicht van de API’s in Java EE 7, afgezet tegen de API’s is Java EE 6 (JSR 316). Zo kan je in een oogopslag zien waar er iets veranderd is.

Volgens Oracle is er bij Java EE 7 voornamelijk aandacht besteed aan scalability en een vlugge blik op de press release leert dat er ook sterk naar HTML5 is gekeken. Twee van de vier nieuwe API’s (JSON-P en WebSocket) zijn hier een direct gevolg van. Ook het toevoegen van een stevig uitgebreid JAX-RS aan het Web-Profile ligt in die lijn.

API Java EE 6 Java EE 7
JSR Version JSR Version
Enterprise Java Beans (EJB) 318 3.1 345 3.2
Servlet 315 3.0 340 3.1
Java Server Pages (JSP) 245 2.2 245 2.3
Expression Language (EL) 245 2.2 341 3.0
Java Message Service (JMS) 914 1.1 343 2.0
Java Transaction API (JTA) 907 1.1 907 1.2
JavaMail 919 1.4 919 1.5
Java EE Connector Architecture (JCA) 322 1.6 322 1.7
Web Services 109 1.3 109 1.4
JAX-RPC (Optional) 101 1.1 101 1.1
JAX-WS 224 2.2 224 2.2
JAX-RS 311 1.1 339 2.0
WebSocket n.a. 356 1.0
JSON-P n.a. 353 1.0
Concurrency Utils for Java EE n.a. 236 1.0
Batch n.a. 352 1.0
JAXB 222 2.2 222 2.2
JAXR (Optional) 93 1.0 93 1.0
Java EE Management 77 1.1 77 1.1
Java EE Deployment (Optional) 88 1.2 88 1.2
Java Authorization Contract for Containers (JACC) 115 1.4 115 1.5
JASPIC 196 1.0 196 1.1
JSP Debugging 45 1.0 45 1.0
JSTL 52 1.2 52 1.2
Web Services Metadata 181 2.1 181 2.1
JavaServer Faces (JSF) 314 2.0 344 2.2
Common Annotations 250 1.1 250 1.2
Java Persistence API (JPA) 317 2.0 338 2.1
Bean Validation 303 1.0 349 1.1
Managed Beans 316 1.0 316 1.0
Interceptors 318 1.1 318 1.2
Contexts and Dependency Injection for Java (CDI) 299 1.0 346 1.1
Dependency Injection for Java 330 1.0 330 1.0

Posted by Erwin De Gier at 19:34 on Wednesday 26 June    Add 'Elke dependency is een risico' site to delicious  Add 'Elke dependency is een risico' site to technorati  Add 'Elke dependency is een risico' site to digg  Add 'Elke dependency is een risico' site to dzone

Het is algemeen gebruik om bij het ontwikkelen van Java software gebruik te maken van frameworks en libraries van anderen. In sommige gevallen zijn dit commerciële producten, in andere gevallen open source. De kracht van het gebruik van deze externe libraries is het kunnen hergebruiken van reeds gebouwde functionaliteit en te profiteren van generieke oplossingen voor veelvoorkomende problemen. Het gebruik hiervan heeft echter ook een keerzijde. Je applicatie wordt afhankelijk van andermans code.

Op de korte termijn is er weinig aan de hand. De open source software wordt nog ontwikkeld en de commerciële leverancier levert nog support op de gebruikte versie. De risico’s zitten vooral in de lange termijn. Wat gebeurt er over 5 jaar? En 10 jaar? Wordt het gebruikte framework nog onderhouden? Is het open source project nog in leven? Is er nog support beschikbaar?

Grofweg zijn er 2 mogelijkheden:

1) je betaalt voor support (commercieel)
2) je beheert de code zelf (open source)

Bij punt 1 is het belangrijk dat de leverancier support blijft leveren. Bij punt 2 moet je ervan bewust zijn dat je uiteindelijk de beheerder (eigenaar) van de broncode wordt, als de code niet meer wordt onderhouden en jouw applicatie er nog gebruikt van maakt.

Enkele tips voor het onderhouden van dependencies in een applicatie:
Blijf up to date met de versies en houd in de gaten wanneer de support op een versie verloopt.
Wees bewust van de activiteit van het onderhoud op de broncode.
Bedenk of het echt nodig is om een bepaalde dependency op te nemen.
Wees ervan bewust dat je in het geval van open source op den duur eigenaar kan worden van de code en dus zelf het beheer zal moeten doen.
Maak gebruik van standaarden indien mogelijk. Voor standaarden zijn meestal meerdere implementaties beschikbaar.
In dit licht wordt de keuze voor standaarden uit de Java Enterprise Edition stack steeds makkelijker. De keuze voor frameworks die niet deze standaarden implementeren hoeft alleen maar gemaakt te worden als deze echt onderscheidende functionaliteit bieden.
De enige dependency die we echt nodig hebben (voor JEE6) is deze:

 

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>

Dit geeft ons de mogelijkheid om onder andere de volgende functionaliteit te gebruiken: Object Relational Mapping (JPA), Web components (JSF), Security (JAAS), Transacties (EJB), REST (JAX-RS) en SOAP (JAX-WS) webservices, Dependency Injection (CDI), Interceptors, Decorators, Bean Validation

Met Java EE 7 komen hier nog meer standaarden bij, bijvoorbeeld voor Batch applicaties (JSR 352), Websockets (JSR356) en JSON (JSR 353).

Uiteraard is het noodzakelijk te deployen op een Java EE gecertificeerde applicatie server. Voor Java EE 6 zijn er meerdere mogelijkheden, waaronder Glassfish 3.x en JBoss AS (WildFly) 7.x. Deze doen niet onder voor applicaties servers als Tomcat op het gebied van opstarttijd en voelen net zo ‘lightweight’. Voor Java EE 7 is er Glassfish 4.x en later in het jaar een JBoss (WildFly) 8.x.

Posted by Martijn van de Rijdt at 11:53 on Monday 3 June    Add 'Hoe simpel is SimpleDateFormat?' site to delicious  Add 'Hoe simpel is SimpleDateFormat?' site to technorati  Add 'Hoe simpel is SimpleDateFormat?' site to digg  Add 'Hoe simpel is SimpleDateFormat?' site to dzone

Het komt nog wel eens voor dat je een datum/tijd wilt parsen. Hiervoor kunnen we in Java de standaard Java-klasse SimpleDateFormat gebruiken, op de volgende manier:

private void mijnMethode() {
   ...
   DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   Date date = dateFormat.parse(text);
   ...
}

Dit is correct, maar heeft wel een nadeel: elke keer dat mijnMethode uitgevoerd wordt, instantieert de JVM een nieuwe SimpleDateFormat en dat is een dure operatie. Het zou dus beter zijn om deze eenmaal aan te maken en vervolgens te hergebruiken.

Het ligt nogal voor de hand dit te doen door de DateFormat als constante op te slaan:

// DateFormat als constante; LET OP: niet threadsafe!
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
 
private void mijnMethode() {
   ...
   Date date = DATE_FORMAT.parse(text);
   ...
}

Dit heb ik in het verleden ook een aantal keer geschreven, en ik kom dit nog regelmatig tegen in projecten waar ik aan werk. Helaas is deze oplossing niet correct! (Zonder extra synchronisatie tenminste.)

In de kleine lettertjes van de Javadoc van SimpleDateFormat staat namelijk:


Synchronization

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

Als mijnMethode in meerdere threads gebruikt wordt kan de parse-methode falen met een exceptie of, erger nog, een foute Date teruggeven.

Gelukkig geeft de Javadoc ook een tip: maak een instantie aan per thread. Een makkelijke manier om dit te doen is met behulp van ThreadLocal. De code komt er dan als volgt uit te zien:

// SimpleDateFormat gewrapt in een ThreadLocal, omdat SimpleDateFormat niet threadsafe is.
private static final ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<>() {
   @Override
   protected DateFormat initialValue() {
       return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   }
};
 
private void mijnMethode() {
   ...
   Date date = DATE_FORMAT.get().parse(text);
   ...
}

Posted by Bart Postma at 22:04 on Wednesday 10 April    Add 'Van DatabaseError tot streepje!' site to delicious  Add 'Van DatabaseError tot streepje!' site to technorati  Add 'Van DatabaseError tot streepje!' site to digg  Add 'Van DatabaseError tot streepje!' site to dzone

Afgelopen winter heb ik samen met Ivar een aantal uren kunnen vullen met het oplossen van een venijnige bug. Dit verhaal begint bij het volledig onderuit gaan van een van onze jobserver applicaties. Bij het nalopen van de verschillende log bestanden vinden we al meteen database errors. Logischerwijs wordt er contact gezocht met de database beheerder om navraag te doen over de status van de database. Verrassend genoeg blijkt hier niets vreemds te bekennen en kan de database beheerder niets vinden dat deze situatie kan verklaren. Dat betekent nader onderzoek!

Ons enige aanknopingspunt is de database error in de log bestanden. De database error duidt op een inconsistente status van de jdbc driver. Aangezien we dit probleem niet eerder hebben gehad, moeten we de oorzaak ergens anders zoeken. Wat opvalt is dat deze database error telkens op hetzelfde moment wordt gegooid bij het uitvoeren van een specifieke methode.

Op de betreffende omgeving hebben we niet de mogelijkheid om te debuggen, dus om te kunnen achterhalen wat hier mis gaat hebben we snel een BeanShell scriptje geschreven dat deze methode uitvoert (zoals de jobserver dit ook zou doen) en hierbij zoveel mogelijk output laten genereren. Wat we vervolgens zien is een StackOverflowError die veroorzaakt wordt door een recursieve methode.

De recursieve methode in kwestie hadden we al enig argwaan over en raken we het liefst zo min mogelijk aan. Het betreft namelijk een recursieve methode van +/- 300 regels code. Deze methode bevat logica voor de verschillende mutatie redenen in het systeem. Het idee achter de recursie is dat bij bijvoorbeeld een inkomende SWITCH reden, dit verder wordt afgehandeld als een SWITCHIN en SWITCHOUT. Hiervoor wordt de parameter ReasonObject gecloned, aangepast naar een reason met SWITCHIN en vervolgens wordt hiermee de methode weer recursief aangeroepen.

In het analyseren van de oorzaak van de oneindige recursie vinden we verschillende design/implementatie fouten terug die erg ongelukkig samenkomen. Allereerst halen we het nieuwe reason object uit de database door service.getReason(..) aan te roepen met als parameter een string. De string waarde halen we op uit een enum. Hierbij gebruiken we de waarde van de ReasonConstant.name() in plaats van ReasonConstant.getReason(). Het verschil zit vervolgens in het streepje (-). Zonder het streepje wordt er niets in de database gevonden en wordt null geretourneerd.

De geretourneerde waarde wordt vervolgens gebruikt om te setten op het nieuw geclonede object. Vervolgens hebben we hier een setter methode die bij een parameter waarde van null niks doet. Een setter dient een waarde te zetten, wanneer dit niet mogelijk is met de meegegeven parameter waarde, dan is een IllegalArgumentException op zijn plaats.

Doordat de setter niets verandert aan het geclonede object, wordt de recursieve methode aangeroepen met exact dezelfde parameter waarde met als gevolg een oneindige recursieve aanroep.

Conclusie

Waar deze foutmelding uiteindelijk door is veroorzaakt is een refactoring van de enum ReasonConstants. Hierbij is aan de aanroepende kant de verkeerde methode aangeroepen. Het verschil zit hem in het streepje. Hierdoor kon de enum waarde niet opgehaald worden en geeft deze methode een null waarde terug. Deze null waarde wordt vervolgens bij het setten genegeerd. Vervolgens wordt de recursieve methode weer aangeroepen met een ongewijzigd gecloned object die vervolgens logischerwijs oneindige recursie veroorzaakt. Dit leidt tot een StackOverflowError wat op zijn beurt een inconsistente jdbc driver en database error veroorzaakt.

Lessons learned

  1. Wees voorzichtig in het gebruik van recursieve methoden. Ga hier geen extra logica inbouwen naast de reden waarvoor de methode recursief     is gemaakt. Recursieve methoden verhogen doorgaans de complexiteit en verlagen de onderhoudbaarheid van de code. En zoals gebleken kan een recursieve methode al snel leiden tot oneindige recursie.

  1. Denk na over waarden die je methode kan teruggeven en geef niet zonder erover nagedacht te hebben null terug.

  1. Setter methoden dienen altijd een waarde te zetten of, als dat niet mogelijk is vanwege een parameter waarde die niet ondersteund wordt, een IllegalArgumentException te gooien.

  1. Wees met het gehele team consistent in de design/implementatie keuzes die gemaakt worden. Hou korte design sessies en commit je hieraan als team. Daily stand ups kunnen hier ook positief aan bijdragen.

  1. Testen, testen, testen…..

  2. Don’t be afraid to refactor! Maar wees wel zorgvuldig.

Posted by Thomas at 21:24 on Wednesday 30 January    Add 'Masters of Java 2013' site to delicious  Add 'Masters of Java 2013' site to technorati  Add 'Masters of Java 2013' site to digg  Add 'Masters of Java 2013' site to dzone

Na het succes van de afgelopen keer vond 15 januari weer een Masters of Java plaats. In deze wedstrijd worden deelnemers geconfronteerd met een aantal problemen die ze in een korte tijd in Java moeten oplossen. Voor de correcte oplossing zal afhankelijk van de hoeveelheid bestede tijd een puntenaantal worden toegekend. De winnaar is het team met de meeste punten. De wedstrijd waarin Java kennis en probleemoplossend vermogen wordt getest.Deelnemers in actie

Dit jaar deden er 14 deelnemers mee verdeeld over 8 teams. Prijs voor de eerste plaats was een Raspberry pi. Voor de tweede plaats eenBoek en voor het team op de 3e plaats heeft Ihomer wat goodies gesponsord zoals een T-shirt en muismat. Alles bij elkaar natuurlijk heel mooi prijzen pakket maar het gaat natuurlijk om de eer en daarnaast is gewoon een hele leuke avond om met je mede Java ontwikkelaars in competitie verband programmeren.

Om rustig te beginnen en iedereen te laten wennen aan de ontwikkelomgeving moesten ze eerst een piramide van Pascal maken. Daarna werd het al lastiger, de deelnemers moesten een opdracht oplossen waarin ze getallen moesten omzetten naar Romeinse cijfers en andersom. Het oplossen van een cijferkruiswoord puzzel was daarna aan de beurt. Dit was een bijzonder moeilijke en grote opdracht waarin alle letters zijn vervangen door een getal. Eén woord is gegeven en aan de hand van dit woord en een bibliotheek van woorden moest de rest van de puzzel worden opgelost. Bij de opdracht die daarop volgde ging het helaas mis. Bij een aantal teams traden er excepties op. Wellicht dat deze opdracht in een aangepaste vorm volgende keer terug komt dus deze houden we geheim. Als laatste opdracht moest er een implementatie worden gemaakt van een barcodescanner.

De deelnemers hebben deze Masters of Java als zeer pittig ervaren. Bij de meeste opdrachten was vooral de beperkte tijd de boosdoener. Veel van de teams redden het bij een aantal opdrachten op een haartje na net niet. De avond werd redelijk gedomineerd door één team, namelijk team Trix.

De uitslag van de Masters of Java is als volgt:

  • 1e plaats: Team Trix. Bestaand uit alleen Richard Minne. Hij mag zich Master of Java noemen.
  • 2e plaats: Team Bazinga bestaand uit Angelo Wentzler en Joep Joosten
  • 3e plaats: The Ace of Spades bestaand uit Jasper Kuperus & Frank Poort

Bij dezen wil ik alle deelnemers bedanken. Zo lang mensen het leuk vinden zullen wij het blijven organiseren. Wij hebben er in ieder geval veel plezier van. De leerpuntjes nemen we mee voor de volgende keer. We willen ook meteen een oproep doen voor opdrachten. Als je een leuk idee hebt neem dan contact met ons op via java@sogeti.nl. Wij kunnen je helpen met het uitwerken van de opdrachten. Tot de volgende Master of Java!

Posted by dorppatr at 15:05 on Friday 18 January    Add 'OSS VM Image depot for Windows Azure' site to delicious  Add 'OSS VM Image depot for Windows Azure' site to technorati  Add 'OSS VM Image depot for Windows Azure' site to digg  Add 'OSS VM Image depot for Windows Azure' site to dzone

 

Just recently MS Open Technologies released a depot for finding and sharing Open Source VM images. VM Depot is a community-driven catalog of preconfigured operating systems, applications, and development stacks that can easily be deployed on Windows Azure. Find your favorite software and deploy it in minutes, or join the community, build a virtual machine image, and share it with others.

VM Depot was released last week and already contains over 40 images. There are a variety of Linux distributions with applications and development stacks pre-configured (e.g. JBoss, Tomcat, SolR, LAMP, Drupal, Django, WordPress, etc.), that you can install in Windows Azure within minutes. The usage fee for a Linux Virtual Machine in Windows Azure starts at $0.02 per hour. The table below shows the rates according to VM size:

You can find more information on the Windows Azure Pricing page.

Everyone can register for free and contribute their own OSS images. You are allowed to publish up to 5 images of 50GB each for free. You can maintain 2 versions per image.

 

 


© 2019 Java Competence Network. All Rights Reserved.