Archive for Marzec, 2010

Odszukanie plików JAR z brakującymi definicjami klas

Często pojawiającym się problem (i bardzo irytującym przy okazji) podczas uruchamiania aplikacji napisanych w Javie jest brak jakiś klas potrzebnych do uruchomienia aplikacji. Ja się ostatnio spotkałem z takim problemem próbując testować jakąś aplikację, której autorów nikt od dawana nie widział.

Znam dwie metody na sprawdzenia, jak nazywa się plik JAR z daną klasą:

Odszukanie pliku JAR przy użyciu strony internetowej

Przy użyciu wyszukiwarki FindJAR.com można w łatwy sposób sprawdzić, w jakich plikach znajduje się poszukiwana klasa. Wystarczy w polu wyszukiwania wpisać nazwę klasy (niekoniecznie nawet z pełną nazwą pakietu), ewentualnie wybrać dokładną nazwę klasy z prezentowanych odpowiedzi i już widać, w jakich plikach znajduje się dana klasa.

Zrobiłem test dla klasy javax.jws.WebParam, wyniki można zobaczyć tutaj: http://www.findjar.com/class/javax/jws/WebParam.html:

findJAR wyniki dla WebParam

findJAR wyniki dla WebParam

Teraz pozostaje tylko pobrać plik i przynajmniej jedną klasę mamy już głowy ;).

Odszukanie pliku jar przy użyciu aplikacji

Do odszukania potrzebnych plików można także użyć aplikacji [cco]jarSearch[/cci]. W artykule Which jar contains my… można znaleźć dokładny opis możliwości aplikacji (większy niż przedstawiony tutaj) oraz link do źródeł.

Aplikacja przeszukuje podany katalog oraz podkatalogi w celu odnalezienia plików JAR i sprawdza czy znajduje się w nim podana klasa. Jeżeli znajdzie ją, to wyświetla odpowiednią informację.

Po pobraniu pliku zip jarSearchSrc.zip z plikami źródłowymi, należy je skompilować:

$ ant build
Buildfile: build.xml

build:
   [delete] Deleting directory /home/lukasz/install/java/jarSearch/classes
    [mkdir] Created dir: /home/lukasz/install/java/jarSearch/classes
    [javac] Compiling 4 source files to /home/lukasz/install/java/jarSearch/classes

BUILD SUCCESSFUL
Total time: 1 second

Aby użyć jarSearch należy z katalogu z plikiem build.xml wydać komendę:

$ java -cp jarSearch.jar com.isocra.utils.jarSearch.DirectorySearcher /jboss-as/client/ javax.jws.WebParam.class
/jboss-as/client/jbossws-native-jaxws.jar: javax/jws/WebParam.class
1 entries found.
Directory searcher: http://www.isocra.com

Pierwszym parametrem jest katalog z który zawiera pliki jar, drugim natomiast nazwa szukanej klasy. W powyższym przykładzie widać, że został odnaleziony jeden plik, który zawiera poszukiwaną klasę jbossws-native-jaxws.jar

Widać, że efekty działania obu sposobów są trochę inne. Strona findJAR oferuje nam możliwość odnalezienia wybranej klasy i następnie ściągnięcia odpowiedniego pliku. Natomiast aplikacja jarSearch pozwala po prostu sprawdzić w której bibliotece ukrywa się szukana klasa.

Źródła

Tags: , , , , ,

Wyłączenie dźwięków systemowych GTK pod KDE

Pracując głównie w środowisku KDE wyłączyłem wszelkie możliwe dźwięki systemowe, niestety ustawienia te nie były respektowane przez aplikacje korzystające GTK, takie jak Firefox czy Eclipse. Ciągle w nich pobrzmiewały pikania przy przełączaniu się pomiędzy zakładkami, plikami, otwieraniu okien dialogowych.

Rozwiązanie jak się okazuje jest całkiem proste ;). Wystarczy do pliku konfiguracyjnego GTK dodać wpis wyłączający wydawanie dźwięków przez aplikacje. W moim przypadku jest jest to plik ~/.gtkrc-2.0-kde4 (podejrzewam, że w środowisku GTK może mieć nazwę bez końcówki -kde4) oraz w pliku należy wstawić to:

gtk-enable-event-sounds=0

Od tego momentu ani Firefox ani Eclipse nie wydają dźwięków.

Źródła

Tags: , , , , ,

Zarządzanie instalacją aplikacji w JBoss AS

Jeżeli JBoss AS zostanie uruchomiony w domyślnej (default) konfiguracji to jest wstępnie skonfigurowany tak, że automatycznie instaluje wszelkie aplikacje jakie pojawią się w katalogu deploy. Podobnie, jeżeli jakąś aplikacja zostanie usunięta z tego katalogu, to automatycznie zostanie ona także odinstalowana z serwera. Zachowanie takie jest bardzo przydatne w momencie gdy tworzymy lub testujemy aplikację, ale niekoniecznie porządne na systemie produkcyjnym. Automatyczna instalacja aplikacji może się wiązać z takimi problemami jak:

  • ciągle jest uruchomiony specjalny wątek, który sprawdza czy nowa aplikacja nie pojawiła się w katalogu deploy;
  • trzeba pamiętać, że aktualizacja aplikacji wiąże się w w praktyce z usunięciem aplikacji z serwera i jej ponowną instalacją, więc jeżeli z jakiś powodów zaktualizujemy aplikację, nastąpi jej usunięcie, co w konsekwencji może przeszkodzić w pracy użytkownikom korzystającym z aplikacji;
  • przypadkowa (czy też nawet zamierzona) edycja plików deskryptora aplikacji także powoduje jej restart.

Konfiguracja skanowania zmian w katalogu deploy

Za konfigurację mechanizmu skanującego zmiany w katalogu deploy odpowiada klasa HDScanner. Konfiguracja usługi znajduje się w pliku deploy/hdscanner-jboss-beans.xml:

10
11
12
13
14
15
16
17
18
19
<!-- Hotdeployment of applications -->
<bean name="HDScanner" class="org.jboss.system.server.profileservice.hotdeploy.HDScanner">
    <property name="deployer"><inject bean="ProfileServiceDeployer"/></property>
    <property name="profileService"><inject bean="ProfileService"/></property>
    <property name="scanPeriod">5000</property>
    <property name="scanThreadName">HDScanner</property>
<!--
   <property name="scanEnabled">false</property>
-->
</bean>

Interesujące parametry:

  • scanPeriod
    Czas odstępu pomiędzy poszczególnymi skanowaniami wyrażona w milisekundach, domyślna wartość to 5000, czyli 5 sekund.
  • scanThreadName
    Nazwa wątka, który skanuje katalogu, domyślna wartość HDScanner. Można zmienić na inną wartość, jeżeli monitorujemy działające wątki serwera.
  • scanEnabled
    Zmienna określająca, czy skanowanie powinno być włączone (wartość true) czy też nie (wartość false). W domyślnej konfiguracji nie występuje w pliku XML. Próba dodanie jej z wartością true powoduje, że serwer wyrzuca szereg wyjątków:

    23:34:18,727 ERROR [AbstractKernelController] Error installing to Configured: name=HDScanner state=Instantiated
    java.lang.RuntimeException: Error configuring property: scanEnabled for HDScanner
            at org.jboss.kernel.plugins.dependency.ConfigureAction.dispatchSetProperty(ConfigureAction.java:112)
            at org.jboss.kernel.plugins.dependency.ConfigureAction.setAttributes(ConfigureAction.java:85)
    ...

    Prawdopodobnie jest to spowodowane błędem Setting HDScanner’s scanEnabled Attribute to True via XML Results In NPE lub też Setting HDScanner’s scanEnabled Attribute to True via XML Results In NPE

Jak widać, nie da się po prostu włączyć odpowiedniego przełącznika i wyłączyć automatyczną instalację aplikacji. W związku z tym, należy usunąć z katalogu deploy plik hdscanner-jboss-beans.xml[.

Po tym kroku przestanie działać usługa odpowiedzialna za skanowanie katalogu deploy, więc zmiany w nim będą sprawdzane tylko podczas startu serwera aplikacji.

Ręczna instalacja aplikacji

Jeżeli jest wyłączone automatyczne skanowanie katalogu deploy a trzeba zainstalować jakąś aplikację, można użyć polecenia twiddle.sh za pomocą którego można wywołać ziarno MainDeployer, które odpowiada za instalację aplikacji:

  • deploy – instalacja wybranej aplikacji
    twiddle.sh -s localhost -u UŻYTKOWNIK -p HASŁO invoke "jboss.system:service=MainDeployer" deploy "file:/ścieżka/do/pliku/do/instalacji"
  • undeploy – odinstalowanie wybranej aplikacji
    twiddle.sh -s localhost -u UŻYTKOWNIK -p HASŁO invoke "jboss.system:service=MainDeployer" undeploy "file:/ścieżka/do/pliku/do/instalacji"
  • redeploy – przeinstalowanie wybranej aplikacji
    twiddle.sh -s localhost -u UŻYTKOWNIK -p HASŁO invoke "jboss.system:service=MainDeployer" redeploy "file:/ścieżka/do/pliku/do/instalacji"
  • hdscanner-jboss-beans.xml – ponowna instalacja skanowania
    1. Skopiuj plik hdscanner-jboss-beans.xml z powrotem do katalogu deploy.
    2. Wykonaj polecenie:
      twiddle.sh -s localhost -u UŻYTKOWNIK -p HASŁO invoke "jboss.system:service=MainDeployer" redeploy "file:/ścieżka/do/pliku/xml"

Co trzeba jeszcze zapamiętać:

  • serwera aplikacji musi mieć dostęp do wskazanego pliku
  • aplikacja do zainstalowania zostanie zainstalowana bezpośrednio, nie będzie ona kopiowania do katalogu deploy, zostanie ona od razu rozkompresowana do katalogu tmp
  • zainstalowane aplikacje nie będę ponownie uruchamiane po restarcie serwera (chyba że zostaną one umieszczone w katalogu deploy ręcznie.

Lista zainstalowanych aplikacji

Można uzyskać listę zainstalowanych aplikacji, przy pomocy polecenie twiddle:

twiddle.sh invoke jboss.deployment:flavor=URL,type=DeploymentScanner listDeployedURLs | sed -e 's/,/\n/g'

Domyślnie poszczególne ścieżki z aplikacji są oddzielone od siebie znakiem ‚,’, polecenie sed zmienia je na znak nowej linii.

Źródła

Tags: , , , , ,

Rozpakowanie plików z archiwum RPM

Komenda, która pozwala na rozpakowanie wszystkich plików znajdujących się danym archiwum RPM:

rpm2cpio pakiet.rpm | cpio -vid

Zawartość pakietu zostanie rozpakowana do aktualnego katalogu.

Tags: , , , ,

Jak uruchomić więcej niż jedną instancję serwera JBoss na jednej maszynie fizycznej?

Czasami zachodzi potrzeba uruchomienia więcej niż jednej instancji serwera JBoss na jednym komputerze, czy to do celów testowych, deweloperskich czy nawet produkcyjnych. Aby było to możliwe, należy spełnić następujące warunki:

  • każda instancja serwera musi posiadać własny profil
  • należy skonfigurować odpowiednio serwer aplikacji oraz maszynę na której go uruchamiamy

W sumie największym problem jaki się pojawia w momencie uruchamiania kolejnych instancji serwera, jest konflikt wykorzystania tych samych portów na wybranej maszynie. Sposobów rozwiązania jest kilka, niektóre wymagają modyfikacji konfiguracji maszyny fizycznej, inne jedynie modyfikacji serwera JBoss AS.

Pierwszym krokiem będzie utworzenie dwóch profili w katalogu $JBOSS_HOME/server, które będą potem wykorzystywane do uruchomienia serwera. W dalszych części przyjmę, że profile te noszą nazwy profile1 oraz profile2 i są kopią profilu default.

Dodanie kolejnych aliasów IP do interfejsów sieciowych

Najprostszą metodą poradzenia sobie z konfliktem portów jest dodanie kolejnego (kolejnych) interfejsu sieciowego, będącego aliasem to już istniejącego. Czyli po prostu przyznanie sobie kolejnego numeru IP i przypięcie do niego konkretnej instancji serwera. Może to być spokojnie kolejny interfejs lokalny (loopback), jeżeli nie chcemy mieć dostępu do serwera z poza lokalnego komputera.

Jak utworzyć kolejne interfejsy? To zależy od używanego systemu operacyjnego:

I teraz nie pozostaje zrobić nic innego, jak uruchomić JBossa. Standardowo JBoss przypina się tylko interfejsu oznaczonego jako localhost (czyli adresu 127.0.0.1) oraz uruchamiania profil default. Aby to zmienić, należy użyć odpowiednich przełączników:

  • -c – nazwa konfiguracji do uruchomienia, a naszym przypadku profile1 lub profile2;
  • -b – nr IP, który ma wykorzystać JBoss do nasłuchiwania na połączenia;

Uruchomienie serwera z konfiguracją profile1 oraz nasłuchiwaniem na adresie 127.0.0.1:

$JBOSS_HOME/bin/run.sh -c profile1 -b 127.0.0.1

Uruchomienie serwera z konfiguracją profile2 oraz nasłuchiwaniem na adresie 127.0.0.2:

$JBOSS_HOME/bin/run.sh -c profile2 -b 127.0.0.2

Po tych operacjach powinniśmy otrzymać dwa uruchomione serwery JBoss, każdy nasłuchujący na innym adresie IP, w związku z czym nie wchodzących sobie w paradę. Sprawdzić można to przy użyciu polecenia netstat:

$ sudo netstat -tlpn | grep java
tcp        0      0 127.0.0.1:8083          0.0.0.0:*               LISTEN      12887/java      
tcp        0      0 127.0.0.2:8083          0.0.0.0:*               LISTEN      12789/java      
tcp        0      0 0.0.0.0:51415           0.0.0.0:*               LISTEN      12789/java      
tcp        0      0 127.0.0.1:51035         0.0.0.0:*               LISTEN      12887/java      
tcp        0      0 127.0.0.1:4444          0.0.0.0:*               LISTEN      12887/java      
tcp        0      0 0.0.0.0:60988           0.0.0.0:*               LISTEN      12887/java      
tcp        0      0 127.0.0.2:4444          0.0.0.0:*               LISTEN      12789/java      
tcp        0      0 127.0.0.1:58460         0.0.0.0:*               LISTEN      12789/java      
tcp        0      0 127.0.0.1:4445          0.0.0.0:*               LISTEN      12887/java      
tcp        0      0 127.0.0.2:4445          0.0.0.0:*               LISTEN      12789/java      
...

Zmiana portów (Service Binding Manger)

Drugim rozwiązaniem problemów konfliktu portów jest ich zmiana. Można to zrobić na albo przy użyciu specjalnej usługi zwanej Service Binding Manger lub też ręcznie

Od wersji 5.0 serwera aplikacji usługa ta jest domyślnie włączona i udostępnia 4 konfiguracje portów:

  • ports-default – domyślna konfiguracja portów
  • ports-01 – dodanie do każdego portu z domyślnej konfiguracji wartości 100
  • ports-02 – dodanie do każdego portu z domyślnej konfiguracji wartości 200
  • ports-03 – dodanie do każdego portu z domyślnej konfiguracji wartości 300

Jak widać konstrukcja jest całkiem prosta, definicja tych mapowań można znaleźć w pliku $JBOSS_HOME/server/PROFIL/conf/bindingservice.beans/META-INF/bindings-jboss-beans.xml. Tam znajduje się zarówno definicja wszystkich domyślnych portów, jak i definicje pozostałych konfiguracji (łącznie z offsetami).

Aby uruchomić JBossa z zadanym zestawem portów, należy ustawić w JVM zmienną jboss.service.binding.set na wartość odpowiadającej jednemu ze sposobów mapowań:

$JBOSS_HOME/bin/run.sh -c profile2 -Djboss.service.binding.set=ports-01

Można także zapisać zmiany w odpowiednim pliku konfiguracyjnym, nie będzie wtedy potrzeby konfigurowania zmiennej dla JVM. Plik, który należy edytować: $JBOSS_HOME/server/PROFIL/conf/bindingservice.beans/META-INF/bindings-jboss-beans.xml:

17
18
19
20
21
22
23
24
25
26
<!-- Provides management tools with a ProfileService ManagementView
interface to the SBM and its components -->
<bean name="ServiceBindingManagementObject"
class="org.jboss.services.binding.managed.ServiceBindingManagementObject">
 
<constructor>
 <!-- The name of the set of bindings to use for this server -->
 <parameter>${jboss.service.binding.set:ports-default}</parameter>
 
 <!--  The binding sets -->

W linii 24 znajduje się wpis wskazujący na domyślnie użyty zestaw portów. Wystarczy zmienić wpis ports-default na jedną z wartości: ports-01, ports-02 czy ports-03 i zrestartować serwer JBossa.

A oto jak wygląda mapowanie portów po uruchomieniu dwóch serwerów:

$ sudo netstat -tlpn | grep java
tcp        0      0 127.0.0.1:8083          0.0.0.0:*               LISTEN      12887/java
tcp        0      0 127.0.0.1:8180          0.0.0.0:*               LISTEN      15787/java
tcp        0      0 127.0.0.1:25460         0.0.0.0:*               LISTEN      15787/java
tcp        0      0 0.0.0.0:32885           0.0.0.0:*               LISTEN      15787/java
tcp        0      0 127.0.0.1:8183          0.0.0.0:*               LISTEN      15787/java
tcp        0      0 127.0.0.1:51035         0.0.0.0:*               LISTEN      12887/java
tcp        0      0 127.0.0.1:4444          0.0.0.0:*               LISTEN      12887/java
tcp        0      0 0.0.0.0:60988           0.0.0.0:*               LISTEN      12887/java
tcp        0      0 127.0.0.1:4445          0.0.0.0:*               LISTEN      12887/java
tcp        0      0 127.0.0.1:4446          0.0.0.0:*               LISTEN      12887/java
tcp        0      0 127.0.0.1:4544          0.0.0.0:*               LISTEN      15787/java
tcp        0      0 127.0.0.1:4545          0.0.0.0:*               LISTEN      15787/java
...

Jak widać, są uruchomione dwa procesy JVM i można zaobserwować podobne mapowania portów z różnicą 100 pomiędzy nimi.

Zmiana portów (admin-console)

W wersji 5.0 JBoss AS istnieje możliwość zmiany portów przy użyciu aplikacji admin-console. Umożliwia ona zarówno zmianę profilu, który będzie użyty podczas tworzenia konkretnych mapować, jak i modyfikację zarówno profili jak i poszczególnych portów dla różnych usług.

Binding Manager in the Admin Console

Binding Manager in the Admin Console

Czyli najprościej otworzyć Service Binding Manager, a następnie zmienić właściwość

Active Binding Set Name

. Pozostaje jeszcze tylko zrobić restart serwera i powinno działać.

Zmiana portów (ręczna)

Jeżeli z jakiś powodów nie można użyć usługi Service Binding Manager do zmiany domyślnych portów, pozostaje jeszcze możliwość ich recznej konfiguracji. W przypadku JBossa 5.1 należy otworzyć plik $JBOSS_HOME/server/PROFIL/conf/bindingservice.beans/META-INF/bindings-jboss-beans.xml oraz przyjrzeć się dokładnie w jaki sposób jest zdefiniowany domyślne mapowanie. W przypadku mojego pliku początek tej definicji wygląda następująco:

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
!-- Base binding metadata that ServiceBindingStore uses to create bindings for each set -->
<bean name="StandardBindings" class="java.util.HashSet">
<constructor>
 <parameter class="java.util.Collection">
    <set elementClass="org.jboss.services.binding.ServiceBindingMetadata">
    <!-- ********************* conf/jboss-service.xml ****************** -->

    <!-- Naming Service -->
    <bean class="org.jboss.services.binding.ServiceBindingMetadata">
       <property name="serviceName">jboss:service=Naming</property>
       <property name="bindingName">Port</property>
       <property name="port">1099</property>
       <property name="description">The listening socket for the Naming service</property>
    </bean>

    <bean class="org.jboss.services.binding.ServiceBindingMetadata">
       <property name="serviceName">jboss:service=Naming</property>
       <property name="bindingName">RmiPort</property>
       <property name="port">1098</property>
       <property name="description">Socket Naming service uses to receive RMI requests from client proxies</property>
    </bean>

    <!-- Remote classloading service -->
    <bean class="org.jboss.services.binding.ServiceBindingMetadata">
       <property name="serviceName">jboss:service=WebService</property>
       <property name="port">8083</property>
       <property name="description">Socket for dynamic class and resource loading</property>
    </bean>

...

Jak widać, każda usługa posiada zdefiniowany jakiś port. Jeżeli mamy potrzebę, to możemy ten port zmienić, zrestartować serwer i powinno działać.

Podsumowanie

Wydaje mi się, że najlepszym sposobem uruchomienia kilku instancji serwera JBoss na jednej maszynie fizycznej jest użycie oddzielnych aliasów IP dla każdej z nich. Tylko jeżeli nie jest możliwe zastosowanie takiego sposobu, można zastanowić się nad zastosowaniem usługi Service Binding Manager. Jedynie ostatecznością powinna być ręczna modyfikacja portów, na jakich nasłuchują różne usługi uruchamiane przez serwera aplikacji:

Dlaczego warto używać oddzielnych adresów IP w zależności od instancji serwera:

  • łatwiej jest skojarzyć konkretną instancje JBossa z konkretnym numerem IP, niż pamiętać na jakie usługi na pracują na których niestandardowych portach
  • łatwiej jest skonfigurować zaporę ogniową
  • jeżeli istnieje na maszynie wiele usług, rośnie prawdopodobieństwo wystąpienia konfliktu portów nawet jeżeli używamy usługi SBM
  • łatwiejsza aktualizacja serwera aplikacji (brak problemów wynikających z nadpisaniem plików konfiguracyjnych, w szczególności w przypadku ręcznej edycji numerów portów)

Powyższe opisy działa w przypadku JBossa 5.1 i 5.0, w przypadku wcześniejszych wymagana jest trochę inna konfiguracja. Zmiana domyślnego adresu IP na którym nasłuchuje serwer jest taka sama, ale w przypadku JBossa 4.2 usługa SBM nie jest domyślnie włączona. Trzeba ją włączyć samodzielnie, co wymaga edycji odpowiednich plików. Podobnie inaczej się przypisuje ręcznie porty, na których nasłuchują poszczególne usługi (należy zmodyfikować pliki konfiguracyjne poszczególnych usług). Dokładniejszy opis można znaleźć w materiałach źródłowych.

Źródła

Tags: , , , , , , , , ,