31 stycznia 2008

XXIII spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na XXIII spotkanie, które odbędzie się we wtorek 5.02.2008 o godzinie 18:00 w sali 5440 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: Przetwarzanie zdarzeniowe (a także o Spring, Spring-DM, OSGi i aplikacjach real-time w Java)
Prowadzący: Waldemar Kot (Waldi)

Celem spotkania jest rozpoznanie koncepcji złożonego przetwarzania strumieni zdarzeń w czasie rzeczywistym (i osłuchanie się z nowymi buzzwordami: ESP - Event Stream Processing, CEP - Complex Event Processing, EDA - Event-driven Architecture, ED-SOA - Event-driven Service Oriented Architecture). Dodatkowo - poznanie koncepcji zdarzeniowego serwera aplikacyjnego, nowego modelu programistycznego dla aplikacji zdarzeniowych oraz jednego z języków przetwarzania zdarzeń.

Dlaczego warto przyjść, zapytasz? Oto kilka istotnych powodów:
  1. Temat jest stosunkowo nowy (a dla środowiska Java bardzo nowy)

  2. Przetwarzanie zdarzeniowe wzbudza coraz większe zainteresowanie i wydaje się że w niedalekim czasie będzie bardzo trendy (zainteresowanie tym tematem obserwuje się już także i w naszej części świata)

  3. Celem poszerzenia horyzontów myślowych - m.in. dlaczego pewne problemy powinno się rozwiązywać przy wykorzystaniu właśnie technologii ESP/CEP, zamiast 'naginać' do tego J2EE/JEE, technologie bazodanowe, czy silniki reguł

  4. Poznanie nieksiążkowego i ciekawego przykładu wspólnego wykorzystania gorących dzisiaj technologii takich jak Spring, czy OSGi (o tym że BEA jest sexy nie trzeba chyba nikogo przekonywać ;-))
Spotkanie jest planowane w formie warsztatowej (tj. pytania z sali będą witane z wielką radością). Czas spotkania 2 godziny (mniej więcej). Liczba slajdów: 10-15, na ok. 30 minut. Pozostały czas to praktyczne demonstracje w/w zagadnień na przykładzie technologii BEA WebLogic Event Server z Eclipse i dyskusje. Przez 'praktyczne demonstracje' rozumie się m.in. pogrzebanie w kodzie Java, XML, a'la SQL i tym podobne.

Zakłada się podstawową znajomość Java (na poziomie podstaw JSE) oraz SQL (na poziomie zrozumienia SELECT, FROM, WHERE, GROUP BY, ORDER, HAVING, INSERT INTO, ...). Nie trzeba posiadać wiedzy o Spring, Spring-OSGi, czy OSGi (choć warto). Wiedzy o produktach BEA typu serwer aplikacyjny WebLogic Server także nie (choć też warto ;-))

Waldemar Kot (bardziej znany jako Waldi w kręgach zaprzyjaźnionych z Warszawa JUG) każdorazowo urozmaica wypowiedzi o rozwiązaniach opartych o platformę Java szczyptą trzeźwego spojrzenia pasjonata Spring Framework. Od lat związany ze społecznością Javy dał się poznać po swoich wypowiedziach na spotkaniach Warszawa JUG, serwisie jdn.pl czy grupie pl.comp.lang.java jako niezwykle przenikliwy obserwator życia javowego i dzięki swemu doświadczeniu nie daje się łatwo zwieść wszelkiego rodzaju nowinkom technologicznym bez ich samodzielnego skosztowania. Gość wie co się jada na śniadanie w domu Wielkiego Programisty Javy, więc warto go wysłuchać ;-)

Planowany czas prezentacji to 30 minut z dalszą 1,5-godzinną kontynuacją w postaci dyskusji.

Wstęp wolny!

Zapraszam w imieniu Waldiego i całej grupy Warszawa JUG!

EJB 3.0 - Rozdział 12.3.1 Kolejność wykonywania interceptorów biznesowych

2 komentarzy
Kolejny podrozdział specyfikacji EJB3 - 12.3.1 Kolejność wykonywania interceptorów biznesowych.

Kolejność wykonania interceptorów biznesowych wyznaczana jest przez adnotacje oraz opcjonalny deskryptor wdrożenia (ejb-jar.xml). Kolejność wykonania interceptorów może zostać zmieniona przez deskryptor wdrożenia.
  1. Najpierw uruchamianie są domyślne interceptory, które mogą być zdefiniowane wyłącznie w deskryptorze rozmieszczenia. Kolejność ich definicji w deskryptorze określa kolejność ich uruchomienia.

  2. Jeśli zdefiniowano klasy interceptorów dla klasy ziarna, ich metody uruchamiane są zanim uruchomione zostaną jakiekolwiek metody przechwytujące definiowane przez samo ziarno.

  3. Metody AroundInvoke zdefiniowane na tych klasach interceptorów są wykonywane w tej samej kolejności jak kolejność odpowiadających im klas interceptorów w adnotacji @Interceptors.

  4. Jeśli klasa interceptora posiada klasy nadrzędne, metody przechwytujące zdefiniowane przez nie są wykonywane przed metodami przechwytującymi zdefiniowanymi przez tą klasę, w kolejności zgodnej z hierarchią dziedziczenia, idąc od java.lang.Object będącym na szczycie hierarchi.

  5. Po wykonaniu metod przechwytujących zdefiniowanych przez klasy interceptorów, następuje wykonanie metod przechwytujących w następującej kolejności:

    1. Jeśli zdefiniowano interceptory na poziomie metody biznesowej, która jest wywoływana, metody AroundInvoke zdefiniowane na tych klasach interceptorów są wykonywane w tej samej kolejności jak ich kolejność w adnotacji @Interceptors przy tej metodzie.

    2. Jeśli klasa ziarna ma klasy nadrzędne, wszystkie metody AroundInvoke są wykonywane najpierw, w kolejności zgodnej z hierarchią dziedziczenia, idąc od java.lang.Object będącym na szczycie hierarchi.

    3. Jeśli istnieje metoda AroundInvoke zdefiniowana w klasie ziarna, jest ona wywołana.

Jeśli metoda AroundInvoke jest przesłonięta przez inną metodę (bez względu na to czy sama jest metodą AroundInvoke), metoda przesłonięta nie będzie wywołana.

Egzemplarz javax.ejb.InvocationContext udostępnia mechanizm kontroli wykonania ciągu interceptorów, wraz z możliwością zatrzymania wykonania kolejnej metody (biznesowej czy interceptora) w łańcuchu kolejnych wywołań oraz ich wartości parametrów i wynik wywołania.

Dla zobrazowania tematu rozszerzyłem przykład z poprzednich relacji z rozdziałów o interceptorach.

Celem nadrzędnym było możliwe minimalne użycie adnotacji związanych z interceptorami w klasach ziarna i interceptorów (z już istniejących zostały zdjęte, a do nowych nie były w ogóle dodawane). Deklaracja adnotacji została wykonana za pomocą deskryptra wdrożenia ejb-jar.xml.

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<interceptors>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.BankomatInterceptor</interceptor-class>
<env-entry>
<env-entry-name>dozwolonaKwota</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>20</env-entry-value>
</env-entry>
</interceptor>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.OdnotujWyplateInterceptor</interceptor-class>
<around-invoke>
<method-name>przechwycWywolanieMetodyBiznesowej</method-name>
</around-invoke>
</interceptor>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorDomyslny</interceptor-class>
</interceptor>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorKlasy</interceptor-class>
</interceptor>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorKlasyZWlasnymiInterceptorami</interceptor-class>
<around-invoke>
<method-name>innePrzechwycWywolanieMetodyBiznesowej</method-name>
</around-invoke>
</interceptor>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorMetody</interceptor-class>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorDomyslny</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>bankomat</ejb-name>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorKlasy</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>bankomat</ejb-name>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorKlasyZWlasnymiInterceptorami</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>bankomat</ejb-name>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.InterceptorMetody</interceptor-class>
<method>
<method-name>wyplac</method-name>
<method-params>
<method-param>int</method-param>
</method-params>
</method>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>
Zmieniłem nazwę metody interceptora dla jej uatrakcyjnienia. Teraz nazywa się ona przechwycWywolanieMetodyBiznesowej(InvocationContext). Przy okazji zmiany zauważyłem, że poprzednio metoda interceptora nie zwracała obowiązkowego parametru typu Object będącego wynikiem wywołania metody biznesowej (bądź ostatecznie ostatniego interceptora w łańcuchu wykonań, jeśli dany interceptor zdecydował o nie wykonaniu metody biznesowej). W ten sposób utworzyłem klasę bazową dla wszystkich nowych interceptorów - pl.jaceklaskowski.ejb3.interceptors.KlasaBazowaInterceptorow.

package pl.jaceklaskowski.ejb3.interceptors;

import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public abstract class KlasaBazowaInterceptorow {

Logger logger = Logger.getLogger("interceptor");

@AroundInvoke
Object przechwycWywolanieMetodyBiznesowej(InvocationContext ic) throws Exception {
logger.info("Wywolano " + this.getClass().getSimpleName());
return ic.proceed();
}

}
Metoda przechwycWywolanieMetodyBiznesowej jest udekorowana adnotacją @AroundInvoke, aby zademonstrować jej wykonanie przed wykonaniem metody interceptora z podklasy - pl.jaceklaskowski.ejb3.interceptors.InterceptorKlasyZWlasnymiInterceptorami.

package pl.jaceklaskowski.ejb3.interceptors;

import javax.interceptor.InvocationContext;

public class InterceptorKlasyZWlasnymiInterceptorami extends KlasaBazowaInterceptorow {
Object innePrzechwycWywolanieMetodyBiznesowej(InvocationContext ic) throws Exception {
logger.info("Wywolano (inne) " + this.getClass().getSimpleName());
return ic.proceed();
}
}
Dalej mamy samo ziarno bez adnotacji @Interceptors.

package pl.jaceklaskowski.ejb3.interceptors;

import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless(name="bankomat")
@WebService(serviceName="bankomat")
public class BankomatBean implements Bankomat {

Logger logger = Logger.getLogger(BankomatBean.class.getName());

public BankomatBean() {
logger.info("Ziarno EJB utworzone");
}

public void wyplac(int kwota) {
logger.info("Wyplacam kwote " + kwota);
}

}
oraz pozostałe interceptory - InterceptorDomyślny, InterceptorKlasy oraz InterceptorMetody.

package pl.jaceklaskowski.ejb3.interceptors;

public class InterceptorDomyslny extends KlasaBazowaInterceptorow {
}

package pl.jaceklaskowski.ejb3.interceptors;

public class InterceptorKlasy extends KlasaBazowaInterceptorow {
}

package pl.jaceklaskowski.ejb3.interceptors;

public class InterceptorMetody extends KlasaBazowaInterceptorow {
}
Wykonanie przykładu demonstrowane jest w konsoli GlassFish następująco:

Ziarno EJB utworzone
Wywolano _InterceptorDomyslny_Serializable
Wywolano _InterceptorKlasy_Serializable
Wywolano _InterceptorKlasyZWlasnymiInterceptorami_Serializable
Wywolano (inne) _InterceptorKlasyZWlasnymiInterceptorami_Serializable
Wywolano _InterceptorMetody_Serializable
Wyplacam kwote 5
Pytanie: Dlaczego nie został wykonany interceptor OdnotujWyplateInterceptor?

p.s. Ja ponownie o konkursie Blog Roku 2007. Trwa III tura konkursu i nawet jeśli głosowałeś/głosowałaś w poprzedniej turze, teraz możesz ponownie wysłać SMSa na swój ulubiony blog (wierzę, że będzie to ten właściwy). Jestem na 13. miejscu z 12-oma głosami. Gratulacje dla tych 3 odważnych, którzy zechcieli zagłosować od wczoraj. Ty możesz być kolejny!

30 stycznia 2008

EJB 3.0 - Rozdział 12.3 Interceptory biznesowe

0 komentarzy
Na dzisiaj przygotowałem krótkie streszczenie z wprowadzenia do rozdziału 12.3 Interceptory biznesowe (interceptory metod biznesowych).

Metody przechwytujące wywołania metod biznesowych (dalej: interceptory biznesowe) ziarna mogą być zdefiniowane dla metod biznesowych ziaren sesyjnych i sterowanych komunikatami (MDB). Interceptory biznesowe określane są adnotacją @AroundInvoke lub elementem around-invoke w deskryptorze wdrożenia ejb-jar.xml.

Metody AroundInvoke mogą być zdefiniowane w nadklasach klasy ziarna lub interceptora. Jednakże, jedynie pojedyńcza metoda AroundInvoke może być zdefiniowana dla danej klasy. Metoda AroundInvoke nie może być metodą biznesową ziarna.

Metody AroundInvoke mogą być publiczne (public), prywatne (private), chronione (protected) lub o widoczności pakietu (aka package protected). Nie mogą być final lub static.

Metody AroundInvoke mają następującą sygnaturę:

Object <METODA>(InvocationContext) throws Exception

Metoda AroundInvoke może wywołać dowolny komponent lub zasób, który może wywołać metoda biznesowa.

Wykonanie interceptora biznesowego występuje w ramach tej samej transakcji i kontekstu bezpieczeństwa jak metoda biznesowa, której wykonanie spowodowało jej uruchomienie.

Metody interceptora biznesowego mogą być zdefiniowane per metoda zamiast per klasa. Zdefiniowanie interceptora biznesowego na poziomie klasy związuje go ze wszystkimi metodami biznesowymi ziarna.

Rozszerzmy przykład z relacji EJB 3.0 - Rozdział 12.2 Cykl rozwojowy interceptora o kolejny interceptor biznesowy - pl.jaceklaskowski.ejb3.interceptors.OdnotujWyplateInterceptor.

package pl.jaceklaskowski.ejb3.interceptors;

import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class OdnotujWyplateInterceptor {

Logger logger = Logger.getLogger(OdnotujWyplateInterceptor.class.getName());

@PersistenceContext
EntityManager em;

@Resource
SessionContext beanContext;

@AroundInvoke
void aroundInvokeBusinessMethod( InvocationContext ic) throws Exception {
String kto = beanContext.getCallerPrincipal().getName();
int ile = (Integer) ic.getParameters()[0];
ic.proceed();
// jeśli jesteśmy tutaj to wywołanie zostało zakończone poprawnie
logger.info("Wyplacona kwota: " + ile + " przez " + kto);

// odnotuj wypłatę w bazie danych
em.persist(new Wyplata(kto, ile));
}
}

Jego przypisanie do ziarna bankomat następuje za pomocą następującego deskryptora wdrożenia ejb-jar.xml.

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<interceptors>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.BankomatInterceptor</interceptor-class>
<env-entry>
<env-entry-name>dozwolonaKwota</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>20</env-entry-value>
</env-entry>
</interceptor>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.OdnotujWyplateInterceptor</interceptor-class>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>bankomat</ejb-name>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.OdnotujWyplateInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>

Deklarujemy w nim istnienie interceptora (sekcja interceptors) oraz jego wiązanie z ziarnami (sekcja interceptor-binding). Ważne jest określenie nazwy ziarna (element ejb-name) jak zdefiniowano w adnotacji @Stateless.

Do pełnego obrazu pozostaje zademonstrować encję Wyplata (klasa pl.jaceklaskowski.ejb3.interceptors.Wyplata):

package pl.jaceklaskowski.ejb3.interceptors;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Wyplata implements Serializable {

@Id
long id;

String kto;

int ile;

protected Wyplata() {
}

public Wyplata(String kto, int ile) {
}

public long getId() {
return id;
}

protected void setId(long id) {
this.id = id;
}

public String getKto() {
return kto;
}

public void setKto(String kto) {
this.kto = kto;
}

public int getIle() {
return ile;
}

public void setIle(int ile) {
this.ile = ile;
}
}

Uruchomienie przykładu na serwerze GlassFish 2.1 daje następujące wyniki (przy wypłacie 5):

Ziarno EJB utworzone
Interceptor utworzony
em == null ? true
dozwolonaKwota == -1 ? true
Wywolanie @PostConstruct dla BankomatBean
em == null ? false
dozwolonaKwota == -1 ? false
Przed wywolaniem metody biznesowej BankomatBean.wyplac()
Wyplata dozwolona - kwota wyplacana 5 mniejsza niz dozwolona 20
Wyplacam kwote 5
Wyplacona kwota: 5 przez ANONYMOUS
TopLink, version: Oracle TopLink Essentials - 2.1 (Build b17-fcs (01/17/2008))
Server: unknown
file:/C:/temp/EnterpriseApplication1/EnterpriseApplication1-ejb/build/jar/-__default login successful
Po wywolaniu metody biznesowej BankomatBean.wyplac()

Interceptor OdnotujWyplateInterceptor jest wykonany po interceptorze BankomatInterceptor (pytanie dla Ciebie: dlaczego?) z ANONYMOUS jako użytkownikiem wykonującym operację (o bezpieczeństwie w EJB3 będzie niebawem). Dostęp do kontekstu trwałego (@PersistenceContext) oraz kontekstu wykonania ziarna (@Resource dla egzemplarza SessionContext) jest możliwy, podobnie jak wykonanie podobnej metody w samym ziarnie EJB (środowisko wykonania ziarna jest współdzielone z interceptorem).

p.s. Już jest lepiej z głosowaniem i mamy szanse konkurować z innymi blogami w konkursie Blog Roku 2007. Zwyżkowałem na 14. miejsce z 9-ma głosami w III etapie (2 miejsca w górę). Ilość głosów wzrasta! Podziękowania dla tych, którzy zechcieli zagłosować. Niewiele kosztuje, a jaka ogromna radość Jacka ;-)

29 stycznia 2008

EJB 3.0 - Rozdział 12.2 Cykl rozwojowy interceptora

5 komentarzy
Pora wrócić do specyfikacji EJB3 - JSR 220: Enterprise JavaBeansTM,Version 3.0 EJB Core Contracts and Requirements. Tym razem pod młotek pójdzie rozdział 12 dotyczący interceptorów. Pisałem już o nich wcześniej - Elementy programowania aspektowego w EJB 3.0 - część 1 oraz Elementy programowania aspektowego w EJB 3.0 - część 2: Interceptory biznesowe, ale wciąż odczuwam niedosyt ich poznania.

Zaczniemy od rozdziału 12.2 Cykl rozwojowy interceptora.

Dla zobrazowania tematu wykorzystamy ziarno EJB - bankomat. Najpierw prezentacja jego interfejsu biznesowego - pl.jaceklaskowski.ejb3.interceptors.Bankomat.

package pl.jaceklaskowski.ejb3.interceptors;

public interface Bankomat {

void wyplac(int kwota);

}

Kolejnym elementem ziarna jest implementacja interfejsu biznesowego w postaci klasy pl.jaceklaskowski.ejb3.interceptors.BankomatBean.

package pl.jaceklaskowski.ejb3.interceptors;

import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.jws.WebService;

@Stateless(name="bankomat")
@WebService(serviceName="bankomat")
@Interceptors(BankomatInterceptor.class)
public class BankomatBean implements Bankomat {

Logger logger = Logger.getLogger(BankomatBean.class.getName());

public BankomatBean() {
logger.info("Ziarno EJB utworzone");
}

public void wyplac(int kwota) {
logger.info("Wyplacam kwote " + kwota);
}

}

Do dyspozycji mamy związany z nim interceptor - BankomatInterceptor.

package pl.jaceklaskowski.ejb3.interceptors;

import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.EJBContext;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class BankomatInterceptor {

Logger logger = Logger.getLogger(BankomatInterceptor.class.getName());

@PersistenceContext
EntityManager em;

@Resource(name="dozwolonaKwota")
int dozwolonaKwota = -1;

@Resource
EJBContext ejbContext;

public BankomatInterceptor() {
logger.info("Interceptor utworzony");
logger.info("\tem == null ? " + (em == null));
logger.info("\tdozwolonaKwota == -1 ? " + (dozwolonaKwota == -1));
}

@PostConstruct
void postConstructBean( InvocationContext ic) {
logger.info("Wywolanie @PostConstruct dla " + ic.getTarget().getClass().getSimpleName());
logger.info("\tem == null ? " + (em == null));
logger.info("\tdozwolonaKwota == -1 ? " + (dozwolonaKwota == -1));
}

@PreDestroy
void preDestroyBean( InvocationContext ic) {
logger.info("Wywolanie @PreDestroy dla " + ic.getTarget().getClass().getSimpleName());
}

@AroundInvoke
void aroundInvokeBusinessMethod( InvocationContext ic) throws Exception {
String metoda = ic.getTarget().getClass().getSimpleName() + "." + ic.getMethod().getName() + "()";
logger.info("Przed wywolaniem metody biznesowej " + metoda);
try {
int kwota = (Integer)ic.getParameters()[0];
if (kwota < dozwolonaKwota) {
String komunikat = String.format("Wyplata dozwolona - kwota wyplacana %s mniejsza niz dozwolona %s", kwota, dozwolonaKwota);
logger.info(komunikat);

ic.proceed();

// Opcjonalnie: odnotuj wypłatę za pomocą zarządcy encji - em
} else {
String komunikat = String.format("Wyplata zabroniona - kwota wyplacana %s wieksza niz dozwolona %s", kwota, dozwolonaKwota);
logger.info(komunikat);
}
} finally {
logger.info("Po wywolaniu metody biznesowej " + metoda);
}
}
}

Pomocniczy persistence.xml dla demonstracji wstrzeliwania zależności:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="bazadanych">
<jta-data-source>jdbc/__default</jta-data-source>
</persistence-unit>
</persistence>

oraz deskryptor wdrożenia ejb-jar.xml, w którym definiuję zmienną środowiskową dla interceptora:

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<interceptors>
<interceptor>
<interceptor-class>pl.jaceklaskowski.ejb3.interceptors.BankomatInterceptor</interceptor-class>
<env-entry>
<env-entry-name>dozwolonaKwota</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>20</env-entry-value>
</env-entry>
</interceptor>
</interceptors>
</ejb-jar>

Egzemplarz interceptora istnieje tak długo, jak długo istnieje egzemplarz ziarna EJB, z którym jest związany. Podczas tworzenia ziarna, tworzone są związane interceptory. Ulegają one zniszczeniu w momencie usuwania ziarna z systemu. W przypadku interceptorów związanych ze stanowymi ziarnami sesyjnymi, egzemplarze interceptorów podlegają tym samym stadiom pasywacji i aktywacji. Więcej w rozdziałach o stanowych ziarnach sesyjnych (4.4 oraz 4.5.1 i 5.5).

Podczas wywołania ziarna bankomat mamy następującą kolejność komunikatów (dla kwoty == 5):

Ziarno EJB utworzone
Interceptor utworzony
em == null ? true
dozwolonaKwota == -1 ? true
Wywolanie @PostConstruct dla BankomatBean
em == null ? false
dozwolonaKwota == -1 ? false
Przed wywolaniem metody biznesowej BankomatBean.wyplac()
Wyplata dozwolona - kwota wyplacana 5 mniejsza niz dozwolona 20
Wyplacam kwote 5
Po wywolaniu metody biznesowej BankomatBean.wyplac()
Wywolanie @PreDestroy dla BankomatBean // wyłącznie podczas Undeploy and Deploy w NetBeans

Zarówno egzemplarz interceptora oraz ziarna są tworzone lub aktywowane zanim wywołane zostaną metody zwrotne @PostConstruct oraz @PostActivate. Dla metod zwrotnych @PreDestroy oraz @PrePassivate jest podobnie z tym, że wywoływane są zanim nastąpi etap zniszczenia lub pasywacji egzemplarza ziarna lub interceptora.

Egzemplarz interceptora może przechowywać stan. Egzemplarz interceptora podlega mechanizmowi wstrzeliwania zależności, który podczas tworzenia interceptora wstrzeliwuje zależności korzystając z przestrzeni nazw związanego ziarna EJB. Metoda przechwytująca @PostConstruct wywoływana jest po zakończeniu wstrzeliwania zależności egzemplarza ziarna EJB oraz wszystkich skojarzonych interceptorów.

Interceptory mogą korzystać z usług JNDI, JDBC, JMS, JPA oraz wywoływać inne ziarna EJB.

Interceptory dzielą przestrzeń nazw ziarna, z którym są skojarzone. Adnotacje i elementy deskryptora ejb-jar.xml dotyczące mechanizmu wstrzeliwania zależności lub bezpośrednie wyszukiwania JNDI dotyczą wyłącznie tej przestrzeni.

Egzemplarz EJBContext może być wstrzelony do klasy interceptora. Interceptor może skorzystać z niego do przeszukiwania przestrzeni nazw JNDI ziarna.

Użycie rozszerzonego kontekstu trwałego jest jedynie wspierane dla interceptorów związanych ze stanowymi ziarnami sesyjnymi.

p.s. Nie zapomnieliście o konkursie Blog Roku 2007? Coś słabo idzie nam z tym głosowaniem i wypadam na 16. miejscu z 2-ma głosami w III etapie (40 głosów w II etapie) (!) Niedobrze. Pora Was rozruszać!

27 stycznia 2008

Dostęp do EntityManager w metodach zwrotnych encji w JPA

2 komentarzy
Kolejny wątek na grupie pl.comp.lang.java sprowokował mnie do szczegółowej analizy działania Java Persistence API (JPA) ze specyfikacją w ręku.

Tym razem Krzysiek (aka Kolszew) zapytał o mechanizm wstrzeliwania zależności w encjach JPA, które są częścią szerszej specyfikacji Enterprise JavaBeans 3.0 (EJB3) - EJB3, JPA, @EJB. Po krótkiej wymianie wiadomości okazało się, że tematem przewodnim wątku jest możliwość wykorzystania javax.persistence.EntityManager w metodzie zwrotnej encji (oznaczonej przez adnotację @PostRemove). Mechanizm wstrzeliwania zależności odpada w tym scenariuszu, gdyż EJB3 nie udostępnia go dla encji JPA. Jak się okazało adnotacje nie są dostępne, ale podstawy, na których są oparte, jak najbardziej, tj. lokalne drzewo JNDI w kontekście wywołania encji. Wynik jest bardzo zaskakujący. Generalnie warto czytać specyfikacje i próbować ich realizację w środowisku, z którym pracujemy.

Więcej znajdziesz w kolejnym artykule w serii o EJB3 - Dostęp do EntityManager w metodach zwrotnych encji w JPA.

p.s. Nie żebym się narzucał, ale o SMSach pamiętacie, nieprawdaż? Więcej na stronie konkursu Blog Roku 2007.

22 stycznia 2008

Czasami Ty opisujesz, a czasami opisują Ciebie

1 komentarzy
Dosyć często zadaje mi się pytanie odnośnie wartości płynących z pisania internetowych pamiętników technicznych, czy jak ja zwykłem je nazywać, notatników (blogów). Jednym z najbardziej zauważalnych dla mnie jest ciągła potrzeba utrzymania płynności materiału na blogu, co jest z korzyścią dla jednej i drugiej strony. Dla tej pierwszej - czytelników jest to możliwość wglądu w materiał prezentowany przez danego "literata" z możliwością jego oceny, podczas gdy dla owego literata jest to możliwość konfrontacji swojego spojrzenia na dany temat z czytelnikami. Czym ich więcej, tym większa szansa na pozyskanie właściwych informacji, a tym samym zdobycia wiedzy i ostatecznie podniesienie własnych kwalifikacji. Ciągłe podnoszenie kwalifikacji jest wpisane w nasz zawód - konsultant, programista, projektant, analityk, tester, czy jak to się jeszcze może nazywać. Zwiększanie liczby czytelników jest również potwierdzeniem zainteresowania tematami, które są publikowane w blogu, co może również być wykładnikiem do oceny aktualności wiedzy autora. Są to wielkości wprost proporcjonalne - czym więcej czytelników, tym bardziej aktualna i pożądana przez rynek wiedza. W końcu jak inaczej możnaby zweryfikować swoją wiedzę, jak nie w projektach, czy podczas rozmowy z osobami zajmującymi się podobnymi zagadnieniami?

I tak możnaby dłużej, ale żeby nie przeciągać, a uspokoić zniecierpliwionych, co to ma wspólnego z tematem dzisiejszego wpisu, spieszę wyjaśnić, że czasami nasza praca, która ma przynieść korzyści obu stronom, jest jeszcze dodatkowo nagradzana komentarzami na innych blogach, a czasami całymi artykułami. Jeśli jeszcze dodać do tego, że niektóre z nich są obcojęzyczne, to możnaby zastanawiać się, dlaczego tam mało technicznych bogów powstaje w języku polskim, a większość z nas, jeśli decyduje się na uruchomienie jednego idzie na całość i pisze po angielsku? Odpowiedź zostawiam na później, a tymczasem dodam, że styczeń 2008 okazuje się być czasem nagród noworocznych w postaci wpisów/artykułu ze mną w tle.

Zacznę od pierwszego, dosyć już zakurzonego, ale autor warty uwagi. Bill Burke na swoim blogu w części Day Two wpisu Java Developer’s Day: Krakow, Poland "zgrabnie" opisał moje wystąpienie na Java Developer's Day 2007 w Krakowie. Wygląda jakby bariery językowe zostały przełamane i rekwizyty w postaci kilku koszulek zdejmowanych w odpowiednich momentach zwróciły uwagę Billa.

Kolejny wpis na blogu uCertify jest odpowiedzią na moją Recenzję uCertify SCBCD Java 5.0 (CX310-091) PrepKit - ich produktu przygotowującego do testów SCBCD5 - Jacek Laskowski appraises uCertify SCBCD Java 5.0 PrepKit. Miło móc pojawić się w gronie osób oceniających produkt, który otrzymało się w zamian w pełnej wersji. Czyżby firma uCertify stwierdziła, że można w ten sposób poprawić jakość moich wpisów, szczególnie o EJB3?! ;-)

Na koniec nie mogłem nie wspomnieć o najnowszym "dziele" Jirki i jego świty z NetBeans - artykule NetCAT 6.0 Top Cats - Jacek Laskowski & Anuradha Gunasekara. Jirka napisał, że artykuł will be soon featured in the Weekly Newsletter and on our homepage, więc nie pozostaje mi nic innego jak kontynuować rozwój kompetencji przez ich publiczną konfrontację, bo nagroda może przekroczyć nasze oczekiwania. Nikt nie traci, a wiele można zyskać!

To jak, przekonany o konieczności rozpoczęcia/kontynuowania własnego notatnika? Koniecznie napisz, jeśli się zdecydujesz. Chętnie pomogę.

XXII spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

4 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na XXII spotkanie, które odbędzie się we wtorek 22.01.2008 o godzinie 18:00 w sali 5820 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: JavaFX
Prowadzący: Bartek "koziołek" Kuczyński / Radosław Holewa

Celem prezentacji jest ukazanie istoty platformy JavaFX oraz najważniejszych i najciekawszych elementów języka JavaFX Script. Uczestnicy będą mogli zobaczyć w jaki sposób można integrować aplikacje napisane w JavaFX z tradycyjną Javą, zarówno w wersji serwerowej, jak też użycia z poziomu JavaFX Script napisanych w czystej Javie komponentów.
A poza tym, nie zabraknie różności programistycznych jak JavaFX a środowiska programistyczne - NetBeans IDE oraz Eclipse, będzie Apache Maven, czyli co i jak budować z wtyczką m2jfxs, której zadaniem jest przygotowanie środowiska do pracy z JFXS. Planowane również niespodzianki programistyczne. Porównanie ze Swingiem, SWT i innymi.

Bartek "koziołek" Kuczyński zajmuje się programowaniem od dawien dawna. Zaczynał od Logo, a po wielu przygodach zainteresował się Javą. Od czterech lat rozmawia z komputerami w języku Java, a od dwóch lat robi to komercyjnie. Bartek jest programistą zatrudnionym przy projekcie PESEL2. Poza tym udziela się na 4programmers.net i udziela porad zbłąkanym javowym duszyczkom.

Radosław Holewa jest studentem V roku Uniwersytetu Ekonomicznego w Krakowie na kierunku Informatyka i Ekonometria. Javą interesuje się od prawie czterech lat. Zajmował się systemami bankowości internetowej, systemami obsługi płatności, platformami e-commerce, bramkami smsowymi oraz aplikacjami RIA pisanymi przy użyciu Adobe Flex. Pracuje jako programista Java w firmie Grape Software oraz pełni funkcję Sun Campus Ambassadora na Uniwersytecie Ekonomicznym. Jest współorganizatorem największego wydarzenia IT w Polsce - Studenckiego Festiwalu Informatycznego oraz konferencji Java TechConf. W roku 2007 wspólnie z Adrianem Nowakiem reaktywował Polish Java User Group, grupę miłośników języka Java. Czas wolny najchętniej spędza z przyjaciółmi.

Planowany czas prezentacji to 1,5 godziny.

Wstęp wolny!

Zapraszam w imieniu Bartka i Radka oraz Warszawa JUG!

17 stycznia 2008

Element beanName w @EJB do rozróżnienia deklaracji ziaren EJB

0 komentarzy
Już jakiś czas temu spotkałem się z pytaniem odnośnie deklarowania zależności do dwóch różnych ziaren EJB, które realizują ten sam interfejs biznesowy. Nadeszła pora na rozwiązanie tej kwestii i tym samym powrót do ponownego rozpoznawania specyfikacji EJB3 z przykładami.

Zebrałem się w sobie i napisałem kolejny artykuł Element beanName w @EJB do rozróżnienia deklaracji ziaren EJB o tym jak za pomocą elementów beanName w adnotacji @EJB oraz name w @Stateless rozwiązuje się tą kwestię. Rozpoczniemy od stworzenia aplikacji korporacyjnej z EJB3 i JSF 1.2. Aplikacja będzie składała się z ziarna JSF oraz dwóch bezstanowych ziaren sesyjnych EJB, które realizują ten sam interfejs biznesowy. Korzystając z adnotacji @EJB określimy zależności ziarna JSF do obu ziaren EJB i od wyboru użytkownika będzie zależało, którą metodę biznesową wywołamy - tą realizowaną przez "pierwsze" ziarno EJB, czy "drugie".

Dużo dobrej zabawy i to w przysłowiowe 5 minut. Uwagi i komentarze mile widziane.

p.s. Zakładam, że SMSy wysłane? ;-)

16 stycznia 2008

Rozpoczął się II etap Konkursu Blog Roku 2007 - numer bloga: B00248

6 komentarzy
A więc się zaczęło! Reguły konkursu Blog Roku 2007 opisane są w poniższej wiadomości, którą dzisiaj otrzymałem od organizatorów. W skrócie - wy wysyłacie SMSy na numer 71222 w treści podając numer konkursowy tego bloga B00248, a ja wygrywam laptopa ;-)

Rozpoczął się II etap Konkursu - kwalifikacja do oceny.

Blogi zgłoszone do udziału w Konkursie przeszły do II etapu. Polega on na głosowaniu SMS.
Na tym etapie rozstrzygnie się, które blogi będą walczyć o tytuły Najlepszych Blogów 2007.

Dzięki temu głosowaniu w każdej z 10 kategorii tematycznych powstanie lista 25 najwyżej ocenionych blogów. Przejdą one do III etapu Konkursu - oceny przez Internautów, a pierwsze 10 z nich dodatkowo ocenione zostaną przez Kapitułę Konkursu.

Jak głosować?

Każdy blog biorący udział w Konkursie posiada swój unikalny numer.

----------------------------------------------------------------
Numer twojego bloga to B00248
----------------------------------------------------------------

Wyświetlamy go w serwisie konkursowym obok adresu Twojego bloga oraz na jego indywidualnej stronie konkursowej.

Poinformuj o nim swoich czytelników. Przekaż im również instrukcję głosowania:

"Jeśli chcesz zagłosować na wybrany blog, to prześlij SMS na numer 71222 w treści SMS podając numer konkursowy tego bloga"

Wszystko o głosowaniu

* Na wybrany blog można zagłosować tylko raz (w tym etapie Konkursu)
* Liczba blogów, na które można zagłosować jest nieograniczona
* Koszt każdego SMS, to 1,22 brutto
* Dochód z głosowania zostanie przeznaczony na wsparcie Ośrodka Szkolno - Wychowawczego dla Dzieci Niewidomych i Słabowidzących w Krakowie
* Głosujący mają szansę na nagrody - czeka na nich 10 Ipod-ów NANO 4GB

Teraz wszystko w Waszych rękach, drodzy czytelnicy. Wy wygrywacie 10 Ipod-ów NANO 4GB, a mnie wystarczy nowiutki Laptop MacBook white 2.0 GHz Intel Core 2 Duo.

Jeśli chcecie, abym cieszył się nowym laptopem i (potencjalnie) w ten sposób podniósł wartość kolejnych wpisów, również o moich doznaniach estetycznych z posiadania nowiutkiego MacBooka, zapraszam do udziału w głosowaniu. Wystarczy przesłać SMS na numer 71222 w treści podając numer konkursowy tego bloga B00248. Zapraszam!

15 stycznia 2008

Recenzja uCertify SCBCD Java 5.0 (CX310-091) PrepKit

10 komentarzy
Jeszcze w grudniu 2007 roku otrzymałem zaproszenie od firmy uCertify do przeprowadzenia recenzji narzędzia uCertify SCBCD Java 5.0 (CX310-091) PrepKit przygotowującego do egzaminu Sun Certified Business Component Developer for the Java Platform, Enterprise Edition 5 (CX-310-091). Z wielkim entuzjazmem przystałem na warunki zadania, które wymagało ode mnie jedynie sprawdzenia narzędzia pod kątem jego przydatności podczas przygotowania się do egzaminu SCBCD5 (EJB3).

Hi Jacek Laskowski,

This is Roger from uCertify. We provide IT certification preparation PrepKits for all major vendors such as Microsoft, Sun, Oracle, CompTIA and CIW.

I found your blog useful and suitable for professionals preparing for IT certifications. Would you be interested in evaluating our PrepKits and in writing a review on them? Your objective review can help professionals preparing for IT certifications.

Our PrepKits have been reviewed on several prominent websites such as About.com, Mcmcse.com, Jars.com etc.


Moje spojrzenie na przydatność narzędzia podczas przygotowań do egzaminu SCBCD5 dostępna jest w dokumencie Recenzja uCertify SCBCD Java 5.0 (CX310-091) PrepKit.

Oceniam narzędzie bardzo wysoko i mimo, że mam już certyfikat SCBCD5 to traktuję uCertify SCBCD Java 5.0 (CX310-091) PrepKit jako doskonały sposób na poprawienie mojej znajomości niuansów specyfikacji Enterprise JavaBeans 3.0.

Dodatkowo firma uCertify zaoferowała zniżkę promocyjną na zakup narzędzia każdemu czytelnikowi mojego bloga, tak że cena produktu spada o 10% przy użyciu następującego kodu (ang. discount code) - JACLASK. Polecam!

14 stycznia 2008

File.delete() pod MS Windows z YourKit Java Profiler 7.0 i ZipFileMonitor

0 komentarzy
Ech, chciałbym napisać, że kolejny artykuł File.delete() pod MS Windows z YourKit Java Profiler 7.0 i ZipFileMonitor to podsumowanie samych sukcesów i dużo zabawy. Dużo zabawy było na pewno, ale o sukcesach wolałbym pisać w umiarkowanym tonie, bo kto by pomyślał, że proste zadanie usunięcia pliku za pomocą java.io.File.delete() może mi zająć tyle czasu i ostateczny wynik będzie jedynie połowicznym sukcesem (przy braku sukcesów połowiczny sukces jest równie bezcenny jak ten pełen)?! Mógłbym nawet skłoniać się ku podsumowaniu, że było to typowe pyrrusowe zwycięstwo. Jest tyle artykułów dotyczących problemu usuwania plików za pomocą File.delete() pod MS Windows, że gdybym o tym wiedział z pewnością nie zabrałbym się za pisanie poprawki do zgłoszenia OPENEJB-746 Command line tool Deploy/Undeploy asymmetry. Szczęśliwie jednak miałem do dyspozycji pomoc na grupie dev@openejb.apache.org oraz narzędzia IntelliJ IDEA 7, YourKit Java Profiler 7.0 oraz niewielki acz bardzo użyteczny ZipFileMonitor. Nigdy wcześniej nie pracowałem z YourKit Java Profiler i muszę przyznać, że możliwości i integracja z IntelliJ IDEA, do której powoli wracam, zaimponowała mi.

Co ja się też będę rozpisywał - sam(a) przeczytaj w kolejnym artykule File.delete() pod MS Windows z YourKit Java Profiler 7.0 i ZipFileMonitor.

12 stycznia 2008

Uzupełnianie w bashu i pierwsze kroki z JRuby

0 komentarzy
Moja saga rozpoznawania uzupełniania w bashu nadal trwa. Do zabawy przyłączył się koziołek, który na swoim blogu opublikował skrypt uzupełnieniowy dla maven - Podpowiadanie dla mavena w bashu. Wystarczy zatem zapisać ów skrypcik do katalogu /etc/bash_completion.d jako mvn, w którym koniecznie dodajemy jeszcze complete -F _mvn mvn na końcu i uruchomić uzupełnianie basha poprzez wczytanie skryptu /etc/bash_completion.

jlaskowski@dev /etc/bash_completion.d
$ pwd
/etc/bash_completion.d

jlaskowski@dev /etc/bash_completion.d
$ cat mvn
_mvn()
{

local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="-Dversion= -DarchetypeArtifactId= -DartifactId= -DgroupId= -q --quiet -C
--strict-checksum -c --lax-checksums -P --activate-profiles -ff --fail-fast
-fae --fail-at-end -B --batch-mode -fn --fail-never
-up --update-plugins -N --non-recursive -npr --no-plugin-registr
-U --update-snapshots -cpu --check-plugin-updates -npu --no-plugin-updates
-D --define -X --debug -e --errors -f --file -h --help
-o --offline -r --reactor -s --settings -v --version -?
clean clean:clean compiler:compile compiler:testCompile compile
deploy:deploy deploy:deploy-file deploy install:install install:install-file
install resources:resources resources:testResources site:deploy
site:attach-descriptor site:site
site:run site:stage-deploy site:stage site surefire:test test verifier:verify verify ear:ear
ear:generate-application-xml ejb:ejb jar:jar jar:test-jar jar:sign jar:sign-verify rar:rar
war:war war:exploded war:inplace changelog:changelog changelog:dev-activity
changelog:file-activity changes:announcement-mail changes:announcement-generate
changes:changes-report changes:jira-report checkstyle:checkstyle checkstyle:check
clover:aggregate clover:check clover:instrumentInternal clover:instrument clover:log
clover:clover clover:save-history doap:generate docck:check javadoc:javadoc
javadoc:test-javadoc javadoc:jar jxr:jxr jxr:test-jxr pmd:pmd pmd:cpd pmd:check pmd:cpd-check
project-info-reports:cim project-info-reports:dependencies
project-info-reports:dependency-convergence project-info-reports:issue-tracking
project-info-reports:license project-info-reports:mailing-list project-info-reports:index
project-info-reports:summary project-info-reports:scm project-info-reports:project-team
surefire-report:report surefire-report:report-only ant:ant ant:clean ant antrun:run
archetype:create archetype:create-from-project -DarchetypeArtifactId=maven-archetype-archetype
-DarchetypeArtifactId=maven-archetype-j2ee-simple -DarchetypeArtifactId=maven-archetype-mojo
-DarchetypeArtifactId=maven-archetype-portlet -DarchetypeArtifactId=maven-archetype-profiles
-DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeArtifactId=maven-archetype-simple
-DarchetypeArtifactId=maven-archetype-site -DarchetypeArtifactId=maven-archetype-site-simple
-DarchetypeArtifactId=maven-archetype-webapp assembly:assembly assembly:attached
assembly:directory assembly:directory-inline assembly:unpack assembly:single
assembly:directory-single dependency:copy dependency:copy-dependencies dependency:unpack
dependency:unpack-dependencies dependency:resolve dependency:list dependency:sources
dependency:resolve-plugins dependency:list dependency:go-offline
dependency:purge-local-repository dependency:build-classpath dependency:analyze
dependency:analyze-only dependency:analyze-dep-mgt dependency:tree enforcer:enforce
enforcer:enforce-once enforcer:display-info gpg:sign gpg:sign-and-deploy-file
help:active-profiles help:describe help:effective-pom help:effective-settings invoker:run
one:convert one:deploy-maven-one-repository one:install-maven-one-repository one:maven-one-plugin
plugin:descriptor plugin:report plugin:updateRegistry plugin:xdoc
plugin:addPluginArtifactMetadata release:clean release:perform release:prepare release:rollback
release:branch remote-resources:bundle remote-resources:process scm:add scm:changelog scm:checkin
scm:checkout scm:diff scm:edit scm:status scm:tag scm:unedit scm:update scm:validate
source:aggregate source:jar source:test-jar eclipse:configure-workspace eclipse:eclipse
eclipse:clean eclipse:m2eclipse eclipse:to-maven eclipse:install-plugins eclipse:make-artifacts
eclipse:myeclipse eclipse:myeclipse-clean eclipse:rad eclipse:rad-clean idea:idea idea:project
idea:module idea:workspace idea:clean build-helper:add-source build-helper:add-test-source
build-helper:attach-artifact castor:generate jdepend:generate native:initialize native:compile
native:link native:javah native:ranlib native:resource-compile native:compile-message sql:execute
taglist:taglist cargo:start cargo:stop cargo:deployer-deploy cargo:deploy
cargo:deployer-undeploy cargo:undeploy cargo:deployer-start cargo:deployer-stop
cargo:deployer-redeploy cargo:uberwar cargo:install jaxme:jaxme jetty:run jetty:run-war
jetty:run-exploded"

if [[ ${cur} == * ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi

}
complete -F _mvn mvn

jlaskowski@dev /etc/bash_completion.d
$ . /etc/bash_completion

jlaskowski@dev /etc/bash_completion.d
$ mvn [TAB][TAB]
Display all 248 possibilities? (y or n)n

jlaskowski@dev /etc/bash_completion.d
$ mvn --[TAB][TAB]
--activate-profiles --define --fail-never --no-plugin-registr --quiet --update-plugins
--batch-mode --errors --file --no-plugin-updates --reactor --update-snapshots
--check-plugin-updates --fail-at-end --help --non-recursive --settings --version
--debug --fail-fast --lax-checksums --offline --strict-checksum
Fajnie byłoby utworzyć uzupełnianie dla innych poleceń, a zaoszczędzimy kilka minut na pisanie tych samych poleceń każdorazowo przy ich uruchamianiu.

Nie jest to jedyna możliwość polecenia complete w bashu. Można również wykonać polecenie, które zbuduje potrzebne informacje dla complete. Wykonanie skryptu następuje poprzez wywołanie z opcją -C. Spójrzmy na przykład skryptu napisanego w...ruby.

jlaskowski@dev /etc/bash_completion.d
$ cat rake
complete -C ~/rake-completion.rb -o default rake

jlaskowski@dev /etc/bash_completion.d
$ cat ~/rake-completion.rb
#!/usr/bin/env ruby

# Complete rake tasks script for bash
# Save it somewhere and then add
# complete -C path/to/script -o default rake
# to your ~/.bashrc
# Nicholas Seckar

exit 0 unless File.file?(File.join(Dir.pwd, 'Rakefile'))
exit 0 unless /^rake(?:\s+([-\w]+))?\s*$/ =~ ENV["COMP_LINE"]

task_prefix = $1

tasks = `rake --tasks`.split("\n")[1..-1].collect {|line| line.split[1]}
tasks = tasks.select {|t| /^#{Regexp.escape task_prefix}/ =~ t} if task_prefix
puts tasks
exit 0


jlaskowski@dev /etc/bash_completion.d
$ rake [TAB][TAB]
bitkeeper clisp freeciv gnatmake isql lisp modules openejb rake sitecopy unace
bittorrent cygport gcl harbour larch mailman mtx p4 ri snownews unrar
cksfv dsniff gkrellm hg lilypond mcrypt mvn povray sbcl svk
Tym razem lista zawiera nazwy plików w bieżącym katalogu, czyli domyślne zachowanie complete w bashu. Wynika to z działania samego skryptu rake-completion.rb, który zakończy działanie, kiedy w bieżącym katalogu nie ma pliku Rakefile.

exit 0 unless File.file?(File.join(Dir.pwd, 'Rakefile'))
Pozostaje zatem dodać plik Rakefile i wypróbować polecenie ponownie. Niestety po chwili okazuje się, że rake dostarczany z JRuby 1.1 RC1 odmawia współpracy kończąc się z następującym komunikatem pod Cygwin:

jlaskowski@dev /etc/bash_completion.d
$ rake
Error opening script file: C:/apps/cygwin/etc/bash_completion.d/cygdrive/c/apps/jruby/bin/rake (The system cannot find the path specified)
Mimo wszystko warto rozpocząć poznawanie konstrukcji językowych Ruby na przykładzie zaprezentowanego wyżej skryptu, który poza sprawdzeniem, czy w bieżącym katalogu istnieje plik Rakefile, odczytuje podane polecenie na linii poleceń.

exit 0 unless /^rake(?:\s+([-\w]+))?\s*$/ =~ ENV["COMP_LINE"]
Na szczęście z analizą w/w polecenia pomogła mi książka Learning Ruby Michaela Fitzgeralda (wydawnictwo O'Reilly), gdzie w rozdziale Regular Expressions na stronie 74 znalazłem potrzebne informacje.

  • /pattern/ to specyfikacja wzorca
  • ^rake określa, że interesujące są wyłącznie linie rozpoczynające się ciągiem rake
  • (?:..) oznacza, że grupujemy wyrażenie bez zapamiętania pasującego tekstu
  • \s pasuje do dowolnego łańcucha białych znaków (tabulacja, nowa linia, powrót karetki i \f - a to nie wiem, co oznacza)
  • + pasuje do wystąpienia pojedyńczego bądź więcej wyrażeń regularnych, których dotyczy
  • [..] pasuje do dowolnego znaku w nawiasach
  • \w dowolny ciąg znaków
W ten sposób polecenie rozpoznaje dowolne polecenie wydane z rake. W przypadku tego skryptu niepoprawnie zakończy się linia rake --tasks, które kończy się komunikatem błędu, więc cały skrypt nic nie zwróci i w ten sposób complete również.

jlaskowski@dev /etc/bash_completion.d
$ rake --tasks
Error opening script file: C:/apps/cygwin/etc/bash_completion.d/cygdrive/c/apps/jruby/bin/rake (The system cannot find the path specified)

jlaskowski@dev /etc/bash_completion.d
$ rake polecenie[TAB][TAB]

W zamian można popróbować się z jruby i jego poleceniami. Chętni?

10 stycznia 2008

Mechanizm uzupełniania w powłoce bash

4 komentarzy
W natłoku wrażeń dzisiaj kolejne, tym razem niezwiązane bezpośrednio z Javą - mechanizm uzupełniania (completion) w powłoce bash.

Dużo czasu spędzam w powłoce bash pod Cygwin (i z wielką przyjemnością przesiadłbym się na Linux bądź OS/X, aby już więcej nie opuszczać linii poleceń), więc kiedy dzisiaj podczas lektury dokumentacji do buildr, a później dokumentacji jego protoplasty rake natrafiłem na artykuł Martina Fowlera Using the Rake Build Language, gdzie w sekcji Further Reading wskazano na mechanizm uzupełniania w bashu o mało nie spadłem z krzesła. Takiego wrażenia nie wywołało u mnie nawet pojawienie się finalnej wersji Java EE 5 ;-) I najbardziej bolesna była świadomość, że funkcjonalność uzupełniania basha była dostępna na wyciągnięcie ręki (!)

W ramach udoskonalania warsztatu wszystko inne zeszło na plan drugi i zabrałem się za poznawanie tego cudeńka. Najpierw zaczęło się od wspomnianego artykułu, a w zasadzie wpisu w blogu Rake tab completion for bash, a później cała masa artykułów na ten temat, gdzie najbardziej interesujące wydały mi się An introduction to bash completion: part 1 oraz An introduction to bash completion: part 2 i na zakończenie CLI Magic: Bash complete.

O co chodzi w tym bash completion, czy jakbym to nazwał uzupełnianiem w bashu. Każdy kto korzystał z basha zapewne korzystał z klawisza TAB, który uzupełniał listę plików przy poleceniu, czy samo polecenie.

jlaskowski@dev ~
$ [TAB] [TAB]
Display all 4545 possibilities? (y or n)

jlaskowski@dev ~
$ java [TAB] [TAB]
java.exe java2groovy javac.exe javadoc.exe javap.exe javaws.exe
java.exe.stackdump java2groovy.bat javacpl.cpl javah.exe javaw.exe
Jeśli jednak wpisałbym polecenie to dwukrotne wciśnięcie klawisza TAB spowoduje wyświetlenie listy plików z bieżącego katalogu lub uzupełnienie nazwy pliku, jeśli rozpoczęliśmy wpisywanie jego nazwy. Na bazie poprzedniego projektu dla buildr:

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ buildr bui[TAB] [TAB]
i mechanizm uzupełniania w bashu uzupełni do

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ buildr buildfile
To zapewne każdy znał, więc czym się tu zachwycać (nie wspominając o tym, po co było w ogóle to przywoływać skoro wszyscy to znają). To jednak nie wszystko. Tu gdzie rozpoczyna się prawdziwa jazda to plik /etc/bash_completion oraz katalog konfiguracyjny /etc/bash_completion.d/, w którym skrypty rozszerzają możliwości uzupełniania (podobnie działa rake i tym samym buildr w kontekście rozszerzeń poleceń użytkownika - o tym jednak napiszę, kiedy będzie o buildr)

jlaskowski@dev ~
$ ls -l /etc/bash_completion
bash_completion bash_completion.d/
Wystarczy zatem wczytać zawartość pliku /etc/bash_completion do powłoki i świat staje się ciekawszy.

jlaskowski@dev ~
$ complete -p

jlaskowski@dev ~
$ . /etc/bash_completion

jlaskowski@dev ~
$ complete -p
complete -F _mmsitepass mmsitepass
complete -F _withlist withlist
complete -F _list_members list_members
complete -F _remove_members remove_members
complete -o filenames -F _filedir_xspec oodraw
complete -o filenames -F _filedir_xspec elinks
complete -o filenames -F _filedir_xspec freeamp
complete -o filenames -F _java java
complete -o filenames -F _longopt split
complete -o filenames -F _longopt sed
complete -o filenames -F _longopt grep
complete -o filenames -F _longopt ld
complete -F _kill kill
complete -F _renice renice
complete -j -P '%' jobs
....
complete -o filenames -F _root_command sudo
complete -o filenames -F _jar jar
complete -o default -o filenames -F _mount mount
complete -a unalias

jlaskowski@dev ~
$ complete -p | wc -l
361
Teraz pozostaje z tego brać garściami, tj. uzupełniać polecenia i...ich argumenty (!)

Weźmy dla przykładu polecenie su (pozwalające przełączyć aktualnego użytkownika). Bez uzupełniania mamy jedynie uzupełnienie polecenia o dostępne pliki w bieżącym katalogu, co w tym przypadku czyni klawisz TAB kompletnie nieprzydatnym.

jlaskowski@dev ~
$ su [TAB] [TAB]
.bash_history .bashrc
Jednakże po wczytaniu pliku /etc/bash_completion klawisz TAB może nas zaskoczyć - pojawia się możliwość uzupełnienia użytkowników (!)

jlaskowski@dev ~
$ . /etc/bash_completion

jlaskowski@dev ~
$ su [TAB] [TAB]
Administrator Administrators Guest SYSTEM jlaskowski
Zatem mamy możliwość uzupełnienia pewnych poleceń systemowych o ich możliwe i dozwolone argumenty.

Pytanie, które mógłby ktoś zadać, to czy istnieje możliwość utworzenia własnej listy argumentów, jakie podamy poleceniu po dwukrotnym wciśnięciu klawisza TAB. Odpowiedź jest twierdząca. W podanych artykułach można doczytać szczegóły, ale teraz wiem, że mogę stworzyć odpowiedni plik konfiguracyjny dla polecenia complete i uzupełniać polecenia skryptów, których składnię każdorazowo musiałem pamiętać i dodatkowo ręcznie wpisywać. Tym razem koniec - korzystam z complete.

Przykładowy plik konfiguracyjny dla polecenia openejb z projektu Apache OpenEJB.

jlaskowski@dev ~
$ cat /etc/bash_completion.d/openejb
# openejb completion
#
# $Rev$ $Date$

_openejb()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="deploy properties start stop undeploy validate"

if [[ ${cur} == * ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
complete -F _openejb openejb
Po wczytaniu tego pliku, co dzieje się automatycznie podczas wczytywania głównego pliku konfiguracyjnego /etc/bash_completion, każdorazowe wywołanie polecenia openejb i podwójny TAB spowodują wyświetlenie dostępnych poleceń.

jlaskowski@dev ~
$ openejb [TAB][TAB]
deploy properties start stop undeploy validate
Tego mi było trzeba. Kiedy jestem na projekcie i przydziela mi się zadanie zestawienia środowiska na Uniksie, każdorazowo dodaję zestaw aliasów, jak psj (wyświetl listę procesów java), psjc (liczba procesów java), czy różnego rodzaju przejścia do odpowiednich katalogów, które teraz rozbuduję o zestaw dostępnych uzupełnień poleceń startujących serwery aplikacyjne. Już nie mogę doczekać się pierwszego wdrożenia cudeńka produkcyjnie. Unix nie przestaje mnie zadziwiać, a korzystam z niego dłużej niż z Javy. Aż strach pomyśleć jak to wpłynie na stan mojego serca, jeśli wziąść pod uwagę ile takich ciekawostek jest jeszcze przede mną i w Uniksie, i w samej Javie ;-)

09 stycznia 2008

Buildr jeszcze raz - tym razem start udany

0 komentarzy
Już miałem jedno niepomyślnie zakończone podejście do Buildr oraz Raven - Raven, Buildr i...JPA - nieudany start. Mimo początkowej porażki wciąż pamiętałem o obietnicach jakie składały te narzędzia, gdzie bolączki mavenowe miały odejść w zapomnienie raz na zawsze (prawdopodobnie przynosząc inne, ale inne będą nowe, a starych mam dość). I właśnie podczas wczorajszego, XXI spotkania Warszawa JUG na moment rozgorzała dyskusja na temat "Jeśli nie Maven, to co?". I faktycznie. Alternatywą mogłyby być Ant czy make, ale według mnie one są jedynie dobre, podczas gdy Maven jest lepszy, przyjemniejszy (coś na wzór porównania C z C++, żeby nie napisać Java - wszystkie są dobre, ale niektóre przypadają do gustu szybciej niż inne). Postanowiłem dzisiejszy wieczór spędzić rozpoznając Raven i Buildr ponownie.

Zacząłem od Ravena. Coś mi mówiło, że należy zaczać od niego. Po chwili już było wiadomo, że już po nim. Strona domowa nie zachęca do odwiedzin, gdzie widnieje Latest version: 1.2.3 (2007-05-12), a na liście dyskusyjnej raven-user głusza, jakby zamarła. Przedostatnia wiadomość jest jakby potwierdzeniem przypuszczenia, że ten projekt, albo dopiero rozpoczyna swoje istnienie (czemu przeczy jego wersja 1.2.3), albo właśnie je zakończył:

Kevin Williams wrote:
> Is Raven dead? JRuby 0.9.1 is quite out of date. JRuby 1.1 should be
> out any day. Will Raven be kept in sync with JRuby?
>
I believe it was killed by buildr.

Skoro nie Raven to pozostaje wskazany Buildr. Wyprzedzając fakty, szybko okazało się, że od niego powinienem zacząć.

Po pierwsze jest to projekt spod parasola ASF, więc rokuje nadzieje na zaistnienie. Po drugie, pobieżna lektura dokumentacji utrwala mnie w przekonaniu, że warto się zainteresować tym projektem, gdyż jego główną zaletą jest tworzenie konfiguracji programując w JRuby. Zero XMLa, którego powoli mam dosyć.

Akurat wczoraj wyszła nowa wersja JRuby 1.1 RC1, więc czym prędzej zabrałem się do instalacji JRuby, aby z nim uruchomić Buildr.

Zgodnie z Getting Started rozpoczynam od polecenia gem install buildr.

jlaskowski@dev ~
$ type gem
gem is /cygdrive/c/apps/jruby/bin/gem

jlaskowski@dev ~
$ gem install buildr
Error opening script file: C:/apps/cygwin/home/jlaskowski/cygdrive/c/apps/jruby/bin/gem (The system cannot find the path specified)

Szybko okazuje się, że rozwiązaniem jest skorzystanie z polecenia gem z projektu rubygems 1.0.1. Instalacja najnowszego wydania rubygems, ustawienie PATH i ponowne podejście.

jlaskowski@dev ~
$ export PATH=`cygpath -u C:/apps/rubygems/bin`:$PATH

jlaskowski@dev ~
$ type gem
gem is /cygdrive/c/apps/rubygems/bin/gem

jlaskowski@dev ~
$ gem

RubyGems is a sophisticated package manager for Ruby. This is a
basic help message containing pointers to more information.

Usage:
gem -h/--help
gem -v/--version
gem command [arguments...] [options...]

Examples:
gem install rake
gem list --local
gem build package.gemspec
gem help install

Further help:
gem help commands list all 'gem' commands
gem help examples show some examples of usage
gem help platforms show information about platforms
gem help show help on COMMAND
(e.g. 'gem help install')
Further information:
http://rubygems.rubyforge.org

jlaskowski@dev ~
$ gem install buildr
Updating metadata for 548 gems from http://gems.rubyforge.org
.................................................................................
.................................................................................
.................................................................................
complete
Building native extensions. This could take a while...
Successfully installed rjb-1.1.1
Successfully installed buildr-1.2.10
2 gems installed
Installing ri documentation for buildr-1.2.10...
Installing RDoc documentation for buildr-1.2.10...

Kolejnym krokiem jest stworzenie projektu nadzorowanego przez Buildr. Tu chwila wahania, gdyż nie jestem przekonany, czy projekt powinien już być stworzony (podobnie jak w przypadku Ant), czy mogę go utworzyć na podobieństwo działania archetype w maven. Na razie nie mam odpowiedzi, ale kontynuuję poznawanie buildr.

jlaskowski@dev ~
$ buildr --help
Buildr 1.2.10

Usage:
buildr [-f buildfile] {options} targets...

Options:
--buildfile=FILE (-f)
Use FILE as the buildfile.
--environment (-e)
Environment name (e.g. development, test, production).
--freeze (-F)
Freezes the Buildfile so it always uses Buildr version 1.2.10
--help (-H)
Display this help message.
--nosearch (-N)
Do not search parent directories for the buildfile.
--quiet (-q)
Do not log messages to standard output.
--require=MODULE (-r)
Require MODULE before executing buildfile.
--trace (-t)
Turn on invoke/execute tracing, enable full backtrace.
--unfreeze (-U)
Unfreezes the Buildfile to use the latest version of Buildr
--version (-V)
Display the program version.

For help with your buildfile:
buildr help

Zgodnie z dokumentacją utworzeniem pliku konfiguracji projektu buildfile może zająć się sam buildr, więc częściowo już otrzymałem odpowiedź, że mogę zacząć z pustym katalogiem projektowym.

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ buildr
To use Buildr you need a buildfile. Do you want me to create one?:
1. From directory structure
2. Skip
? 1
Created /cygdrive/c/projs/sandbox/buildr-projekt/buildfile

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ ls -ltr
total 1
-rw-r--r-- 1 jlaskowski None 536 Jan 9 22:30 buildfile

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ cat buildfile
# Generated by Buildr 1.2.10, change to your liking
# Version number for this release
VERSION_NUMBER = "1.0.0"
# Version number for the next release
NEXT_VERSION = "1.0.1"
# Group identifier for your projects
GROUP = "buildr-projekt"
COPYRIGHT = ""

# Specify Maven 2.0 remote repositories here, like this:
repositories.remote << "http://www.ibiblio.org/maven2/"

desc "The Buildr-projekt project"
define "buildr-projekt" do

project.version = VERSION_NUMBER
project.group = GROUP
manifest["Implementation-Vendor"] = COPYRIGHT
end

Mam plik konfiguracji projektu, więc ponownie wywołuję buildr.

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ buildr
(in /cygdrive/c/projs/sandbox/buildr-projekt)
Building buildr-projekt
Testing buildr-projekt

Nie ma żadnego błędu, więc po cichu zakładam, że działa.

Pora na kolejną porcję dokumentacji buildr - Projects.

Wciąż poszukuję odpowiedzi na pytanie o strukturę katalogową projektu. Za czasów Ant należało samemu zadbać o strukturę katalogów i z nią związać (czytaj: manualnie utworzyć) plik build.xml, który był odpowiednikiem Makefile z make. Nie ukrywam, że ostatecznie zamierzałem użyć Mavena do utworzenia struktury katalogowej projektu, a na niej "posadowić" buildr. Pytanie wciąż pozostaje bez odpowiedzi.

Doszukałem się jednakże ciekawego zestawu artykułów, których źródłem był artykuł wprowadzający na InfoQ - Apache to incubate its first Ruby Project: Buildr - Ruby Build System for Java Projects. W zasadzie można powiedzieć, że wspomniany artykuł jest pierwszym jaki należy przeczytać, który wskaże kolejne, co ostatecznie pozwoli na zorientowanie się w sytuacji i podjęcie decyzji, czy Agile or Maven. A jest nad czym się zastanawiać, jeśli wierzyć:

It builds the same except that the scripts have been downsized by 91% from 52 XML abused files to 1 script. But that's not all, Buildr managed to cut the build time by 50%! Even on partial builds, Buildr performs similarly or better than Maven.

Dobrym wprowadzeniem w temat Buildr jest Recenzja Buildr, w którym dowiaduję się kolejnej potrzebnej rzeczy - buildr do dyspozycji udostępnia mam kilka(dziesiąt/set) gotowych do użycia zadań, jak np.

  • clean
  • compile
  • upload
  • install
  • javadoc
  • package
  • test
  • uninstall

W podsumowaniu pada ciekawe stwierdzenie, które zaczyna się u mnie materializować mimo braku doświadczenia z Raven i Buildr:

Overall I believe that Buildr is a much more likely to become the defacto ruby build language, than Raven. If simply because of the active community that Raven seems to lack. So if you are up to replacing the trainwreck that is Maven 2 then I would encourage you to look into Buildr.

Ciekawa uwaga.

Przypominam sobie, że właśnie uruchomienie buildr help wskazuje na dostępne i najczęściej stosowane zadania gotowe do użycia. I jest to napisane w pierwszym poleceniu jakie przyjdzie każdemu nowicjuszowi wykonać przy początkowym rozpoznawaniu buildr (!)

jlaskowski@dev /cygdrive/c/projs/sandbox/buildr-projekt
$ buildr help
(in /cygdrive/c/projs/sandbox/buildr-projekt)
Buildr 1.2.10

Usage:
buildr [-f buildfile] {options} targets...

Top-level projects (buildr help:projects for full list):
buildr-projekt # Moj pierwszy projekt zarzadzany przez Buildr - buildr-projekt

Common tasks:
artifacts # Download all artifacts
build # Build the project
clean # Clean files generated during a build
compile # Compile all projects
default # The default task it build
eclipse # Generate Eclipse artifacts for all projects
help:projects # List all projects defined by this buildfile
help:tasks # List all tasks available from this buildfile
idea # Generate Idea artifacts for all projects
install # Install packages created by the project
javadoc # Create the Javadocs for this project
junit:report # Generate JUnit tests report in reports/junit
package # Create packages
release # Make a release
test # Run all test cases
uninstall # Remove previously installed packages
upload # Upload packages created by the project


For help on command line options:
buildr --help

Using Java 1.5.0_14, Ant 1.7.0.

To run a full build without running any test cases:
buildr test=no
To run specific test case:
buildr test:MyTest
To run integration tests:
buildr integration

Okazuje się, że taką pomoc otrzymamy jedynie w projekcie zarządzanym przez buildr. Zresztą było to napisane przy buildr --help (trzeba było czytać dokumentację oraz wyniki poleceń dokładniej!):

For help with your buildfile:
buildr help

Na dzisiaj koniec, zasypiam z kilkoma pytaniami dotyczącymi Buildr jak np. czy struktura katalogów powinna istnieć przed wprowadzeniem buildr do projektu, czy buildr wspomoże mnie w tej kwestii oraz fundamentalne dla mnie pytanie, jak zbudować ear i uruchomić go na serwerze aplikacji. Istnieje gem dla GlassFish, więc światełko w tunelu jest (oby to było wyjście, a nie nadjeżdżający pociąg ;-)). Przy kolejnym podejściu z pewnością padną te i wiele innych (p)odpowiedzi.

08 stycznia 2008

XXI spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na pierwsze w roku 2008, XXI spotkanie, które odbędzie się we wtorek 8.01.2008 o godzinie 18:00 w sali 5820 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: Okiełznąć Mavena 2
Prowadzący: Piotr Tabor

UWAGA: Spotkanie będzie nagrywane, więc uprasza się o ładne stroje ;-)

Jest rzeczą powszechnie znaną, że informatyka to dziedzina magii. W magii - oprócz zgłębiania wiedzy i czarodziei - rzeczą, która pochłania najwięcej czasu są rytułały magiczne (ot, takie tam tańczenie wokół gara, itp.). Apache Maven jest magicznym narzędziem, które próbuje zajmować się odprawianiem rytułałów za nas. Jednak, żeby to robił w zgodny z naszymi intencjami sposób - my musimy zakląć...Mavena (i pewnie kilkakrotnie na niego również).

Bardzo często można spotkać się z opinią, że lepiej jest używać Anta niż Mavena. A bo to nad Mavenem się nie panuje, że się traci strasznie dużo czasu, by Maven zrobił to, co my chcemy, a nie to, co on chce, i takie tam. Stan taki wynika z kilku rzeczy: strachu użytkowników, braku wiedzy użytkowników, brakach w dokumentacji Mavena i bugów Mavena (i pewnie kilku innych rzeczy, o których wspomnę na spotkaniu, ale jasno wynika z tego, że winą obarczymy użytkowników, bo magia nie jest dla wszystkich).

Spotkanie poświęcone będzie mechanice działania Mavena. Prześledzimy proces od hierachi plików pom.xml do momentu, w którym Maven ma rozwiązane zależności (dependency resolution) - czyli wie, które zależności (najczęściej jary) i w których wersjach są potrzebne. Skupimy się na tym fragmencie dokładniej, gdyż nieco głębsze poznanie jak on działa: 1) pozwoli szybciej uporać się z najczęstymi problemami oraz 2) pokaże jakie są możliwości Mavena i co można zrobić (pisząc pliki pom.xml) sprytniej.

W trakcie spotkania zaprezentowane zostaną narzędzia, które pomogą zobaczyć wyniki cząstkowe działania Maven'a, które pomagają w diagnozie naszych problemów (z tymi życiowymi Maven sobie *jeszcze* nie radzi).

Pełną wartość spotkania można zakosztować eksperymentując z przykładowym projektem 3-modułowym zarządzanym przez Maven jak opisano w dokumencie Maven Getting Started Guide.

Piotr Tabor jest studentem V roku magii na wydziale MIM UW, programistą z niemal 10 letnim doświadczeniem zawodowym. Trzy lata z tego poświęcił zgłębianiu Java EE. Z Mavenem związany od czasów, gdy Jacek zachwycał się nim (Mavenem) na spotkaniach Warszawskiej Grupy Użytkowników Technologii BEA. Skonfrontował entuzjazm Jacka z prawdziwymi przypadkami biznesowymi... ... i po zaledwie tygodniu umiał już skompilować projekt. Z rozwojem Maven'a związany od roku, choć nadal bez uprawnień commitera, uczestnik Google Summer of Code 2007 pod opieką samego Jason'a van Zyl'a (Maven Founder) przy zestawie narzędzi do generowania diagramów dokumentujących różne aspekty analizowanej aplikacji (zależności pomiędzy modułami, schemat klas).

Planowany czas prezentacji to 1,5 godziny.

Wstęp wolny!

Zapraszam w imieniu Piotra i Warszawa JUG!

06 stycznia 2008

W sprawie Recenzja książki "Hibernate. Od Nowicjusza do Profesjonalisty"

6 komentarzy
Hibernate - Od Nowicjusza do ProfesjonalistyNie tak dawno napisałem recenzję do książki Hibernate. Od Nowicjusza do Profesjonalisty wydawnictwa Power Net - Recenzja książki "Hibernate. Od Nowicjusza do Profesjonalisty". Okazało się, że skończywszy książkę miałem tak samo pozytywnych uwag odnośnie jej wydania i zawartości, co i uwag krytycznych, co mogłoby wskazywać na niską jej wartość. Nic bardziej mylnego! Uwagi mają na celu podniesienie wartości książki i są paradoksalnie wyrazem uznania za dobrze przeprowadzone tłumaczenie książki (czasami zastanawiam się, jak często wartość tłumaczenia jest lepsza od oryginału i nie zdziwiłbym się, gdyby w tym przypadku faktycznie tak było).

Nie ukrywam, że ciekaw byłem kto był autorem tłumaczenia, więc niezmiernie się ucieszyłem, kiedy w mojej skrzynce mogłem przeczytać wiadomość następującej treści, którą cytuję za pozwoleniem jej autora. Cytuję jej treść, gdyż sądzę, że warto upubliczniać inicjatywy oczyszczania naszego języka z naleciałości obcojęzycznych, kiedy istnieją ich polskie odpowiedniki, a dodatkowo nigdy nie sądziłbym, że książkę techniczną może przetłumaczyć osoba nietechniczna, tak że wynik będzie wart uwagi. Lektury szkolne były fajne, ale ich czas w moim kalendarzu minął (i tylko czasami do nich wracam sprawdzając moje dzieciaki i ich przygotowanie do lekcji ;-)), więc dzieła filologów zakwalifikowałbym właśnie do kategorii beletrystyka, a nie książka techniczna.

Najciekawszym fragmentem wiadomości jest wyjaśnienie odmiany słowa Hibernate oraz wprowadzenia nazwy serwlet zamiast skorzystania z servlet (co uzasadniałem podobieństwem do słowa volvo).

Witam serdecznie,

jestem tłumaczem polskiego wydania książki "Hibernate. Od nowicjusza do profesjonalisty" dla wydawnictwa Power Net. Chciałbym Panu podziękować za rzetelną i wnikliwą recenzję książki. Na pewno razem z wydawnictwem wiele na tym skorzystam, tym bardziej że była to moja pierwsza tłumaczona książka, a Power Net też jest nowym wydawnictwem.

Cieszą mnie Pańskie pochlebne uwagi dotyczące tłumaczenia (a z uwag krytycznych na pewno wyciągnę wnioski). Jeśli przekład ten miał swoje zalety, to były one efektem pracy całego zespołu. Ja sam nie jestem programistą, a filologiem (skończyłem polonistykę i anglistykę), więc ogromne dla mnie znaczenie miała korekta merytoryczna zapewniona przez wydawcę.

Nie będę się ustosunkowywał do wszystkich Pańskich uwag, ale chciałbym się odnieść do kilku z nich i ewentualnie wytłumaczyć się z pewnych swoich wyborów translatorskich (nie na wszystko miałem też wpływ - jak np. użycie słowa "framework" a nie choćby "szkielet aplikacji", "log" zamiast "dziennik zdarzeń", bo były to też decyzje wydawcy).

Po pierwsze (i to chyba Pana najbardziej raziło) - odmiana słowa "Hibernate". Wyszedłem z założenia, że jeśli programiści w rozmowach ze sobą odmieniają ten wyraz (a to jest po prostu naturalne), to należy tę odmianę zachować również w piśmie. Co się tyczy samego zapisu - tutaj reguły ortograficzne są jednoznaczne, ponieważ w tego rodzaju słowach zakończonych na "e" niewymawiane trzeba w przypadkach zależnych użyć apostrofu, a więc pisać "Hibernate'a", "Hibernate'em" (tutaj mamy obok siebie dwa "e"), "Hibernate'owi". Ma to tę zaletę, że zawsze w niezmienionej postaci pozostaje wyraz zapożyczony, co ma znaczenie w przypadku nazw własnych, nazw firm itd. Jedynym wyjątkiem byłby miejscownik, w którym powinno się pisać "Hibernacie", jednak aby zanadto nie razić taką formą czytelników, decydowałem się ją omijać i pisać zamiast "o Hibernacie" np. "o frameworku Hibernate".

Słowo "Linux" nie kończy się na samogłoskę, więc apostrofy nie są tam potrzebne, a właściwie byłyby nawet błędne (notabene, również wśród językoznawców panuje spór dotyczący odmiany: Linuxa czy Linuksa - jest tutaj dopuszczalna wariantywność odmiany, choć w miejscowniku zawsze musi być Linuksie). Pańskie porównanie do wyrazów obcych zakończonych na "-o" typu radio", kakao" nie było może najtrafniejsze, ponieważ słowa te są w języku polskim nieodmienne (choć coraz częściej "radio" jest odmieniane przez przypadki, jednak odmienianie "kakao" jest bardzo potoczne i nie może pojawić się w druku) - natomiast z moich obserwacji wynika, że programiści jednak w rozmowach często odmieniają słowo "Hibernate" (bo nie ma ku temu przeciwwskazań, dlatego że język polski jest językiem fleksyjnym i stara się włączać zapożyczenia w jakiś najbliższy im paradygmat odmiany), a problem dotyczy tylko zapisu, i to jest już regulowane zasadami ortograficznymi (które przedstawiłem w dużym uproszczeni!
u - piszemy dlatego np. Juliusza Verne'a, Ala Gore'a itd.).

Aby się zanadto nie rozpisywać, to wspomnę jeszcze, że wydawało mi się, iż zamienne stosowanie słów "wczytywanie" i "ładowanie" nie wprowadzi czytelnika w błąd, a może uniknąć pewnej monotonii stylistycznej i powtórzeń (rozumiem, że przy innego rodzaju terminach należy bezwzględnie zachować konsekwencję w tłumaczeniu, ale w tym wypadku chyba nie wprowadziło to zamieszania, bo słowa te są powszechnie rozumiane i można traktować je właściwie jako synonimy, przy czym "ładowanie" wydaje się bardziej potocznym wariantem).

I już ostatnia sprawa - "serwlet". Wychodzę z założenia, że skoro angielski wyraz "servlet" jest połączeniem słów "server" i "applet", to ponieważ w języku polskim już od dawna funkcjonuje forma "serwer", powinno się zachować konsekwencję i przenieść owo "w" z "serwera" również do "serwletu".

Jeszcze raz dziękuję Panu za kompetentną i bardzo pomocną recenzję wraz z erratą.

Pozdrawiam serdecznie,

Marcin Leszczyński

03 stycznia 2008

Więcej atrakcji javowych w 2008!

5 komentarzy
Koniec roku 2007 i rozpoczęcie 2008 spędziłem z rodziną w Bukowinie Tatrzańskiej. W zasadzie to większość czasu spędziłem w Białce Tatrzańskiej na stokach Bani i Kotelnicy doskonaląc swój warsztat narciarski. Brzmi wyniośle, a sprowadza się do doskonalenia panowania nad nartami, kiedy te decydują się na ruch wbrew oczekiwaniom narciarza. Wydawałoby się, że zjazd na nartach nie należy do trudnych. Nic bardziej mylnego! To samo możnaby w końcu powidzieć o programowaniu w Javie, czy tworzeniu aplikacji korporacyjnych z Java EE. Należę do tego grona narciarzy, którym daleko do określenia średniozaawansowany, więc kiedy przyszła pora na naukę techniki, zamiast utrwalania niedoskonałości (które jakkolwiek pozwalają mi na zjazd bez upadku, to angażują wszystkie możliwe mięśnie, stawy, nerwy, itp.), okazało się, że tak niewiele trzeba, aby doświadczenie wzrosło znacząco w zaskakująco krótkim czasie (przez doświadczenie rozumiem baczniejsze przywiązywanie uwagi do jazdy na krawędziach oraz testy weryfikujące na nowej trasie na Kotelnicy - numer 13). Kilka trafnych uwag i zaleceń instruktora, wskazówki od doświadczonego narciarza (ukłony dla Sławka) i w końcu podpowiedzi mojej żony, która po lekcji z instruktorem dla początkujących "sprzedała" mi tzw. "krakowiaka" (zjazd szkoleniowy z ręką od stoku w górze, z drugą w pasie, która powoduje wygięcie ciała ku stokowi, powodując ostatecznie jazdę na krawędziach) i już widać postępy. Generalnie ubaw po pachy. Upadki były, bolące nogi są, i dobry humor również. Było tak wspaniale, że nie daje mi spokoju myśl o powrocie do Białki za 4-6 tygodni i tak jeszcze kilkakrotnie. Może tak jakiś projekt informatyczny w okolicy?! Warto się nad tym zastanowić, bo przyjemnie w Białce zimą i gdyby tak połączyć przyjemne z pożytecznym byłoby ciekawie.

Zabawa zabawą, ale okazuje się, że i w niej można znaleźć wiele pouczającego dla nauki nowych technologii informatycznych. Widzę tutaj same analogie. Weźmy na początek podstawy. Często o nich zapominamy, traktując je jako zbędne dodatki, o których wiemy, że istnieją, ale ich znajomość praktyczna jest znikoma (najbardziej "wychodzi", kiedy podchodzimy do certyfikatu, np. SCJP, SCBCD lub SCEA). Osobiście, często doskwiera mi brak owej "podstawowej" wiedzy, szczególnie podczas rozmowy z adeptami sztuki programowania w Javie. Wiele pytań w stylu Jak zacząć? pada na grupach, czy w bezpośredniej rozmowie i trudno cokolwiek doradzić bardziej trafniejszego niż Próbuj, upadaj, wstawaj i tak na okrągło, aż znajdziesz swój, własny sposób na doskonalenie warsztatu. Bardzo ważna jest rozmowa z osobami zaawansowanymi w danej technologii, ale nie można zapominać o początkujących, gdyż ich pytania już wielokrotnie "sprowadziły" mnie na ziemię. Gromadzenie doświadczeń za pomocą lektury blogów, podcastów, artykułów, książek i wdrażanie zdobytej wiedzy praktycznie jest w/g mnie najważniejszym elementem każdej osoby pretendującej do miana profesjonalisty. Moim mottem przewodnim jest ciągła konfrontacja wiedzy publicznie, gdzie moje wpadki natychmiast wyłapywane są przez słuchających/czytających powodując, że kolejne publiczne wystąpienia mają szanse być doskonalszymi. Jest kilka rzeczy w Javie, z którymi planuję się zapoznać w roku 2008 i jedynym, potencjalnym problemem może być co najwyżej brak czasu. Napisałem "co najwyżej", gdyż faktycznie nie jest to żaden problem, jeśli założyć, że na naukę potrzeba dziennie kilka minut. Jeśli systematycznie podejdę do owych nowinek, rozpoczynając od dokumentów wprowadzających, jak specyfikacje, podręczniki, czy 5-minutowe ćwiczenia można "spacyfikować" każdy problem, nawet i ten związany z czasem. Weryfikowanie zdobywanej wiedzy w działaniu powinno stać się nieodzownym elementem otwarcia dnia. Najważniejsze, aby próbować, improwizować i nie obawiać się porażek. Ciągłe wystawianie wiedzy publicznie pozwala na wyłapanie błędów w bardzo krótkim czasie. Osobiście uważam, że to brak porażek jest największą porażką, więc spodziewam się, a wręcz oczekuję ich na każdym kroku. Takim podsumowującym powiedzeniem mógłby być Experience is simply the name we give our mistakes Oscara Wilde'a. Gość wiedział, co mówi. Mnie przekonał.

Szczęśliwego nowego roku 2008!

p.s. Byłoby całkowicie doskonale, gdyby nie ten powrót do Warszawy Zakopianką, gdzie przejechanie trasy od 11:00 2-iego zajęło mi 13 godzin (!). Jeśli dodać do tego niedozwolone prędkości w międzyczasie możnaby zastanawiać się, co ja robiłem z rodziną w samochodzie?! O przegrzanym silniku nie wspomniając (coś nie tak z chłodzeniem w rocznym Fordzie!).

p.s.2 Właśnie natrafiłem na zdjęcie z 93. roku z moją żoną na jej studniówce! Ale czasu minęło. Glanów już nie ma...rozpadły się. Może ktoś z czytających był na tej studniówce również?!