Xis’ blog - Mój wirtualny schowek
Polska Społeczność Symfony

Hojna Gwiazdka

Tegoroczna Gwiazdka była dla mnie, jako programisty, niesamowicie obfita. Pod choinką znalazłem stos świetnych pozycji dotyczących ogólnie Javy, ale i jej poszczególnych technologii. I tak, dostało mi się:

  • JUnit – Pragmatyczne testy jednostkowe w Javie
  • JAVA – Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
  • Eclipse Web Tools Platform – Tworzenie aplikacji WWW w języku Java
  • J2EE – Wzorce projektowe
  • Enterprise Java Beans 3.0 (którą dostałem nieco wcześniej, ale jest mi szczególnie bliska ze względu na ostatnie tą platformą zainteresowanie)

Z takim arsenałem lektur mam teraz zajęć na zimowe wieczory pod dostatkiem.  W tej jednak chwili prawdziwym dylematem będzie dla mnie pytanie „Od czego zacząć?” gdy zasiądę na kanapie z filiżanką kawy ;)

Muszę się zwierzyć, że książki papierowe to mój ulubiony sposób zdobywania wiedzy w zakresie programowania, ale też niestety najbardziej zaniedbany. W epoce Google’a trudno jest ‚marnować’ czas na wyszukiwanie odpowiednich pozycji książkowych, podczas gdy łatwo sobie coś znaleźć w Sieci ‚na szybko’. Ja także stałem się ofiarą czegoś w rodzaju fast-foodu w dziedzinie zdobywania wiedzy (szybkie wyszukiwanie, krótka lektura wiki, krótka lektura tutoriala, krótkie ‚Hello World’ i już ‚znam’ techonlogię) i trochę tego żałuję. Mam teraz idealną okazję, by nadrobić zaległości, pozagłębiać się trochę w szczegóły i – wreszcie – poznać polskie nazwy niektórych terminów, które stosuję w praktyce od dłuższego czasu (kolejna wada ‚fast-foodów wiedzy’ to taka, że większość pozyskiwanych informacji przychodzi w języku angielskim i nie zna się jej oficjalnych tłumaczeń).

Dodatkową niespodzianką, jaka zawitała pod Świąteczne drzewko, była koszulka z bardzo fajnie wykonanym napisikiem (za którą dziękuję Adze i Zbigowi) ;)

Prezenty pod choinką

Wesołych Świąt!

Tagi: , , , , , , , , ,

Komentarze (6)

Bardziej online

Ostatnio dość często zmieniam komputery na których pracuję/spędzam wolny czas. Tak już mam, że do niektórych czynności wolę wykorzystywać laptopa, do niektórych komputera stacjonarnego. Czasem lepiej pisze mi się pod Linuksem – czasem w Windows. W każdej z maszyn/systemów operacyjnych mam zainstalowaną ulubioną Operę, skonfigurowaną ‚pod siebie’ ze swoimi zakładkami i kanałami informacyjnymi RSS/Atom. Oczywiście, często jest tak, że gdy znajdę wartościowy link, czy zasubskrybuję ciekawy kanał informacyjny i dodaję go do ustawień Opery. Niestety, z oczywistych powodów, ustawienie to nie propaguje się do pozostałych konfiguracji, co kończy się tym, że raz na jakiś czas muszę przekopiowywać ustawienia z maszyny na maszynę.

Postanowiłem z tym skończyć i wynieść swoje ustawienia do Sieci. Z pomocą przychodzi tu Google Reader, który jest naprawdę ciekawym i funkcjonalnym czytnikiem kanałów informacyjnych. Wiem, że nie jest to epokowe odkrycie i wszyscy miłośnicy nowinek internetowych dawno mają już ten temat przewałkowany, ale mi jakoś nigdy wcześniej nie wydawał się on w żaden sposób przydatny, toteż jego istnienie doceniłem dopiero teraz – gdy pojawiła się realna potrzeba jego używania. Google Reader ma etykietowanie, pozwala na szybkie dotarcie do nowych informacji, no i jest online! Nie jest to może tak wygodne narzędzie jak Akregator, ale jest (poprzez swoją online’owość) wieloplatformowy, a swoją funkcjonalnością z pewnością przewyższa ubogi pod tym względem czytnik wbudowany w Operę.

Jedyny mankament używania Google Readera to taki, że nie mogę w żaden sposób skonfigurować Opery do tego, by po wybraniu domyślnej ikony kanału, uruchamiała Google Readera właśnie – Opera nadal dodaje kanał do swojego czytnika.

Na szczęście znalazłem sposób obejścia tego problemu za pomocą gadżetu oferowanego przez samego Readera. Wystarczyło wybrać link zawierający skrypt pozwalający na automatyczną subskrypcję zawartości oglądanej strony i przeciągnąć go w dowolne miejsce interfejsu Opery trzymając klawisz Shift.

Dzięki tej operacji, klikając w przycisk stworzony przez Operę, mogę swobodnie dodawać oglądaną stronę do swojego czytnika.

Rozwiązanie nie jest oczywiście idealne, ale wystarczające (choć wolałbym jakoś skonfigurować domyślne zachowanie Opery – może przyszłe wersje tej przeglądarki będą bardziej otwarte na takie rozwiązania).

Znalazłem także ciekawy programik pozwalający sprawdzać, czy w naszej skrzynce znalazły się nowe nieprzeczytane wiadomości z kanałów informacyjnych i informujący o tym za pomocą okienka popup - Google Reader Notifier, ale z nieznanych mi jeszcze przyczyn to narzędzie w ogóle nie działa :)

Tagi: , , , ,

Skomentuj

Znajdź sobie

„Pogoogluj” to jedna z częściej udzielanych w internecie odpowiedzi na pytania – właściwie na każdy rodzaj pytań. Niestety, często odpowiedź ta jest uznawana za odpowiednik „nie chce mi się z tobą gadać”, lub jeszcze mniej elegacki sposób pozbycia się dyskutanta. Nic bardziej błędnego, ponieważ to tak jak w powiedzeniu, że lepiej jest głodnemu dać wędkę zamiast ryby. Umiejętność wyszukiwania informacji w Sieci jest bardzo ważna. To, czy potrafisz dobrać odpowiednio słowa kluczowe do wyszukiwania często ma wpływ na Twoje sukcesy w nauce lub pracy zawodowej, a dobrze skonstruowane zapytanie do Google‚a może drastycznie skrócić czas naszych poszukiwań. Sam często odsyłam do wyszukiwarki, ale przy okazji staram się podpowiadać jakie słowa kluczowe mogą być przydatne przy wyszukiwaniu, albo jakich słów sam bym użył gdybym szukał odpowiedzi na takie pytanie.
Zdarzają się jednak sytuacje, w których pytający wykazuje się wybitną wręcz ignorancją i nie wykorzytuje otrzymanej wędki, tylko co rusz wraca po rybę – chce by pomagać mu w każdej sytuacji, w ogóle samemu nie wykazując się inicjatywą. Niedawno dowiedziałem się o istnieniu doskonałego narzędzia pozwalającego „delikatnie” zasugerować im, że sami mogą sobie poradzić. Let me google that for you pozwala na dość uszczypliwe wyjaśnienie danej osobie, że szukanie nie boli, a jednocześnie pokazuje jej jak prosta jest to czynność. Polecam! :)

Tagi: , , ,

Skomentuj

Java Server Faces i parametry GET

Java Server Faces to całkiem ciekawy framework dla Javy. O jego zaletach dużo by pisać, toteż odsyłam w tym temacie do odpowiednich wpisów w Sieci. JSF ma jednak jedną wadę; dość słabo wspiera przesyłanie parametrów za pomocą metody GET protokołu HTTP. Oto krótki poradnik jak używać parametrów przekazanych za pomocą metody GET do strony obsługiwanej przez Java Server Faces.

Załóżmy, że mamy listę pracowników, z poziomu której możemy podejrzeć konkretnego zatrudnionego. Do obsługi naszej miniaplikacji wykorzystamy zatem dwie  strony employee_list.jsp i employee.jsp. Przyjmijmy także, że chcielibyśmy, aby dostęp do szczegółów dot. pracownika możliwy był po wprowadzeniu adresu np. http://localhost:8080/company/employee.jsf?e=10. Naszą aplikację zasili ziarno zarządzane (managed bean) CompanyController, którą wyposażamy we własność selectedEmployeeId i własność selectedEmployee zawierającą obiekt wskazanego pracownika:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package net.schowek.jsf.ui;
 
public class CompanyController
{
    @EJB
    CompanyServiceLocal companyService;
 
    private DataModel   empDataModel;
    private Long        selectedEmployeeId;
    private Employee    selectedEmployee;
 
    public DataModel getAllEmployees()
    {
        empDataModel = new ListDataModel();
        empDataModel.setWrappedData( companyService.findAll() );
        return empDataModel;
    }
 
    public Employee getSelectedEmployee()
    {
        if (selectedEmployee == null)
        {
            selectedEmployee = (Employee) companyService.findById( selectedEmployeeId );
        }
        return selectedEmployee;
    }
 
    public void setSelectedEmployee( Employee selectedEmployee )
    {
        this.selectedEmployee = selectedEmployee;
    }
 
    public Long getSelectedEmployeeId()
    {
        return selectedEmployeeId;
    }
 
    public void setSelectedEmployeeId( Long selectedEmployeeId )
    {
        this.selectedEmployeeId = selectedEmployeeId;
    }
}

Wygląda to więc dość standardowo, tylko posługujemy sie tą tajemniczą własnością selectedEmployeeId. I skąd nasz CompanyController ma wiedzieć, że w tejże własności ma znaleźć się parametr przekazany w metodzie GET pod zmienną ‚e‚?

Zdefiniujemy to pliku faces-config.xml:

<managed-bean>
    <managed-bean-name>company</managed-bean-name>
    <managed-bean-class>net.schowek.jsf.ui.CompanyController</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
        <property-name>selectedEmployeeId</property-name>
        <value>#{param.e}</value>
    </managed-property>
</managed-bean>

Oraz nasze pliczki stron:

Lista pracowników:

<!-- employee_list.jsp -->
<f:view>
    <h:form>
        <h:datatable var="employee" value="#{company.allEmployees}">
            <h:column>
                <h:outputtext value="#{employee.id}" />
            </h:column>
            <h:column>
                <h:outputtext value="#{employee.name}" />
            </h:column>
            <h:column>
                <h:outputlink value="employee.jsf">
                    <f:verbatim>Szczegóły</f:verbatim>
                    <f:param value="#{employee.id}" name="e" />
                </h:outputlink>
            </h:column>
        </h:datatable>
    </h:form>
</f:view>

…, karta pracownika…

<!-- employee.jsp -->
<f:view>
    <h:form>
        <h2>Szczegóły pracownika #<h:outputText value="#company.selectedEmployee.id"/></h2>
        <div>
            <span>Imię i nazwisko:</span>
            <span><h:outputText value="#company.selectedEmployee.name"/></span>
        </div>
        <div>
            <span>Stanowisko:</span>
            <span><h:outputText value="#company.selectedEmployee.position"/></span>
        </div>
        <div>
            <span>Dodatkowe informacje:</span>
            <div><h:outputText value="#company.selectedEmployee.comments"/></div>
        </div>
    </h:form>
</f:view>

Takie rozwiązanie ma jednak dość poważną wadę, bowiem wspiera jedynie ziarna zarządzane, których zasięg (scope) dotyczy żądania. Własności ziaren zarządzanych deklarowanych w pliku faces-config.xml muszą mieć czas życia co najmniej taki jak czas życia samego ziarna, toteż #{param}, który żyje tylko wraz z żądaniem ogranicza zasięg całego ziarna. Często jednak zdarza się, że potrzebujemy ziarna żyjącego przez całą sesję, wtedy nie możemy skorzystać z własności deklarowanej w faces-config.xml. Możemy jednak, zamiast oczekiwać wstrzyknięcia wartości naszej własności przez JSF, sami pobrać wartość parametru żądania.

W tym celu usuwamy z pliku faces-config.xml deklarację parametru pozostawiając:

<managed-bean>
    <managed-bean-name>company</managed-bean-name>
    <managed-bean-class>net.schowek.jsf.ui.CompanyController</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Modyfikujemy tez nasze ziarno usuwając własność selectedEmployeeId wraz z getterem i setterem i zmieniając metodę getSelectedEmployee():

public Employee getSelectedEmployee()
{
  Map<String, String> reqParams = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
  String eId = reqParams.get( "e" );
  Long selectedEmployeeId = Long.parseLong( eId );
  if (selectedEmployee == null)
  {
    selectedEmployee = (Employee) companyService.findById( selectedEmployeeId );
  }
  return selectedEmployee;
}

Od tej pory ziarno o czasie życia sesji również potrafi obsługiwać parametry GET, a my możemy dodawać do zakładek odnośniki do kart konkretnych pracowników :)

Tagi: , , , ,

Komentarze (2)

Bałagan w mrowisku

Dość długo nic nie pisałem, szczerze mówiąc zastanawiałem się, czy nie przestać całkowicie (jak się okazuje, strasznie trudno pisać o tym, co możnaby w tym czasie robić ;) ), ale postanowiłem coś jednak naskrobać i dalej prowadzić ten swój zapiśnik. Nie będę chyba jednak publikował wpisów zbyt często, bo postanowiłem już całkowicie sprowadzić tego bloga do roli swego rodzaju notatnika zawierającego po prostu rzeczy do zapamiętania.

Dziś o pewnym narzędziu, z którym życie programisty Java staje się łatwiejsze – Ant.

Ant to – jak pewnie każdy Javowiec wie – doskonałe narzędzie upraszczające nie tylko proces budowania projektów, ale pomagające zautomatyzować każdą rutynową operację. Wachlarz instrukcji, które potrafi on wykonać jest ogromny i stale się powiększa.

Ostatnio miałem okazję budować projekt, który zależał od kilku innych podprojektów, których z kolei wynikami były różne typy archiwów (JAR/WAR). Całość (projekt główny) była pakietem EAR zawierającym wspomniane wcześniej archiwa. Z poziomu mojego ulubionego Eclipse można oczywiście wyklikać eksport owych składników do projektu docelowego, ale wykonywanie tego przy każdej próbie sprawdzenia efektów swojej pracy było dość uciążliwe. Na szczęście Eclipse jest doskonale zintegrowany z Antem, toteż przygotowanie pliku budującego dla moich projektów trwało dosłownie chwilę. Ant dysponuje również instrukcją ‚ant’ pozwalającą na wykonanie innego pliku budującego z poziomu pliku głównego. To idealne rozwiązanie dla mojej sytuacji z podprojektami.

<property name="ejbjar.dir" value="${basedir}/../MyEJBModule"/>
<property name="webmodule.dir" value="${basedir}/../MyWEBModule"/>        
<target name="preparecomponents">
  <ant antfile="build.xml" dir="${ejbjar.dir}"/>
  <ant antfile="build.xml" dir="${webmodule.dir}"/>
</target>

Pojawił się jednak pewien problem, otóż tak wykonywane skrypty Ant’a posiadały dość dziwne własności (properties). Okazało się, że dziedziczą one po projekcie głównym i tak najczęściej używane przeze mnie własności jak np. project.distname, czy basedir miały wartości zdefiniowane w projekcie głównym, a nie te, których definicja występowała u nich samych, co oczywiście powodowało błędy przy budowaniu i ogólną porażkę. Rozwiązaniem może tu być zmiana nazw własności na unikalne dla każdego z projektów, ale to oczywiście nie jest najelegantsze rozwiązanie, pomijając już jego sensowność.

Na szczęście Ant zabezpiecza nas przed tym dodając atrybut inheritall, pozwalający na zbudowanie zupełnie nowego środowiska dla każdego poszczególnego skryptu wykonywanego z poziomu skryptu głównego.

<target name="preparecomponents">
  <ant antfile="build.xml" dir="${ejbjar.dir}" inheritall="false"/>
  <ant antfile="build.xml" dir="${webmodule.dir}" inheritall="false"/>
</target>

W ten sposób każdy z komponentów zostanie zbudowany tak, jakbyśmy wykonali osobno każdy ze skryptów budowania. Warto zanotować, że w elemencie ant można zagnieżdżać elementy property i przekazywać je do wykonywanego skryptu, zatem komunikacja skryptu głównego z komponentami jest również możliwa.

Tagi: ,

Skomentuj