October 25, 2008

JMX, MBeans, jconsole, VisualVM och Spring MBean

Java Management Extension (JMX) är enkelt sätt att managera produktionssatt kod. Dels man kan inspektera property värden, men även anropa exponerade metoder och slutligen skicka och ta emot event. För exponera metoder/klasser använder man MBeans. Det finns fem MBeans:

Statiska MBeans:

  • Standard MBeans
  • MXBeans (J2SE 5/6)
Dynamiska MBeans:
  • Dynamic MBeans
  • Model MBeans
  • Open MBeans

Statiska MBeans

Standard MBeans

Standard MBeans är den enklaste MBean typen och bygger på att man använder fördefinierade namnsättningar på sina klasser (introspection).

package se.msc.jmx;

public interface CalculatorMBean {

   public int getMemory();
 
   public void setMemory(int memory);
 
   public int add(int x, int y);
 
   public int divide(int x, int y);
}
package se.msc.jmx;

public class Calculator implements CalculatorMBean {

   private int memory;
 
   public int getMemory() {
       return memory;
   }
 
   public void setMemory(int memory) {
       this.memory = memory;
       System.out.println("New memory=" + memory);
   }
 
   public int add(int x, int y) {
       return x + y;
   }
 
   public int divide(int x, int y) {
       return x / y;
   }
}
package se.msc.jmx;

import java.lang.management.ManagementFactory;

import javax.management.MBeanServer;
import javax.management.ObjectName;

public class Bootstrap {

   public static void main(String[] args) throws Exception {
       MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
     
       mbs.registerMBean(new Calculator(), 
           new ObjectName("se.msc.jmx:type=Calculator"));

       System.out.println("Running...");
       Thread.sleep(Long.MAX_VALUE);
   }
}

Kompilera koden och start sedan:

$ java se.msc.jmx.Bootstrap

Starta sedan jconsole:

$ jconsole

och dubbelklicka se.msc.jmx

Bild 1. Attribut
Bild 2: Metoder

MXBeans

MXBeans skiljer sig inte mycket från Standard MBeans utan tillkom för att adressera brister i Standard implementationen:

  • Interface och implementation måste ligga i samma paket.
  • Man behöver inte följa namnstandard längre utan kan använda annotation - @MXBean.
  • Man kan nu använda enum (Open Types)

Intressant är också att JRE tillhandahåller en hel del MXBeans, t.ex. GarbageCollectorMXBean och ThreadMXBean, se java.lang.management för komplett lista.

Dynamiska MBeans

Skillnaden mellan statiska och dynamiska MBeans är att dynamiska MBeans exponerar sina attribut och metoder i runtime och är inte hårt satta som i det statiska fallet.

Nyheter i J2SE 6

I J2SE 6 så har det inte tillkommit så mycket för JMX, men en stor skillnad på verktyg sidan är VisualVM. VisualVM är en sammanslagning av:

  • jconsole – JMX console för Java SE 5/6
  • jstat – JVM statistik monitoreringsverktyg
  • jstack – stack trace för java processer
  • jinfo – konfiguration av java processer
  • jmap – minnesanvändning av java processer

Spring och JMX

Spring Framework gör livet enklare (som vanligt) för JMX utvecklare och om du redan använder Spring i ditt projekt, så rekommenderar jag varmt att använda Spring JMX. Det Spring JMX erbjuder:

  • Exponering av vanliga klasser (icke JMX klasser) som MBeans
  • Enklare notifieringshantering.
  • Rikare metadata via annotering

Se Spring JMX http://static.springframework.org/spring/docs/2.0.x/reference/jmx.html för fullständig dokumentation.

Referenser:

Bugg i JMX local JMX registry: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6754672

J2SE 6 JMX Guide: http://java.sun.com/javase/6/docs/technotes/guides/jmx/

Remote Monitoring and Management: http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#remote

October 23, 2008

Maven2, m2eclipse och Nexus

För er som fortfarande använder Ant som byggstöd, borde kolla Maven2. Maven2 är ett komplett byggverktyg, fast med tre skillnader: Det har inbyggt stöd för Code Lifecycle, vilket innebär om ska bygga ett projektet ska koden gå igenom alla livscyklar upp till package. Detta tänkande är väldigt uppfostrande och innebär att innan man kodat klart en komponent ska man även ha skrivet testfall, och dessa testfall ska gå igenom innan man skeppar en jar.
Validate → Generate Source → Generate Resource → Compile → Test → Package → Install → Deploy
Nästa är att Maven2 Project Object Model, POM, blir väldigt kompakt om man använder de fördefinierade katalogstrukturer, vilket innebär om en ny utvecklare ska sättas in i projektet och är bekant med Maven2, genast kommer att hitta i projektkatalogerna, men också veta hur han eller hon bygger eller testar kod utan att detta är dokumenterat. Sist men inte minst, finns de flesta tänkbara plugins till Maven2, som kommer med vettiga defaultvärden, vilket leder till att de flesta plugins fungerar out-of-the-box. Men ett byggverktyg blir inte komplett om det inte finns bra IDE stöd och för eclipse är det m2eclipse. M2eclipse har genomgått stora förändringar de senaste 8 månader då 6 personer på heltid arbetat med m2eclipse plugin. För att enklast installera m2eclipse, så använder man Eclipse Software Update och anger:
http://m2eclipse.sonatype.org/update-dev/
I större organisationer där man vill dela byggda moduler eller där säkerhetspolicys begränsar användare att vara direkt uppkopplad mot Internet finns Nexus. Nexus blir den repository som man användare frågar efter moduler, istället för att direkt gå till Maven2 centrala repository. Sist men inte minst så behöver man inte längre komma ihåg vilka archetypes det finns för Maven2, alla tillgängliga finns direkt sökbara via m2eclipse, då man skapar nytt Maven2 projekt innefrån Eclipse.

Apache Camel presentation av Bruce Snyder på Colorado Software Summit 2008

I måndags var jag på en riktig bra presentation av Bruce Snyder (http://softwaresummit.com/2008/speakers/snyder.htm) som presenterade Apache Camel. Camel erbjuder implementation av alla pattern som Gregor Hohpe och Bobby Woolf beskriver I Enterprise Integration Pattern, men det som är fascinerade är hur enkelt det är att använda Camel. För att implementera Content-Based Router, dvs. beroende på innehåll i XML-fil från ActiveMQ (JMS) meddelande så skickar man det vidare till olika kataloger på disk.
RouteBuilder builder = new RouteBuilder() {
public void configure() {
 from("activemq:topic:Quotes").choice()
     .when(xpath("/order/item = ‘paper’")).to("file://orders/paper")
     .otherwise().to("file://orders/other");
     }
 };
Och för att implementera Message Filer, som här filtrerar mha XPath XML-fil på disk och skickar vidare till ActiveMQ.
public class MyRouteBuilder extends RouteBuilder {
   public void configure() {
       from("file://orders").
           filter().xpath("/quote/product = ‘widget’").
               to("mqseries:WidgetQuotes");
   }
}
Och för Message Translator, som här transformerar XML-fil på disk och skickar transformerad XML till HTTP.
public class MyRouteBuilder extends RouteBuilder {
   public void configure() {
     from("file://incoming”).
       to("xslt:se/msc/mytransform.xsl").
         to("http://outgoing.msc.se/foo");
   }
 }
Komplett lista över alla Integration Pattern, finns på http://www.enterpriseintegrationpatterns.com/toc.html. Vad också värt att notera är att man definerat ikoner för de flesta pattern, så om man skall modulera flöde i sitt projekt, så behöver man inte tänka på hur man skall representera mönstren. Om inte detta redan har övertygat dig att använda Camel, så kolla in listan över de protokoll, som de stödjer out-of-the-box, http://activemq.apache.org/camel/components.html, saknar du något protokoll?

October 21, 2008

Att gå från Windows till Ubuntu 8.04 på Dell Latitude D830

För ett tag sedan så gick jag över till att enbart köra Ubunut på min lapptopp och de svårigheter jag hade tänkte jag skriva om nedan. Till och börja med så vill jag säga till er alla som funderar att gå över till Linux, välj Ubuntu, det av två anledningar. Dels så kan man först testa att köra Ubuntu utan att installera den (Live CD) och för det andra, så fungerade det mesta direkt, utan strul med drivrutiner eller att behöva konfigurera inställningar till dödsdagar för att nå en acceptabel nivå. I mitt fall så hittade Ubuntu alla mina hårdvaror och konfigurerade dem till vettiga standardvärden - Helt otroligt! Så varför denna artikel? Jo, några saker kom inte med i en standardinstallation. 1. Dubbla skärmar. Installera nvidia-settings: sudo apt-get install nvidia-settings För att ändra, kör: sudo nvidia-settings 2. Blutooth Börja med att kontrollera om den blåa Bluetooth lampan lyser. Om inte kontrollera att skjutreglaget till vänster på datorn är satt till >>. Lyser lampan nu? Om inte måste man aktivera Bluetooth från windows. Start Windows och dubbelklicka på trash icon nere till höger, välj sedan settings och därifrån klicka på on-knappen under settings. Nu kan du gå tillbaka till Ubuntu. Installera sedan alla BlueZ (the Bluetooth Stack) komponenter. Enklast från Synaptic Package Manager. Sök efter alla komponenter bluez-* och installera dessa. Starta Bluetoot service: /etc/init.d/bluetooth start Kontrollera konfiguration: hciconfig Konfigurera: gedit /etc/bluetooth/hcid.conf
#
# HCI daemon configuration file.
#

# HCId options
options {
    # Automatically initialize new devices
    autoinit yes;

    # Security Manager mode
    #   none - Security manager disabled
    #   auto - Use local PIN for incoming connections
    #   user - Always ask user for a PIN
    #
    security auto;

    # Pairing mode
    #   none  - Pairing disabled
    #   multi - Allow pairing with already paired devices
    #   once  - Pair once and deny successive attempts
    pairing multi;

    # Default PIN code for incoming connections
    passkey "1234";

        # PIN helper
        #pin_helper /etc/bluetooth/pin-helper;
}

# Default settings for HCI devices
device {
    # Local device name
    #   %d - device id
    #   %h - host name
    name "%h-%d";

    # Local device class
    class 0x000100;

    # Default packet type
    #pkt_type DH1,DM1,HV1;

    # Inquiry and Page scan
    iscan enable; pscan enable;
    #discovto 0;

    # Default link mode
    #   none   - no specific policy
    #   accept - always accept incoming connections
    #   master - become master on incoming connections,
    #            deny role switch on outgoing connections
    lm accept;

    # Default link policy
    #   none    - no specific policy
    #   rswitch - allow role switch
    #   hold    - allow hold mode
    #   sniff   - allow sniff mode
    #   park    - allow park mode
    lp rswitch,hold,sniff,park;
}
Start om bluetooth service: /etc/init.d/bluetooth restart Du kan nu kolla dina inställningar: hciconfig -a Slå nu på din mobiltelefon eller annan bluetoot device och sök efter den: hcitool scan Koppla sedan ihop dem via: hcitool inq Du kan nu kolla förbindelse genom att pinga MAC-adressen, mha l2ping. Det enklaste sättet sedan att föra över bilder från en mobiltelefon är att göra det från mobiltelefonen. 4. Kalender med Lightner plugin för Thunderbird Om du inte redan har installerat thunderbird, gör så: sudo apt-get install thunderbird För att lightner skall fungera, måste du installera: sudo apt-get install libstdc++5 Installera sedan plugin till thunderbird via thunderbird Tools | Adds-on. Inte via synaptic package manager!

October 20, 2008

Domain Driven Design och Dependency Injection

För ett tag sedan var jag med i ett projekt, där jag fick möjligheten att använda domän driven design. Det var spännande, men inte helt problemfritt efter ha läst POJO in Actions (Manning Publications), Applying Domain-Driven Design and Patterns (Addison-Wesley Professional) och valda bitar av Domain-Driven Design (Eric Evans), hittade jag fortfarande inte svaren på mina frågor. De problemen som jag stötte på när jag skulle realisera DDD i verkligheten vill jag dela med er, men framförallt höra era synpunkter.


Vad är då domän driven design - DDD? DDD var framtagen från en projektledares ögon, som hade problemet att utvecklare och kravställare/affärsanalytiker pratade förbi varandra. Detta ledde till missförstånd och värdefull tid gick förlorad. Detta är inget nytt och många har lösningen på detta, varav RUP är en.

Men vad DDD skiljer sig mot traditionella metoder är enkelheten. Man skulle bara behöva ett diagram i designdiskussioner mellan utvecklare och kravställare/affärsanalytiker – en domän modell. Detta kan låta som det blir klottrigt, men syftet med detta diagram är att enbart visa objekt som har förankring i funktionella krav och är av arkitekturisk vikt. Låt oss nu arbeta vidare med ett exempel för tydliggöra metodiken.


Anta att vi ska bygga ett biljettbokningssystem åt ett biografföretag och vi har följande krav.

  1. Söka efter föreställningar.
  2. Boka föreställning.
  3. Registrera användare.
  4. Kontrollera kreditkort med 3-partsystem.
  5. Skicka skriftlig bokningsbekräftelse med 3-partssystem.

Efter att ha läst krav så har vi identifierat följande substantiv, som blir våra domänobjekt:

  • Föreställning
  • Användare

Av funktionella och arkitekturiska och skäl lägger vi även till:

  • Salong
  • Stol
  • Bokning
Låt oss nu rita domän modellen.


I domänmodellen finns det flera designbeslut man kan göra, men jag vill inte fastna i dessa detaljer här, men ett anmärkningsvärd beslut är att duplicera bokningar, dvs. man skapar upp lika många bokningsobjekt som det finns stolar, med flaggan bokad till false, när man skapar en föreställning. Anledning är att snabba upp sökningen av lediga stolar och att det blir enklare att hantera flera samtidiga bokningar. Slutligen så är det rätt osannolikt att antal stolar ändras över tiden.


Nu är det dags att lägga till metoder/funktionalitet, men innan dess behöver vi även lägga till persistenshantering och interaktion med 3-partssystemen. Vi inför 3 facade klasser, som kapslar in detta:

  • Persistens
  • Kreditkort
  • Bekräftelse


Nu börjar problemen komma. Enligt DDD så vill man knyta logik och domän objekt nära varandra. I vårt fall skulle det innebära att Föreställningsobjektet skulle ha metoderna:

  • sökaFöreställning
  • bokaFöreställning

För Användare skulle det vara:

  • spara

Ett direkt val som jag inte heller tror Eric motstrider är att flytta ut alla direkta persistensanrop, till någon mera övergripande klass. I POJO in Actions kallar man dem tjänsteklasser.


Men hur gör man med den mera komplexa metoden bokaFöreställning? Till och börja kan vi bryta ner den:

  • Validera.
  • Är användare registrerad?
  • Finns önskade platser lediga?
  • Kontrollera kreditkort.
  • Genomför bokning.
  • Skicka bekräftelse.

Det vi ser är att de olika delarna behöver tillgång till våra facade klasser. Hur får de det? Vi vill definitivt inte hårdkoda detta, då vi vill kunna göra systemet testbart, samtidigt som vi vill dölja implementation av facaderna bakom interfaces, så de blir utbytbara.


Som jag ser det finns det 3 alternativt:

  1. Ha all logik i domänobjekten och skicka med facaderna som inparametrar.
    1. Nackdel: ohållbart i längden, då inparameterlistan kan bli väldigt lång.
  2. Ha set-metoder i domänobjektet, som man måste anropa innan logik metoder.
    1. Nackdel: inga kompileringsfel om man inte har anropat set-metod och enkelt att skapa fel, för inte insatta utvecklare.
  3. Ha all logik i domänobjekt, som INTE kräver facade interaktion och resterande kod i tjänsteklasser.
    1. Nackdel: man sprider ut logiken, vilket är det DDD försöker motsträva.
    2. Fördelar: Man får en naturlig uppdelning av komplexa och tunga metoder till flera små metoder, vilket leder till mera lättläst kod och gör valet av vilka metoder man skall modultesta naturligare.

Som jag ser det finns det inga andra vettiga alternativ än 3.


Vi har hittills inte pratat om Dependency Injection – DI, men innan dess skulle jag vilja fundera över när vi skapar domänobjekten. Och detta leder in oss till om vi skall använda våra domänobjekt som databärare genom hela applikationen, dvs. genom alla lagren eller inte. I vår enkla applikation är övriga lager här presentationslagret. Jag antar här att de flesta förespråkar Hibernate, som persistenslagerhanterare och där använder man samma modell rakt igenom.

I de flesta av system så är det nästan ett-till-ett förhållande mellan presentationslagret och domänmodellen och i dessa fall så ser jag inte att ett nytt databärarlager tillför något, därför rekommenderar jag att använda domänobjekten även i presentationslagret. Däremot så ska man INTE införa presentationsspecifika attribut till domänobjektet, utan oftast har man ändå någon presentationsmodell, som man lägger domänobjektet i och det är i denna presentationsmodell, som specifika presentationsattribut hör hemma.


Värt att notera är om vi inte hade valt tredje alternativet ovan, så hade jag inte rekommenderat att använda domänobjekten rakt igenom, för då hade man exponerat spara, sök, etc. logik/metoder i presentationslagret.


Så svaret på min fråga, var man skapar domänobjekten i en presentationsdriven applikation, är i presentationslagret. Om man däremot har ett integrationslager i form av Web Service eller JMS, så ska man istället använda sig av en gemensam överenskommen modell, som passar alla integrerande system och i det fallet, så måste man konvertera sin applikationsspecifika modell.


För att avsluta diskussionen med DI, så måste man nu blanda in hur man skall realisera transaktionshantering. Jag tänkte måla upp tre alternativ, men listan kan göras längre, men principen bör kvarstå.

  • Spring med enbart JTA
  • Spring med SessionBean
  • SessionBean utan Spring och DI

För att möjliggöra DI, så rekommenderar jag tjänsteklassen enbart har referenser till facadinterface och man vill använda SessionBean så får de hantera injection av beroenden. Detta leder till den mest flexibla lösningen och mest testbara.