Zapraszam tu: www.paulszulc.com
ś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>2. powiadomić każdą z aplikacji do jakiego serwera wirtualnego należą
(...)
<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>
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
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) {
SortedSetnames = 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.
czwartek, 13 listopada 2008
Name clash: has the same erasure but does not override it
Pisząc aplikacje wykorzystujące generyki, możecie natrafić na przedziwny błąd. Wyobraźcie sobie interfejs IDao (z pojedyncza metoda updateStubs(List<T>) oraz klasę, która go implementuje AbstractDao. I nagle kompilator krzyczy:
Name clash: The method updateStubs(List) of type AbstractDao<T> has the same erasure as updateStubs(List) of type IDao but does not override it.
Zaraz zaraz, metoda z klasy ma taką samantykę i erasure jak nadrzędna metoda z interfejsu, ale jej nie nadpisuje? O co chodzi?
Spójrzmy na początek definicji interfejsu:
public interface IDao<T extends IStub> {
a następnie na początek defnicji klasy AbstractDao:
public abstract class AbstractDao<T extends IStub> implements IDao {
Co jest nie tak? Otóż wprawna osoba odrazu zauważy (a nieroztropny [czytaj ja] programista przegapi) fakt, iż przy IDao brakuje odwołania do typu generycznego! Poprawnie powyższa definicja powinna wyglądać następująco:
public abstract class AbstractDao<T extends IStub> implements IDao<T> {
Po tej małej zmianie wszystko powino być już w porządku, a kompilator nie krzyczy, że ma metode w podklasie, ale jej nie nadpisze.
poniedziałek, 10 listopada 2008
Java Killers #009
Jakiś czas temu odezwał się do mnie dobry znajomy Paweł Badeński, który uhahany rozpoczął rozmowę na gadu z tekstem "Patrz na to: ..." po czym wkleił kawałek kodu. Kod przerzuciłem na szybko do ulubionego IDE i już wtedy wiedziałem, że te kilka lini ma predyspozycje na kolejny odcinek killersów. Problem pozostawał jednak wciąż, gdyż za diabła nie wiedziałem, czemu kod zachowywał się właśnie tak a nie inaczej. Szybkie przestudiowania Java Language Specification nie dało odpowiedzi, google na szybko też nie były takie cwane, jak zwykle. Dopiero po dłuższej chwili grzebania udało mi się dotrzeć do buga na bugs.sun.com, gdzie po dogłebnej lekturze i ponownym otworzeniu Java Language Specification, wszystko stało się jasne. Jestem ciekaw czy i dla Was dziewiąta odsłona Java Killers będzie taką samą łamigłówką jak była dla mnie. A oto ona:
Mając poniższy kod, jakiego spodziewamy się outputu:
Odpowiedź poprawna tylko jedna, a kilka do wyboru:
public class Foo
{
public int loo(List<String> a)
{
return 1;
}
public double loo(List<Integer> a)
{
return -1;
}
public static void main(String[] args)
{
List list = new ArrayList<Integer>();
System.out.println("output: " + new Foo().loo(list));
}
}
A. Klasa nie skompiluje się, javac poinformuje nas, że "name clash: loo(java.util.List
B. Klasa nie skompiluje się, javac poinformuje nas, że "reference to loo is ambiguous"
C. Skompiluje się, ale wyrzucony zostanie RuntimeException po uruchomieniu programu
D. Program skompiluje się i uruchomi się bez wyjątków i zostanie wypisane na ekranie 'output: -1'
E. Program skompiluje się i uruchomi się bez wyjątków i zostanie wypisane na ekranie 'output: 1'
I uwaga uwaga, poprawna odpowiedź to B!
Osoby, które przekonane były, że oby dwie metody loo miały taką samą sygnaturę i przez to kod się nie kompilował, nie martwcie się, nie byliście jedyni, którzy zaznaczyli odpowiedź A. Otóż okazuje się, że jednak sygnatury obu metod się różnią i występuje najprostszy w świecie method overloading. Później w czasie wywołania metody loo w ciele metody main, następuje konsternacja, gdyż kompilator widzi zmienną niegenneryczną List list i nie ma pojęcia do której metody loo ma się odwołać, stąd jego krzyk
Ok, ktoś się spyta, jak to metody loo mają taką samą sygnaturę? Patrząc na Java Language Specification punkt 8.4.9, widzimy, że:
* obie metody mają taką samą nazwę
* obie metody mają taką samą liczbę formalnych parametrów oraz parametrów typów prostych
* ALE typy tych parametrów się różnią, List<String> to co innego niż List<Integer>! Mimo, że przed samą kompilacją wszystkie generyki zostają zrzucone i nie są brane pod uwagę podczas kompilacji (pisałem o tym w poprzednich killersach) o tyle są uwzględniane podczas operacji zwanej "type erasure" - dlatego właśnie List<String> to co innego niż List<Integer>.
No i to tyle na dziś. Kto znał poprawną odpowiedź?
PS. Wspomniana strona do której dotarłem (i musiałem się nieźle nagooglać) znajduje się tutaj:
środa, 5 listopada 2008
Maven javaee-api-5
Jeśli dane jest Wam pisać aplikacje JEE5 z użyciem mavena, dość paradoksalnie możecie się spotkać z brakiem w dostępnych repozytoriach pliku javaee-api-5.jar (definiującego API standardu JEE5). Jeśli więc kiedykolwiek dostaniecie informacje od mavena, że nie może za żadne skarby znaleźć API JEE5, polecam zajrzeć tutaj:
https://maven-repository.dev.java.net/nonav/repository/javaee/jars/
W repozytorium java.net jar z API standardu leży sobie grzecznie, czekając, aż go ktoś ściągnie.
wtorek, 4 listopada 2008
Zmiana portu JBoss Application Server z 8080 na inny
JBoss Application Server uruchamia się standardowo na porcie 8080. W odróżnieniu od Glassfisha nie ma admina webowego (co jest zastanawiające czemu) i żeby cokolwiek zmienić w konfiguracji, trzeba poedytować pliki konfigów.
W tym poście zakładam, że JBoss zainstalowany jest w katalogu /opt/jboss/. Aby zmienić port HTTP z 8080 na jakiś inny należy dostać się do pliku server.xml zlokalizownego w /opt/jboss/server/default/deploy/jboss-web.deployer/ i wyedtować go. Odnajdujem poniższy wpis i w miejscu XXX wpisujemy intersujący nas port (na przykład 80):
<Connector port="XXX" address="${jboss.bind.address}"
maxThreads="250" maxHttpHeaderSize="8192"
emptySessionPath="true" protocol="HTTP/1.1"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
poniedziałek, 3 listopada 2008
Oracle Apex widoczny poza localhost'em
Ostatnio pisałem jak zainstalować Oracla na Ubuntu, dziś pora przyjrzeć się aplikacji webowej Apex (pozwalająca zarządzać bazą danych), która standardowo instaluje się wraz z Oraclem i dostępna jest pod adresem http://localhost:8080/apex. Wszystko działa fajnie, do czasu gdy chcielibyśmy dostać się do aplikacji przez inny adres niż http://localhost, czyli zdalnie. Poniżej krótka instrukcja jak to zrobić:
1. zainstaluj sqlplus jeśli (jeszcze nie masz):
apt-get install sqlplus
2. ustaw ORACLE_HOME (jesli jeszcze tego nie zrobiles):
ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server
3. zaloguj się do sqlplusa jako user SYSTEM
sqlplus system
4. gdy pojawi się sql prompt (ktoś zna polski odpowiednik słówka prompt?) wpisz:
SQL> EXEC DBMS_XDB.SETLISTENERLOCALACCESS(FALSE);
Powinno zacząć działać.
niedziela, 2 listopada 2008
Where is everybody?

"Where is everybody???" No właśnie, dobre pytanie. Blog trochę podumarł i przycichł. Czemu? Otóż zaczynamy z kolegami mały skromny start-up (o którym może kiedyś, jak już coś będzie wydane na świat) i przez ostatnie dwa miesiące poświęciłem się mu bezgranicznie. Teraz troszkę się już uspokoiło i ponownie mogę wrócić do zajęcia, które sprawia mi też sporo radości - blogowania.
Do zobaczenia niebawem, trochę się nazbierało dziwnych sytuacji, o których warto by tu napisać.
czwartek, 28 sierpnia 2008
Wyszedł pierwszy numer JAVA exPress!
Wyszedł pierwszy numer JAVA exPress, jakieś kilka godzin temu, a w polskiej blogosferze wciąż cicho (nawet odziwo na blogu głównego pomysłodawcy), więc pozwalam sobie poinformować o wydaniu pierwszego (i mam nadzieje nie ostatniego) numeru JAVA exPress, który w postaci pdf'a można za darmo sciągnąć stąd.
Coż można powiedzieć po wstępnym przejrzeniu gazetki? Widać, że zarówno pomysłodawca (Grzegorz Duda) jak i autorzy (Bartek Kuczyński, Jakub Jurkiewicz, Mariusz Sieraczkiewicz, Jackiw Pospychała oraz Marek Kliś) bardzo mocno się postarali, aby pierwszy numer wypadł ciekawie. Jeśli kolejne numery utrzymają formę, zapowiada się bardzo ciekawy zin w polskim światku javowym.
Boli tylko troszkę, że nie można takiej gazetki nigdzie kupić w formię drukowanej. Piękno przecież takich artykułów polega na tym, że można je sobie spokojnie poczytać w pociągu, samolocie czy też w domu leżąc wygodnie na kanapie. Niestesty na papierową wersję JAVA exPress trzeba będzie nam jeszcze sporo poczekać i narazie zadowolić się będzie trzeba SDJ (gdzie poziom artykułów zwykle bliżej dna niż powierzchni).
środa, 27 sierpnia 2008
Instalacja Oracle na Ubuntu
For English press http://paulszulc.wordpress.com/2009/05/25/installing-oracle-on-ubuntu/
Oracle to baza danych przez duże B i duże D. Wystarczy poczytać sobię trochę o architekturze Oracla, aby przekonać się czemu jest to jedna z najczęściej wykorzystywanych baz w biznesie. Dotychczas (na studiach :) ) wiedza o bazach danych była mi na tyle potrzebna, co założyć bazę, stworzyć strukture (tabele, widoki, indexy) i na końcu zmapować to wszystko w jakis ORM (Hibernate czy inny TopLink). Ponieważ w pracy wymagają ode mnie troszkę większej wiedzy na temat Oracla i baz danych w ogólności, postanowiłem po godzinach przyjrzeć się tej bazie u siebie na mojej lokalnej maszynie.
Aby to uczynić należało wpierw bazę tą zainstalować, co okazało się względnie prostym zadaniem na systemie Ubuntu (obecnie w wersji 8.04). Kolejne kroki w wersji skróconej podaje poniżej:
1. Dodać nowe repozytorium
1.1 Do listy należy dodać deb http://oss.oracle.com/debian unstable main non-free. Można to zrobić wyklikując System->SoftwareSources->Third-Party Software (jak na poniższym obrazku) lub dodać wpis ręcznie do /etc/apt/sources.list - jak kto woli.
1.2 Dodać klucz publiczny, najprościej w konsoli wpisując
wget http://oss.oracle.com/el4/RPM-GPG-KEY-oracle -O- | sudo apt-key add -ale można oczywiście również wyklikać przez System->SoftwareSources->Authentication
2. Uruchomić instalację Oracla
Wystarczy teraz już tylko standardowe:
sudo apt-get install oracle-xe
i po wykonanej instalacji uruchomić program konfigurujący:
sudo /etc/init.d/oracle-xe configure
gdzie odpowiada się na cztery proste pytania: o port dla Oracle Application Express (defaultowo 8080), port do połączeń z bazą danych (defaultowo 1521), hasło dla administratora (użytkownika SYSTEM) oraz określa się czy baza ma uruchamiać się wraz z uruchamianiem się systemu.
I to tyle! Mamy działającą instancję Oracla. Możemy zacząć zabawę z systemem uruchamiając SQL*Plus'a lub application express (http://127.0.0.1:8080/apex).
poniedziałek, 25 sierpnia 2008
java.util.Date vs java.sql.Date
Natknąłem się na ciekawe rozwiązanie architektoniczne w JDBC: obiekt java.sql.Date. Jest to obiekt, który dziedziczy bezpośrednio po java.util.Date, pozwalający nam mapować w naszych beanch pola typu Date z naszych baz danych.
Czy wszystko jest takie piekne? Nie do końca, gdyż w naszych beanach zwykle trzymamy obiekty typu java.util.Date.
Wyboraźmy sobie prosty przykład:
Mamy klase User w postaci
public class UserPosiadamy również odpowiadającą jej tabelę w bazie danych:
{
protected String userName;
protected Date birthDate; // tutaj java.util.Date czyli standard
//odpowiednie gettery i settery
}
CREATE TABLE Users (
userName VARCHAR2(150),
birthDate DATE );
Sytuacja jak najbardziej standardowa. Teraz jeśli wyciągnięte dane z bazy (przy pomocy ResultSeta) dodamy do naszego beana:
User u = new User();
u.setUserName(rSet.getString(1));
u.setBirthDate(rSet.getDate(2));
nic się nie stanie. W prawdzie metoda User.setBirthDate oczekuję java.util.Date, a ResultSet.getDate zwraca java.sql.Date, to jednak wszystko jest w porządku, gdyż java.sql.Date dziedziczy po java.util.Date. Jaja zaczynają się, gdy informacje chcemy ponownie przekazać do bazy danych.
Teraz gdy updateujemy jakies informacje przy pomocy jakies procedury skladowanej czy poprzez wywolanie SQL'owego UPDATE, zawsze ale to zawsze poprosza nas o Date w postaci java.sql.Date. Czyli kod
statement.setDate(2,user.getBirthDate());sie po prostu nie skompiluje. Rzutowanie nic tu nie da, gdyż przykładowo poniższy kod:
user.setBirthDate(new Date());się poprostu wywali przy pierwszym wywołaniu. Trzeba utworzyć explicite obiekt java.sql.Date, ale żeby nie było za prosto, nie ma żadnego konstruktora typu public Date(java.util.Date utilDate). Nie, przecież to by było zbyt proste. Zamiast tego musimy zrobic new java.sql.Date(utilDate.getTime()). Konstruktor java.sql.Date przyjmuje longa jako liczbę milisekund od roku 1970, a metoda getTime z java.util.Date taka informacje zwraca. Wszystko działa okej, ale czy na pewno to jest dobre rozwiązanie? Szczerze mówiąc, ja nie wiem. Skoro sami ludzie z Sun Microsystems mówią, że java.sql.Date to tylko "thin wrapper", to po co w ogóle został wprowadzony? Czy istnieje jakiś lepszy (w sensie nie polegający na roku 1970) sposób na konwertowanie dat z java.util na java.sql? Googlałem pobieżnie, nie znalazłem. Może ktoś zna?
statement.setDate(2,(java.sql.Date)user.getBirthDate()); // tu exception
środa, 20 sierpnia 2008
Po przerwie wakacyjnej
Minał okres wakacji i laby. Po obronie pracy magisterskiej nie mogłem przez jakiś czas dojść do siebie - w czym z pewnością usilnie pomagał mi alkohol ;). Potem wyjechałem ze znajomymi na długo wyczekiwany rejs po Mazurach (długi, bo aż ponad trzy tygodniowy). No a teraz..., teraz znów wróciłem do świata żywych i czas odświeżyć wiele spraw, między innymi tego bloga :)
Rozpocząłem prace w ifirma.pl, po moim długim maratonie po firmach IT we Wrocławiu. Zatrudnony jestem jako programista Java oraz PL/SQL, zatem spodziewać się można, że sporo zagadnień na blogu związanych będzie teraz z Oraclem. Obecnie w pracy rozgryzam sprawy związane z webserwisami, więc zapewne jakieś relacje z moich walk z Axis'em (implementacja z Apache'a) się tu pojawią.
Generalnie każdego dnia czegoś nowego się uczę, nierzadko na własnych błedach. Chciałbym aby ten blog był też zapiskiem z tych moich walk i pojedynków z technologiami, tak żeby w przyszłości mógł ktoś kiedyś z tego skorzystać.
Aby zatem nie przedłużać, w wielkim skrócie: I am back :)
wtorek, 24 czerwca 2008
Tools Dig: LiquiBase
Wczoraj marudziłem na brak railsowych migracji w popularnych frameworkach javowych, a już dziś dzięki uprzejmości Pawła Sto (p100 :) ), poznałem bardzo ciekawe narzędzie jakim jest LiquiBase. Narzędzie to posiada większość elementów z railsowych migracji oraz jest nawet śmiem twierdzić nieco lepsze od nich (odczuć mogą to zwłaszcza teamy developerskie, gdzie jest więcej niż 4 programistów i jedno repozytorium kodu :) ).
Dlatego wszem i wobec zachęcam wszystkich do zapoznania się z toolem (http://www.liquibase.org). Warto zwłaszcza zerknąć na screencasty: krótkim (6min) lub dłuższym, obszerniejszym (30min). Omawiają starszą wersję narzędzia, ale dają ogólny taki overviewu, warto obejrzeć.
Niniejszym rozpoczynam też nową mini-serię na moim blogu: Tools Dig . Często napotykam na ciekawe narzędzia w sieci. Jak zwrócił mi uwagę mój kolega, warto się takim znaleziskami dzielić z szerszą publiką, a do tego idealnie nadaje się ten blog. Co niniejszym czynię.
