piątek, 24 kwietnia 2009

ANT i UTF-8

Ostatnio spotkałem się z dziwnym problemem. Projekt skompilowany w IntelliJ IDEA - wszystko ok. Odpalam Ant'a - kompilacja przebiega pomyślnie, ale po odpaleniu aplikacji zaczynają się problemy z polskimi znaczkami. Rozwiązanie dość proste ale trochę się naszukałem ;)
Wystarczy przy wywołaniu kompilacji (tag <javac>) dodać kolejny atrybut encoding="UTF-8". Proste, ale potrafi napsuć krwi.

środa, 22 kwietnia 2009

Apache 2.2 + Apache Tomcat + ErrorDocument

Opis sytuacji:
Serwer Apache HTTP Server z przodu, za nim Apache Tomcat 6.0.18. Wszystko połączone ze sobą za pomocą mod_jk.

Problem:
W przypadku braku połączenia z Tomcatem należy wyświetlić ładny komunikat o tymczasowych problemach i próbować odświeżyć stronę co 10 sekund w celu sprawdzenia czy Tomcat nie jest ponownie dostępny.

Rozwiązanie:
Mogłoby się wydawać, że banalne. W pliku konfiguracyjny Apache HTTP ustalenie ErrorDocument i po sprawie. Niestety nie do końca tak jest.
Ale od początku. Musimy przekazać do strony obsługującej stronę błędu parametry. Odpada nam więc wykorzystanie ErrorDocument w postaci bezwględnego adresu. Jak więc to zrobić?
  1. Przygotujemy alias /error wskazujący na katalog /var/www/error

    <Directory "/var/www/error">
    AllowOverride None
    Order allow,deny
    Allow from all
    </Directory>

    Alias /error /var/www/error



  2. W katalogu /var/www/error tworzymy plik 503.php o następującej zawartości

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" >
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta http-equiv="Refresh" CONTENT="10; URL=http://<?php echo $_SERVER['HTTP_HOST'];?>">
    <title>Serwer Tomcat tymczasowo niedostępny - proszę czekać</title>
    <style type="text/css" media="all">
    h1
    {
    color: red;
    }
    </style>
    </head>
    <body>
    <h1>Serwer Tomcat tymczasowo niedostępny - proszę czekać</h1>
    </body>
    </html>



  3. Musimy poinformować serwer http żeby pliki *.php nie były przekazywane do Tomcata. Jest to kluczowa rzecz, z którą miałem największy problem.

    SetEnvIf Request_URI "/*.php" no-jk



  4. Pozostało już tylko wskazać dokument, który ma być wywoływane w przypadku błędu 503.

    ErrorDocument 503 /error/503.php


środa, 8 kwietnia 2009

Rozdział 3. Budujemy pierwszą aplikację (część I)

W rozdziale trzecim zostały zebrane wszystkie informacje w całość. Autorzy budują prostą aplikację, której zadaniem jest sprzedaż różnego rodzaju serów (jeden z autorów książki jest Duńczykiem i w rozdziale drugim twierdził, że jest ich miłośnikiem...). Tak jak zostało to wspomniane w poprzednich rozdziałach każda aplikacja musi mieć główną klasę rozszerzającą WebApplication. Zwraca ona stronę główną w metodzie:

public Class getHomePage()
{
return Index.class; // klasa reprezentująca stronę główną
}

W rozdziale szczególna uwaga została skupiona na wyświetlaniu różnego rodzaju list. W Wicket jest to zadziwiająco przyjemne. Zacznijmy od prostej listy bez stronnicowania. Stworzymy plik Index.html i klasę z nim związaną Index. Najpierw trochę kodu:
Index.html


<div wicket:id="books">
<h3 wicket:id="title">Tytuł książki</h3>
<p wicket:id="autor">Autor</p>
<p wicket:id="cena">Cena</p>
<a wicket:id="dodaj" href="#">do koszyka</a>
</div>
<wicket-remove>
<div wicket:id="books">
<h3 wicket:id="title">Tytuł książki</h3>
<p wicket:id="autor">Autor</p>
<p wicket:id="cena">Cena</p>
<a wicket:id="dodaj" href="#">do koszyka</a>
</div>
</wicket-remove>
A teraz trochę magii i Wicket na podstawie powyższego kodu stworzy ładną listę :)
Index:


public class Index extends WebPage {
public Index() {
add(new ListView("books",BookStoreApplication.get().getBooks()){
protected void populateItem(ListItem listItem) {
Book book = (Book) listItem.getModelObject();
listItem.add(new Label("tytul", book.getTitle()));
listItem.add(new Label("autor", book.getAuthor()));
listItem.add(new Label("cena", ""+book.getPrice()));
listItem.add(new Link("dodaj",listItem.getModel()){
public void onClick() {
Book selectedBook = (Book) getModelObject();
//teraz możemy dodać książkę np. do koszyka w sesji
}
});
}
});

Oczywiście należy się trochę wyjaśnień. Skąd wziąć listę książek? Oczywiście z bazy, ale można też np. w celach testowych w klasie aplikacji stworzyć sobie zwykłą listę. Do klasy tej mamy dostęp z poziomu wszystkich stron można więc umieścić w niej np. referencję do DAO. Ponadto w kodzie HTML da się zauważyć nowy znacznik . Kod umieszczony w tym tagu zostanie usunięty. Służy on tylko i wyłącznie do lepszej prezentacji widoku. Myślę, że reszta powinna być w miarę jasna.
W kolejnej części relacji z rozdziału trzeciego znajdzie się kilka informacji na temat wykorzystania formularzy oraz zastosowania stronnicowanych list.

poniedziałek, 6 kwietnia 2009

Rozdział 2. Dużo szczegółów na temat wnętrzności Wicket

Rozdział drugi skupia się na zasadach działania Wicketa oraz założeniach jakie zostały przyjęte w trackie jego tworzenia. Rozdział ten, według autorów, można pominąć i wrócić do niego w miarę potrzeb. Sprawdźmy jednak, czy aby nie starają się ukryć czegoś ciekawego...
Za obsługę żądań w Wicket odpowiedzialne są 3 klasy: Application, Session i Request. Nie ma nic zaskakującego w przypadku Application - ot, każda aplikacja ma dokładnie jej jedną instancję, ale już dla Session Wicket ma ciekawą funkcjonalność. Mianowicie, nie jesteśmy już skazani na pamiętanie poszczególnych wartości w mapie dostarczanej przez HttpSession. Teraz mamy specjalizowane obiekty, które mogą być przechowywane w sesji. Wygląda to mniej więcej tak:

public class MySession extends WebSession {

private User user;

public static MySession get() {
return (MySession) Session.get();
}

public MySession(Request request) {
super(request);
}

public synchronized User getUser() {
return user;
}

public synchronized boolean isAuthenticated() {
return (user != null);
}

public synchronized void setUser(User user) {
this.user = user;
}
}

Warto zwrócić uwagę na to, że wszystkie metody są synchronized - sesje nie są "thread-safe".
When using Wicket, you typically never need to deal with the raw HttpServlet-
Request or Response objects; this holds true even when you’re dealing with custom
sessions.
Ponadto zostały omówione elementy takie jak SessionStore (odpowiedzialny za przechowywanie informacji o sesji oraz śledzenie historii przeglądanych przez użytkownika stron), Request, Response, RequestCycle, RequestCycleProcessor, RequestTarget. Nie staram się narazie zgłębić co poniektóre z nich tak naprawdę robią - myślę, że przyjdzie na to pora w dalszych rozdziałach jak przyjdzie do kodowania.
W kolejnym podrozdziale omówione zostały komponenty w Wicket. Podsumowując, Wicket daje możliwość stworzenia własnych komponentów. Każdy taki komponent musi dziedziczyć po Component, posiadać model oraz sposób prezentacji. Autorzy podają kilka cech komponentów:
  • Są niezależne i samowystarczalne - jeżeli chcemy użyć jakiegokolwiek komponentu wystarczy go umieścić na stronie. Inne komponenty nie muszą wiedzieć nic na jego temat.
  • Nadają się do ponowego użycia.
  • Można je stworzyć wykorzystując czystą Javę.
  • Żeby je wykorzystać również możemy posłużyć się tylko i wyłącznie językiem Java.
W dalszej części autorzy zagłębiają się w zagadnienia związane z łączeniem widoku (markup) z klasami oraz zagnieżdzaniem komponentów na stronie. Myślę, że temat ten sam wyjaśni się w miarę zdobywania wiedzy z kolejnych rozdziałów. Ewentualnie powrócę do tego podrozdziału później.
Jednym z ostatnich tematów poruszanych w rozdziale 2 są rozważania na temat rozdzielenia logiki i prezentacji. Wicket wymusza na nas takie podejście. Używając Wicketa nie ma prawa dojść do sytuacji, w której w widoku mamy pętle, instrukcje warunkowe itp. Autorzy wymieniają wiele zalet tego podejścia, ale najważniejszy chyba jest fakt, że tak naprawdę wiadomo gdzie tej logiki szukać. Ponadto takie podejście daje większe szanse na ponowne użycie kodu. Poza tym nie wiem jak Wy, ale ja nigdy nie przepadałem za specyficzną formą np. JSP.
Dalej zostały omówione zagadnienia związane z modelem, które szczerze mówiąc pominąłem oraz interfejs IBehavior pozwalający na dodawanie zachowań do komponentów. Dzięki temu jeżeli chcemy stworzyć link służący do usunięcia pozycji koszyka, który po kliknięciu wyświetli komunikat potwierdzający ten fakt, wcale nie musimy tworzyć nowej klasy dziedziczącej po Link i dodającej tę funkcjonalność. Właśnie w tym celu można dodać nowe zachowanie dla wybranego komponentu.
Podsumowując rozdział drugi to bardzo duża dawka wiedzy teoretycznej, która dla osoby zaczynającej przygodę z Wicket może być ciężkastrawna. Myślę, że w miarę poznawania kolejnych rozdziałów wiele zagadnień będzie się wyjaśniało.
Przekartowałem rozdział 3 - długi, dużo kodu i wygląda interesująco. Wkrótce relacja.

niedziela, 5 kwietnia 2009

"Wicket in Action" - rozdział 1. Co to jest Wicket?

Zgodnie z zapowiedzią relacja z rozdziału pierwszego "Wicket in Action". Wyprzedzając fakty, mam wrażenie, że wybór Wicketa do poznania był dobrym strzałem. Brakowało mi czegoś tak przyjemnego. Ale po kolei...
W rozdziale pierwszym autorzy (Martin Dashorst i Eelco Hillenius) przedstawiają krótko historię tego rozwiązania oraz definiują jego miejsce i przeznaczenie na rynku szkieletów. Mówiąc wprost, Wicket stanowi pomost pomiędzy HTMLem, a starą dobrą Javą po stronie serwera, a jego głównym zadaniem jest zarządzanie stanem aplikacji.

We can break it into three parts: just Java, just HTML, and meaningful abstractions.
Tworząc Twoją nową aplikację internetową logikę i sposób zachowania zakodujesz wykorzystując Javę, widok stanowi praktycznie czysty HTML, a ponadto dla elementów często spotykanych na stronach WWW Wicket dostarcza odpowiednich komponentów.
Ponadto w rozdziale pierwszym przedstawionych jest kilka przykładów, które dają wyobrażenie o działaniu Wicket'a. Standardowa "aplikacja" - Hello World (odsyłam do tutoriala na stronie Apache Wicket) oraz dwa krótkie przykłady pokazujące wykorzystanie komponentów Label, Link oraz przeplecenie tego wszystkiego z AJAXem.
Podsumowując, poniżej przedstawiam mały przykład, którego zadaniem jest wyświetlenie dwóch linków:
  • link 1: zliczający ilość kliknięć w niego
  • link 2: przenoszący nas do strony "HelloWorld"
W pierwszej kolejności stwórzmy klasy odpowiedzialne za poszczególne strony. Klasę: LinkPage - odpowiedzialną za główną stronę, na której wyświetlone są linki oraz klasę SecondPage - odpowiedzialną za wyświetlenie strony po kliknięciu drugiego linku. Strona ta wyświetli komunikat Hello World, ale wykorzystując komponent Label.
Do dzieła!
Klasa LinkPage:

package com.blogspot.matecki.ch01;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.PropertyModel;


public class LinkPage extends WebPage {

private int counter = 0;

public LinkPage() {
add(new Link("link1"){
public void onClick() {
counter++;
}
});

add(new Link("link2"){
public void onClick() {
setResponsePage(new SecondPage());
}
});
add(new Label("lCounter", new PropertyModel(this,"counter")));
}
}

Klasa SecondPage:



package com.blogspot.matecki.ch01;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;

public class SecondPage extends WebPage {
public SecondPage() {
add(new Label("label", "Hello World!"));
}
}

Mamy już klasy odpowiedzialne za poszczególne strony. Brakuje jeszcze klasy reprezentującej całą aplikację. Oto i ona:


package com.blogspot.matecki.ch01;

import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.Page;

public class HelloWorldApplication extends WebApplication {
public Class getHomePage() {
return LinkPage.class;
}
}

Zgodnie z filozofią Wicketa każdej klasie reprezentującej stronę odpowiada plik HTML o dokładnie takiej samej nazwie znajdujący się w tej samej paczce. Odpowiedzialny on jest za widok. Stwórzmy więc dwa pliki SecondPage.html i LinkPage.html.
SecondPage.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
<h1 wicket:id="label">Tutaj wstaw tekst</h1>
</body>
</html>

LinkPage.html:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
<a href="#" wicket:id="link1">This link</a> has been clicked
<span wicket:id="lCounter">123</span> times. Go to <a href="#" wicket:id="link2">second page</a>.
</body>
</html>

Co tu jest ciekawego? Zwróć uwagę na element wicket:id jest on ściśle powiązany z identyfikatorami w klasach odpowiedzialnych za poszczególne strony. Ponadto klasy odpowiedzialne za strony rozszerzają WebPage, a klasa reprezentująca aplikację rozszerza WebApplication. Jeszcze tylko odpowiednie wpisy do web.xml i możemy próbować to uruchomić.
WEB.XML:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<display-name>Wicket Examples</display-name>
<filter>
<filter-name>HelloWorldApplication</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>com.blogspot.matecki.ch01.HelloWorldApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HelloWorldApplication</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

Podsumowując. Rozdział pierwszy zapoznaje nas z założeniami rządzącymi światem Wicket i pozwala (prawie) zbudować coś działającego. Do ściągnięcia projekt w IntelliJ IDEA z działającą "aplikacją" na podstawie powyższych kodów źródłowych.
Jak Wam się podoba ta forma relacji?

sobota, 4 kwietnia 2009

"The Productive Programmer" - relacja

Jestem właśnie po lekturze książki "The Productive Programmer". W trakcie wystąpienia na konferencji 4Developers Neal Ford, autor książki, prezentował wybrane informacje zawarte w pierwszej części (Mechanics).
Książka obfita w różnego rodzaju dobre rady, przykłady, anegdoty, opowieści. Książkę przyjemnie i szybko się czyta, a i sporo rzeczy można się z niej dowiedzieć. Jednym słowem - polecam!
W tej chwili biorę się za "Wicket in Action". Postanowiłem przetestować metodę Jacka na utrwalenie zdobytej wiedzy poprzez relacje z poszczególnych rozdziałów na blogu. Tak więc na dniach możecie spodziewać się pierwszych wpisów poświęconyh Wicketowi. Mam nadzieję, że uda mi się wytrwać w postanowieniu ;)