Monthly Archives: January 2009

Co tam u konkurencji słychać

Jak widać w blogrollu widnieje sporo linków do innych serwisów. Sporo z nich to twórczość programistów PHP, ale niemałą już grupę stanowią osoby zajmujące się Javą na co dzień. Wiele wiadomości, które otrzymuję poprzez RSS dotyczy ciekawych zagadnień, ale póki co dla mnie jeszcze za bardzo “pro”. Jednakże często trafiają się ciekawe wpisy/cykle, które zajmują zaciszne miejsce w zbiorze wiadomości Opera-RSS. Przy okazji postanowiłem podzielić się nimi z szeroką publicznością – zarówno ze względu na tematykę, jak i przydatność blogów ich autorów w ogólności.

Języki skryptowe to języki skryptowe. Java to java – język uruchamiany w maszynie wirtualnej. A co by zrobić, gdyby ktoś połączył te dwa podejścia i skonstruował ich hybrydę? Ano byłoby ciekawie i tutaj pojawia się język Groovy oraz stworzony dla niego framework Grails (zbieżność z Rubym i ROR zamierzona). Środowisko to można poznać dzięki tej książce, a sprawozdanie z jej lektury można znaleźć w notatniku projektanta JEE, Jacka Laskowskiego.

Swego czasu bawiłem się dość intensywnie systemem linux Slackware. Ale było, minęło, a dziś brakuje czasu by zainstalować jakikolwiek system z tej rodziny i zapoznać się z nim bliżej (choć może mniej o system, a bardziej o usługi chodzi). Łukasz Milewski ostatnio popełnił kilka wpisów, które przydadzą się na pewno każdemu programiście, ot choćby po to, aby nie zgubił się podczas odświeżania SVNa.

Swego czasu mile zaskoczył mnie JDN i zaserwowali linki do bardzo ciekawego miejsca. Artykuły napisane solidnie i bardzo treściwe – kto ciekawy nowego w Javie niech zajrzy, a z pewnością nie pożałuje. Artykuły o języku Scala, Swing Application Framework czy UMLu. Warto.

Wzorce projektowe to taki dziwny twór. Wszyscy o nich mówią, wszyscy uważają, że to wielkie narzędzia i… niewielu używa. A najczęściej nie używa bo nie zna i nie umie. Dla takiego właśnie ‘targetu’ powstają regularnie kolejne wpisy na blogu Michała Bartyzela o używaniu konkretnych wzorców projektowych. W tym samym miejscu sieci można natknąć się na ciekawą pozycję książkową.

Na sam koniec zostawiłem sobie tematykę SCJP. Palce mnie świerzbią by wziąść się za przygotowania do tego egzaminu na poważnie, ale póki przygotowanie do niego przy małym doświadczeniu w pisaniu kodu Javy byłyby chyba trochę zbyt męczące. Dlatego najpierw trochę popiszę, a dopiero potem wezmę się za przygotowania. Jednakże w międzyczasie zajmuję się czytaniem tekstów osób, które ten egzamin mają już za sobą, albo też przymierzają się do jego zdania. Fajne materiały można znaleźć u Racjonalnego, a także u Mariusza Lipińskiego (masa wpisów, polecany w wielu miejscach w sieci).

To tyle. Kiedy zachomikuję kolejne ciekawe miejsca lub artykuły z pewnością powstanie kolejny wpis. Póki co zapraszam do lektury.

Advertisements

GridBagLayout w akcji

Do tej pory w ChlebikClient wywoływane były zdarzenia oparte na pokazywaniu kolejnych okien JPane. Główna zaś ramka aplikacji została ‘narysowana’ w NetBeans. Kiedy zatem przyszła pora na stworzenie wewnętrznego okna z możliwością wyboru kolorów zaczęło się robić ciekawie, a konkretniej rzecz w zabawie z ułożeniem elementów wewnątrz ramki.

Do pozycjonowania elementów na kolejnych oknach aplikacji używane są tzw. layout managery. Zgodnie z nazwą zawiadują one rozmieszczeniem poszczególnych elementów – w zależności od potrzeb, używać można jednego z zaimplementowanych w Swingu. Co więcej, można nawet użyć IDE do ‘narysowania’ takiego okienka. Zaintrygował mnie jednak fragment ‘Thinking in Java’, gdzie autor napisał, że menadżer GridBagLayout jest bardzo trudny, ale daje też sporo możliwości. Stwierdziłem zatem, że na prostym przykładzie przećwiczę ten element, skoro niby jest trudny, to tym większa radocha z jego poznania.

Oto wstępny kod (bez importów i takich tam):

JFrame okienko = new JFrame("Testowe okienko");
GridBagLayout layout = new GridBagLayout();</code>

okienko.setLayout(layout);
okienko.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
okienko.setSize(250, 250);
okienko.setLocation(400, 400);
okienko.setVisible(true);

Wyjaśniać za wiele raczej nie trzeba. Tworzymy sobie ramkę – w aplikacji byłaby to instancja klasy JInternalFrame, ale jako, że to jest nasze jedyne okienko to musi ucieleśniać ‘klasę wyżej’ w hierarchii kontenerów. Domyślnie kończymy działanie aplikacji po zamknięciu ramki, ustawiamy jej wymiary i położenie. Należy zwrócić uwagę, że tworzymy już obiekt GridBagLayout, choć na razie z braku elementów wewnątrz ramki niewiele z tego wynika.

Naszym celem jest stworzenie prostego wybierania kolorów. Każdy element aplikacji może mieć przypisany inny kolor niż domyślny. Dlatego też wylistujemy dostępne opcjew takiej formie:

JLabel (nazwa) JLabel (pusta, tylko tło z kolorem) JButton (przycisk zmień)

W ten sposób wypełnimy całą ramkę. Do pracy!

Przy dodawaniu elementów do kontenera, którym zawiaduje GridBagLayout, możemy przypisać do każdego takiego elementu obiekt GridBagConstraints, który odpowiednio ustawi dany element w kontenerze. Cała idea tego menadżera layoutu polega na podzieleniu całego kontenera na ‘komórki’, w które wkładamy następnie elementy. Przypomina to budowanie stron WWW w oparciu o tabelki i zasadniczo porównanie jest dość trafne, z tym tylko, że daje o wiele więcej możliwości ustawienia położenia.

Jak pokazałem powyżej, zależało mi na 3 kolumnach, w których umieściłbym elementy JLabel i JButton. Oczywiście powinny być one wyrównane oraz posiadać dokładnie te same wymiary. Do kodu dodałem wywołanie metody pack(), która rozszerza kontener do zadanych rozmiarów, a kiedy ich nie ma – do rozmiaru odpowiedniego, aby zmieściły się w nim wszystkie elementy (i jednocześnie były widoczne). Zatem możemy zakomentować linijkę określającą rozmiar naszej ramki, a komponenty wewnątrz niej rozepchają ją do odpowiednich rozmiarów.

Tworzymy obiekt GridBagConstraints i następnie przypisujemy jego właściwości insets odpowiedni obiekt, który określa ‘oddalenie’ danego elementu od krawędzi ‘komórki’. Komórki, gdyż następnymi własnościami obiektu GridBagConstraintsgridx i gridy. One określają w której komórce ma znaleźć się wskazany element – numeracja zaczyna się w obu przypadkach od 0 i oznacza górny lewy róg ramki. Kiedy mamy już tak określony obiekt, tworzymy nową etykietę i dodajemy ją do istniejącej ramki (poprzez metodę add kontenera). Oto zatem fragment kodu:

GridBagConstraints ogranicznik = new GridBagConstraints();
ogranicznik.insets = new Insets(5, 10, 5, 5);
ogranicznik.gridx = 0;
ogranicznik.gridy = 0; </code>

JLabel kolor1name = new JLabel("kolor1");
kolor1name.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLUE, 1));
okienko.add(kolor1name, ogranicznik);

okienko.pack();

Dodam tylko, że parametry konstruktora obiektu Insets oznaczają kolejno górę, lewo, dół i prawo (czyli odwrotnie niż w przypadku CSSa). Do etykiety dodałem też ramkę, aby było dobrze widać efekty naszych poczynań.

1kolor

Ramka została utworzona w taki oto sposób (głównie chodzi o szerokość), aby zmieścić podstawowe elementy górnej belki (ikonkę, część tytułu, przyciski), a w środku mamy naszą etykietę. Wygląda to jednakże niezaszczególnie zatem dopiszmy do kodu dalszą część:

ogranicznik.gridx = 1;
JLabel kolor1bg = new JLabel("kolor1tło");
kolor1bg.setBorder(javax.swing.BorderFactory.createLineBorder(Color.RED, 1));
okienko.add(kolor1bg, ogranicznik);

ogranicznik.gridx = 2;
JButton kolor1zmien = new JButton("Zmień");
okienko.add(kolor1zmien, ogranicznik);

I tak to oto powinno wyglądać:

2kolor

Jak widać przy dodawaniu kolejnych elementów zmieniam tylko wartość własności gridx, co powoduje rozciąganie całej ramki, gdyż powiększa się ilość komórek ‘w poziomie’. Dodajmy teraz drugi wiersz takich samych elementów – wystarczy skopiować kod zmieniając nazwy obiektów i modyfikując na początek wartość gridy na 1. Oto efekt:

3kolor

Na zakończenie omówimy jeszcze jedną rzecz – położenie elementu w konkretnej ‘komórce’. Otóż w obiekcie GridBagConstraints mamy statyczne zmienne, które określają położenie elementu. Jeśli zatem chcemy, aby np. nasza etykieta kolor1 znalazła się w górnym-lewym rogu swej komórki, wówczas w obiekcie GridBagConstraints modyfikujemy własność anchor na GridBagConstraints.NORTHWEST i efekt gotowy! Oczywiście wtedy ustawiamy właśność insets na wartości domyślne (0,0,0,0). Tak to wygląda po uruchomieniu:

4kolor

Jak zatem widać nie taki diabeł straszny jak go malują. Oczywiście to taki mały przedsmak – polecam zapoznanie się z dokumentacją, która z pewnością pokaże jeszcze masę możliwości związanych z tym menadżerem layoutu. Jak to mówią – Position is everything 🙂

Miało być pięknie, a wyszło jak zawsze

I znowu przerwa. Widać, że ten rok zaczyna się nieszczególnie i wciąż się tak toczy. Ostatnimi czasy dorwało mnie jakieś choróbsko – powoli dopiero zaczynam dochodzić do siebie, dzięki mądrym ludziom, którzy wymyślili antybiotyki. Niestety mocy by ruszyć coś na blogu na razie nie mam – zbyt długie przesiadywanie przed kompem jest dla mnie póki co jeszcze zbyt męczące. Musicie zatem uzbroić się w cierpliwość.

Na pocieszenie dodam, że zrealizowałem świąteczny prezent od Helionu, który obdarował mnie 20% zniżką na zakupy w ich sklepie internetowym do końca stycznia (niestety jednorazowy rabat). Korzystając z okazji zamówiłem:

– “Head First JSP & Servlets, ed. 2
– “Java Server Faces
– “Java. Rozmówki” (to wybrałem jako gratis do zamówienia powyżej 100zł).

Paczka dotarła kilka dni temu. Na razie przeglądam sobie ostatnią pozycję, na te większe nie czuję się na razie fizycznie na siłach. Dojrzewa też ostatecznie koncepcja wydania 2 wersji ChlebikClienta – jak się leży w łóżku przychodzą do głowy całkiem dobre pomysły. No nic, trzeba jeszcze trochę pozdrowieć.

Adnotacje w Javie

Przyznaję, że wykrakałem. Wykrakałem potencjalne opóźnienie we wpisach no i viola – w ostatni dzień urlopu żona miała mały wypadek na nartach no i w związku z tym dopiero dziś trochę czasu się znalazło by usiąść do klawiatury. No nic, zaczynamy.

Na warsztacie dziś adnotacje. Jest to rozszerzenie Javy, które zostało wprowadzone w wersji 1.5 i miało ponoć mieć fundamentalne znaczenie. Hmmmm, no dobrze. W “Thinking in Java” jej autor pisze o nich następująco: “Adnotacje (zwane też metadanymi) to sformalizowany sposób uzupełniania kodu o informacje z przeznaczeniem do wykorzystania w przyszłości”. Bardzo klarownie.

I dalej zasadniczo nie jest lepiej. Cały rozdział opisuje ich tworzenie, a także predefiniowane adnotacje istniejące w samym języku. Jednakże wciąż do końca nie wiadomo po co w ogóle one istnieją i dlaczego są takie przełomowe. Postanowiłem wyruszyć na poszukiwania i znalazłem takie oto zastosowania adnotacji:

– automatyczne generowanie deskryptorów wdrożenia i inszych tego typu rzeczy (co tyczy się głównie JavaBeans, ale też i zwykłej choćby konfiguracji i to zaraz omówię)
– dodatkowa dokumentacja kodu (poza komentarzami). Najbardziej reprezentatywnym przykładem jest JUnit, który od wersji 4.0 biblioteki używa adnotacji by uniknąć tworzenia własnej przestrzeni nazw (poprzez dodawanie suffixa -Test do nazw klas). Przykład można zobaczyć we wpisie poświęconym TDD.

Pisząc klienta do gry w Arkadię zetknąłem się z zadaniem konfiguracji aplikacji. Wypadałoby bowiem dać użytkownikowi możliwość dopasowania jej zachowania pod własne wymagania. W jednym z poprzednich wpisów podałem przykład oparcia tego tematu na plikach XML. Jednakże problem polega na tym, że zawsze taki plik mógł np. zostać uszkodzony, nie będzie można go odczytać, ktoś go brzydko zmienił (usunięto pewne fragmenty). Zawsze zatem w aplikacji musimy mieć podstawowe wartości inicjacyjne dla zmiennych, albo też po prostu sypniemy wyjątkiem w razie jakiegokolwiek problemu – wówczas aplikacja najlepiej by w ogóle się nie uruchomiła. Jednakże nie jest to rozwiązanie ani eleganckie, ani profesjonalne. U mnie póki co funkcjonuje oddzielna klasa, której jedynym zadaniem jest trzymanie defaultowych danych konfiguracyjnych. Teraz jestem mądrzejszy i pewnie przerobię to na adnotacje, ale to później…

Póki co rozpatrzmy taki oto przykład. Mamy aplikację w języku Java, którą uruchamiamy dość często z różnymi silnikami baz danych. Wynika z tego prosty wniosek, że wypadałoby gdzieś trzymać dane konfiguracji połączenia (host, driver, etc). Import danych z plików zewnętrznych lub samo wywołanie odpowiedniej metody z danymi przekazanymi w parametrze może zakończyć się niepowodzeniem (najczęściej wyrzuceniem wyjątku). Czy nie byłoby dobrze wówczas obsłużyć go poprzez próbę nawiązania ponownego połączenia z danymi domyślnymi? Jest to rozwiązanie bardzo eleganckie i bezpieczne. Jeśli bowiem inicjalizacja z danymi domyślnymi nie powiedzie się, to znaczy, że jest z naszą bazą danych naprawdę źle.

Krok 1: budujemy adnotację

package net.chlebik;
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface dbAnnotation
{
String login();
String password();
String host();
String driver();
}

Krok 2: tworzymy klasę z metodami łączącymi (to takie rozbudowane w celach edukacyjnych)

package net.chlebik;

public class dbAnnotationDrivers {

private String driver;
private String host;
private String login;
private String password;

@dbAnnotation(driver = "com.mysql.jdbc.Driver",host = "jdbc:mysql://localhost/chlebik",login = "rootmysql",password = "haslomysql")
public void mysqlDriver( String driver, String host, String login, String password )
{
this.driver = driver;
this.host = host;
this.login = login;
this.password = password;
}

@dbAnnotation(driver = "org.postgresql.Driver",host = "jdbc:postgresql://localhost/chlebik",login = "rootpg",password = "haslopg")
public void pgDriver( String driver, String host, String login, String password )
{
this.driver = driver;
this.host = host;
this.login = login;
this.password = password;
}

}

Krok 3: parser adnotacji

package net.chlebik;
import java.lang.reflect.Method;

public class NewMain
{
public static void main( String[] args ) throws Exception
{

//dobieramy sie do klasy jako takiej
Class drivery = dbAnnotationDrivers.class;

//Mamy klase zatem dobierzmy sie do jej metod
// Przejdziemy po wszystkich metodach i wyciagniemy ich adnotacje
for( Method metoda : drivery.getMethods() ) {

if( metoda.getAnnotation(dbAnnotation.class) instanceof dbAnnotation )
{
System.out.println( "Driver dla tej metody to: " + metoda.getAnnotation( dbAnnotation.class).driver() );
System.out.println( "Host dla tej metody to: " + metoda.getAnnotation( dbAnnotation.class).host() );
System.out.println( "Login dla tej metody to: " + metoda.getAnnotation( dbAnnotation.class).login() );
System.out.println( "Hasło dla tej metody to: " + metoda.getAnnotation( dbAnnotation.class).password() );
System.out.println("");
}

}

}
}

Wynik działania programu:

Driver dla tej metody to: com.mysql.jdbc.Driver
Host dla tej metody to: jdbc:mysql://localhost/chlebik
Login dla tej metody to: rootmysql
Hasło dla tej metody to: haslomysql

Driver dla tej metody to: org.postgresql.Driver
Host dla tej metody to: jdbc:postgresql://localhost/chlebik
Login dla tej metody to: rootpg
Hasło dla tej metody to: haslopg

Ostatni krok tylko przechodzi po całej klasie dbAnnotationDrivers, wybiera jej metody, które posiadają dbAnnotation i drukuje na konsolę dane przekazane poprzez wywołanie adnotacji przed konkretną metodą. Wystarczyłoby objąć ten kod blokiem try..catch, dopisać próbę połączenia, a w blok catch wrzucić ponowną próbę połączenia z domyślnymi danymi, które wyciągnąć należy w sposób przeze mnie podany.

Jak widać takie adnotacje oszczędzają pracy – ponoć obecnie to trend by tzw. metadane umieszczać w kodzie klas. Trochę dla mnie to dziwne, gdyż potencjalna zmiana tychże danych wymaga ponownej kompilacji klasy (o opozycji XMLa pisali mądrzejsi ode mnie). Jednakże pewność, że podstawowe dane pozostaną zawsze dostępne, a także, że będą poprawne (kontrola typów!) sprawia, iż adnotacje są bardzo mocnym elementem języka, który na pewno wypada poznać.