poniedziałek, 27 września 2010

Oracle Coherence - tworzenie klastra

Żeby w pełni wykorzystać możliwości jakie daje Coherence trzeba utworzyć klaster składający się z wielu węzłów. Mogą być one uruchamiane na jednej maszynie lub wielu - zależnie od potrzeb i możliwości sprzętowych.

Zanim przejdę do tego w jaki sposób jest tworzony klaster przypomnijmy sobie co jest wyświetlane podczas uruchamiania węzła w konsoli:
W pierwszej kolejności konsola wyrzuca informację o używanej wersji Coherence. Później trochę informacji o przyłączaniu węzła do klastra (pierwszy uruchamiany węzeł wyświetla tam informację o tworzonym przez niego klastrze).
Krótka sekcja Group jest bardzo ważna ponieważ zawiera adres multicastowy, port oraz wartość TTL. Coherence podczas uruchamiania węzła używa tych parametrów aby nawiązać komunikację z innymi uruchomionymi węzłami. Jeśli z jakimś nawiąże komunikację (oraz nie będzie innych konfiguracyjnych problemów) przyłączy się do jego klastra. Adres multicastowy jest ściśle związany z wersją Coherence. W moim przypadku wersją jest 3.6.0, więc adresem jest 224.3.6.0, dla 3.5.1 będzie to 224.3.5.1. Podobny mechanizm zastosowany został także co do numeru portu, tylko tam wykorzystywany jest numer builda. Taka numeracja została użyta aby zapobiec łączeniu węzłów obsługiwanych przez różne wersje Coherence.
Sekcja MasterMemberSet zawiera dane o wszystkich węzłach przyłączonych do klastra. W pierwszej kolejności wypisany jest aktualny węzeł oraz węzeł najstarszy (ten który najdłużej znajduje się w klastrze). Następnie wymienione są wszyscy członkowie wraz z adresami sieciowymi i portami na których działają.

Jeśli występuje jakiś problem podczas uruchamiania węzła, to najczęściej jest to problem z mutlicastem. W katalogi /bin/ instalacji jest dostępny skrypt multicast-test umożliwiający przetestowanie czy mechanizm ten działa prawidłowo na Twojej maszynie.
Aby uruchomić test tak aby sprawdził działanie na pojedynczej maszynie (najczęstsza konfiguracja podczas tworzenia oprogramowania) można uruchomić skrypt z parametrem -ttl 0:
mutlicast-test -ttl 0
Konsola w odpowiedzi zwróci nam jeśli wszystko jest ok:
Jeśli coś jest nie tak to powinno się sprawdzić konfigurację firewalla oraz inne ustawienia sieciowe.

Domyślnie użycie multicastu do odnajdywania innych węzłów może zostać zastąpione poprzez skonfigurowanie konkretnych adresów IP serwerów (w terminologii Coherence: Well Known Addressess - WKA). Dla ograniczenia klastra tylko do maszyny lokalnej należy w skrypcie cache-server dodać wpis dla parametrów JAVA_OPTS:
-Dtangosol.coherence.wka=localhost
Całkowicie wyłączy to multicast, co może być bardzo pożądane w fazie produkcyjnej projektu.
Po tej operacji zamiast sekcji Group podczas uruchamiania węzła znajdować się będzie sekcja WellKnownAddressesList, np:

WellKnownAddressList(Size=1,
    WKA{Address=192.168.0.2, Port=8088}
    )

Kolejną kwestią podczas tworzenia klastra są porty na których działają węzły. Domyślnie pierwszy węzeł uruchamiany jest na porcie 8088 i jest on zwiększany o 1 dla każdego kolejnego węzła na tej samej maszynie. Jeśli jakaś inna aplikacja zajmuje już dany port możliwe jest skonfigurowanie Coherence aby użył innego numeru jako początkowy poprzez parametr:

-Dtangosol.coherence.localport=[numer portu]

Opcje te mogą być także konfigurowane za pomocą pliku XML, ale o tym już w jednym z następnych odcinków ;-)

sobota, 11 września 2010

Oracle Coherence - działający przykład

Po krótkim wstępie do Oracle Coherence, czas uruchomić prosty przykład z użyciem Javy. Coherence jest dość duży i wymagane jest wprowadzenie w wiele rzeczy zanim będzie można go sprawnie używać, jednak mam nadzieje, że uda mi się wszystko opisać w miarę kolejnych wpisów. Jak na razie zróbmy sobie prosty przykład bez używania konsoli ;-)

Projekt Javy można utworzyć w dowolnym IDE.Ważne tylko aby dodać do niego bibliotekę coherence.jar z paczki pobranej ze strony Oracle.
Zacznijmy od stworzenia klasy która będzie przechowywana w klastrze Coherence. Niech to będzie wałkowany wszędzie pracownik.
Employee.java:
package pl.lstachowiak.coherence.example1;

import java.io.Serializable;
import java.math.BigDecimal;

public class Employee implements Serializable, Comparable {

 private int id;
 private String name;
 private String surname;
 private BigDecimal salary;
 private String city;

 public Employee() {
 }

 public Employee(int id, String name, String surname,
     BigDecimal salary, String city) {
  this.id = id;
  this.name = name;
  this.surname = surname;
  this.salary = salary;
  this.city = city;
 }

 public String getCity() {
  return city;
 }

 public void setCity(String city) {
  this.city = city;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public BigDecimal getSalary() {
  return salary;
 }

 public void setSalary(BigDecimal salary) {
  this.salary = salary;
 }

 public String getSurname() {
  return surname;
 }

 public void setSurname(String surname) {
  this.surname = surname;
 }

 @Override
 public String toString() {
  return "Employee{" + "id=" + id + " name=" + name + " surname="
    + surname + " salary=" + salary + " city=" + city + '}';
 }

 public int compareTo(Object o) {
  Employee other = (Employee) o;
  if (id > other.id) {
   return 1;
  } else if (id < other.id) {
   return -1;
  } else {
   return 0;
  }
 }
}
Jak widać klasa nie różni się niczym w stosunku to standardowych klas typu POJO. Jedyne co zostało dodane to implementacja interfejsu Serializable, ponieważ obiekt będzie przesyłany przez sieć oraz Comparable, żeby było po czym sortować, gdy będzie to potrzebne.
Napomnę tutaj, że Coherence wprowadził swój własny format serializacji obiektów. Jest od  bardziej wydajny, a obiekty po serializacji mniejsze. Więcej o tym w jednym z kolejnych wpisów.

Operacje na Coherence przeprowadźmy w metodzie main...
CoherenceExample1.java:
package pl.lstachowiak.coherence.example1;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;

public class CoherenceExample1 {

    public static void main(String[] args) {
  // #1
        NamedCache employees = CacheFactory.getCache("employees");

  // #2
  employees.put(1, new Employee(1, "John", "Travolta", new BigDecimal(300000.0), "New York"));
  employees.put(2, new Employee(2, "Jason", "Statham", new BigDecimal(550000.0), "Chicago"));
  employees.put(3, new Employee(3, "Sylvester", "Stalone", new BigDecimal(600000.0), "Miami"));
  employees.put(4, new Employee(4, "Bruce", "Willis", new BigDecimal(780000.0), "Los Angeles"));
  employees.put(5, new Employee(5, "Chuck", "Norris", new BigDecimal(1300000.0), "Kansas"));
  employees.put(6, new Employee(6, "Steven", "Seagal", new BigDecimal(20100.0), "Lansing"));

  // #3
  System.out.println("Pracownik o ID=1: " + employees.get(1));
  System.out.println("Rozmiar cache: " + employees.size());
  System.out.println("Usuwam: " + employees.remove(5));
  System.out.println("Rozmiar cache: " + employees.size());

  // #4
  Set<Map.Entry> entries = employees.entrySet();
  for (Map.Entry entry : entries) {
   System.out.println(entry.getKey() + ": " + entry.getValue());
  }
    }
}
#1 - pierwszym co trzeba zrobić to uzyskać referencję do Cache w którym będą przechowywane obiekty pracowników. CacheFactory odpowiada za jego stworzenie jeśli nie istnieje i zwrócenie referencji. Obiekt zwracany jest typu NamedCache, który implementuje standardowy interfejs Map z biblioteki Javy.
2# - umieszczanie elementów jest bardzo proste, zwykły put na mapie.
3# - podobnie wszystkie operacje pobierania oraz usuwania, wszystko bardzo intuicyjne
4# - można też pobrać całą listę obiektów w cache. Metoda entrySet() występuję w kilku wersjach, można jest podać także filtr oraz komparator jeśli szukamy odpowiedniego podzbioru obiektów w cache.

Po uruchomieniu powinno nam się pojawić coś podobnego do poniższego ekranu:
Chciałbym tutaj zwrócić uwagę, że nie napisałem nic o uruchamianiu węzła Coherence przed odpalaniem aplikacji. Pomimo tego wszystko działa! Jest tak ponieważ domyślnie aplikacja którą stworzyliśmy automatycznie staje się pełnoprawnym węzłem w klastrze. Często jest to niepożądane zachowanie i można tego uniknąć poprzez uruchomienie jej z parametrem:
-Dtangosol.coherence.distributed.localstorage=false
co prawda nadal aplikacja będzie pełnoprawnym węzłem w klastrze, ale nie będzie przechowywać danych;) Wymagany jest wtedy co najmniej jeden węzeł to robiący aby uniknąć wyjątków po uruchomieniu.

poniedziałek, 9 sierpnia 2010

Oracle Coherence - zabawy z in memory data grid

Obiecałem tematykę o skalowalności w bardziej praktyczny sposób to czas się z tego wywiązać i zacząć pisać! Przy okazji oczywiście samemu się ucząc, bo po to głównie to miejsce powstało.

Przy okazji GeeCONa podczas University Day w wolnej chwili dosiadłem się na szkolenie Waldemara Kota o Oracle Coherence. To było moje pierwsze zetknięcie z tak zwanym in memory data grid, temat mnie zaciekawił i postanowiłem coś więcej o tym poczytać (przy okazji szkolenia dostałem książkę;)
Oracle Coherence jest (komercyjnym:-/) narzędziem które w łatwy sposób pozwala nam poprawić skalowalność, wydajność oraz dostępność aplikacji.
Umieszczane jest pomiędzy warstwą danych a aplikacją. Najczęściej między bazą danych a klastrem serwerów aplikacyjnych. Komunikacja między tymi warstwami odbywa się tylko poprzez Coherence (konfigurowalne) co w znacznym stopniu odciąża bazy danych i zwiększa czas odpowiedzi do warstwy aplikacji. Coherence przechowuje takie same obiekty jakie używane są w aplikacji, co eliminuje potrzebę ciągłego ładowania i przetwarzania danych w obiekty. Obiekty te rozprowadzane są pomiędzy węzły w klastrze co równoważy obciążenie przy czym dla aplikacji klaster pozostaje widoczny jako pojedynczy system. Zapewniona jest wysoka dostępność i odporność na błędy poprzez przechowywanie więcej niż jednej kopii danego obiektu w różnych miejscach. Co więcej, przechowywane są w pamięci co w znacznym stopniu poprawia czas dostępu do nich.
Co możemy robić z Coherence?
  • rozproszony cache - to chyba podstawowe zastosowanie, nie trzeba się martwić o synchronizację, w bardzo łatwy sposób można też podpiąć się pod wybrany ORM
  • rozproszone zapytania - dane można wyciągać nie tylko wg nadanego klucza głównego, ale także możliwe jest wykonywania zapytań na klastrze. Np wybrać klientów powyżej 35 lat, którzy dodatkową posiadają kwotę na koncie pomiędzy 4000 a 6000 PLN
  • współbieżne operacje i procedury składowane - podobnie jak w bazach danych możliwe jest tworzenie procedur i wykonywanie ich wewnątrz klastra, bez potrzeby przesyłania wszystkich danych do aplikacji. Co więcej możliwe jest też wykonywania operacji współbieżnie
  • zdarzenia - możliwe jest skonfigurowanie Coherence tak by informował i wykonywał podane operacje gdy wybrane dane zostały zmienione
Teraz możemy przejść do zabawy :)
Ze strony Oracle Coherence Download pobieramy paczkę "Oracle Coherence for Java Version 3.6.0" i rozpakowujemy gdzie nam pasuje. Następnie uruchamiamy konsolę, przechodzimy do katalogu coherence/bin i uruchamiamy skrypt cache-server. Po chwili powinien pojawić się napis "Started DefaultCacheServer..." - oznacza to, że węzeł Coherence został uruchomiony.
Ponieważ dzisiaj jest tylko takie małe wprowadzanie, nie będziemy używać Javy tylko wbudowanej konsoli, na początek starczy. Uruchamiamy skrypt coherence. Na konsoli uruchomionego wcześniej węzła powinno na końcu pojawić się coś w stylu: "2010-08-09 20:34:43.552/180.953 Oracle Coherence GE 3.6.0.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1". Oznacza to, że konsola podłączyła się pod węzeł.
Korzystając z Coherence należy najpierw utworzyć cache w którym będą przechowywane będą obiekty. Można tworzyć ich wiele oraz (co trochę później) konfigurować zgodnie z wymaganiami. Z konsoli utworzenie cache wykonuje się poleceniem: cache [nazwa]. Po utworzeniu jesteśmy automatycznie do niego podłączani. Co jest bardzo fajne - API korzystania z cache jest identyczne ze standardową mapą Javową. Aby coś włożyć do cache używamy put [klucz] [wartosc], aby wyciągnąć get [klucz], aby wypisać całą zawartość cache należy wpisać list. Poniżej zamieszczam bardzo prostą sesję z użyciem Coherence:
To tyle słowem wstępu. Polecam pobawić się konsolą. Uruchomić nawet więcej niż jedną oraz więcej węzłów i sprawdzić jak to działa. Polecam testy z zamykaniem kolejno węzłów i sprawdzaniem czy jakieś obiekty straciliśmy.

Więcej o tym jak Coherence działa i jak go używać w następnych odcinkach ;)

czwartek, 8 lipca 2010

GeeCON 2011 - Kraków!

Na oficjalnej stronie GeeCONa pojawiła się informacja, że przyszłoroczna edycja konferencji odbędzie się w Krakowie! Wybrana data to 11 do 13 maja, więc podobny termin jak w tym i poprzednim roku.
Już teraz zapraszam serdecznie, bo znowu będzie baaaaardzo ciekawie :)

ps. to chyba pierwszy news w sieci o GeeCONie 2011 :)

niedziela, 13 czerwca 2010

JMeter - losowe wartości w żądaniach/zapytaniach

Często zdarza się, że chcemy wywoływać strony z parametrami które mieszczą się w jakimś przedziale liczbowym, np. productView.php?id=XXX, gdzie XXX jest zmienną. W JMeter generowanie losowych wartości jest bardzo proste.
Dodajemy do planu testów Thread Group a następnie do niego Config Elements -> HTTP Request Defaults
Wpisujemy nazwę serwera oraz port na którym nasłuchuje.
Następnie dodajemy element odpowiedzialny za generowanie losowej liczby Config Element -> Random Variable. Najważniejsze parametry jakie możemy dla niego ustawić to:
Name: nazwa elementu w drzewku
Variable name: nazwa po której będziemy się odwoływać do tej zmiennej
Output format: format w jakim ma być zwracana wartość. Można wpisać np. PROD_ID_000 wtedy będziemy otrzymywać wartości typu PROD_ID_435. Gdy pozostawi się to pole puste to będzie zwracana tylko liczba.
Minimum Value i Maximum Value jest chyba oczywiste
Per Thread(User)?: czy ten generator liczb ma być współdzielony między wszystkie wątki czy dla każdego utworzony osobny
Użycie jest bardzo proste. Wystarczy utworzyć nowe żądanie Sampler -> HTTP Request i odwołać się do losowej zmiennej poprzez ${[Nazwa zmiennej]}.
Dla podanego na obrazku przykładu będą wywoływane adresy localhost/jmeter/index.php?id=XXX, gdzie XXX jest zmienną losową.
Podobnie może ta zmienna być użyta w zapytaniach do bazy danych:
I w wielu innych miejscach gdzie potrzebna jest losowa wartość ;)

poniedziałek, 31 maja 2010

O skalowaniu baz danych słów kilka

Część druga o skalowalności. Dzisiaj trochę o bazach danych które sprawiają zawsze najwięcej problemów.

Ze względu na naturę baz danych, to co najbardziej obrywa na serwerze to dyski. Wszelkie zmiany muszą być jak najszybciej utrwalane żeby można było zwolnić blokady i zapewnić trwałość danych. Obojętnie jaki wypas serwer by się nie posiadało i tak w końcu dojdzie do tego, że nie będzie już posiadał możliwości by przyjąć więcej obciążenia, a nas nie będzie stać na zakup lepszego. Trzeba będzie się przeskalować w poziomie co jest trochę hardcorowe :)

Podejść jest kilka i chciałem omówić 3 najważniejsze z nich.

1. Master-Slave replication
W tym podejściu mamy jeden węzeł typu master oraz jeden lub więcej węzłów typu slave. Zadaniem węzła master jest tylko i wyłącznie przyjmowanie operacji modyfikacji danych. Ten serwer odpowiada za wszystkie zapytania typu INSERT, UPDATE i DELETE. Jest do tego specjalnie skonfigurowany by operacje te były jak najszybciej wykonywane. Węzły typu slave natomiast odpowiadają za wykonywanie zapytań typu SELECT. Może być ich kilka oczywiście. Aktualizują swoje dane poprzez asynchroniczną komunikację z węzłem master. Co określony czas przesyła on zgrupowane zapytania aktualizujące dane na węzłach slave.
Problemy związane z master-slave replication to:

  • na dobrą sprawę to nie ma tutaj skalowania poziomego. Co prawda mamy więcej węzłów, ale ciągle istnieje tylko jeden master, który może stać się wąskim gardłem, gdy liczba modyfikacji które musi wykonać przekroczy jego możliwości
  • synchronizacja aktualizowanych danych może powodować błędy. Jeśli klient coś zmodyfikuje i natychmiast to będzie chciał odczytać to może otrzymać błędne dane. To jednak można obejść stosując cache z polityką write-through
  • wymagana jest modyfikacja logiki aplikacji aby kierować SELECTy do slave, a modyfikacje do master
Podejście jest bardzo dobre, gdy mamy mało modyfikacji i dużo zapytań.

2. Database clustering 

Klastrowanie bazy danych polega na utworzeniu wielu instancji bazy danych współdzielących jedną wspólną pamięć trwałą. Daje to dużo większą przepustowość i nie wymaga prawie zmian w logice aplikacji.
Jednak posiada też wady:

  • SAN jest drogi i też ma swoje granice
  • wymagana jest kosztowna synchronizacja między wszystkimi węzłami (blokady itp.). Może nawet dojść do momentu, gdy dodanie nowego węzła spowolni działanie całości
3. Database sharding
Bazę danych można też podzielić na wiele mniejszych baz i tak z nich korzystać. Najpierw należy przeanalizować dokładnie sposób jej używania a później znaleźć grupy tabel które są używane razem w zapytaniach. Na tej podstawie można dzielić ją na mniejsze.
Problemy:

  • trzeba bardzo dobrze przemyśleć podział, każda późniejsza zmiana jest bardzo trudna do wprowadzenia
  • gdy jedna z mniejszych baz zacznie działać niewydajnie trzeba będzie ją znowu dzielić. Może dojść do tego, że trzeba będzie mięć np. 3 bazy danych z produktami
  • zapytania łączące z wielu baz są bardzo wolne
  • zapytania modyfikujące wymagają rozproszonych transakcji
  • wymaga znacznych zmian w logice aplikacji

To są tylko koncepcje, firmy w swoich produktach (tych "dużych" głównie) wprowadziły technologie, które ułatwiają skalowanie poziome. Np. w DB2 mamy Database Partitioning Feature, który jest połączeniem podejść database sharding i clustering i eliminuje kilka wad z nimi związanymi. 
Problem jest jednak bardzo złożony i wymaga długich przemyśleń. Trzeba zawsze pamiętać aby wdrożone rozwiązanie spełniało wymagania ACID.

niedziela, 30 maja 2010

O skalowaniu aplikacji słów kilka

W niedługim czasie zamierzam trochę szerzej pisać o skalowalności, więc postanowiłem napisać kilka słów wstępnych na ten temat. Ale spokojnie, planuję bardziej o produktach i narzędziach niż teoriach jak dzisiaj;)

Żeby później nie mylić trzeba sobie zdefiniować skalowalność. Jest to taka cecha oprogramowania która charakteryzuje jego zdolności do wydajnego działania przy wzrastającym obciążeniu. Np. załóżmy, że mamy super serwis randkowy który ma 1000 użytkowników i generuje strony w 50ms. Po jakimś czasie serwis robi się popularny i przychodzi do niego kolejnych 1000 użytkowników. Byłoby dobrze jakby strony generowały się w powiedzmy w czasie 100-200ms, ale generują się w 5000ms co niestety wskazuje na jego słabą skalowalność. Oczywiście ze wzrostem obciążenia zbliżamy się do limitu jaki może uciągnąć serwer, więc decydujemy się na wymianę starego ,zasłużonego na nowy, dwa razy lepszy. To jak aplikacja będzie się spisywać na nowym serwerze też określa jej skalowalność. Jeśli nadal strony będą się generować powoli przy takim obciążeniu to znaczy, że coś skopaliśmy przy implementacji, jeśli jest znowu fajnie i 50ms to znaczy, że aplikacja daje rade;) Podsumowując skalowalność to także łatwość w rozszerzaniu aplikacji lub jej architektury celem zwiększania wydajności.

Są dwa podstawowe podejścia co do skalowania aplikacji: pionowe (scaling up) oraz poziome (scaling out).

Podejście pionowe to po prostu wymiana lub dodawanie coraz to nowszego i szybszego sprzętu. Jak 12GB RAMu to już mało to dodajemy kolejne 12. Jak procesor nie wyrabia - dodajemy drugi itd. Sprawa jest niezwykle prosta i nie wymaga od nas w większości przypadków ingerencji w aplikację. Jednak posiada wady:

  • koszty - zakup coraz to lepszego sprzętu odbija się na budżecie i gdy po raz kolejny przyjdzie nam wymienić serwer może się okazać, że nas na niego nie stać, lub zyski z tej wymiany mogą być znacznie mniejsze niż poniesione koszty
  • bariera technologiczna - nawet jeśli mamy tyle kasy, że nas stać na każdy sprzęt na rynku to i tak w końcu dojdziemy do miejsca kiedy już nie będziemy mogli kupić lepszego sprzętu, bo po prostu nie on będzie istnieć
  • niska odporność na awarie, jak serwer padnie to system znika z sieci
Dlatego skalowanie pionowe jest dobre do czasu, gdy wymiana sprzętu na lepszy się jeszcze opłaca, lub gdy wiemy jaka jest górna granica wydajności jaką potrzebuje aplikacja.
Podejście poziome to też dodawanie nowego sprzętu, ale tym razem powiększamy jego zbiór dodając go do sieci istniejących już maszyn działających ku dobru systemu. Gdy obciążenie rośnie to dostawiamy kolejny serwer który przejmuje część zadań. Potrzebny jest nam jakiś mechanizm równoważenia obciążenia (load balancer), który będzie rozkładać równo żądania do wszystkich serwerów. 
Oczywiście to podejście też posiada swoje wady:
  • wyższe koszty administracji i konserwacji sprzetu
  • trzeba (bardzo) dobrze przemyśleć architekturę (zwłaszcza w kwestii bazy danych)
  • dodanie nowego węzła wcale nie musi przynieść wzrostu wydajności, możemy nawet zanotować spadek
No, ale mamy znacznie większą odporność na błędy. Jak jeden serwer padnie to mamy jeszcze kilka innych które po prostu przejmują jego ruch. Sprawa odporności na awarie to trochę inny wątek, więc może innym razem coś o tym napiszę.

Skalowanie poziome po jakimś czasie jest naturalnym krokiem przy rozwoju systemu. Przynosi lepsze rezultaty i przy dobrej architekturze może nam dać teoretycznie nieograniczoną skalowalność. Poza tym trudno sobie wyobrazić by np. Google działał na jednym serwerze :)

Dodawanie lub wymiana sprzętu to nie jedyna droga by przyspieszyć aplikację. W pierwszej kolejności powinna być wykonana dokładna analiza wszystkich komponentów czy możliwa jest ich optymalizacja. Wymaga to trochę czasu, ale przynosi rezultaty. Np. digg.com zyskał 4000%, gdy przeniósł sortowanie z bazy danych do php. Optymalizacja to niestety niekończąca się podróż :)

Zainteresowanych tematem zachęcam do zaglądania do serwisu highscalability.com, gdzie można poczytać dużo artykułów od strony praktycznej. Ja postaram się też ciągnąć temat u siebie, bo jest o czym pisać ;)

wtorek, 25 maja 2010

Dziwny wyjątek podczas uruchamiania skryptu JavaFX

Wczoraj w zamian za to, że nie mogłem pojawić się na Poznańskim JUGu (trochę się przeziębiłem), zabrałem się za JavaFX. Bardzo mało o tym widzę na (Polskich) blogach, więc stwierdziłem, że może coś poczytam i może coś też popiszę u siebie. Niestety pierwsze wrażenie nie było zbyt miłe :P Przyszło mi walczyć kilka godzin z wyjątkiem który wyglądał jak błąd implementacji czegoś w JavaFX.
Plan był taki aby wziąć jeden z przykładów na stronie JavaFX.com, zmodyfikować i zobaczyć co z tego wyjdzie. Jako środowiska użyłem oczywiście NetBeans IDE w wersji 6.8.
Na komputerze lokalnym mój piękny skrypt działał bez zarzutów (uruchamiałem w trybie run in browser), to samo na serwerze.... do czasu aż nie wyłączyłem NetBeans! Kiedy był wyłączony otrzymywałem w consoli javy taki wyjątek:
java.lang.NullPointerException
at sun.plugin2.applet.JNLP2Manager.initialize(Unknown Source)
at sun.plugin2.main.client.PluginMain.initManager(Unknown Source)
at sun.plugin2.main.client.PluginMain.access$300(Unknown Source)
at sun.plugin2.main.client.PluginMain$2.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Error while initializing manager: java.lang.NullPointerException, bail out
Ten problem występował także na moim laptopie i u znajomych. No to się zaczęło wielkie googlowanie i podmiany SDK/JDK na wszystkie możliwe wersje łącznie z instalacją bety NetBeans 6.9 (swoją drogą zapowiada się bardzo ciekawie!). Nic nie pomogło, nic się nie zmieniło :-/ Ostatecznie poległem i napisałem na forum NetBeans z prośbą o pomoc jakoś przed północą. Do rana nikt nie odpisał, ale dziś gdy wstałem wyjątek już był inny. Konsola zgłaszała, że brakuje pliku xxx_browser.jnlp który na 100% znajduje się zaraz obok JARa. Podejrzałem ten plik, a tam ujrzałem bardzo ładny i krótki XML:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/I%3A/workspace/NetBeans/WebSiteJavaFx/dist/" href="website_browser.jnlp">
    <information>
        <title>website</title>
        <vendor>wookasz</vendor>
        <homepage href="http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/I%3A/workspace/NetBeans/WebSiteJavaFx/dist/"/>
        <description>website</description>
        <offline-allowed/>
    </information>
    <resources>
        <j2se version="1.5+"/>
        <extension name="JavaFX Runtime" href="http://dl.javafx.com/1.3/javafx-rt.jnlp"/>
        <jar href="website.jar" main="true"/>
    </resources>
    <applet-desc name="website" main-class="com.sun.javafx.runtime.adapter.Applet" width="700" height="500">
        <param name="MainJavaFXScript" value="pl.lstachowiak.javafx.website.WebSite"/>
    </applet-desc>
    <update check="always"/>
</jnlp>
No jak widać dwie ścieżki coś nie takie jakie powinny być. Podmieniłem na http://lstachowiak.pl i vuala! Działa!:) plik ostatecznie wygląda następująco:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://lstachowiak.pl/" href="website_browser.jnlp">
    <information>
        <title>website</title>
        <vendor>wookasz</vendor>
        <homepage href="http://lstachowiak.pl/"/>
        <description>website</description>
        <offline-allowed/>
    </information>
    <resources>
        <j2se version="1.5+"/>
        <extension name="JavaFX Runtime" href="http://dl.javafx.com/1.3/javafx-rt.jnlp"/>
        <jar href="website.jar" main="true"/>
    </resources>
    <applet-desc name="website" main-class="com.sun.javafx.runtime.adapter.Applet" width="700" height="500">
        <param name="MainJavaFXScript" value="pl.lstachowiak.javafx.website.WebSite"/>
    </applet-desc>
    <update check="always"/>
</jnlp>
Szkoda, że nigdzie nie wyczytałem wcześniej, że ten plik jest plikiem tekstowym. Z pewnością zajrzałbym tam na początku i oszczędziłoby mi to trochę czasu i nerwów.
Zapraszam na lstachowiak.pl, co prawda nie jest to dzieło sztuki, ale zawsze jakieś początki ;-)

UPDATE:
A jednak ciągle nie działa :-/ Nie rozumiem tego zupełnie. Będę rozwijać wątek jak do czegoś dojdę. Może ktoś ma jakieś sugestie ?

UPDATE2:
Dzięki bardzo Krzysztofowi Kula :) Skompilowałem za pomocą eclipsowej wtyczki i zaczęło działać.

czwartek, 20 maja 2010

Spotkanie Poznań JUG - Processing [24.05.2010]

Znowu info z Poznania :) Kolejne spotkanie się szykuje! W najbliższy poniedziałek posłuchamy o Processing -środowisku do tworzenia sztuki elektronicznej. Zapowiada się bardzo widowiskowo:) Oto krótkie streszczenie od prelegenta Marcina Ignaca:
Przedstawie swoje doświadczenia z pracy ze środowiskiem Processing. Prezentacje rozpoczne krótkim wyjaśnienie czym jest Processing oraz wprowadzeniem do sposobu pracy z tym środowiskiem. W dalszej części spotkania możecie się spodziewać projektów z obszarów grafiki generatywnej, przez interaktywne instalacje aż do multimedialnych projekcji w przestrzeni publicznej. Od fazy konceptualnej przez prototypowanie aż do finalnego produktu – Processing sprawdza się na każdym kroku. Opowiem również o wadach i zaletach tego narzędzia, a także jak “szkicowanie w kodzie” (sketching in software) zmieniło moje podejście do programowania.
Aby zapoznać wstępnie z tematem zapraszam na stronę prelegenta pod tag processing.org.
To mi się bardzo spodobało:

MSAFluid with motion tracking from Marcin Ignac on Vimeo.

Nie muszę już raczej nikogo namawiać aby się zjawić! ;)

Szczegóły:
Poniedziałek 24.05.2010
Siedziba Cognifide - Aleje Wielkopolskie 4, Poznań
Godzina 18:00
Na spotkanie wymagana jest rejestracja

Do zobaczenia !

ps. ostatnio u mnie czysto informacyjne, ale postaram się niedługo to nadrobić ;)

niedziela, 16 maja 2010

Zmiana adresu bloga na blog.lstachowiak.pl

Drobny post informacyjny. Jutro zmieniam adres bloga na blog.lstachowiak.pl Nie wiem jak to się odbije na dostępie do niego ze starego adresu (Google twierdzi, że powinno być spoko) oraz RSS (to też podobno) dlatego jeśli byłyby jakieś problemy to proszę tylko zupdatować sobie adres.

ps. testy wypadły poprawnie ;-)

wtorek, 11 maja 2010

Eclipse DemoCamp Helios 2010 - Poznań [10.06.2010]

Dużo się dzieje ostatnio w Poznaniu! Bardzo dużo! GeeCON, spotkanie PJUG a teraz dochodzi jeszcze Eclipse DemoCamp. Parę dni temu zaczęły się zapisy oraz Call for Papers. Jeśli pracujesz z Eclipsem i chcesz podzielić się swoimi doświadczeniami nie wahaj się tylko zgłoś jako prelegent!
Na tę chwilę zgłosiły się już 3 osoby ze swoimi tematami:

  1. Krzysztof Daniel/IBM Eclipse Support Center, EMF supports GWT or Eclipse Extended Preferences
  2. Krzysztof Kazmierczyk, OSGI in the cloud
  3. Jacek Pospychała
Osoby które jeszcze nie są pewne co by mogły przedstawić jak i te co się zdecydowały muszą się dopisać do listy uczestników na wiki Eclipsa: wiki.eclipse.org/Eclipse_DemoCamps_Helios_2010/Poznan.
Impreza odbędzie się 10 czerwca na terenie Centrum Wykładowego Politechniki Poznańskiej w salach 6 i 8.
Rozpoczęcie zaplanowano na godzinę 18:00.
Pizza oczywiście będzie :)

Serdecznie zapraszam!

ps. jak tak dalej pójdzie to Poznań powalczy o miano stolicy Javowej społeczności w Polsce ;-P

niedziela, 9 maja 2010

Spotkanie JUGs@GeeCON [12.05.2010]

Poznań JUG w wydaniu specjalnym! Z okazji zbliżającego się GeeCONa odbędzie się spotkanie zorganizowane we współpracy z Polish Java User Group. A na nim wystąpi aż trzech prelegentów z różnych miejsc na świecie:

Geertjan Wielenga:
The NetBeans Platform is the framework that underlies the NetBeans IDE – and many other desktop applications, some of which you may have already used. The Platform saves years of development time in building any significant desktop application, by providing a modular framework that simplifies both developing and updating desktop applications. It is used by vendors as diverse as Nokia (NetACT – cellular network monitoring and management) and Boeing (engineering materials analysis), UNESCO and many others, to develop applications as diverse as photo library management, satellite network management, semiconductor testing, planning oil drilling and music composition.

The NetBeans Platform is based on pure Java and uses the Java standard Swing toolkit, making applications based on it portable – and even deliverable via Java WebStart directly via the web. This talk will provide a comprehensive overview of the NetBeans Platform, how it works, and how to get started using it.
Chris Aniszczyk:
Eclipse e4 brings a new set of technologies into the existing Eclipse platform that make Eclipse applications easier to write, more configurable by developers and integrators and easier to reuse in a variety of runtime environments.
In the end, attendees will be introduced to Eclipse e4 and learn about the future of the Eclipse platform.
Ed Burns:
Ed has developed a 50 minute audio-visual presentation recounting his experience in writing the book. This presentation includes audio clips from the programmers themselves, including subtitles for those for whom English is not their native language, together with insight to tie it all together.
Myślę, że nie muszę nikogo przekonywać do tego, że tego spotkania JUGa przegapić nie można :)

Uwaga! Wyjątkowo spotkanie odbędzie się w innym miejscu - Poznańskim Ośrodku Nauki znajdującym się na ul. Wieniawskiego 17/19, sala 312. Miejsce to zaznaczone jest na GeeCONowej mapce:

Pokaż GeeCON in Poznan na większej mapie


Godzinę rozpoczęcia zaplanowano na 18:00. Do uczestnictwa wymagana jest rejestracja pod tym adresem.
Do zobaczenia!!

sobota, 8 maja 2010

GeeCON już w Poznaniu!

GeeCONowy baner już uświetnia Poznańskie Multikino, gdzie za kilka dni odbędzie się konferencja.
Rozpiska tego co, kto i gdzie dostępna jest tutaj -> geecon.org/site/schedule. Jak widać udało się nam zaprosić wiele gwiazd świata Javowego i nie tylko - nie można tego przegapić!
Jeśli jeszcze się nie zarejestrowałeś/zarejestrowałaś to zostały już ostatnie chwile! Spiesz się!
Można także zapisać się na University Day gdzie czeka kilka bardzo ciekawych szkoleń :)

Zapraszam i do zobaczenia na GeeCONie!!

GeeCON w sieci:
www: www.geecon.org
twitter: twitter.com/Geecon_news
facebook: www.facebook.com/pages/GeeCON/

piątek, 23 kwietnia 2010

Rozproszone testy wydajnościowe z użyciem Apache JMeter

Kolejny wpis o JMeter. Bardzo przydatne narzędzie :)
Dzisiaj chciałem pokazać jak wykonywać rozproszone testy wydajnościowe. Do tego będzie nam potrzebne kilka maszyn z kopią JMeter. Ważne by na każdej maszynie były takie same wersje aplikacji.
Moje środowisko testowe wygląda następująco: (Paint wymiata;)
Zadaniem węzła master jest uruchomienie testów na wszystkich slaveach oraz odbieraniem od nich informacji o wynikach pomiarów. Slave natomiast bombarduje cel żądaniami zdefiniowanymi i przesłanymi przez Master.
Aby uruchomić slave należy na każdej węźle uruchomić Server JMeter -> JMETER_HOME/bin/jmeter-server.bat
Tutaj należy uważać, bo z tego co zauważyłem jest wybierany losowy port a nie jakiś stały przez co mogą wystąpić problemy z firewallem. Jeśli wszystko poszło dobrze coś podobnego do tego powinno się pojawić w konsoli:

To wszystko co należy zrobić na tych węzłach. W węźle master należy otworzyć do edycji plik JMETER_HOME/bin/jmeter.properties. W linii remote_host=127.0.0.1 należy wpisać adresy serwerów slave. W moim przypadku będzie to wyglądać następująco:
remote_hosts=192.168.0.6,192.168.0.7,192.168.0.4,192.168.0.15
Po uruchomieniu JMeter w menu Run-> Remote Start -> powinna pojawić się lista serwerów które dodaliśmy. Możemy odpalać je pojedynczo lub wszystkie jednocześnie za pomocą Remote Start All. Wystarczy już tylko przygotować jakiś plan testów i odpalić. Konsola na węzłach Slave powinna nas informować o rozpoczęciu i zakończeniu testów:
W przypadku jakiś problemów polecam sprawdzić plik jmeter.log w ktalogu /bin/.

Podoba mi się to narzędzie:) Bardzo szybko i prosto można skonfigurować duże źródło ruchu dla testowanego środowiska. Jedna maszyna do zastosować domowych może spokojnie symulować ponad 2000 wirtualnych użytkowników. W zupełności mi to wystarcza dla testowanych przeze mnie projektów.
Postaram się niedługo napisać coś więcej na temat skalowalności JMeter i tego kiedy on może stać się wąskim gardłem, a nie aplikacja lub przepustowość sieci w środowisku.

niedziela, 18 kwietnia 2010

Recenzja - "Wydajne witryny internetowe - Przyspieszanie działania serwisów WWW"

Tematyka optymalizacji oraz skalowania aplikacji WWW jest obiektem moich zainteresowań przez dłuższy już czas. Nie tylko ze względu na temat pracy magisterskiej, ale także ze względu na projekt nad którym aktualnie pracuję, oraz (tak po prostu;) zwykłą ciekawość co i gdzie poprzestawiać by było szybciej, ładniej i wydajniej :)

Przeglądałem parę dni temu zasoby biblioteki na PP i natrafiłem na książkę o interesującym dla mnie tytule "Wydajne witryny internetowe - Przyspieszanie działania serwisów WWW", której autorem jest Steve Souders. Pomyślałem sobie, że to będzie kolejna książka o tym czy używać for czy while oraz, że w php szybsze jest isset od is_null. Jednak zamówiłem, odebrałem i przeczytałem z przyjemnością !
Co ciekawe książka nie zawiera odniesienia do żadnego języka programowania (bezpośrednio przynajmniej) i nie mówi o żadnych wzorcach projektowych. Jej tematem jest optymalizacja bardziej etapu dostarczania strony www do klienta niż logiki biznesowej aplikacji. Jest w niej mowa m.in. o ograniczaniu połączeń TCP, kompresji dokumentów HTML czy buforowaniu zapytań asynchronicznych - prawie nic z programowania.
Wg badań autora sama faza dostarczania dokumentu HTML to około 10-20% całego czasu przesyłania odpowiedzi, reszta czyli ok 80-90% to pobieranie obrazków, cssów jsów i przekierowania. I właśnie te 80-90% jest przez większość lektury przedmiotem optymalizacji.
Książka podzielona została na 17 części z czego 14 to opisane reguły (wraz z przykładami) po których zastosowaniu nasza strona powinna ładować się szybciej - od 25 do 50%, niezły wynik jak na 160 stronicową książkę :)
Oto te reguły posortowane wg autora od najbardziej znaczącej:
  1. Wykonywania mniejszej liczby żądań HTTP
  2. Używanie Content Delivery Network (to rozwiązanie raczej dla bogatszych ;)
  3. Używanie nagłówka Expires
  4. Kompresja gzip
  5. Umieszczanie arkuszy stylów na początku dokumentu
  6. Umieszczanie skryptów na końcu dokumentu
  7. Unikanie wyrażeń CSS
  8. Używanie zewnętrznych plików JavaScript i CSS
  9. Redukcja liczby zapytań DNS
  10. Zmniejszenie objętości kodu JavaScript
  11. Unikanie przekierowań
  12. Usuwanie duplikujących się skryptów
  13. Konfiguracja nagłówka ETag
  14. Buforowanie zapytań Ajax
Trzeba przyznać, że Pan Souders posiada bardzo dużą wiedzę w tej dziedzinie, za każdym razem dane zagadnienie przedstawione jest z dokładnym uzasadnieniem, stosownym przykładem oraz wynikami pomiarów jakie otrzymał. Bardzo dużo wspominane jest o portalu Yahoo! gdzie pracował przy jego optymalizacji, więc przykłady trafiają się także z "dużych" witryn. W ostatnim rozdziale ponadto poddano analizie 10 jednych z największych serwisów internetowych (YouTube, Google, MSN, Amazon, CNN, Wikipedia, AOL, Amazon, Yahoo!, eBay), gdzie zostają wytknięte wszystkie ich słabości. Swoją drogą ten rozdział mógłby być dedykowany administratorom tych serwisów:)
Z czystym sercem polecam tę książkę każdemu webmasterowi, administratorowi, programiście witryn i komukolwiek kto ma do czynienia z WWW. Te 160 stron może przynieść bardzo duże oszczędności finansowe, gdy serwis zacznie się rozrastać. A co najlepsze - książka kosztuje tylko 29,00 zł !

sobota, 17 kwietnia 2010

Testy wydajnościowe bazy danych z Apache JMeter

Dzisiaj na tablicy od rana mam Apache JMeter - świetne i darmowe narzędzie do testowania obciążenia. Kto by chciał się zapoznać z tym jak testować swoje witryny za pomocą tego narzędzia zapraszam (który to już raz?;]) na blog Mateusza Zięby -> Na Jawie - perwszy test z Apache JMeter.
U mnie potestujemy za to jak sprawuje się silnik bazy danych dla zapytań używanych w tworzonej przez nas aplikacji.
Pobrać JMeter można tutaj. Po ściągnięciu, ale przed uruchomieniem należy przegrać sterownik JDBC bazy danych której będziemy używać do katalogu /lib/ znajdujący się w katalogu głównym aplikacji. W moim przypadku bazą danych będzie DB2, więc kopiuję tam plik db2jcc4.jar.
 Po uruchomieniu programu zabieramy się za tworzenie testu. Do węzła "Test Plan" po prawej stronie dodajemy Add -> Thread Group. Grupa wątków definiuje ilu użytkowników będzie symulować test, ile razy każdy z nich będzie wykonywać wszystkie zdefiniowane żądania oraz co jaki czas powinien startować kolejny użytkownik. Dla przykładowego testu ustawiłem następujące wartości:
Number of threads: 8
Ramp-Up Period: 0 (startują wszyscy od razu)
Loop count: 20

Teraz do grupy wątków należy dodać konfigurację połączenia z bazą danych: Add -> Config Element -> JDBC Connection Configuration.W tym oknie uzupełniamy:
Variable Name: (tutaj dowolna nazwa, u mnie: DB2_SAMPLE)
Database URL: (ścieżka połączenia do bazy danych, u mnie: jdbc:db2://localhost:5000/SAMPLE)
JDBC Driver class: (klasa sterownika, u mnie  com.ibm.db2.jcc.DB2Driver
Username: użytkownik
Password: hasło
Bardzo ważne jest uzupełnione przez nas pole Variable Name ponieważ to na podstawie tej nazwy będziemy się odwoływać do tego połączenia przy tworzeniu zapytań. Możliwe jest utworzenie wielu połączeń i korzystanie z nich w różnych zapytaniach, właśnie na podstawie tej nazwy (musi być ona unikalna!).
Teraz należy dodać zapytania które będą wykonywane: Add -> Sampler -> JDBC Request. Ja do testów podałem dwa bardzo proste zapytania zwracające listę pracowników oraz listę departamentów z przykładowej bazy w DB2.
EmpoyeeList:
DepartmentList:
Należy pamiętać by w obu zapytaniach pole Variable Name miało wartość taką jak nazwa puli połączeń z konfiguracji połączenia. W moim wypadku jest to DB2_SAMPLE.
No to już praktycznie wszystko gotowe. Dodajmy jeszcze Add -> Listeners -> Summary Report do wyświetlenia wyników podsumowujących testy.
I można startować z testem: Run -> Start :) Podczas symulacji łącznie powinno zostać wykonanych: liczba użytkowników * liczba powtórzeń * liczba zapytań SQL żądań.
Miłego testowania !

piątek, 16 kwietnia 2010

Mapowanie parametrów GET w JSF

Jak miło można "pobierać" wartości GET z URL w JSF - praktycznie samo się robi. Wystarczy powiązać w faces-config.xml nazwę pola w GET z polem w zarządzanym ziarnie
Dla przykładowego linka: /employeeView.faces?employeeId=000010
faces-config.xml:
<managed-bean>
        <managed-bean-name>employeeBean</managed-bean-name>
        <managed-bean-class>com.sampleproject.jsf.EmployeeBean</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
            <property-name>employeeId</property-name>
            <value>#{param.employeeId}</value>
        </managed-property>
</managed-bean>

I nie trzeba się o nic martwić, bo zrobi się samo. Co jest bardzo dobre JSF nie rzuca wyjątkami gdy brakuje wartości w GET tylko wstawia null.

środa, 7 kwietnia 2010

Karmimy bazę danych - dbMonster

Przez ostatni czas szukałem narzędzia do generowania dużej ilości danych dla baz danych.
Natrafiłem na dość sporo ich w sieci ale niestety znaczna większość była komercyjna a ich wersje trialowe umożliwiały generowanie np. tylko 40 rekordów. Ale na szczęście udało mi się także napotkać na miły program autorstwa Polaka Piotra Maja - dbMonster. Narzędzie to obsługuje się z poziomu (niestety) konsoli i wymaga stworzenia mapowania w pliku XML oraz prostej konfiguracji.
Zacznijmy od stworzenia tabeli w bazie danych którą później zapchamy danymi:
CONNECT TO DBMNTEST;
CREATE TABLE WOOKASZ.PRODUKTY ( 
ID_PRODUKTU BIGINT  NOT NULL  GENERATED ALWAYS AS IDENTITY (START WITH 0, INCREMENT BY 1, NO CACHE ), 
NAZWA VARCHAR (80)  NOT NULL, 
CENA DECIMAL (9, 2)  NOT NULL, 
CONSTRAINT CC1270576608403 PRIMARY KEY (ID_PRODUKTU)
);
CONNECT RESET;
W konfiguracji podajemy podstawowe dane do połączenia i kilka parametrów potrzebnych do pracy dbMonster.
test.properties:
# podstawowe dane do połączenia
dbmonster.jdbc.driver=com.ibm.db2.jcc.DB2Driver
dbmonster.jdbc.url=jdbc:db2://127.0.0.1:50000/dbmntest
dbmonster.jdbc.username=WOOKASZ
dbmonster.jdbc.password=password
# po ilu insertach wykonywać commit
dbmonster.jdbc.transaction.size=1000

# nazwa schematu dla takich baz jak Oracle lub DB2
dbmonster.jdbc.schema=WOOKASZ

# ile razy próbować wygenerować unikalny klucz
dbmonster.max-tries=1000

# domyślna liczba wierszy dla SchemaGrabber (o tym innym razem;)
dbmonster.rows=1000

# klasa wizualizująca progress bar
dbmonster.progress.monitor=pl.kernelpanic.dbmonster.ProgressMonitorAdapter
Myślę, że tak konfiguracja jest dość prosta i nie trzeba jej głębiej omawiać.
Teraz czas dla schematu w którym opisana jest struktura tabel dla których generowane będą dane. W naszym przypadku jest to tylko jedna tabela PRODUKTY.
testSchema.xml:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE dbmonster-schema PUBLIC
    "-//kernelpanic.pl//DBMonster Database Schema DTD 1.1//EN"
    "http://dbmonster.kernelpanic.pl/dtd/dbmonster-schema-1.1.dtd">
<dbmonster-schema>
   <name>DB Monster Test Schema ! ^^</name>
    <table name="PRODUKTY" rows="15000">
        <key databaseDefault="true">
           <generator type="pl.kernelpanic.dbmonster.generator.MaxKeyGenerator">
               <property name="columnName" value="ID_PRODUKTU"/>
           </generator>
        </key>
        <column name="nazwa">
            <generator type="pl.kernelpanic.dbmonster.generator.StringGenerator">
                <property name="nulls" value="0"/>
                <property name="minLength" value="4"/>
                <property name="maxLength" value="80"/>
                <property name="allowSpaces" value="true"/>
            </generator>
        </column>
        <column name="cena">
            <generator type="pl.kernelpanic.dbmonster.generator.NumberGenerator">
                <property name="nulls" value="0"/>
                <property name="minValue" value="10"/>
                <property name="maxValue" value="30000"/>
                <property name="returnedType" value="numeric"/>
    <property name="scale" value="2"/>
            </generator>
        </column>
    </table>
</dbmonster-schema>
Opis struktury tabeli zawiera się w znaczniku table którego pierwszy atrubuty name musi zawierać poprawną nazwę tabeli, a drugi rows liczbę wierszy ile ma być wygenerowanych dla tej tabeli. dbMonster obsługuje klucze główne tabel, informacje o nich zawiera się w znaczniku key. W tym przypadku nie używamy generatora udostępnianego przez dbMonster do generowania wartości dla kluczy (używane są identity columns) dlatego atrybut databaseDefault ma wartość true. Dalej umieszczone zostały definicje kolumn. Każda kolumna zawiera parametry do generowania, zależne są one od tego jakiego typu generatora używamy. Listą dostępnych generatorów wraz z opisem parametrów dostępna jest tutaj. Co jest bardzo miłe dostępne jest pełne API który pozwala na tworzenie własnych generatorów.
Co mi się bardzo spodobało StringGenerator nie generuje dziwnego zlepku losowych liter tylko normalne słowa z dostępnego dla niego słownika:) Dlatego nazwą produktu nie będzie np. "AhT8ddnoJuuTQpp" ale np. "keypad's tingle". Wiem, że to i tak bez sensu (a może to coś znaczy ?) ale lepiej to wygląda gdy prezentujemy nasz system.
Zanim będzie można uruchomić generację należy przekopiować do katalogu /lib/ sterownik JDBC dla używanej bazy danych.
Teraz możemy użyć gotowego skryptu bat z katalogu /bin/ aby uruchomić generację:
dbmonster -c test.properties -s testSchema.xml

rem Batch file to run dbmonster under Windows

rem Contributed by Peter De Bruycker
2010-04-07 12:21:55,776 INFO  DBMonster - Let's feed this hungry database.
2010-04-07 12:21:56,257 INFO  DBCPConnectionProvider - Today we are feeding: DB2/NT SQL09070
2010-04-07 12:21:56,465 INFO  Schema - Generating schema .
2010-04-07 12:21:56,473 INFO  Table - Generating table <PRODUKTY>.
2010-04-07 12:22:28,570 INFO  Table - Generation of table <PRODUKTY> finished.
2010-04-07 12:22:28,574 INFO  Schema - Generation of schema <DB Monster Test Schema ! ^^> finished.
2010-04-07 12:22:28,579 INFO  DBMonster - Finished in 32 sec. 804 ms.
I mamy tabelę pełną danych:)
Dodam jeszcze, że tworzenie schematu nie jest konieczne, gdy w tabelach znajdują się jakieś dane. Można użyć tzw. SchemaGrabber aby wygenerować schemat xml. Jednak jeszcze nie udało mi się tego dokonać, ciągle otrzymuję pustą definicję tabeli. Jak mi się to uda to postaram się opisać.

Narzędzie jest bardzo dobre gdy nie mamy jakiś skomplikowanych warunków do tego jakie dane mają być składowane w bazie danych, do prostych zastosować idealne. Szkoda tylko, że projekt ten już od 2006 roku nie jest rozwijany, według mnie ma solidne podstawy do tego by konkurować z komercyjnymi rozwiązaniami. Może ktoś przejmie pałeczkę i zajmie się rozbudową dbMonster ?

niedziela, 28 marca 2010

Spotkanie Poznań JUG - Programowanie na platformę iPhone - Wprowadzenie [30.03.2010]

Spotkanie Poznań-JUG które odbędzie się w najbliższy wtorek 30 marca tym razem nie będzie dotyczyć technologii Javowych, ale iPhonowych!:) Bardzo ciekawa odmiana :)

O czym dokładnie będzie na spotkaniu ?
Omówione zostaną:
- Kwestie techniczne: urządzenie, wymagania
- Prezentacja narzędzi oraz języka (ObjectiveC)
- Pierwszy program iPhonowy - kodzenie Live
- Szybki przegląd API iPhone oraz komponentów UI
- Tworzenie gier na iPhone'a - (genialny, opensourceowy) silnik
Cocos2d for iPhone
- Wdrażanie aplikacji na AppStore na podstawie własnego doświadczenia
- jak to naprawdę jest z tą żyłą złota na jaką jest kreowany AppStore...
- (owocna mam nadzieję) dyskusja

Trochę info o prelegencie:
Mariusz Lisiecki, jest studentem V roku Informatyki na UAM. Od ponad
roku pracuje w SuperMemo World na stanowisku Programista iPhone jest
odpowiedzialny za aplikację SuperMemo for iPhone. Kierownik, główny
projektant-programista projektu: "GuLiMaRo - Empires At War" (gra to
luźny mix takich tytułów jak "Age Of War" i "Age Of Empires" na
iPhone'a). Aktualnie w trakcie pisania swojej pracy magisterskiej nt.
"Tworzenie silnika fizycznego dla gier 3D - przeznaczonego na
platformę iPhone".

Wszystko jak zwykle odbędzie się w Poznańskiej siedzibie firmy Cognifide znajdującej się pod adresem al. Wielkopolskie 4 w Poznaniu. Początek spotkania zaplanowano na godzinę 18:00.
Uwaga! Wymagana jest REJESTRACJA.

sobota, 27 lutego 2010

Tworzenie własnych komponentów w Facelets

Tworzenie własnych komponentów w JSF (przynajmniej 1.2, z wersją 2.0 nie miałem się jeszcze okazji zapoznać) jest dość skomplikowane i wymaga poświęcenia trochę czasu. Trzeba utworzyć dwie klasy oraz deskryptor komponentu TLD, no i zarejestrować nowy komponent. W Facelets sprawa jest dużo prostsza i wymaga tylko utworzenia pliku .xhtml, w którym najzwyczajniej tworzymy komponent w HTMLu i rejestracji.
Stwórzmy przykładowy komponent o dość banalnym zadaniu: wyświetlanie pola tekstowego wraz z etykietą.
Czyli dla:
<cust:labeledInput value="#{myBean.name}" id="myInput" label="Podaj imię: " />
Ma się wygenerować:
<label for="myInput">Podaj imię: </label>
<input id="myInput" type="text" name="myInput" value="" />
Zacznijmy od pliku .xhtml tworząc to co normalnie byśmy pisali za każdym razem dla takich komponentów:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core">

 <ui:composition>
  <h:panelGroup>
   <h:outputLabel for="#{id}" value="#{label}"/>
   <h:inputText id="#{id}" value="#{value}" />
  </h:panelGroup>
 </ui:composition>
</html>
Jeśli przypisujemy do tagu atrybut np. label="napis" to w definicji komponentu odwołujemy się do jego wartości poprzez #{label}. Trzeba przyznać, że jest to dość wygodne.
Pozostało już tylko zarejestrować komponent. Należy najpierw utworzyć plik XML definiujący bibliotekę tagów. myTags.taglib.xml:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "facelet-taglib_1_0.dtd">
<facelet-taglib>
    <namespace>http://wookasz.blogspot.com/tags</namespace>
 <tag>
  <tag-name>labeledInput</tag-name>
  <source>LabeledInput.xhtml</source>
 </tag>
</facelet-taglib>
I ten plik należy dopisać w konfiguracji web.xml:
<context-param>
 <param-name>facelets.LIBRARIES</param-name>
 <param-value>
  /WEB-INF/facelets/tags/myTags.taglib.xml;
 </param-value>
</context-param>
I to starczy. Przykład użycia:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:cust="http://wookasz.blogspot.com/tags">

 <ui:composition>
  <f:view>
   <h:form>
    <cust:labeledInput value="#{myBean.name}" 
     label="Podaj imię: " id="nameInput"/>
   </h:form>
  </f:view>
 </ui:composition>
</html>
Po drobnej modyfikacji pliku komponentu:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core">

 <ui:composition>
  <h:panelGroup>
   <h:outputLabel for="#{id}" value="#{label}"/>
   <h:inputText id="#{id}" value="#{value}">
    <ui:insert/>
   </h:inputText>
   <h:message for="#{id}" />
  </h:panelGroup>
 </ui:composition>
</html>
Można będzie wstawiać inne węzły w węzeł komponentu. Umieszczane one będą w miejsce <ui:insert/>. Dodałem jeszcze wyświetlanie komunikatów błedów od walidatora co umożliwia takie użycie:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:cust="http://wookasz.blogspot.com/tags">

 <ui:composition>
  <f:view>
   <h:form>
    <cust:labeledInput value="#{myBean.name}" 
     label="Podaj imię: " id="nameInput">
     <f:validateLength maximum="15" minimum="2"/>
    <cust:labeledInput>
   </h:form>
  </f:view>
 </ui:composition>
</html>
...i nie martwienie się oprócz etykiety także o komunikat walidacji.

czwartek, 25 lutego 2010

Uwierzytelnianie w Spring Security z użyciem haseł zakodowanych funkcją MD5

Kolejny wpis dotyczący Spring Security. Tym razem do skonfigurowania jest aplikacja która podczas logowania użytkownika korzysta z haseł zapisanych po wcześniejszym zakodowaniu ich algorytmem MD5. Oczywiście będzie to dość proste i szybkie w skonfigurowaniu:)

Praktycznie jedynym co musimy zrobić to trochę zmodyfikować kontekst bezpieczeństwa aplikacji pliku w XML. W pierwszej kolejności należy dodać ziarno które będzie odpowiadać za tworzenie skrótu z hasła, będzie nim obiekt Md5PasswordEncoder:
<beans:bean id="passwordEncoder" 
        class="org.springframework.security.providers.encoding.Md5PasswordEncoder"/>
Następnie to ziarno musi być przypisane do beana odpowiedzialnego za uwierzytelnianie:
<beans:bean id="daoAuthenticationProvider"
 class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
 ...
 <beans:property name="passwordEncoder" ref="passwordEncoder"/>
 <beans:property name="saltSource"><beans:null/></beans:property>
        ...
</beans:bean>
W tym przykładzie nie używana jest sól, która może wpłynąć na poprawę bezpieczeństwa skrótu. Jeśli ktoś chce zwiększyć bezpieczeństwo powinien z niej skorzystać.
Algorytm kodowania może być w bardzo prosty sposób zmieniony, poprzez zmianę klasy Md5PasswordEncoder na inną (MD5 nie jest już zbyt bezpieczny:). Jeśli chcielibyśmy użyć algorytmu SHA-1 wtedy klasa ShaPasswordEncoder będzie bardziej pomocna.

Warto używać tego samego algorytmu do autoryzacji jak i do kodowania hasła przy zapisie do bazy danych. W przypadku MD5 (bez soli) poniższa metoda wykonuje to zadanie używając bibliotek Springowych:
public String encodePassword(final String password) {
    final Md5PasswordEncoder encoder = new Md5PasswordEncoder();
    // drugi parametr to źródło 'soli'
    return encoder.encodePassword(password, null);
}
Dla osób nie znających jeszcze Spring Security ponownie polecam wpis na blogu Mateusza Zięby -> Bezpieczeństwo szybko, łatwo i przyjemnie czyli wstęp do Spring Security :)

niedziela, 21 lutego 2010

Spotkanie Poznań JUG - Clojure

Teraz o czymś bliższym terminowo niż GeeCON :) W najbliższy wtorek odbędzie się spotkanie Poznańskiej Grupy Użytkowników Javy dotyczące programowania funkcyjnego oraz języka Clojure.
Pozwolę sobie wkleić streszczenie prelegenta Filipa Koczorowskiego:
Jeśli jeszcze nie wiecie, to przestała rosnąć prędkość działania procesorów. W zamian producenci oferują nam ich coraz większą liczbę. Aby móc jednak skorzystać z tego prezentu, musimy przestawić się na aplikacje wielowątkowe i współbieżne. Programowanie wielowątkowe jest bardzo trudne, więc jak to zrobić? Niektórzy twierdzą, że znaleźli odpowiedź i że nazywa się ona programowanie funkcyjne.
Termin oraz namiary:
Siedziba Cognifide - Aleje Wielkopolskie 4, Poznań
Wtorek 23.02.2010
Godzina 18:00

Zapraszam!!

Rejestracja na GeeCON 2010 otwarta !

Od 4 dni można już zacząć rejestrować się na drugą edycję konferencji GeeCON! W roku poprzednim odbyła się ona w Krakowie, w tym stolicą Javowego świata będzie Poznań! Cała impreza odbędzie się w dniach 12-14 maja i już zapraszam do zapisania się, ponieważ im później - tym drożej ;-)
Przewidziano 3 okresy rejestracji, w pierwszym ceny biletów są następujące:
399 PLN (105 EUR) - bilet normalny
299 PLN (80 EUR) - bilet studencki

Pierwszy okres kończy się 15 marca.
Oprócz możliwości wysłuchania prezentacji osób z całego świata, firma Adobe (złoty sponsor GeeCON) funduje także dla uczestników licencje na Adobe Flex Builder (dla zastosowań niekomercyjnych).

Chciałem jeszcze przypomnieć, że za tydzień kończy się Call for Papers. Więc jeśli masz coś ciekawego do powiedzenia i chcesz się tym podzielić z resztą świata to zachęcam do szybkiego zgłoszenia swojej propozycji! Call for Papers kończy się 28 lutego.

Więcej szczegółów o rejestracji tutaj, a o Call for Papers tutaj. Zapraszam też do przyłączenia się do grupy GeeCON Planet na Facebooku!

Do zobaczenia na GeeCONie !!

niedziela, 7 lutego 2010

Co nowego w Java 7 ? Część trzecia - będą domknięcia !

Wiadomość może nie jest najświeższa, niestety nie miałem ostatnio czasu aby czytać o rozwoju JDK 7, ale 10 grudnia ubiegłego roku ogłoszono akceptację projektu Lambda, czyli wprowadzanie domknięć w Javie! Udało się przepchnąć je do JDK 7 z powodu przesunięcia wydania finalnej wersji na wrzesień 2010, poza tym i tak pojawiłyby się w wersji 8.
Co nam dadzą domknięcia ? Dużo uproszczeń, kilka przykładów:

Typy funkcyjne:
#int(int, int) mnoz = #(int x, int y)(x*y);
int a = mnoz(10,20);
Funkcje też można zwracać:
#int(int, int) mnoz = #(){ return #(int a, int b)(a*b)};
int a = mnoz(10,20);
Definicja komparatora:
List<Person> list = ...
Collections.sort(list, #(Person a, Person b)( a.getAge() - b.getAge() ));
I najważniejsza funkcjonalność - extension methods:
// Załóżmy, że mamy metodę w klasie Collections:
class Collections {
  ...
  static <T> Set<T> filter(Set<T> s, #boolean(T) pred) { ... }
  ...
}
// interfejs dla zbioru:
interface Set<T> extends Collection<T> {
  ...
  Set<T> filter(#boolean(T)) import static Collections.filter;
  ...
}
// dzięki temu będziemy mogli wykonać filtrowanie w taki sposób:
Set<Integer> newSet = set.filter(#(int x)(x > 0));
// nowy zbiór będzie zawierać tylko wartości większe od zera
Polecam zapoznać się ze stroną Project Lambda: Straw-Man Proposal w poszukiwaniu większej liczby przykładów oraz stroną Closures for Java (v0.6a) gdzie opisano całą propozycję rozszerzenia.
Można też przeczytać: Closures for Java: The Q&A.

sobota, 6 lutego 2010

Tagi Spring Security i Facelets

Ostatni projekt przy którym pracowałem zmusił mnie do ponownego spotkania ze Spring Security. Wcześniej pracowałem z tym świetnym frameworkiem przy okazji pisania pracy inżynierskiej. Wtedy nie miałem praktycznie żadnych problemów z osadzeniem go w projekcie i podpięciem wszystkich funkcji (wielka chwała Mateuszowi Zięba za wpis na jego blogu - Bezpieczeństwo szybko, łatwo i przyjemnie czyli wstęp do Spring Security - polecam!). Tym razem Spring trochę mnie nie słuchał :)
Pojawił się problem całkowitego ignorowania tagów spring security w kodzie szablonu, silnik renderujący po prostu wyrzucał je do wynikowego HTMLa. Nie mogąc znaleźć na to rozwiązania spytałem grupę dyskusyjną o pomoc w sprawie, gdzie otrzymałem sugestie, że być może tagi springowe nie są kompatybilne z Facelets który był używany w projekcie. Okazało się to strzałem w dziesiątkę! Wersja Spring Security z którą wtedy pracowałem to 2.0.5 i wtedy (nie wiem jak jest z ver. 3.0 ? Ktoś wie ?) nie było tagów zgodnych z Facelets :-/
Z pomocą przyszedł wujek Google i projekt Spring Security Facelets Tag Library. Jest to autorskie rozwiązanie, ale gdzieś przeczytałem, że trwają rozmowy nad integracją ze Springiem.
Projekt jest bardzo ciekawy ponieważ rozwijane są wersje zgodne z JSF 1.2 jak i 2.0 oraz Spring Security 2.0 jak i 3.0.
No ale wracając to konkretów, biblioteka definiuje własne tagi działające z Facelets. Ich nazwy trochę odbiegają od tych w Springu ale możliwości są te same. Aby ich użyć w szablonie należy dodać namespace: http://www.springframework.org/security/facelets/tags
Drobne przykłady:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" 
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core" 
      xmlns:security="http://www.springframework.org/security/facelets/tags">
<ui:composition>
 <f:view>
  <security:ifNotGranted roles="ROLE_ADMIN">
     <h:outputText value="Użytkownik nie ma uprawnienia ROLE_ADMIN" />
  </security:ifNotGranted>
  <security:ifAnyGranted roles="ROLE_USER, ROLE_ADMIN">
     <h:outputText value="Użytkownik posiada chociaż jedno z uprawnień, ROLE_USER lub ROLE_ADMIN" />
  </security:ifAnyGranted>
  <security:ifAllGranted roles="ROLE_BOSS, ROLE_ADMIN">
     <h:outputText value="Użytkownik posiada oba uprawnienia, ROLE_BOSS oraz ROLE_ADMIN" />
  </security:ifAllGranted>
 </f:view>
</ui:composition>
</html> 
I wszystko ładnie śmiga :)

sobota, 9 stycznia 2010

Domyślne ukrywanie kodu w edytorze - NetBeans

Czasami nasze klasy posiadają bardzo dużo metod lub pól przez które musimy się przebijać zanim dotrzemy do odpowiedniego miejsca w kodzie. Gdy często korzystamy z tej klasy może to się zdać dość męczące i czasochłonne.
We wszystkich znanych mi chyba środowiskach wbudowana jest opcja ukrywania ciał metod lub pól z komentarzem za pomocą intuicyjnego minusika na pasku bocznym. Jak na obrazku:

Jednak jeśli tak jak wspominałem na początku w klasie mamy bardzo wiele metod jak np. gettery i settery na które nie musimy ciągle patrzeć nawet bo schowaniu ich ciał może nadal zajmować to dość sporo miejsca.
W NetBeans możemy to obejść dodając odpowiedni komentarz w kodzie.
Miejsce od którego chcemy aby kod był domyślnie ukryty po otwarciu pliku rozpoczynamy od:
// <editor-fold defaultstate="collapsed" desc="Getters & setters">
a kończymy go zamykając tag:
// </editor-fold>

Wynikiem będzie tylko jedna linijka dla całego kodu z opisem umieszczonym w atrybucie desc:

Z tego co zauważyłem działa to dla wszystkich języków programowania w NetBeans:)

Ktoś wie jak takie coś się robi np. w eclipse ? Lub innym IDE ?

ps. Oczywiście możemy używać Ctrl+G (skok do linii) lub używać okna nawigatora, ale to nie zawsze wystarcza ;-)