środa, 8 lipca 2009

środa, 13 maja 2009

svn merge -r:53:1

Bum Bum Bum, Bęc Bęc, Tadam: www.paulszulc.com
A teraz szczegóły:

Troszeczkę ponad rok temu zadebiutowałem z moim blogiem. Teraz po wypoceniu 53 postów nadchodzi dość poważna zmiana: przechodzę na język angielski!
Powiesz: język angielski? Już to kiedyś było... Zgadza się, pierwszy post jaki powstał na tym blogu, był w języku angielskim. Wtedy jednak Jacek Laskowski i Radek Holewa przekonali mnie, aby bloga prowadzić w języku polskim. Chociaż wciąż biłem się z myślami, w końcu decydowałem się na ojczysty język.

To było rok, zatem skąd ta zmiana, czemu rollback do wersji 1? Coż, złożyło się na to kilka spraw.
Nie bez znaczenia był wpis na blogu Pawła Badeńskiego, a tak naprawdę follow up do bloga Jeff'a Atwooda. Ten konkretny post polecam przeczytać wszystkim, którzy piszą swoje blogi po polsku. Można się z nim zgadzać lub nie, mnie osobiście to przekonało całkowicie. To znaczy nawet nie tyle co mnie przekonało, a utwierdziło w przekonaniu.

Po co pisać bloga technicznego? Jaki jest tego cel? Różni ludzie mają różne powody. Dla mnie najważniejsze były zawsze dwa: po pierwsze aby poznać przez niego jak najwięcej osób, po drugie aby dostać jak największy zastrzyk wiedzy. Każdy (no nie przesadzajmy, że każdy, ale powiedzmy każdy ciekawy) post na moim blogu powodował sprzężenie zwrotne. Dostawałem ogromny feedback od czytających (czy to w komentarzach czy w mailach). Napisać post to dopiero połowa frajdy z pisania bloga, obronić go potem przed krytyczną publiką, podyskutować, tu sie zaczyna prawdziwa jazda.

Kiedy spojrze sobie na swoje staty, widze, jak często ludzie z całego świata, zachęceni jakimś hasłem na googlu, wchodzili na mojego bloga, żeby tylko przekonać się, że informacje, które poszukiwali są napisane w jakimś obcym dla nich języku. Miałem w ciągu dnia 50 wejść na strone, z czego 20 wejść trwało do 3 sekund maksymalnie. No bo co z tego, że Protugalczyk chciał wiedzieć jak zainstalować Oracla naUbuntu, skoro polskiego nie zna ani trochę? Czy nie zdażyło Wam się kiedykolwiek szukać odpowiedzi na jakiś rzadki problem i jedyne co google pokazywały to pojedyńcze forum w języku japońskim? Ta jedna jedyna odpowiedź w całym necie na dręczący Was problem, musiała być akurat napisana w "ślaczkach" I taka myśl tylko przychodzi wtedy do głowy: "Czemu on kurde nie napisał tego po angielsku?!".
I tu dochodzimy do sedna sprawy. Angielski stał się defacto takim esperanto świata IT. Trudno mi sobie wobraźć pracę w moim zawodzie bez znajomości tego języka choćby w czytaniu. Niedawno odbyta konferencja GeeCON2009 w Krakowie (za którą nota bene wielkie brawa dla organizatorów) uświadomiła mi, że tak naprawdę polscy programiści, znają język angielski bardzo dobrze. Jaki jest więc sens pisania po polsku?

"Polacy nie gęsi, też swój język mają". Prawda, ale ja prowadze blog techniczny, zawężony do konkretnej grupy osób, dla której nie ma już barier, granic. One po prostu nie istnieją. Może gdybym prowadził bloga o Wrocławiu, polskich lasach mieszanych, czy muzyce folklorystycznej Dolnego Śląska, wydawanie go po angielsku miałoby się z celem. Ale gdy pisze te moje wypociny, często zadając w postach, więcej pytań, niż dając odpowiedzi, czemu ograniczać mam grono słuchaczy, skoro i tak wszyscy język angielski znają?

Tak sobie myślę, że fajnie byłoby się pokłócić z jakimś Francuzem czy Chińczykiem o wyższkości Springa nad EJB (czy EJB nad Springa). Teraz mam nadzięję będę miał taką okazję :)
Pytanie pozostaje tylko jedno, czy nowego bloga dodacie też do swoich RSSów? Mam cichą nadzieję, że tak :). Wystarczy wejść: http://paulszulc.wordpress.com/

Paweł Szulc

PS. Pytanie czemu nagle wordpress.com a nie blogspot.com? Bo WordPress jest o niebo bardziej konfigurowalny, łatwiej zarządzalny i kilka fajnych rzeczy (jak staty wejść czy rssów) ma na starcie.

wtorek, 24 lutego 2009

Pierwsze spotkanie Wrocław Java User Group


Tak tak moi mili, w końcu doczekaliśmy się wrocławskiego JUGa! Od czasu jak skończyłem zabawę ze studiami na Politechnice Wrocławskiej (i pałeczkę nad PWrJUG przejął kto inny), zastanawiałem się czy i kiedy ruszyć z wrocławskim JUGiem. No i tyle czasu mi to zastanawianie się zajęło, że temat w końcu ruszył ktoś inny, a mi pozostaje się już tylko przyłączyć. W głowie mam pełno pomysłów, jeśli chociaż połowe z nich uda się zrealizować, myślę, że będzie ciekawie.

Poniżej oficjalne zaproszenie ze strony Wrocław JUG:

Witam,
Mam ogromną przyjemność poinformować Was o powstaniu Wrocławskiej Grupy Użytkowników Technologii Java (tak, wreszcie ;-)

Już w najbliższy wtorek 24 lutego o godzinie 18:30 w sali 119 Instytutu Informatyki Uniwersytetu Wrocławskiego odbędzie się nasze pierwsze spotkanie. Wszystkich serdecznie zapraszamy.

Na początek Przemysław Pokrywka przybliży nam statycznie typizowaną wersję dobrze znanego wzorca builder. Wzorzec ten przeżywa teraz renesans popularności dzięki publikacjom Josha Blocha i oddźwięku w blogosferze. Nie radzi sobie jednak najlepiej z obsługą najbardziej skomplikowanych przypadków. Sprawdzenie poprawności parametrów tworzonego obiektu następuje późno - dopiero w czasie wykonania. Przemek przedstawi jego usprawnienie, dzięki któremu można zablokować możliwość tworzenia niepoprawnych obiektów już na etapie kompilacji. Pokaże, jak je wykorzystać na przykładzie zaczerpniętym z wrocławskiej rzeczywistości - czynności, która normalnie powinna być prosta, a została wspaniale skomplikowana - płatności za przedszkole :)

Przemek programuje w Javie od 9 lat, od 4 lat komercyjnie. Interesują go tematy z kręgu OOP, refaktoryzacji, wzorców projektowych, podejścia funkcyjnego, AOSD, SCM, Linux, open-source, agile, lean.

Z racji tego, że będzie to pierwsze spotkanie Wrocław JUG, po prelekcji Przemka zamierzamy omówić sprawy organizacyjne. Chcemy się przedstawić :-) , powiedzieć Wam jakie mamy plany i pomysły związane z Wrocław JUG. Wysłuchać Waszych opinii, pomysłów, dowiedzieć się jakie macie oczekiwania. Liczymy też na Waszą pomoc przy dalszym rozwijaniu całej inicjatywy.

Przewidywany czas spotkanie to około 2 godziny. Wstęp wolny!

Więcej informacji oraz aktualności związane z działalnością Wrocław JUG możecie znaleźć na www.wroclaw.jug.pl.

Serdecznie zapraszam (w moim i moich kolegów imieniu)
Paweł Zubkiewicz


Z mojej strony powiem tyle: przybywajcie licznie, im więcej nas, tym lepiej dla wszystkich :)

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.