czwartek, 29 stycznia 2009

JBoss: jeden serwer, wiele domen

JBoss w standardowej konfiguracji przygotowany jest do pracy z jedną domeną. Oczywiście może obsługiwać więcej domen, ale wszystkie domeny dla danego serwera będą odwoływać się do tej samej instancji.
Przykładowo załóżmy, że kupiliśmy dwie domeny dla naszych dwóch niezależnych biznesów:

kwiaty-na-zamowienie.pl
antypatia.pl

Obie domeny wskazują na ten sam adres IP naszego serwera aplikacyjnego.

Napisaliśmy dwie niezależne aplikacje wykorzystując J2EE i spakowaliśmy je do war'ów lub ear'ów, w naszym przykładzie kwiaty.war oraz antypatia.war. Jeśli wdrożymy je na serwer aplikacyjny, bedziemy mieli do nich dostep z adresów:

http://kwiaty-na-zamowienie.pl/kwiaty
http://antypatia.pl/antypatia

Co jest nie tak z tym rozwiązaniem? Cóż, abstrachując narazie od faktu, że nikt nam nigdy nie wejdzie na naszą stronę (bo ludzie przezwyczajeni są do tego, iż w adresie wpisują tylko adres domeny (antypatia.pl, kwiaty-na-zamowienie.pl) i nie dopisują nic po slashu), musimy mieć jeszcze na uwadze, że takie adresy też będą działać:

http://kwiaty-na-zamowienie.pl/antypatia
http://antypatia.pl/kwiaty

a to już jest totalnie nie do zaakceptowania. O ile obie aplikacje są wdrożone na tym samym serwerze , o tyle chcielibyśmy http://kwiaty-na-zamowienie.pl przenosilo nas do aplikacji kwiaty.war, a http://antypatia.pl/ do aplikacji aplikacja.war.

Na szczęście serwer JBoss obsługuje wirtualne serwery w ramach różnych domen. Innymi słowy jesteśmy wstanie tak skonfigurować serwer aplikacyjny, aby obługiwał żądania w zależności od tego z jaką domeną będzie każdorazowo żadanie powiązane.
Konfirgurację tą przeprowadzamy w pliku server.xml (gdzie znaleźć ten plik pisałem w poście o zmianie defaultowego portu w JBossie). Cały trik polega na dodaniu tagów <Host> dla każdego wirtualnego serwera, który chcemy obsługiwać. Tak więc, aby obsłużyć dwie wspomniane już wcześniej domeny należy:

1. w pliku server.xml dodać:

<Server>

(...)
<Engine name="jboss.web" defaultHost="vhost1">
<Realm className="org.jboss.web.tomcat.security.JBossSecurityMgrRealm"
certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
/>
<Logger className="org.jboss.web.tomcat.Log4jLogger"
verbosityLevel="WARNING"
category="org.jboss.web.localhost.Engine"/>

<Host name="kwiaty" autoDeploy="true"
deployOnStartup="true" deployXML="true">
<Alias>kwiaty-na-zamowienie.pl
<Alias>www.kwiaty-na-zamowienie.pl
<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="vhost1" suffix=".log" pattern="common"
directory="${jboss.server.home.dir}/log"/>


<DefaultContext cookies="true" crossContext="true" override="true"/>
</Host>
<Host name="antypatia" autoDeploy="true"
deployOnStartup="true" deployXML="true">
<Alias>www.antypatia.pl
<Alias>antypatia.pl

<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="vhost2" suffix=".log" pattern="common"
directory="${jboss.server.home.dir}/log"/>

<DefaultContext cookies="true" crossContext="true" override="true"/>
</Host>
</Engine>
</Service>
</Server>
2. powiadomić każdą z aplikacji do jakiego serwera wirtualnego należą

W tym celu wystarczy w pliku jboss-web.xml dodać wpis (na przykładzie aplikacji antypatia.pl):
<jboss-web>
<virtual-host>antypatia.pl</virtual-host>
</jboss-web>

Na koniec aby nasza strona była widoczna z adres www.antypatia.pl a nie z www.antypatia.pl/antypatia, zmieniamy contextRoot na /.

Aby tego dokonać należy:

a) w przypadku aplikacji webowych będących poza plikiem .ear ponownie wyedytować plik i dodac wpis
<jboss-web>
<context-root>/</context-root>
<virtual-host>antypatia.pl</virtual-host>
</jboss-web>

b) w przypadku aplikacji pakowanych do pliku .ear

* wyedytować plik wdrożeniowy application.xml


<application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4"

(...)

<module>        
   <ejb>antypatia.jar    
</module>    
<module>        
   <web>            
     <web-uri>web-client.war</web-uri>            
     <context-root>/</context-root>        
   </web>    
</module>
</application>


Jesli naszego .eara budujemy przez Mavena, odpowiednik powyższego wpisu znajdziemy w POMie.


referencje:
http://docs.jboss.org/jbossas/guides/webguide/r2/en/html/ch07.html#ch9.virtualhost.ex
http://docs.jboss.org/jbossas/guides/webguide/r2/en/html/ch06.html
http://ranjankumar.com/2008/08/14/how-to-set-context-root-of-web-application-in-jboss/

środa, 28 stycznia 2009

News Buzz: 28 styczeń 2009

Kilka ciekawych artykułów znalezionych w sieci:

  • GIT: kompedium wiedzy - GIT to repozytorium kodu stworzone przez Linusa Torvaldsa (tak, ten gość od Linuxa), które zbiera ostatnimi czasy coraz większe rzesze zwolenników. Główne zalety to szybkość, rozproszona struktura oraz cudowne podejście do branch'y (jeśli kolejny dzień klniesz na svn, bo znów rzucił jakiś konflikt przy zwykłym margeu, zapoznaj sie z GITem - tu wszystko od poczatku do konca jest branchem i marge działają o niebo lepiej). W tym poście autor zebrał ogromną ilość linków do najróżniejszych zasobów w sieci odnoszących się do GITa. Gorąco polecam.
  • Optimize Your Team - ciekawy i relatywnie krótki post odnoszący się do metodyk zwinnych. Trendy, których w polskich firmach IT pewnie jeszcze długo nie zobaczymy
  • Maven 2 advanced - jak mówi sam autor, w sieci jest trylion tutoriali pokazujących podstawy Mavena, o wiele mniej artykułów odnośnie ciutke bardziej skomplikowanych przykładów niż przysłowiowe Hallo world. Pokaz slajdów ze spotkania włoskiego JUG Roma.
  • JEE6 - JPA 2.0 - aby być na czasie i wiedzieć w jakim kierunku zmierza enterprise Java, zachęcam do zapoznania się z tym krótkim wpisem
Miłego czytania :)

wtorek, 27 stycznia 2009

Unable to find valid certification path to requested target

--------------------------

Unable to find valid certification path in English

--------------------------

Jeśli nawiązujecie połączenie z usługą sieciową (web service) poprzez https (czyli z użyciem SSL) natrafić możecie na dość znany wyjątek:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


Oznacza to tyle, że łączymy się z usługą przez SSL i nie znamy lub nie akceptujemy certyfikatu uwierzytelniającego tej usługi. Gdybyśmy łączyli się ze stroną www przez przeglądarkę, wyskoczyłoby nam znane okienko informujące nas, że połączenie nie może być nawiązane, gdyż (cytując Firefox'a) "certyfikat nie jest zaufany, ponieważ certyfikat wystawcy nie jest zaufany.". Wtedy najczęściej klikamy "Zaufaj witrynie" lub "Potwierdź wyjątek bezpieczeństwa" i już możemy oglądać naszą witrynę w bezpiecznym połączeniu SSL.

W przypadku programów napisanych w języku Java, nie mamy pewności, że zawsze po drugiej stronie aplikacji będzie siedział użytkownik, który kliknie "Potwierdź wyjątek bezpieczeństwa". Dlatego, aby aplikacja łączyła się zawsze poprawnie przez SSL, należy wcześniej ten "wyjątek" potwierdzić.
Najprostszym sposobem jest wygenerowanie tak zwanego keystore'a dla danego certyfikatu i potem użycie go w aplikacji. Robi się to w sposób następujący:

1. wygenerowanie pliku .cer

Jest to plik reprezentujący certyfikat. Często jest udostępniany przez firmę, z której serwerem łączymy się przez SSL. Jeśli jednak nie mamy do niego dostępu najprościej go zdobyć wchodząc na dany adres usługi (ten adres uslugi, z która później ma łączyć się nasza aplikacja) poprzez dowolną przeglądarkę. Potwierdzić certyfikat, następnie odnaleźć go w ustawieniach przeglądarki i na końcu wyeksportować do pliku .cer. Większość przeglądarek (na pewno Firefox i Opera) udostępniają taką funkcjonalność.

2. wygenerować keystore

Keystore możemy wygenerować wraz z narzędziem keytool, które dostępne mamy zawsze wraz z naszym JDK. Wywołujemy ten program w konsoli w sposób następujący:

keytool -import -trustcacerts -keystore cacerts -storepass twoje_haslo -noprompt -file cert.cer

gdzie: -file to wygenerowany w punkcie pierwszym plik .cer, -keystore to nazwa pliku keystore (może być dowolna), -storepass to hasło które będzie używane wraz z danym keystorem.

3. ustawienie propertiesów

Na końcu należy wygenerowany plik keystore (w naszym przypadku nazywa się cacerts) wrzucić do katalogu naszej aplikacji, a w samym kodzie ustawić dwa dodatkowe propertiesy:


System.setProperty("javax.net.ssl.trustStore", "cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "twoje_haslo");


Od tego momentu powinniśmy bez problemów łączyć się z dowolną bramką webservicową (czy też jakąkolwiek usługą w sieci) poprzez SSL.

Referencje:
http://wso2.org/forum/thread/3018
http://blogs.sun.com/andreas/entry/no_more_unable_to_find

czwartek, 22 stycznia 2009

Java Killers #10

Dziejszy Java Killer prosty i niezbyt wyrafinowany. Ależ jak wiele bólu może dostarczyć, gdy taki kod dostanie się na produkcje, wie tylko programista, który to przeżył...
No dobra, nie jest, aż tak tragicznie, ale mimo wszystko boli. Pytanie na dziś, co wypisze na konsoli działanie poniższego programu:


public static void main(String[] args) {

SortedSet names = new TreeSet();

names.add("Gąskalska Anna");
names.add("Enigmatyczna Jola");
names.add("Ambroży Tomasz");
names.add("Ędward Ącki");

System.out.println(names);

}



Odpowiedzi możliwych kilka, a prawdziwa jak zwykle tylko jedna:

A) [Gąskalska Anna]
B) [Ambroży Tomasz, Enigmatyczna Jola, Gąskalska Anna, Ędward Ącki]
C) [Ambroży Tomasz, Enigmatyczna Jola, Ędward Ącki, Gąskalska Anna ]
D) [Ambroży Tomasz, Ędward Ącki, Enigmatyczna Jola, Gąskalska Anna ]
E) java.util.SortedSet@122cdb6
F) błąd kompilacji



Otóż okazuje się, że prawidłowa odpowiedź to:
B) [Ambroży Tomasz, Enigmatyczna Jola, Gąskalska Anna, Ędward Ącki]

Jak to!? Przecież miała być lista posortowana alfbatecznie! Co jest grane? Cóż, program zachowuje się zgodnie ze specyfikacją, gdzie wyraźnie czytamy:

Method comparesTo (...) compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. (...) Method compareTo returns the difference of the two character values at position k in the two string -- that is, the value this.charAt(k)-anotherString.charAt(k).


A jak przyjrzymy się znakom Unicode, polskie krzaczki mają wartości o niebo większe od standardowych literek z alfabetu łacińskiego. I tak ę, ą, ć, ń, ż, ź, ś, ó oraz ł będzie zawsze stać za całą resztą abecadła.
Miejscie to prosze na uwadze, sortując swoje listy :)

środa, 21 stycznia 2009

Oracle Application Server (Apex) nie wstaje

Instalując Oracla na Ubuntu natknąłem się na ciekawą sytuację. Instancja bazy była uruchomiona, jednakże nie mogłem połączyć się z Application Serverem (a konkretnie z aplikacja apex, zarządzającą bazą danych). Ponieważ podobną sytuację spotkałem na dwóch różnych kompach, pomyślałęm, że podziele się wiedzą jak wyjść z takiego impasu.

Ponieważ żadnym Oraclowym ekspertem nie jestem, zrobiłem to co wydawało się intuicyjne:

1. sprawdziłem status

pawel@ingrid:~$ sudo /etc/init.d/oracle-xe status
[sudo] password for pawel:

LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 03-NOV-2008 19:35:13

Copyright (c) 1991, 2005, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
TNS-12541: TNS:no listener
TNS-12560: TNS:protocol adapter error
TNS-00511: No listener
Linux Error: 111: Connection refused
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=ingrid)(PORT=1521)))
TNS-12541: TNS:no listener
TNS-12560: TNS:protocol adapter error
TNS-00511: No listener
Linux Error: 111: Connection refused


2. Zrestartowałem

pawel@ingrid:~$ sudo /etc/init.d/oracle-xe restart
Shutting down Oracle Database 10g Express Edition Instance.
Stopping Oracle Net Listener.

Starting Oracle Net Listener.
Starting Oracle Database 10g Express Edition Instance.

3. I zaczeło działać :)

pawel@ingrid:~$ sudo /etc/init.d/oracle-xe status

LSNRCTL for Linux: Version 10.2.0.1.0 - Production

Copyright (c) 1991, 2005, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.1.0 - Production
Uptime 0 days 0 hr. 0 min. 52 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Default Service XE
Listener Parameter File /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/network/admin/listener.ora
Listener Log File /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/network/log/listener.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC_FOR_XE)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=ingrid)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=8080))(Presentation=HTTP)(Session=RAW))
Services Summary...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
Service "XE" has 1 instance(s).
Instance "XE", status READY, has 1 handler(s) for this service...
Service "XEXDB" has 1 instance(s).
Instance "XE", status READY, has 1 handler(s) for this service...
Service "XE_XPT" has 1 instance(s).
Instance "XE", status READY, has 1 handler(s) for this service...
The command completed successfully


Ot wielka filozofia... Ale działa i to chyba najważniejsze :)

wtorek, 20 stycznia 2009

SCJP passed, na horyzoncie SCBCD

Ten post przygotwany miałem już kilka miesięcy temu, ale gdzieś się zawieruszył w czeluściach archiwum. Cóż, lepiej późno niż wcale :)

Od dłuższego czasu jestem czytelnikiem bloga Racjonalny Developer. Z autorem bloga nie znam się za bardzo (wymieniliśmy kiedyś jedną czy dwie korespondencje), ale jednak mamy coś wspólnego. Po pierwsze w podobnym czasie pozakładaliśmy blogi, oboje mamy wpisy o trikach w javie (u mnie seria Java Killers u niego luźne wpisy), a teraz na dodatek zdaliśmy oboje SCJP w podobnym czasie i oboje przymierzamy się do SCBCD. Może to zbieg okoliczności, choć jak mówił Vandetta "nie ma zbiegów okoliczności, jest tylko ich złudzenie".
No ale pomyślałem sobie, że skoro racjonalny developer się chwali to ja też mogę. Zdałem SCJP 6.0. Hurra! Czy było trudno, hm... ciężko powiedzieć co znaczy trudno. Wydawało mi się, że będzie to bułka z masłem, a zdałem na 80%. Jeśli chcesz wiedzieć czy zdasz wystarczy przerobić 3 symulatory SCJP (których pełno w książkach i na sieci) i jeśli średnia wyniesie więcej jak 70% to spokojnie możesz się wybrać. Jeśli natomiast zależy ci na dogłebnym zdobyciu wiedzy, czyli nie idziesz po certyfikat tylko po to, żeby go mieć, ale też chcesz się czegoś po prostu w świecie nauczyć, polecam zdecydowanie książkę "SCJP, SCJD - Complete Java 2 Certification - Study Guide, 5Ed". Nie ma chyba bardziej kompletnego podręcznika do SCJP niż właśnie ta książka autorstwa Philip Heller oraz Simon Roberts (nota bene autorów wielu pytań egzaminacyjnych SCJP). Dodatkowo jako reviewu polecam "Sun Certified Programmer for Java 5 Study Guide" autorstwa Kathy Sierra. Książka jest prawie kompletna (kilku informacji w niej nie znalazłem), ale zawiera za to CD z mock egzaminami. Bardzio fajnie rozwiązane są te próbne egzaminy, gdyż jeśli nie znasz odpowiedzi na dane pytanie, program wskazuje Ci dokładne miejsce w książce, gdzie odpowiedź na to pytanie znajdziedz. Narzędzie bardzo przydatne przy powtórkach.