środa, 8 października 2008

Pierwsze kroki z JMX

JMX - czyli Java Management Extensions, to kolejna technologia javowa z którą przyszło mi się spotkać i zainteresować. Dziś mały wstęp do tej technologii i może "krótki" przykład ;-)

JMX jak Wikipedia nam tłumaczy jest technologią Javy, która zawiera narzędzia potrzebne do zarządzania oraz monitorowania aplikacji, urządzeń, usług zorientowanych sieciowo.
A teraz kilka pojęć i informacji wstępnych:
Ziarno zarządzane - m-ziarno - mbean - jest to obiekt Javy którym można zarządzać. Taki obiekt posiada atrybuty, operacje oraz sygnały. O ile atrybuty i operacje są dość oczywiste to sygnały są obiektami pewnych klas, które przy spełnieniu pewnych warunków mziarno może rozsyłać do słuchaczy.
M-ziarno musi implementować interfejs zarządzania - m-interfejs, który określa jakie właściwości posiada m-ziarno i jakie operacje na nim można wykonywać w aplikacji. Sygnałów nie uwzględniamy w interfejsie, a atrybuty są deklarowane przez metody set/get.
Interfejs oraz klasa mziarna muszą być publiczne.
Teraz ważna kwestia nazewnictwa. Nazwa klasy m-ziarna, natomiast m-interfejs musi przyjmować nazwę [nazwa klasy]MBean. Czyli, jeśli nasza klasa ma nazwę Ship, to interfejs który implementuje musi się nazywać ShipMBean. Co do nazewnictwa metod get/set to są one takie same jak w przypadku JavaBeans.

To chyba tyle z teoretycznych podstaw, reszta wyjdzie w praniu ;-)

Rejestrowanie m-ziarna
Żeby skorzystać z m-ziarna należy je wcześniej zarejestrować w serwerze m-ziaren. Domyślnie każda JVM przechowuje systemowy serwer m-ziaren i do niego będziemy dorzucać nasze ziarenka.
Obiekt serwera zwraca nam metoda (statyczna)
MBeanServer ManagementFactory.getPlatformMBeanServer()


Zanim jednak dodamy do niego nasz obiekt należy go wcześniej opakować tak, żeby był łatwiejszy do wyszukania na serwerze. Dokonujemy tego poprzez utworzenie dla niego nazwy, a dokładniej obiektu: ObjectName. Konstruktor przyjmuje 3 parametry:
- String domena - my będziemy używać domeny domyślnej dla serwera m-ziaren
- String klucz
- String wartosc
Ostatnie dwa parametry służą określenia nazwy m-ziarna, które może nam sugerować jego przeznaczenie.

Teraz możemy zarejestrować mbean (zakładamy że Test to klasa naszego ziarna:
Test mbean = new Test();

MBeanServer server = ManagementFactory.getPlatformMBeanServer();

ObjectName name = new ObjectName(server.getDefaultDomain(),
"JMXLearning",
"TestBean");

ObjectInstance mbeanObj = server.registerMBean(mbean, name);

mbeanObj przechowuje informacje o zarejestrowanym ziarnie.
Ok, mamy zarejestrowany obiekt. Możemy teraz odpalić naszą aplikacje. Uruchamianie wymaga podania maszynie wirtualnej javy następujących parametrów:
-Dcom.sun.management.jmxremote.port=[numer portu] - numer portu na którym nasłuchiwać będziemy na sygnały
-Dcom.sun.management.jmxremote.authenticate=[true/false] - czy ma być przeprowadzona autoryzacja
-Dcom.sun.management.jmxremote.ssl=[true/false] - czy używać bezpiecznego protokołu ssl
To by było na tyle z części "serwerowej". Teraz czas na klienta.

Dostęp do m-ziaren
Żeby wykonać jakieś operacje na m-ziarnach trzeba najpierw znać adres serwera na którym są one udostępnione. Adres taki ma postać:
service:jmx:rmi:///jndi/rmi://[nazwa hosta]:[numer portu]/jmxrmi

i reprezentowany jest przez obiekt typu JMXServiceURL. Jego konstruktor przyjmuje jako parametr String z adresem postaci takiej jak powyżej.
Połączenie z m-serwerem uzyskuje się następująco:
JMXConnector con = JMXConnectorFactory.connect(url);
MBeanServerConnection server = con.getMBeanServerConnection();

Poprzez obiekt łącznika JMXConnector otrzymujemy połączenie z m-serwerem który reprezentowany jest przez obiekt typu MBeanServerConnection.
W tym momencie jeśli nie znamy m-interfejsu ziarna na serwerze to możemy pobierać odpowiednie wartości poprzez metodę getAttribute lub przypisywać je poprzez odpowiednio setAttribute.
Jeśli znamy m-intefejs to możemy pobrać zdalną referencje na m-ziarno i wykonywać na nim operacje tak jakby był do niego dostęp bezpośredni w aplikacji. Aby tego dokonać należy wywołać statyczną metodę klasy MBeanServerInvocationHandler o nazwie getProxyInstance.
Przyjmuje ona 4 parametry, odpowiednio:
MBeanServerConnection connection - połączenie z serwerem
ObjectName objectName - reprezentacja nazwy obiektu m-ziarna
Class interfaceClass - interfejs implementowany przez m-ziarno
boolean notificationBroadcaster - czy pośrednik (czyli obiekt który otrzymamy) ma informować o sygnałach emitowanych przez m-ziarno
Przykład:
ShipMBean mbean = (ShipMBean)MBeanServerInvocationHandler.
newProxyInstance(server,
name,
ShipMBean.class,
false);
Teraz wykonując operacje na obiekcie mbean wykonujemy zdalnie operacje na m-ziarnie na serwerze.
To wszystko z teorii :) Poniżej zamieszczam kompletny kod źródłowy przykładowej aplikacji dzięki której będzie można pobierać informacje o liczbie użytkowników podłączonych do serwera oraz ustalać ich limit.

M-Interfejs - ServerMBean.java
package com.blogspot.wookasz.jmxtutorial;

public interface ServerMBean {
public void setUsersLimit(int limit);
public int getUsers();
}
M-Ziarno - Server.java
package com.blogspot.wookasz.jmxtutorial;

import java.util.Random;

public class Server implements ServerMBean {
private int limit = 100;
private int users = 0;

public Server() {
Random rnd = new Random();
users = rnd.nextInt(100);
}

public void setUsersLimit(int limit) {
this.limit = limit;
System.out.println("Limit uzytkowników zmieniono na: " + limit);
}

public int getUsers() {
return users;
}
}
Rejestracja m-ziarna - ServerRegistration.java
package com.blogspot.wookasz.jmxtutorial;

import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class ServerRegistration {

public static void main(String[] args) {
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName(server.getDefaultDomain(), "tutorial", "server");
Server mbean = new Server();
server.registerMBean(mbean, name);

Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Uruchamiamy ten plik z parametrami:
-Dcom.sun.management.jmxremote.port=2005
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

I program klienta - Client.java
package com.blogspot.wookasz.jmxtutorial;

import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class Client {

public static final String servelUrl = "service:jmx:rmi:///jndi/rmi://localhost:2005/jmxrmi";

public static void main(String[] args) {
new Client().doTest();
}

public void doTest() {
try {
JMXServiceURL url = new JMXServiceURL(servelUrl);

JMXConnector con = JMXConnectorFactory.connect(url);
MBeanServerConnection server = con.getMBeanServerConnection();
ObjectName name = new ObjectName(server.getDefaultDomain(),
"tutorial", "server");

ServerMBean mbean = (ServerMBean)MBeanServerInvocationHandler.
newProxyInstance(server,
name,
ServerMBean.class,
false);

System.out.println("Liczba użytkowników na serwerze: " + mbean.getUsers());
mbean.setUsersLimit(120);
} catch(Exception e) {
e.printStackTrace();
}
}
}

Kompletne kody źródłowe można pobrać tutaj (projekty w NetBeans).

Zapraszam do komentowania ;-)

ps. zna ktoś plugina do bloggera, żeby dzielić posty ? Tzn. całość postu żeby pojawiała się po wybraniu czytaj dalej jak np w wordpress.

3 komentarze:

  1. M-ziarno :D Dzięki za to tłumaczenie, już dawno nie popłakałem się ze śmiechu podczas nauki do egzaminu :-)

    OdpowiedzUsuń
  2. dzięki :D
    to jest wpis z 2008 roku, wtedy to m-ziarno to było coś! ^^

    OdpowiedzUsuń