poniedziałek, 1 czerwca 2009

RESTful webservices

w 2000 roku Roy Thomas Fielding opracował w swojej pracy doktorskiej ciekawy sposób realizowania wymiany komunikatów XML poprzez HTTP. Jego pomysł otrzymał już swoją specyfikację JAX-RS (JAX-311) i stał się częścią J2EE 6.
Aktualnie większość serwisów oparta jest na SOAP/WSDL i serwisy te działają - dlaczego więc REST miałby być lepszy? Dlaczego stał się standardem?

Rozszyfrujmy skrót REST: REpresentational State Transfer. REST opiera się przede wszystkim na tym, że każdy zasób w internecie ma swój unikalny identyfikator np.:

http://web-services.pl/klieci (lista wszystkich klientów)
http://web-services.pl/klient/34 (konkretny klient o identyfikatorze 34)
http://web-services.pl/zamowienia/2009/06 (wszystkie zamówienia z czerwca 2009)
http://web-services.pl/zamowienie/2009/06/1234 (konkretne zamówienie)

Użytkownik "chodząc" po aplikacji klika w linki, czego wynikiem jest kolejny ekran. Kolejne ekrany można określić jako nowy stan aplikacji - prezentowane są inne zasoby, lub te same, ale w inny sposób (np. zaktualizowane). Użytkownik ma więc wpływ na zmianę stanu tego, co aktualnie widzi. Stąd nazwa, której próba tłumaczenia mogłaby być taka: abstrakcyjna zmiana stanów.


Ponadto został wykorzystany fakt, że HTTP posiada m.in. takie metody jak: POST, GET, PUT, DELETE. Z kolei operacje na obiektach to zazwyczaj standardowy CRUD. Wiążąc te dwa fakty można użyć standardowych metod HTTP do wykonania standardowych akcji na obiektach:

  • POST - tworzenie obiektów (Create)
  • GET - pobieranie danych (Read)
  • PUT - tworzenie/aktualizacja obiektów (Create/Update)
  • DELETE - usuwanie obiektów (Delete)

przykładowe wywołania:
  • http://web-services.pl/klient za pomocą metody POST - zostanie utworzony nowy klient (identyfikator zostanie nadany przez operację)
  • http://web-services.pl/klient/34 za pomocą metody GET - zostaną zwrócone dane klienta o podanym identyfikatorze
  • http://web-services.pl/klient/34 za pomocą metody PUT - dane klienta zostaną zaktualizowane
  • http://web-services.pl/klient/34 za pomocą metody DELETE - klient o podanym identyfikatorze zostanie usunięty

Ważne jest to, żeby w URI posługiwać się rzeczownikami. To tak samo jak w rzeczywistym świecie - mamy np. stół, a na nim szklankę, ołówek, notes, dziurkacz. Każdą z tych rzeczy możemy wziąć (ang. GET). wziąć (GET) szklankę, wziąć (GET) ołówek, wziąć (GET) notes itd...
Ten sam czasownik (GET) stosowany do RÓŻNYCH przedmiotów (rzeczowniki). Proste, nie? Niektóre czasowniki można stosować jednak tylko do wybranych rzeczowników - nie można np. pisać notesem, albo pić z ołówka :)

jak może wyglądać przykładowa odpowiedź na pytanie http://web-services.pl/klieci (GET):

<?xml version="1.0"?>
<p:Part xmlns:p="http://www.parts-depot.com"
xmlns:xlink="http://www.w3.org/1999/xlink">
<klienci>
<klient id="34" xlink:href="http://web-services.pl/klient/34"/>
<klient id="35" xlink:href="http://web-services.pl/klient/35"/>
<klient id="36" xlink:href="http://web-services.pl/klient/36"/>
</klienci>
</p:Part>

Nie jesteśmy jednak ograniczeni do używania XMLa - możemy produkować inny rodzaj na wyjściu. W ogóle nie musimy używać XMLa, możemy użyć np.: JSONa, ATOMa, YAMLa... Poniżej kod prostego serwisu - pozostawiam bez komentarza, ponieważ jest dość intuicyjny:

@Path("/klient/{id}")
public class UserResource {

@GET @Produces("application/xml"})
public User getKlient(@PathParam("id") String id) {
return lookupCustomer(id);
}

@PUT @Consumes("application/xml"})
public void putUser(@PathParam("id") String id, Customer u) {
return updateCustomer(id, u);
}

}

wtorek, 16 grudnia 2008

kompilatory: microsoft vs jrockit

ale buba :)

zwróć uwagę na podwójną annotację "deprecated" w poniższym listingu:

public class Deptest {

/**
* @deprecated aasadsa
* @deprecated sddsfsdf
*/
public String hello() {
return "hello";
}

public static void main(String[] args) {
Deptest t = new Deptest();
System.out.println(t.hello());
}
}

okazuje się, że ten kod skompilowany kompilatorem Microsoftu (tak, jest taki kompilator...) nie zadziała w środowisku uruchomieniowym JRockit firmy Bea (Oracle). Wygenerowany zostanie błąd ClassFormatException:

D:\Programy\Java\bea102\jrockit_150_11\bin>java Deptest
Exception in thread "Main Thread" java.lang.ClassFormatError: Deptest :
duplicate attribute Deprecated
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at
java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)


Ciekawa sprawa - ten sam kod działa w środowisku JRE Suna. Dlaczego tak jest? Otóż okazuje się, że JRockit o wiele bardziej restrykcyjnie sprawdza poprawność bytecodu plików .class.

Poradzić sobie z tym problemem można na dwa sposoby:
1) usunąć podwójną annotację i przekompilować klasę
2) uruchomiająć środowisko JRockit (np. serwer weblogic) użyć przełącznika-Xverify, który wyłączy wspomnianą restrykcyjną politykę JRockit.

poniedziałek, 15 grudnia 2008

SCRUM - religia dobra na kryzys?

11 grudnia 2008 roku miało miejsce kolejne spotkanie Dolnośląskiej Grupy Regionalnej SPMP. Spotkanie było tym razem poświęcone SCRUM - metodyce modnej ostatnio w świecie zarządzania projektem informatycznym.

SCRUM w kilku słowach - jest to metodyka zaliczana do tzw. metodyk zwinnych, jej głównymi cechami są:
  • samoorganizacja zespołów,
  • codzienne spotkania na stojąco (daily scrums),
  • odizolowanie członków od innych prac (dba o to scrum master),
  • skupianie się nad sprawami aktualnie najważniejszymi.
Po dwóch ciekawych wykładach: teoretycznym i praktycznym nadszedł czas na dyskusje. Jednym z tematów, który utkwił mi w głowie było porównanie metodyki do religii. Coś w tym rzeczywiście jest - można przecież być 'ateistą' i zarządzać projektem bez żadnych zasad. Można też być mocnym 'wyznawcą' którejkolwiek z metodyk i w zarządzaniu skrupulatnie przestrzegać wszystkich jej reguł. Okazuje się, że życie jest zupełnie inne - liczne przykłady pokazują, że w organizacjach trudno zastosować w 100% jakąkolwiek z metodyk i to nie ważne czy jest to SCRUM, RUP czy też PMBOK. Po co więc poznawać metodyki, jeśli w realu nie można z nich skorzystać? Otóż można - trzeba maksymalnie wpasować je organizacje, w których tworzony jest projekt. Rozsądne więc wydaje się być wyznawcą metodyki, jednak nieco liberalnym...

Dlaczego więc instytucje mające swoje zasady zarządzania projektami IT miałyby zastosować SCRUM? Odpowiedź jest krótka - w praktyce metodą tą można szybciej realizować zmiany (Time 2 Market) i lepiej wykorzystać zasoby.

Jako istotna wada SCRUM została wskazana trudność w początkowych etapach wdrożenia tej metodyki. Dopiero po kilku (3-4) tzw. sprintach zespoły zaczynają pracować efektywniej niż było to wcześniej, a jak zapewniają osoby, które wdrożyły SCRUM wzrosty wydajności jest znaczący

Zgadzam się z tym, że w dużych organizacjach zasoby w IT często nie są dobrze wykorzystane. Jeszcze niedawno byłem gorącym zwolennikiem procesowego zarządzania w IT i nie wyobrażałem sobie lepszej organizacji pracy. Po ponad 3 godzinach zajęć ze SCRUM, a w szczególności po godzinnej dyskusji na jego temat spojrzałem na to zarządzanie nieco inaczej. Wydaje mi się, że SCRUM ma szanse na rozwój szczególnie teraz, gdy stajemy na schyłku nieuniknionej już chyba recesji. Co z tego, że mamy 5 dobrych zespołów zarządzanych procesowo, jeśli w szybkiej realizacji zadania istotnym problemem staje się brak koordynacji zadań między członkami? To właśnie dla takich, procesowo zarządzanych, firm SCRUM może być lekarstwem na czas spowolnienia gospodarczego, gdzie każda złotówka będzie miała coraz większą wartość.

Warto więc zainteresować się SCRUM i to nie tylko w czasach kryzysu żeby nie tracić, ale także w czasach silnego wzrostu, kiedy trzeba zyskać przewagę nad konkurencją.

poniedziałek, 8 grudnia 2008

zastosowanie fragmentów do tłumaczenia pluginów

Załóżmy, że chcesz mieć aplikację ze stroną intro. Skorzystałeś z plugina org.eclipse.ui.intro i np. żeby mieć mniej pracy dodałeś jeszcze org.eclipse.ui.intro.universal. Aplikacja ma być zlokalizowana na język polski, ale okazuje się, że stworzona strona intro wygląda mniej więcej tak:

mamy więc przynajmniej 2 teksty, które się nie przetłumaczyły i nie mamy wpływu na ich treść. Są to: 'overview' oraz 'workbench'.

Teksty te znajdują się w pluginie org.eclipse.ui.intro.universal, a konkretniej w pliku Messages.properties. Ale przecież nie będziesz modyfikował żródeł standardowego plugina eclipsowego tylko po to, żeby zaczął on mówić po polsku. Co możesz zrobić? Fajnie byłoby móc rozszerzyć istniejący plugin bez możliwości ingerowania w jego ciało. Okazuje się, że można to zrobić i jest to całkiem proste! Wystarczy wykorzystać do tego tzw. plugin fragment.

Czym jest fragment? Jest to nic innego jak opcjonalna część plugina, która może być dostarczona do dystrybucji wraz z pluginem. Fragment może zawierać dodatkowe biblioteki, zasoby (obrazki) oraz rozszerzenia (extensions) - nie może jednak nadpisywać istniejących w pluginie macierzystym klas. Kiedy fragment jest wczytywany przez eclipsa, jest on logicznie (nie fizycznie!) łączony z pluginem macierzystym. Nowe biblioteki i zasoby znajdujące się we fragmencie są automatycznie widoczne w pluginie, z którym powiązany jest dany fragment i tym samym plugin może z nich korzystać.

Tak więc jeśli w pluginie znajduje się plik Messages.properties, to jeśli znajdowałby się tam również plik Messages_pl.properties, plugin potrafiłby mówić w języku polskim! Zatem do dzieła:

new -> other -> Fragment project
project name: org.eclipse.ui.intro.universal.nl.fragment

->next
Host plug-in -> Plug-in ID: org.eclipse.ui.intro.universal
-> finish

w nowo powstałym fragmencie należy w źródłach utworzyć pakiet
org.eclipse.ui.internal.intro.universal i następnie dodać do niego plik Messages_pl.properties, który powstał przez skopiowanie pliku Messages.properties z pluginu org.eclipse.ui.intro.universal. Docelowo otrzymujemy taką strukturę:




Tłumaczymy kolejne linie w Messages_pl.properties lub tylko te, które są potrzebne, m. in. workbench oraz overview, które nam się nie podobały na pierwszym zrzucie.

Gdy plik zostanie przetłumaczony, należy zapewnić, żeby fragment org.eclipse.ui.intro.universal.nl.fragment znajdował się w classpath uruchamianego produktu. Efekt końcowy wygląda tak:




podsumowanie
Za pomocą plugin fragmentu można rozszerzyć plugin bazowy, dodać do niego różne zasoby. Jednym z częściej wykorzystywanych zastosowań fragmentów jest lokalizowanie plugina: plików .properties oraz obrazków specyficznych dla danego kraju.

dlaczego eclipse RCP?

Niedawno miałem okazję uczestniczyć we Wrocławskim Democampie i uzmysłowiłem sobie, że mimo iż wielu programistów java korzysta z eclipse to mało z nich wie, że z technologii eclipse można korzystać do tworzenia własnych aplikacji! Ja też kiedyś o tym nie wiedziałem...

Nieco ponad rok temu zainteresowałem się platformą eclipsa i postanowiłem poznać ją bliżej. Wiedziałem, że eclipse składa się z pluginów i często zdarzało się, że instalowałem nowe wtyczki kopiując pliki .jar do podfolderu \plugins. Nic prostszego - ale dlaczego to działa? Jak to się dzieje, że w eclipse pojawiają się nowe opcje, fukncjonalności, ikony? Wydawało mi się, że to jakaś totalna magia i że nigdy nie dowiem się jak to działa. Pierwsze próby zgłębienia wiedzy niestety nie skończyły się sukcesem. Miałem wrażenie, że jest mało materiałów, które pozwalają poznać podstawy architektury eclipse, szczególnie jeśli chodzi o materiały po polsku. Nie udało mi się też znaleźć zbyt dużo informacji o całkowitych podstawach - a wiadomo, że bez podstaw dalej ani rusz.

Teraz, gdy co nieco już wiem chciałbym się tą wiedzą podzielić i przy okazji czegoś nowego się nauczyć - może kogoś to zaciekawi :) Szerzej o eclipse RCP opowiem w osobnym poście - teraz napiszę krótko:

Eclipse oparty jest na bardo ciekawej architekturze, w której mamy do czynienia z ponownym używaniem raz stworzonych komponentów (reusability). Składa się on z kilkudziesięciu (kilkunastu?) bazowych pluginów, wzajemnie od siebie zależnych oraz z pluginów niosących różne funkcjonalności. Opierając się na bazowych pluginach, można stworzyć własną aplikację dodając (za pomocą plugina!) swoją funkcjonalność, design, zachowanie. Minimalny zestaw pluginów, który pozwala na uruchomienie aplikacji to właśnie Rich Client Platform (w skrócie RCP).

To naprawdę nie jest trudne. Jest jedna rzecz, o której trzeba pamiętać tworząc cokolwiek w RCP to zmiana podejścia do programowania. Myśląc o problemie nie można od razu mieć przed oczami zestawu dziesiątek klas i metod. Trzeba się zastanowić jak wykorzystać funkcjonalności z innych pluginów i jednocześnie napisać funkcjonalność w taki sposób, żeby dało się ją kiedyś powtórnie wykorzystać.