2009. szeptember 27., vasárnap

IBM WebSphere MQ

A Java mellett az egyik fő érdeklődési területem az alkalmazásintegráció. Ez utóbbi egyik első, és legelterjedtebb eszköze az IBM WebSphere MQ (korábban MQSeries) az üzenetkezelő middleware-ek családjába tartozó (message oriented middleware - MOM) üzenetsorakoztató middleware. Persze nem független a Java-tól, hiszen JMS provider-ként tud üzemelni. A múlt héten az IBM WebSphere MQ V7 System Administration tanfolyamon voltam, ezzel kapcsolatban írnék a JMS-ről, valamint az MQ-ról. A bejegyzés eleje mindenkinek szól, a vége inkább már csak azoknak, akik használnak, vagy használni terveznek MQ-t (különösen Java-ból). A post-hoz tartozik egy 46 oldalas magyar nyelvű cikk is a WebSphere MQ-ról.

A JMS-t a JSR 914 specifikálja, a Java EE része, de természetesen külön is használható. A JMS csak egy egységes API-t definiál, melyel üzenetkezelést lehet megvalósítani, és a különböző gyártók különböző megvalósítást adhatnak (JMS provider), hasonlóan az adatbázis-kezeléshez, amihez a JDBC az egységes API. A Java EE alkalmazásszerverekben kötelező JMS megvalósításnak lennie.

A JMS üzenetek küldésére és fogadására használható. Ezzel kialakítható aszinkron kommunikáció, mikor az alkalmazás végzi a saját feladatát, és mikor üzenetet kell küldeni, elhelyezi egy sorban, és halad tovább. Nem várja meg, míg a címzett alkalmazás azt megkapja, és feldolgozza. Persze szinkron kommunikáció is kialakítható, amikor ezt megvárja, de ekkor pont a lényege veszik el. Bár biztonságossága miatt szinkron kommunikációra is alkalmazni szokták, szemben pl. a megbízhatatlanabb, de kisebb infrastruktúrát követelő web szolgáltatások helyett. Az aszinkronitáshoz kapcsolódó fogalom a kommunikáció iránya, ami lehet egyirányú, vagy kérés-válasz típusú is. Ez utóbbi esetben alakítható ki szinkron kommunikáció, mikor a küldő alkalmazás addig nem halad tovább, míg a választ meg nem kapja. De hatékonyabb, ha külön küldi el az alkalmazás az üzeneteit, és külön dolgozza fel a válaszokat. A kérés és a választ úgy lehet egymásnak megfeleltetni, hogy minden üzenet kap egy azonosítót (message id), és a válaszban a kérés üzenet azonosítóját kell egy másik, un. correlation id mezőbe bemásolni.

A JMS-sel kialakítható pont-pont kommunikáció, mikor két alkalmazás közvetlenül küldözget üzeneteket egymásnak (e-mail típusú kommunikáció), valamint kialakítható publish and subscribe kommunikáció is (levelezési lista kommunikáció). Az utóbbi esetben az előfizetők feliratkoznak egy témára (topic, melyek felépítése hierarchikus is lehet), míg a közzétevők erre a témára küldenek üzenetet. Ekkor az összes témára feliratkozott megkapja azt. Ezzel csökkenthető a kapcsolat szorossága, és bármikor új alkalmazásokat kapcsolhatunk az adott témára.

Egy üzenetnek van fejléce és lehet törzse. A törzsben különböző információk utazhatnak, mint szöveges, bináris, map típusú, stb. Az üzenetnek van perzisztenciája, azaz vagy le kell írni lemezre, hogy a JMS provider újraindítása után is megmaradjon, vagy elegendő memóriában tárolni. Az üzenetek prioritással, lejárattal rendelkezhetnek.

Jelenleg a JMS 1.0.2b és 1.1 szabvány a legfrissebb, a kettő között a legnagyobb különbség, hogy a pont-pont és publish and subscribe kommunikációt ugyanúgy lehet kezelni, ugyanis az előbbit reprezentáló Queue interfész, és az utóbbit reprezentáló Topic interfész közös ősinterfészt kapott Destination névvel. Így a modellt nem az alkalmazás dönti el, hanem attól függetlenül konfigurációval állítható.

Az IBM WebSphere MQ jó helyen volt jó időben. Elterjedtségét magas ára ellenére annak köszönheti, hogy ez volt az első, megbízható, és a legtöbb platformon támogatott üzenetsorakoztató middleware. Nem csak az aszinkroniztása miatt, hanem platformfüggetlensége (hardver, operációs rendszer, hálózati protokoll) miatt is kedvelték, hiszen pillanat alatt össze lehetett kötni egy Sun Solaris-on futó C alkalmazást, egy IBM RS/6000-on, AIX operációs rendszeren futó COBOL alkalmazással, ami akkor, mikor a web szolgáltatásoknak nyoma sem volt, igen kemény feladat volt. Ma már a banki, sőt a közigazgatási szférában is kvázi standard.

Apropó ár. Az IBM WebSphere MQ Processor Value Unit [PVU] alapján licencelődik, ami azt jelenti, hogy minden típusú processzorhoz (, akár meghoz) egy értéket rendelnek, amit aztán be kell szorozni az árral. Pl. egy Intel Xeon (Nehalem) 70 PVU/processzor mag. Ez egy négy processzoros, Quad-core processzorokkal felszerelt gép esetén 4 * 4 * 70 = 1120, ahol Magyarországra a PVU ára egy éves support-tal 66,65 dollár, az majdnem 75 ezer dollár. A PVU azért jó, mert ha kevesebb processzormagot dedikálunk, kevesebbet kell fizetni.

Persze vannak nyílt forráskódú változatok is, mint pl. a Apache ActiveMQ (mely a Geronimo-ban a JMS provider), OpenJMS, JBossMQ (JBoss JMS provider), OpenMQ (Glassfish JMS provider, support-ált változata a Sun Java System Message Queue), stb. Amit tudni kell, hogy a JMS csak egy közös interfész, melyet mindegyiknek implementálnia kell, de ezen felül rengeteg szolgáltatást biztosítanak. Valamint, ahogy említettem, az alkalmazásszervereknek is JMS provider-nek kell lenniük. Persze több kereskedelmi termék is van, mint pl. Oracle Advanced Queuing.

A WebSphere MQ a pontosan egyszeri biztos üzenetküldést garantálja. Ezt úgy oldja meg, hogy mind a küldő oldalon, mind a fogadó oldalon el kell indítani egy szoftver komponenst (Queue Manager), mely addig tárolja lokálisan az üzeneteket, míg a másik oldalra át nem vitte. Ezzel az alkalmazás fejlesztőjének nem kell foglalkoznia. Használható, ha a hálózati kapcsolat megbízhatatlan, a hívott fél lassan válaszol, vagy megbízhatatlan, a platform különbségek áthidalására és terheléselosztásra. Használatával így lazán kapcsolt rendszerek alakíthatóak ki.

Az MQ-nak két programozási interfésze is van, az egyik az MQI, mely hasonlóan van implementálva az összes programozási nyelven, és az MQ összes speciális szolgáltatását ki tudjuk használni, valamint a JMS, ami provider független, így az tetszőlegesen cserélhető.

Az MQ-ról annak idején írtam már egy cikket, melyet most teljes egészében közzéteszek. Ebből az alapok elsajátíthatóak, itt már csak a tanfolyam által bemutatott újdonságokat, és a Java specifikus dolgokat mutatnám be.

Teljes IBM Websphere MQ cikk letöltése

Az MQ-val kapcsolatos összes kézikönyv publikus, és elérhető a IBM WebSphere MQ V7 information center-ben.

Amire vigyázni kell JMS használata esetén, hogy az üzeneteket próbáljuk egymástól teljesen függetleníteni, egy üzenetben az összetartozó információk utazzanak, és ne legyenek szétosztva több üzenetre. Ugyanis egyrészt nem biztosított az üzenetek sorrendje, erre külön oda kell figyelni, másrészt terheléselosztás esetén nem biztos, hogy ugyanaz a komponens kap két egymás utáni üzenetet.

A JMS lehetőséget biztosít tranzakciókezelésre, akár lokálisra (JMS provider-en belül), akár globálisra (több erőforrás kezelő részvételével). Ez utóbbi esetben megoldható pl. hogy egy tranzakcióba tartozzon egy adatbázis módosítás és egy JMS művelet. Itt különösen kell vigyázni arra, hogyha kiveszünk a sorból egy üzenetet, és nem sikerül feldolgozni, és rollback történik, akkor az üzenet visszakerül a sorba. Ekkor az alkalmazás újra fel akarja dolgozni, és újra hiba történik. Így remek végtelen ciklus alakulhat ki, amire figyelni kell. Vagy alkalmazásban kell kivételt kezelni, és figyelni, hogy ne legyen rollback, vagy az üzenettől le lehet kérni, hogy hányszor került már vissza a sorba. Ha ez elér egy határértéket, máshogy kell kezelni. A JMS provider-ek is tudhatnak olyant, hogy pl. valamennyi visszakerülés után vagy eldobják az üzenetet, vagy átteszik egy másik sorba. Ennek megvalósításáról egy remek cikk jelent meg Handling Poison Messages With Glassfish címmel. A tranzakciókezelésnél az egyik leggyakoribb hiba, hogy a programozó egy tranzakcióban próbál üzenetet küldeni, és a választ is abban fogadni. Ekkor remek kis deadlock alakul ki, hiszen a commit-ig nem megy ki a kérés üzenet, így a hívott fél válaszolni sem tud, így hiába vár a hívó fél a válaszra.

Java EE-ben nem lehet szálakat indítani. Viszont szükség lehet olyanra, hogy egy hosszú folyamatot kell elindítani, de nem kell megvárni a választ, hanem valami státuszt kell visszaadni bizonyos időközönként. Ez megoldható úgy is, hogy a web konténerben dobunk szálat, de megoldható JMS-sel is. Ez az aszinkron tervezési minta, azaz egy üzenetet beteszünk a sorba, amelynek a másik végén egy Message Driven Bean figyel, és elindítja egy folyamatot. A szál, amelyik betette az üzenetet a sorba, nem vár válaszra, folytathatja a futását, visszaadhatja a választ a felhasználónak. A Bean meg végzi a feladatát. Figyeljünk ilyenkor ilyen timeout-okra, ugyanis lehet, hogy az alkalmazásszerver egy idő után lecsapja a folyamatot.

Nézzük, hogy mit érdemes még tudni az MQ-ról adminisztrátori oldalról, mely számomra is új volt, és nem tartalmaz a fenti dokumentáció.

  • Az üzenet biztonságát az MQ úgy biztosítja, mint a relációs adatbázisok. Egyrészt egy külön állományban tartja a sorokban lévő üzeneteket (queues könyvtár), másrészt egy napló állományt is fenntart (log könyvtár), amit folyamatosan vezet. commit esetén addig nem megy tovább a végrehajtás, míg a log fájlba a módosítások kiírásra nem kerültek. Amennyiben a sort tartalmazó állomány megsérül, vagy nem történt meg a cache-elés miatt az írás, és az MQ elszáll, a log alapján mindig vissza lehet állítani az üzeneteket (strmqm -r paranccsal). Így pl. az adatok és a naplók külön disk-en tartása nem csak a sebességet, de a biztonságot is növeli. A checkpoint az a művelet, mikor kiírja a sorokat is a disk-re, így annak állapota megegyezik a naplóban rögzítettel. Cirkuláris és lineáris naplózás is beállítható. A cirkuláris esetén a régebbi napló állományokat felülírja, lineáris esetén az összes előzmény megmarad. Az utóbbi sokkal biztonságosabb, de több adminisztrációs tevékenységgel jár, hiszen folyamatosan archiválni kell a régi napló állományokat.
  • A WebSphere MQ client ingyenes, és arra való, hogy a távoli sorkezelővel tartja a kapcsolatot, így az alkalmazásnak elegendő lokális hívásokat végrehajtani. Ez nem véd a hálózat megszakadásától. Java esetén az MQ kliens csak pár JAR állomány.
  • A listener az a komponens, mely a hálózati hívásokat figyeli, és amennyiben ilyen jön, elindítja a megfelelő receiver channel-t, amennyiben szükséges. Őt vagy az inetd indítja, vagy manuálisan kell (runmqlsr parancs, vagy a START LISTENER MQSC parancs). Az is beállítható, hogy a sorkezelővel együtt induljon. A channel a két sorkezelő közötti kapcsolatért felelős, és egyirányú. A channel két végén a message channel agent van. Az egyszerű mód, mikor az üzenetet küldő indítja a kommunikációt (sender - receiver). Azonban tűzfalas megfontolások miatt (pl. a DMZ-ből ne indítson kifele kapcsolatot a sorkezelő) lehet olyan is, hogy a fogadó fél beszól, hogy mostmár küldheti az adatokat a küldő (requester - server).
  • Nem csak közvetlen kapcsolatban álló sorkezelőre, hanem távolabbi sorkezelőre is küldhetünk üzenetet. ezt hívják multi-hopping-nak.
  • Adminisztrátori eszköz egy Eclipse 3.3-ra épülő plugin, mellyel távoli sorkezelőkhöz is lehet kapcsolódni.
  • Amennyiben hibát kapunk, általában csak egy kód jelenik meg (reason code - RC). Ezt feloldani nem kell a dokumentációt megnyitni, hanem az MQRC paranccsal a kódhoz lekérdezhető a leírás.
  • Maximálisan átvihető méret 100 megabyte. Amennyiben ennél többet akarunk átvinni, szegmentálnunk kell. Ezt az MQ tudja, viszont a JMS API nem. Így nekünk kell úgy leprogramoznunk, hogy speciális üzenetfejléc értékeket állítunk be.
  • Az üzenet csoportok valók arra, hogy a logikailag egybe tartozó üzeneteket összekössünk, valamint biztosítsuk azok sorrendjét, ami alapban nem biztosított. Szintén fejlécekkel kezelhető.
  • Az IBM WebSphere MQ-ban az adminisztrációs felületről (WebSphere MQ Explorer) egyszerűbben lehet a publish and subscribe módot megadni, sorkezelő csoportokat definiálhatunk a könyebb adminisztráció érdekében, valamint a JNDI objektumokat is könnyen kezelhetjük, ha Java-ban programozunk.
  • Az MQ egy közös kódbázisra alapul, mely a platformok között hordozható. Erre épülnek a speciális platformhoz kapcsolódó részek, mint pl. Windows esetén a GUI. A z/OS teljesen külön állatfajta, az teljesen külön ág.
  • Konfigurációs adatok az mqs.ini állományban, Windows esetén a registry-ben találhatóak.
  • Az IBM WebSphere MQ-hoz un. SupportPacs-ek tölthetőek le, melyek lehetnek kereskedelmi termékek, ingyenesek és támogatottak, ingyenesek, de nem támogatottak és 3rd party termékek is. Ezek közül szinte van, ami kötelező darab. Az MS03 egy sorkezelőben definiált objektumokat tudja létrehozó script-ként elmenteni. Így egy frissen telepített sorkezelőn futtatva a kapott script-et meg fog egyezni az eredeti konfigurációjával. Kiváló mentésre. A különböző event üzenetek speciális formátumban kerülnek a sorba, mely nem olvasható. Ezen segít az MS0P SupportPacs. Az MH03 SupportPacs-szel az SSH konfigurációt tudjuk ellenőrizni. A legfontosabb, az IH03 SupportPacs, mellyel üzeneteket tudunk browse-olni, kivenni, visszarakni, fejléct módosítani, stb. Az MA0R Axis és .NET keretrendszer számára biztosítja, hogy SOAP átviteli protokoll legyen az MQ. A MA0Y gyakorlatilag egy servlet, mely lehetővé teszi, hogy az MQ funkcionalitását REST-en keresztül, egyszerű HTTP hívásokkal érjük el.
  • A 6-os verziótól kezdve elérhető a File Transfer Application is. Hiszen ha kialakítottunk egy MQ vonalat, miért ne vihetnénk át egyszerűen fájlokat is át. Ezt megtehetjük GUI felületen a mqftapp használatával, de akár parancssorból is a mqftsnd, mqftrcv parancsokkal.
  • Létezik egy trace route utility (dspmqrte), mellyel végig lehet követni egy üzenet útját, csak a legutolsó művelet visszavonásra kerül, így az alkalmazások nem veszik észre ezt a speciális üzenetet. Ez könnyen elemezhető szöveges formában írja ki a különböző aktivitásokat, azon belül pedig az operációkat. A WebSphere MQ Explorer-ből az MS0P SupportPacs telepítése után használhatjuk.
  • Amennyiben hiba keletkezik, érdemes benézni az errors könyvtárba. Az itt található log állományok egyszerű szöveges állományok. Belső hiba esetén FFST (first failure support technology) un. FDC állományokat generál, melyre az errors log is hivatkozik. Trace-elni is lehetséges (strmqtrc, endmqtrc, dspmqtrc), de ezt igazából már tényleg csak akkor használjuk, ha a support kéri.

Amennyiben Java EE-ből akarjuk használni a JMS-t, nem érdemes beégetni a sorkezelő elérési paramétereit, sőt még konfigurálhatóvá tenni sem, hanem ezt oldja meg az alkalmazásszerver. Ezt megoldhatjuk úgy, hogy a JNDI fájába bejegyezzük az un. administered object-eket, ilyen a Connection Factory és a Destination. A Connection Factory, mint a neve is mutatja, a kapcsolódási beállításokat tartalmazza, és ennek segítségével lehet konkrét kapcsolatokat kiépíteni, míg a Destionation a sorok és témák reprezentációja. JNDI-be bejegyezni egyeket az objektumokat a JMSAdmin utility segítségével is lehet, ekkor a classpath-ba be kell állítani a Connection Factory osztályt, és meg kell adni a JNDI url-jét.

Tomcat esetén ez máshogy történik. Első lépésként a következő JAR állományokat kell bemásolni a Tomcat lib könyvtárába: com.ibm.mq.jar, com.ibm.mqjms.jar, connector.jar, jms.jar. Ezen kívül a server.xml-be fel kell venni a Connection Factory-t és a Destination-öket a GlobalNamingResources tag alá.

<Resource
name="MyConnectionFactory"
auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory"
factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="jtechlog.hu"
PORT="1414"
TRAN="1"
QMGR="MY_QM"        
CCS="437"
/>

A TRAN a TRANSPORT, ami lehet BIND, CLIENT és DIRECT a dokumentáció szerint. A dokumentációval ellentétben itt azonban csak számot lehet megadni, az 1 a CLIENT transport-ot adja meg. A CSS a character code set.

<Resource
name="MyQueue"
auth="Container"
type="com.ibm.mq.jms.MQQueue"
factory="com.ibm.mq.jms.MQQueueFactory"
description="JMS Queue"
QU="MY_Q"
TC="1"/>

A TC a TARGCLIENT, ami megadja, hogy JMS-sel kapcsolódó kliensnek, vagy egyéb kliensnek akarunk üzenetet küldeni. A TC=1 azt mondja, hogy nem JMS-es kliensnek, így nem rak az üzenetbe JMS fejléc információkat.

Ekkor a context.xml-ben vegyük fel az erőforrás linkeket.

<ResourceLink global="MyConnectionFactory" name="jms/MyConnectionFactory" type="javax.jms.QueueConnectionFactory"/>
<ResourceLink global="MyQueue" name="jms/MyQueue" type="javax.jms.Queue"/>

Ezek után az alkalmazásból egyszerű JNDI lookup-pal lekérhető a java:/comp/env/jms/MyConnectionFactory és java:/comp/env/jms/MyQueue neveken.

A cikk írásakor jelent meg a 7.0.1-es verzió.

2009. szeptember 19., szombat

Java monitorozás és menedzsment

Technológiák: Servlet 3.0, JMX

Sajnos fejlesztés közben viszonylag kevés figyelmet fordítunk arra, hogy könnyen üzemeltethető alkalmazásokat készítsünk. Pedig a Java technológia lehetőséget biztosít, csak kicsit jobban oda kell figyelnünk, kicsit jobban ki kell használni az eszközöket és az API-kat.

Hogy erre felhívjam a figyelmet, 2009. szeptember 16-án a SZÁMALK Aktuális 2009 rendezvényén előadást tartottam "Hol a határ? - Java alkalmazások üzemeltetéséről fejlesztőknek és üzemeltetőknek" címmel.

Az előadás során végigvettem egy fejlesztési életciklust, valamint egy tipikus n-rétegű alkalmazás architektúrát, és elemeztem a fejlesztők és az üzemeltetők feladatait, valamint a lehetséges konfliktus forrásokat.

Konklúzióként levonható, hogy a technológia már nagyon jó eszközöket ad a kezünkbe, a probléma mindig emberi oldalon szokott jelentkezni.

Java szempontjából talán a következőket érdemes kiemelni:

  • Vastag kliens esetén a telepítés és a frissítések kezelésére érdemes a Java Web Start technológiát használni, mely alapban a JRE része.
  • Hasznos eszköz a JConsole, mely a JDK része, és a futó Java alkalmazásokhoz képes hozzákapcsolódni, és azok állapotát lekérdezni.
  • Hasznos API a Java Management Extensions (JMX), mely használatával könnyen üzemeltethető alkalmazásokat tudunk készíteni.

A JMX a Java SE 5.0-tól a platform része, olyan szabványos programozói interfész (JSR 3), melyel monitorozható és menedzselhető alkalmazásokat tudunk készíteni. A JMX alapját egy vagy több Java objektum, un. managed bean (MBean) képviseli. Az MBean-eket az MBean szerverbe kell regisztrálni, hogy a kliensek el tudják érni. Egy MBean-nek lehetnek attribútumai, melyeket lehet írni és/vagy olvasni, lehetnek műveletek (operations), melyeket meg lehet hívni, valamint bizonyos értesítéseket küldhetnek. Ezáltal az MBean-eken keresztül megfigyelhető egy alkalmazás állapota, közbe lehet avatkozni, és bizonyos eseményekről is értesítést kaphat az üzemeltető. Az MBean-ek lokálisan, de távolról is elérhetőek (JSR 160, Java Management Extensions Remote API).

Amennyiben elindítunk egy Java programot, és elindítjuk a JConsole alkalmazást, információt kaphatunk a memóriafogyasztásról, futó szálakról, betöltött osztályokról, stb. Az utolsó, MBeans nevezetű fülön jelennek meg az MBean-ek. Látható, hogy minden konfiguráció nélkül is van pár MBean, melyek a JVM-ről adnak információkat (memóriahasználat, szemétgyűjtő, osztálybetöltő, operációs rendszer környezet, stb.), valamint a JVM működésébe lehet beavatkozni (pl. java.lang/Memory - gc művelet).

A legtöbb alkalmazásszerver menedzsmentje is a JMX-re épül. Ilyen a Tomcat is, mely szintén JMX-en biztosítja a monitorozást és a menedzsmentet. Ekkor amint csatlakozunk a JConsole-lal a Tomcat-et futtató JVM-hez, az MBeans fülön megjelenik a Catalina és a Users folder. Ezekben rengeteg MBean-t találhatunk. A Tomcat olyan szinten biztosít információkat, mint pl. egy servlet betöltési ideje, meghívásának száma, legkisebb és legnagyobb lefutási idő, összes idő, mennyit hibázott, stb (Catalina/Servlet folder).

Nézzünk is egy példát, írjunk egy egyszerű webes alkalmazást. Letölthető a https://github.com/vicziani/jtechlog-jmx címről. Jettyn is megy, Maven-nel build-elhető, és a letöltést követően a 'mvn jetty:run' paranccsal futtatható. Az alkalmazás egy servletből áll, mely egy számlálót növel minden egyes meghívásakor. Ezt szeretnénk kiajánlani JMX-en. A számlálóhoz készítsünk egy külön osztályt Counter néven.

public class Counter
    implements CounterMBean {

private long value;

public long getValue() {
    return value;
}

public void setValue(long value) {
    this.value = value;
}

public void storno() {
    value = 0;
}

synchronized public void incrementCounter() {
    value++;
}
}

Ennek incrementCounter metódusát hívja a szerver. Ahogy látható, implementálja a CounterMBean interfészt, melyen keresztül a JMX-en ki lesz ajánlva.

public interface CounterMBean {
public long getValue();
public void setValue(long counter);
public void storno();
}

Eztán már csak egy ServletContextListener-t kell implementálni, mely az induláskor regisztrálja az MBean-t, leálláskor meg megszünteti a regisztrációt.

@WebListener
public class InitServletListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
    try {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        CounterMBean counter = new Counter();
        mbs.registerMBean(counter, 
    new ObjectName("jtechlog:type=Counter"));
    
        sce.getServletContext().setAttribute("counter", counter);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void contextDestroyed(ServletContextEvent sce) {
    try {
     MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
     mbs.unregisterMBean(new ObjectName("jtechlog:type=Counter"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

A web alkalmazást, majd a JConsole-t elindítva láthatjuk, hogy megjelent a jtechlog folder, és azon belül a Conter MBean. Lekérdezhetjük vagy beállíthatjuk a value értékét, vagy meghívhatjuk a storno műveletet.

Amennyiben értesítést is szeretnénk kapni a számláló értékének változásáról, a NotificationBroadcasterSupport osztályból kell származtatni, implementálni kell a getNotificationInfo metódust, majd meghívni a sendNotification metódust.

...
synchronized public void incrementCounter() {
    value++;
    Notification n =
        new AttributeChangeNotification(this,
        sequenceNumber++,
        System.currentTimeMillis(),
        "Counter value has changed",
        "Counter value",
        "long",
        value - 1,
        value);

        sendNotification(n);
}

@Override
public MBeanNotificationInfo[] getNotificationInfo() {
    String[] types = new String[]{
        AttributeChangeNotification.ATTRIBUTE_CHANGE
    };
    String name = AttributeChangeNotification.class.getName();
    String description = "An attribute of this MBean has changed";
    MBeanNotificationInfo info =
            new MBeanNotificationInfo(types, name, description);
    return new MBeanNotificationInfo[]{info};
}
...

A legjobb, hogy ezeket az értékeket nem csak JConsole-ról tudjuk lekérdezni, hanem parancssorból is, a Tomcat Ant task-okat definiál erre. (Használatához a catalina-ant.jar-t kell a $CATALINA_HOME/lib könyvtárból az $ANT_HOME/lib könyvtárba másolni.) A következő build.xml részlettel lehet lekérni a számláló értékét.

<jmx:open
host="${jmx.server.name}"
port="${jmx.server.port}"/>
<jmx:get
name="jtechlog:type=Counter"
attribute="Value"
resultproperty="value"
echo="false"
/>
<echo message="${value}" />

Ez azért nagyszerű, mert így bármilyen monitorozó vagy menedzsment eszközbe (pl. Munin, Nagios) könnyen be tudjuk kötni.

2009. szeptember 15., kedd

Glassfish távoli szerveren

Szintén egy oktatás alkalmával szerettem volna demonstrálni a Java platformfüggetlenségét, és a Java EE lokális transzparenciáját. Írtam egy egyszerű Java EE alkalmazást, megy egy Stateless Session Bean-ből állt, valamint egy Message Driven Bean-ből. Valamint írtam hozzá egy kliens osztályt, mely egyrészt távolról meghívja a Session Bean metódusát, valamint egy üzenetet elhelyez abban a JMS sorban, melyen az MDB hallgat.

A cél az volt, hogy az elkészült EAR-t egy Solaris szerveren futó alkalmazásszerverre telepítsem, és a kliens alkalmazás azt távolról hívja meg.

Erről a postot egyrészt azért írom meg, hogy az itt szerzett tapasztalatok másnak is jól jöhetnek, másrészt feltehetőleg még meg kell ismételnem későbbi oktatásokon, ezért magamnak is jól fog még jönni. Fontos, hogy nem vagyok Solaris adminisztrátor, így nem biztos, hogy mindent úgy állítok be, ahogy egy szerveren kéne, viszont egy fejlesztői környezet működésre bírásához elegendő.

Használt verziók:

  • Solaris 10 5/08 s10x_u5wos_10 x86
  • Java SE Development Kit 6u13, pontosabban 1.6.0_13-b03
  • NetBeans 6.5.1
  • Glassfish v2.1, melyet a Netbeans Java bundle is tartalmaz, pontos száma v2.1 b60e Promoted Build

Első feladatként egy működő Solaris-t kellett szerezni. Kaptam egy előre telepített VirtualBox VDI (Virtual Disk Image ) állományt, így azt már csak hálózatba kellett kapcsolni. NAT-tal semmiképp nem tudtam elindítani, így maradt a bridge-elt kártya, PCnet-Fast III virtuális hálózati kártyával. Amíg nem sikerültek a beállítások, a Solaris már boot-oláskor a következő hibaüzenetet adta:

Failed to plumb IPv4 interface(s): pcn0
Failed to configure IPv4 DHCP interface(s): pcn0
Sep 13 08:33:29 svc.startd[7]: svc:/network/physical:default: Method "/lib/svc/method/net-physical" failed with exit status 96.
Sep 13 08:33:29 svc.startd[7]: network/physical:default misconfigured: transitioned to maintenance (see 'svcs -xv' for details)

Amennyiben a hálózati kártya helyesen lett beállítva, megjelent a pcn0 interfész, de nem kapott a DHCP-től új ip-címet. Új cím kéréséhez a következő parancsokat kellett kiadni:

ifconfig pcn0 dhcp release
ifconfig pcn0 dhcp start

Ekkor a ifconfig –a parancs valami hasonlót adott, amin már látszik a jó ip-cím:

lo0: flags=2001000849 mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
pcn0: flags=1004843 mtu 1500 index 2
inet 192.168.68.107 netmask ffffff00 broadcast 192.168.68.255
ether 8:0:27:7b:8e:7c

Amíg a hálózat nem jól volt beállítva, csak az első sor jelent meg, vagy a második is, rossz ip-címmel.

Ezután a /etc/hosts fájlban is megjelent a következő sor:

192.168.68.107  unknown # Added by DHCP

Az unknown lett a host neve, amit meg kell jegyezni, mert később szükség lesz rá (ezt persze már boot közben is kiírja). Amint van hálózat, javasolt nem a VirtualBox-ban bejött konzolon tevékenykedni, hanem pl. putty-tyal SSH-n keresztül bejelentkezve.

A következő feladat a JDK feltelepítése volt a /opt könyvtárba. Ehhez a jdk-6u13-solaris-i586.sh állományt töltöttem le, mely egy önkicsomagoló állomány. Letöltés után állítsuk futtathatóra (chmod +x), és indítsuk el. Én elkövettem azt a klasszikus hibát, hogy szöveges módban scp-ztem fel a Windows-os gépről a Solaris-ra (az sh kiterjesztés miatt az alapértelmezett mód), és így állandóan hibát jelzett (megsérült az állomány - corrupted), és az állomány mérete sem egyezett. Ezen túllendülve létrejött a jdk1.6.0_13 könyvtár. Ezután a .bash_profile-ba beállítottam a megfelelő környezeti változókat:

export JAVA_HOME=/opt/jdk1.6.0_13
export PATH=$JAVA_HOME/bin:/usr/local/bin:$PATH

Ezután következett a Glassfish telepítése. Ehhez a glassfish-installer-v2.1-b60e-sunos_x86.jar állományt töltöttem le. Először próbálkoztam a V2 UR2 verzióval is, de nagyon rejtélyes kivételeket kaptam, mire rájöttem, hogy a V2 UR2, és a NetBeans-emmel telepített 2.1 nem kompatibilis egymással, így a távoli metódushívás nem jött össze. Telepíteni a java -Xmx256m -jar glassfish-installer-v2.1-b60e-sunos_x86.jar parancs kiadásával kell, a 256 mega memória megadása nélkül nem sikerült. Ezt is a /opt könyvtárban indítottam. Mégegy érdekesség, hogy csak parancssort használva képtelen volt elindulni, a következő hibaüzenetet dobta:

X connection to localhost:10.0 broken (explicit kill or server shutdown).

Igen, egy X-et kellett hozzá indítani, csak azért, hogy kitegye a Licence Agreement képernyőt.

Ezután konfigurálni kellett Ant alapú eszközzel a Glassfish-t a következő parancsok kiadásával:
cd glassfish
chmod -R +x lib/ant/bin
lib/ant/bin/ant -f setup.xml

Eztán már csak el kellett indítani a /opt/glassfish könyvtárban:

bin/asadmin start-domain domain1

Leállítása:

bin/asadmin stop-domain domain1

A napló állomány a /opt/glassfish/domains/domain1/logs/server.log. A webes adminisztrációs felületet a http://unknown:4848 címen lehet elérni, ahol a default felhasználónév "admin", és a default jelszó "adminadmin".

Az alkalmazás egy NetBeans-ben létrehozott Enterprise Application, ami a következőkből állt. Távoli interfész:

@Remote
public interface HelloEJB {
public String sayHello(String name);
}

Stateless session bean:

@Stateless
public class HelloEJBBean implements HelloEJB {
public String sayHello(String name) {
    System.out.println("Invoking sayHello");
    return "Hello " + name;
}
}

És a Message driven bean:

@MessageDriven(mappedName = "jms/MyQueue", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class HelloMDB {

public void onMessage(Message message) {
    try {
        System.out.println(((TextMessage) message).getText());
    } catch (JMSException jmse) {
        jmse.printStackTrace();
    }
}
}

Ez utóbbihoz létre kellett hozni az adminisztrációs felületen (Resources/JMS Resources/Connection Factories és Destination resources) egy jms/MyConnectionFactory és egy jms/MyQueue JNDI néven található JMS objektumokat.

Az alkalmazást a NetBeans EAR-ba csomagolta, amit a következő módok egyikén lehet telepíteni:

  • EAR bemásolása a /opt/glassfish/domains/domain1/autodeploy könyvtárba
  • Webes adminisztrációs felületen: Applications/Enterprise Applications képernyőn a deploy gombbal
  • Meglepően jól működik a NetBeans távoli deploy szolgáltatása is. Ekkor fel kell venni egy új szervert (Tools/Servers képernyő Add server gomb), ki kell választani a lokális telepítési könyvtárat, majd a Register Remote Domain rádiógombot, majd meg kell adni a távoli szerver ip címét és az admin portját (4848). Az alkalmazásnál a Properties ablakban válasszuk ki ezt az alkalmazásszervert, és a projekten a jobb gomb/deploy-ra nyomva települ az alkalmazás a távoli alkalmazásszerverre. Az alkalmazásszerver a Services fülön is megjelenik, ahol alapvető információkat kapunk róla, és alap műveleteket el tudunk végezni.

Ha telepítettük az alkalmazást, érdemes megnézni, hogy sikerült-e, pl. a globális JNDI nevek megjelentek-e a JNDI fában. Ezt a webes felületen az Application Server képernyőn a JNDI browsing gombra kattintva lehet előhívni. Itt a session bean nevének meg kell jelennie: jtechlog.HelloEJB.

A kliens elkészítéséhez két megoldás közül választhattam volna. Vagy egy Application Client Container-ben (ACC) futó alkalmazást készíthettem volna, vagy egy különálló alkalmazást. Az előbbinél a deployment descriptor-okban kell leírni, hogy hol vannak a távoli erőforrások, és egy pehelysúlyú alkalmazásszerverben fut. Az utóbbi esetén csak a JNDI context-et kell definiálni, lookup műveletekkel lekérni a távoli referenciákat, és egy egyszerű JVM-ben fut. Emiatt az utóbbira esett a választásom. Tehát a NetBeans-ben elegendő volt egy Java Application projektet létrehozni. Ehhez persze a távoli interfészt is a projektbe kellett másolni. A kliens alkalmazás így nézett ki:

public class Main {
public static void main(String[] args) throws Exception {
Context ic = new InitialContext();
HelloEJB helloEJBBean = (HelloEJB) ic.lookup("jtechlog.HelloEJB");
System.out.println(helloEJBBean.sayHello("jtechlog"));
}
}

Ehhez persze el kellett helyezni a következő JAR állományokat is a CLASSPATH-ban: $GLASSFISH_HOME/lib/appserv-rt.jar, $GLASSFISH_HOME/lib/javaee.jar (, ahol értelemszerűen a $GLASSFISH_HOME a lokális GlassFish telepítési könyvtára). Ekkor a appserv-rt.jar-ban lévő jndi.properties miatta localhost-hoz csatlakozna, így a következő jndi.properties állományt kellett elhelyezni a CLASSPATH-ban:

java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
org.omg.CORBA.ORBInitialHost=192.168.68.107

Ahol az utolsó sor mutatja a szerver ip címét. Ezután már a Solaris-on futó alkalmazásszerverbe telepített EJB meghívása egy Windows-os kliensről tökéletesen müködött.

A következő feladat a JMS beállítása volt. Ehhez a következővel egészítettem ki a kliens alkalmazást:

ConnectionFactory connectionFactory = (ConnectionFactory) ic.lookup("jms/MyConnectionFactory");
Queue queue = (Queue) ic.lookup("jms/MyQueue");
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
TextMessage message = session.createTextMessage();
message.setText("Message");
messageProducer.send(message);
messageProducer.close();
session.close();
connection.close();

Az import-ok és a kivételkezelés az olvasó feladata. Ezt elindítva a következő osztályt hiányolta: java.lang.NoClassDefFoundError: org/netbeans/modules/schema2beans/BaseBean. Melyet kicsit furcsálok, hogy mit keres benne netbeans-es osztály. A megoldáshoz a következő JAR állományokat kellett még a CLASSPATH-ba tennem: $GLASSFISH_HOME/lib/appserv-admin.jar, $GLASSFISH_HOME/lib/appserv-ws.jar, $GLASSFISH_HOME/lib/install/applications/jmsra/imqjmsra.jar. Ez után a futtatás a következő hibával szállt el:

May 19, 2009 1:36:24 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: SJSMQ JMS Resource Adapter starting...
May 19, 2009 1:36:26 PM com.sun.messaging.jmq.jmsclient.ExceptionHandler throwConnectionException
WARNING: [C4003]: Error occurred on connection creation [unknown:7676]. - cause: java.net.UnknownHostException: unknown

Ez ugye azt jelenti, hogy a visszaadott JNDI referencia tartalmazza a JMS server host nevét, ami jelen esetben az unknown. Ezt a /opt/glassfish/domains/domain1/config/sun-acc.xml tartalmazza, valami ilyen formában:

<target-server name="unknown" address="unknown" port="3700"/>

Ebben a sorban az address értékét kicseréltem a megfelelő ip címre, de ez nem segített, így egyszerűen a Windows host fájljába felvettem a unknown nevet a Solaris virtuális gép ip-címére.

Ennek megoldására ezen a fórumon kaptam tippet.

Így az alkalmazás lefutott, de a kapcsolat bezárása után sem lépett ki, folyamatosan futott. A futó szálakat elemzve kiderült, hogy imqConnectionFlowControl és iMQReadChannel nevű szálak sokasága fut, melyek miatt nem tud leállni a kliens alkalmazás.

Erről több írás is van a weben, ez a legérdekesebb fórum, valamint itt van felvéve egy Glassfish bug és mégegy Glassfish bug. Sajnos javítás rájuk még nem érkezett. Addig is a javasolt megoldás a System.exit metódus hívása.

Összegzésként megállapítható, hogy még mindig nem hiszek az alkalmazásszerverekben, szerintem egy ilyen egyszerű demonstrációnak sokkal gördülékenyebben kellett volna mennie, hiszen nagyon egyszerű alkalmazást próbáltam, és az alkalmazásszerver nagyon alap funkcionalitását szerettem volna kipróbálni. Sajnos az utolsó problémára megoldást sem találtam.

Hivatkozások:

JavaTM SE 6 Release Notes Solaris Operating System Installation (32-bit)

GlassFish Project - v2.1 FinalBuild

Sun Java System Application Server Platform Edition 9 Developer's Guide, Chapter 11 Developing Java Clients

EJB FAQ

2009. szeptember 9., szerda

Virtualizáció fejlesztői gépen

Manapság a virtualizáció nagyon divatos irány, így én sem maradhattam ki belőle. Egyelőre nézzük az egyszerű munkaállomásokon futtatható virtualizációt. Mikor is lehet erre szüksége egy egyszerű fejlesztőnek:

  • Jelenlegi operációs rendszere feladása nélkül ki akar próbálni egy másik operációs rendszert.
  • A fejlesztett alkalmazás célplatformja eltérő lesz, mint a fejlesztési platform.
  • Ki akar próbálni egy szoftvert, de feltelepítésével nem a saját környezetét akarja veszélyeztetni.
  • Az előbbi speciális esete, mikor fejlesztési munkához szükséges. Pl. most több hardver elemet kell programoznom, aminek driver-eit, fejlesztőeszközeit nem akarom a jelenlegi környezetemre telepíteni. Különösen akkor, mikor az adott munkán csak ritkán kell dolgozni, de jó, ha mindig rendelkezésre áll.
  • Egy szoftverhez csak egy számítógépre érvényes licence-et kap, mégis több fejlesztő akar vele dolgozni. Nem jogtalan használatra gondolok.
  • Egy teljes infrastruktúra működését kell letesztelni, pl. egy különálló adatbázisszervert, alkalmazásszervert, webszervert, mindezeket duplázva, cluster-be kötve. Persze a teljesítménye sokkal alacsonyabb lesz, de az architektúra, alkalmazás működése tesztelhető.
  • Egy fejlesztési környezetet több fejlesztő között is el kell osztani. Pl. egy felépített adatbázist. Persze senkinek nem ajánlom, hogy a virtuális gépen fejlesszen.
  • Környezetek hordozhatóságának biztosítására. Otthoni laptopon elkészítettem egy virtuális gépet, melyet átmásoltam az irodai gépemre, és azonnal elérhetővé váltak az arra telepített szolgáltatások.
  • Oktatási, prezentációs célokra. Jobb, ha egy előadáson, vagy egy videón nem a jelenlegi környezetemet mutatom a sok feltelepített programmal, ikonnal, hanem egy szűz környezetet, amin csak a demózni kívánt alkalmazás szerepel.
  • Más platform oktatásakor. Pl. a SZÁMALK-nál az egyik oktatáson Windows-on fejlesztettünk, de a Java EE platformfüggetlenségét bizonyítandó telepíteni kellett az alkalmazást egy Solaris szerverre is.
  • Oktatás esetén infrastruktúra biztosítására. Pl. az egyik oktatáson az oktatói gépen futó virtuális gépen volt feltelepítve a Subversion szerver, a wiki és az issue tracking rendszer.

Ezekben az esetekben nem kell külön hardvert szereznünk, hanem a virtualizációs szoftverrel egy külön hardvert emulálunk, és erre telepítjük rá az operációs rendszert és a különböző alkalmazásainkat. Így gyakorlatilag egy ablakban futtathatunk egy másik operációs rendszert. A magyar elnevezés szerint az eredeti operációs rendszer a hordozó (host), az ezen belül futó operációs rendszer a vendég (guest) operációs rendszer. Egyszerre párhuzamosan akár több vendég is futhat, határt csak a hardverünk teljesítménye szab.

Elsőként a Microsoft Windows Virtual PC-t próbáltam, mellyel semmi gondom nem volt, megbízhatóan működött. Mégis váltottam a következő okok miatt a VirtualBox-ra, melynek a post írása pillanatában legfrissebb verziója a 3.0.4:

  • Solaris-t kellett futtatnom
  • Többen mondták, hogy gyorsabb a Virtual PC-nél
  • Sun vásárolta meg
  • GPL-es nyílt forráskódú termék

Telepítés nagyon egyszerű, varázslóval történik. Párszor megjelenik a felirat: "A telepítés alatt álló szoftver szoftver nem ment át a Windows Logo tesztelésen, amely a Windows XP-vel való kompatibilitását vizsgálja.", de ezzel nem kell törődni. Egy új virtuális gép létrehozása is adja magát, először egy virtuális lemezt kell létrehozni, majd ehhez kapcsolódóan egy virtuális gépet. A VirtualBox képes bármilyen ISO állományt is csatolni, így gyorsan csatoltam is egy Windows XP telepítő CD ISO-ját, így sikerült arról telepítenem. Telepítés után hasznos lehet még a Guest Addition telepítése a vendég operációs rendszerbe, mely a következő funkcionalitásokat biztosítja:

  • Egérmutató integráció: az egeret a hordozó desktop-ról egyszerűen át lehet húzni a vendég desktop-jára.
  • Jobb videó kártya támogatás: közvetlenül a hordozó videó kártyáját használja ki, így nem csak a standard felbontások választhatóak, valamint gyorsabb is.
  • Óra szinkronizáció.
  • Megosztott könyvtárak: a hordozó és a vendég közötti állomány megosztásra.
  • Seamless windows: az egyik legérdekesebb, ilyenkor a vendég operációs rendszer nem egy külön ablakban fut, hanem annak ablakai ablakként jelennek meg a desktop-unkon. Így nem is látszik, hogy mely operációs rendszer futtatja az adott alkalmazást. Mint a Windows 7-ben a Windows XP virtualizációja. Alapértelmezetten a jobb Ctrl + L billentyűkkel aktiválható.
  • Megosztott vágólap: rendkívül hasznos.
  • Automatikus bejelentkezés.

Érdemes egy tiszta operációs rendszert tartalmazó virtuális lemezt elmenteni, és különböző környezetek kialakításakor abból kiindulni.

A többi funkció használata és felderítése nagyon egyszerű, egyedül a hálózatkezelés okozhat némi fejtörést. A VirtualBox 8 virtuális hálózati kártyát tud kezelni, ebből 4 felületről konfigurálható, többi parancssorból. Megadhatjuk a hálózati kártya típusát, PCNet FAST III az alapbeállítás, mert szinte minden operációs rendszer ismeri és támogatja. Majd meg kell adni a virtualizáció módját is, mely azt határozza meg, hogy hogyan csatlakozzon a jelenlegi hálózathoz. Lássuk, hogy ez a verzió milyen lehetőségeket biztosít, először is a képernyő, amin a konfigurációt lehet állítani:

  • not attached (nincs csatolva): ugyan hálózati kártyát jelez a vendég operációs rendszer, de azt mutatja, hogy nincs kábel bedugva, ennél a módnál is, mint a többinél a fogaskerékre csatlakoztatva lehet a virtuális hálózati kártya MAC címét megadni.
  • NAT (Network Address Translation): ez a leggyakoribb beállítás. Használatakor a vendég operációs rendszer látja a hordozó hálózatát és az Internetet is, ha be van kötve, de a hálózatról nem lehet látni a vendég gép szolgáltatásait. Ez úgy működik, hogy egy külön hálózat kerül kialakításra a vendég és a hordozó között (a vendég a 10.0.2.x címet kapja, míg a hordozó a második ip-címet az azonos privát hálózaton belül). Ezt az ip címet a VirtualBox beépített DHCP szervere adja. A külső hálózatot a vendég úgy éri el, hogy a küldött csomagokat a VirtualBox NAT engine újracsomagolja, és elküldi, majd a választ a vendégnek továbbítja. Port forward-dal megoldható, hogy a hálózat többi tagja is elérje a vendég szolgáltatását, ilyenkor egy port-on a VirtualBox hallgat, és továbbítja a kéréseket a vendég operációs rendszerhez.
  • Bridged networking: használatakor a vendég kívülről is egy külön gépnek látszik. Pl. a hálózaton lévő DHCP szervertől is kérhet ip címet. Ekkor a hálózat többi tagja is el tudja érni a vendég szolgáltatásait. Ezt úgy oldja meg, hogy egy device driver-t telepít, mely a hordozó hálózati kártyájáról kiszűri a neki szükséges forgalmat, ezt hívják "net filter" driver-nek is. Ez gyakorlatilag bridge-elés, azaz egy Layer 2 switch. Konfigurációkor ki kell választani a fizikai hálózati kártyát, melyre rátelepszik. Ehhez a régebbi verziókban a Windows "Hálózati kapcsolatok" ablakában kellett varázsolni, szerencsére ez ebben a verzióban már nem szükséges.
  • Internal networking (belső csatoló): hasonló a bridged networking-hez azzal a különbséggel, hogy a vendég csak az ugyanazon belső hálózathoz kapcsolódó vendégekkel tud kommunikálni, még a hordozóval sem. Ez azért fontos, mert ilyenkor a forgalom nem megy át a host halózati kártyáján, és emiatt nem lehet sniffer-elni, és gyorsabb is.
  • Host-only networking: átmenet az internal networkin és a bridged networking között. Az elsőnél annyival több, hogy a vendég tud beszélgetni a hordozó géppel is, de nem érhető el kívülről. Ezt úgy valósítja meg, hogy egy szoftveres interfészt, "loopback" hoz létre. Konfigurációjakor egy szoftveres interfészt lehet itt kiválasztani: VirtualBox Host Only Network Adapter. Ezt előzőleg telepítette a VirtualBox, ekkor az Internet egy rövid időre elmegy, mert telepítése újraindítja a hálózatot. Ezzel meg lehet oldani, hogy a pl. két virtuális gép (adatbázis és alkalmazásszerver) egy hálózatban van kötve, míg kiajánlva csak az alkalmazásszerver van egy másik (bridge-elt) hálózaton keresztül, így kinntről az adatbázis közvetlenül elérhetetlen.

Nagyon meg vagyok vele elégedve, egyetlen negatívumnak azt hoznám fel, hogy a magyar fordításban nagyon sok hiba (nem csak érdekes szóhasználat, hanem elírás is) van.