czwartek, 3 września 2009

Configuring HermesJMS to work with Tibco

I assume that you have Tibco installed in <TIBCOHOME>

1) Download & install HermesJMS. I assume that <HERMES_HOME> is the installation directory for Hermes.
2) Copy <TIBCOHOME>/ems/clients/java/*.* into <HERMES_HOME>/lib. There is no need to overwrite existing files.
3) For next steps, there is a presentation prepared here and we will follow it with the following note: See the first step of the presentation, then stop and come back here :) In the first step the presentation shows already prepared, long list of providers. To work with Tibco, we will only need one provider, which we have to add manually. To add a provider, go to Providers tab in Preferences dialog, right click under Classpath Groups, select Add Group and type the name (i.e. Tibco Ems). When the provider appears on the list, expand it's subtree to see the Library item. Right click on Library and select Add JAR(s). Add all JARs in <TIBCOHOME>/ems/clients/java directory. Click Apply, then OK to close Preferences window. Continue with step 2 of the presentation.

In Step 3, don't be surprised if just after selecting the Loader from the dropdown list, the list will disappear. It actually didn't dissapear, it's just behind the right edge of the dialog, and you can see it again, if you resize the dialog.

Good luck!

poniedziałek, 31 sierpnia 2009

JDK5, Ubuntu i Summer Time

Zacznijmy od tego że jestem właśnie w trakcie przesiadki na Linuksa, a konkretnie Kubuntu.

Pierwszy poważny problem który napotkałem dotyczy strefy czasowej widzianej przez Jave. Konfiguracja:

1) JRE6 zainstalowane "z paczki" (za pomocą aptitude), aby za jego pomocą uruchamiać Javowe narzędzia, aplety w przeglądarce itp.
2) JDK5 ściągnięte od Suna i rozpakowane. Służy do celów deweloperskich. Tutaj wskazuje JAVA_HOME.

Problem polegał na tym że Java w JDK nie uwzględniała przesunięcia czasu letniego (w zainstalowanym "z paczki" JRE jest OK). Po kilku godzinach rwania włosów z głowy znalazłem to zgłoszenie buga. W tytule mowa jest co prawda o JDK6, ale jak się okazuje pasuje również do wersji 5. Wykonałem z drobną zmianą to co tam jest opisane, czyli:

sudo cp /etc/localtime /etc/localtime.bak
sudo ln -s -f /usr/share/zoneinfo/Europe/Warsaw /etc/localtime
i po problemie. Weird...

P.S.
Jaki komunikator polecacie? Najlepsze by było coś co obsłuży zarówno GG jak i Jabbera.

środa, 12 sierpnia 2009

Testowalny kod

Mamy sezon ogórkowy, więc tylko krótki post o tym co niezwykle ważne, nawet w wakacje. Świetny artykuł Misko Hevery zatytułowany Writing Testable Code. Artykuł kieruje do mini-książki w formacie PDF zawierającej praktyczne przykłady jak istniejący, kiepski kod doprowadzić do sensownej i testowalnej postaci. Autorzy wykorzystują framework Guice, ale koncepcyjnie proponowane rozwiązania są uniwersalne.
Planuję również przyjrzeć się projektowi Testability Explorer, którego współautorem jest Misko, a który umożliwia analizowanie kodu pod względem testowalności (statyczna analiza bytecodu z tego co na szybko wyczytałem). Na razie ściągnąłem źródła i przekonałem się na własne oczy, że możliwości oferowane przez Guice są naprawdę bardzo ciekawe.

Miłej lektury!

wtorek, 7 lipca 2009

Manifesto for Software Craftsmanship




Nie ma już odwrotu :) Świadomy praw i obowiązków, pełen chęci ciągłego doskonalenia swego rzemiosła podpisałem dziś manifest. Do czego gorąco także i Ciebie zachęcam, jeśli nie jest Ci obca troska o jakość Twojej pracy.

niedziela, 5 lipca 2009

Javarsovia 2009 za nami

Największa bezpłatna konferencja polskiej społeczności javowej niestety już za nami. Piszę niestety, ponieważ to wydarzenie było niewątpliwym sukcesem i chciałoby się mieć takie konferencje co tydzień ;) Na Javarsovii nie zabrakło ciekawych prezentacji i niejednokrotnie ciężko było mi się zdecydować który wykład o danej godzinie wybrać. Szkoda mi kilku wykładów, które zmuszony byłem ominąć - mam nadzieję że organizatorzy szybko udostępnią filmy z konferencji i będzie można nadrobić tę stratę. Szczególnie żałuję wykładu Szczepana Fabra na temat testowania - ten temat od dłuższego czasu coraz bardziej mnie wciąga a wczoraj nie wiedzieć czemu poszedłem na Cloud Computing, który szczerze mówiąc trochę rozczarował... Uczestniczyłem już kiedyś w (rewelacyjnej zresztą) prezentacji Szczepana na temat Mockito (chyba było to na JDD) i tym razem pomyślałem że również będzie o Mockito - dlatego wybrałem inny wykład... Ominęła mnie także prezentacja Łukasza Lipki z naszego rodzimego Silesia JUG nt. Mule ESB. Łukasz mówił już kiedyś o Mule na spotkaniu JUGa, chociaż na Javarsovii na pewno rozszerzył jeszcze i tak ciekawą prezentację ;)

To może teraz coś o wykładach na których byłem :) Wymienię trzy, które zrobiły na mnie największe wrażenie, dostarczyły najwięcej nowej wiedzy - wybór oczywiście subiektywny.

Konrad Kamiński przedstawił Garbage First - nowy garbage collector w maszynie HotSpot. Szczerze przyznam, że przed tym wykładem nie miałem pojęcia jak działają wewnętrzne algorytmy GC a wykład Konrada dał dużo światła na ten jakże ważny temat. Nowy GC wygląda ciekawie, a możliwość określenia ile maksymalnie czasu może zajmować jego praca w danym odcinku czasu jest w aplikacjach serwerowych bardzo pożądana.

Kolejnym świetnym wykładem był wykład Jarosława Kijanowskiego na temat Drools Guvnor. Temat mi osobiście bliski, ponieważ używam Drools w projekcie nad którym obecnie pracuję. Jarek poprowadził prezentację w bardzo ciekawy, luźny sposób oraz - co należy podkreślić - pominął wiele niepotrzebnych detali technicznych które z punktu widzenia meritum tematu były nieistotne a jedynie zaciemniłyby obraz. Tej umiejętności niestety wciąż brakuje wielu polskim prelegentom, którzy potrafią zasypać słuchacza tonami XMLi wylewających się z projektora... Oprócz Guvnor'a Jarek zaprezentował również Drools CEP (Complex Event Processing) które pozwala na podejmowanie decyzji nie tylko na podstawie bieżących faktów, ale również "patrząc wstecz" (np 10 ostatnich zdarzeń, zdarzenia z ostatnich 20min) - ciekawa sprawa. Nie próbowałem jeszcze użyć Drools CEP, ale wygląda na to, że może być on darmową, opensource'ową konkurencją dla Oracle CEP.

Ostatnim wykładem na który się wybrałem był Spring TestContext Framework Jakuba Milkiewicza. Bardzo, bardzo ciekawy wykład poprowadzony w świetnym stylu. Publiczność wręcz domagała się przedłużenia prezentacji i przedstawienia jeszcze kilku przykładów. Do tej pory używałem małej części tego mini-frameworku, ale po tym wykładzie na pewno to się zmieni. Muszę się również przyjrzeć HamCrest'owi, którego Jakub używał do tworzenia asercji.

Na koniec dygresja na temat organizacji konferencji. To że organizatorzy DARMOWEJ konferencji zorganizowali DARMOWY lunch dla wszystkich uczestników - to jak dla mnie (jako głodomora) mistrzostwo świata!!! Poza tym ogólnie nie było rzeczy do której można by się przeczepić :) Wykłady ciekawe, żołądek pełny, sale dobre, miejsca dosyć, widoczność dobra itd itp. Podnieśliście poprzeczkę Panowie!

czwartek, 11 czerwca 2009

Pragmatyczny programista

Właśnie skończyłem czytać książkę "Pragmatyczny programista. Od czeladnika do mistrza". Nie będę odosobniony, jeśli powiem, że każdy programista powinien tę książkę przeczytać. Ten post jest zgrupowaniem haseł i zasad, które dla mnie osobiście były najciekawszą nauką płynącą z tej lektury. Większość z nich to tematy znane, ale moim zdaniem na tyle ważne żeby jeszcze raz o nich powiedzieć i podkreślić ich znaczenie.

Wybite okno
Kiedy w bloku pojawi się wybite okno i nikt dostatecznie szybko tego nie naprawi, szybko pojawią się kolejne wybite okna i inne oznaki postępującego zniszczenia. Podobna zasada dotyczy kodu źródłowego - nie pozostawiaj w swoich systemach wybitych okien (zły kod, antywzorce, błędne decyzje projektowe, work-around'y). Nie dopuszczaj do powstania "ogniska rozkładu" Twojego systemu.

Ortogonalność

Poruszając się wzdłuż osi pionowej, rzut aktualnego położenia na oś poziomą nie zmienia się. Tak powinny być zaprojektowane systemy informatyczne: zmiany w module A nie powinny być zauważone przez moduł B. Oba moduły powinny komunikować się za pomocą dobrze zdefiniowanych interfejsów, a szczegóły implementacji powinny być ukryte tak, aby każdy z modułów mógł zostać zmieniony, a nawet zastąpiony bez konieczności zmian w pozostałych modułach.

Prawo Demeter (zasada minimalnej wiedzy)
W dużym skrócie: rozmawiaj tylko z obiektami z własnego otoczenia. Nie wyciągaj z nich innych obiektów ("wnętrzności") aby z nimi porozmawiać (byłoby to wnikanie w implementację). Niech obiekt nadrzędny odpowiednio oddeleguje wywołania, sam decydując jak chce zrealizować zadany cel. Zamiast:
car.getOnboardComputer().getGPS().getLocation();
napisz
car.getLocation()
pozostawiając klasie Car decyzję, jak zaimplementować określanie lokalizacji.

Pociski smugowe
Autorzy nazwali tak technikę podobną nieco do prototypowania, która zaleca stworzenie na początku rozwiązania bardzo ubogiego, ale przechodzącego przez wszystkie warstwy i stanowiącego bazę dla dalszego rozwoju systemu. W odróżnieniu od prototypu, rozwiązanie to nie trafia do kosza po sprawdzeniu że działa, lecz staje się integralną częścią systemu, wokół której tworzone są kolejne funkcjonalności aż do zakończenia projektu. Nazwa pociski smugowe wzięła się z tego, że stworzony kod pozwala stwierdzić, czy projekt "trafia do celu" czyli idzie w dobrym kierunku już na początku, posiadając zaimplementowaną jedynie najmniejszą możliwą część funkcjonalności. Dziś w dobie agile, chyba bardzo często stosowana technika ;)

Odwracalność
Podejmuj decyzje odwracalne. Przygotuj się na to, że klient zechce zmienić wersję, lub nawet producenta bazy danych, serwer aplikacyjny etc...

Programowanie przypadkowe
Fred nie wie dlaczego program nie działa, ponieważ wcześniej nie wiedział, dlaczego program działał.

Poznaj API
i technologie które używasz, aby nie tworzyć kodu na oślep, kodu który działa przez przypadek.

Testowanie jednostkowe
jest jak testowanie układów scalonych - sygnały podane na odpowiednie wejścia powodują odpowiednie stany na wyjściach.

DRY
Na temat tej zasady nie będę się powtarzał :)

czwartek, 21 maja 2009

JBoss Drools - działająca aplikacja w 10 minut

Postanowiłem stworzyć minimalną aplikację JavaSE korzystającą z silnika reguł JBoss Drools oraz tablic decyzyjnych zapisanych w postaci arkuszy Excela. Poniżej przedstawiam moje wyniki. Najważniejszą wytyczną podczas tworzenia tej aplikacji była prostota, aby zobaczyć jakie minimalne kroki są konieczne aby uruchomić Drools. Dlatego też aplikacja jest pozbawiona kontroli błędów, walidacji parametrów itp - nie o to tu chodziło.

No to się wytłumaczyłem - teraz do dzieła :)

Zaczynamy od stworzenia tablicy decyzyjnej:
Podstawowym pojęciem w tematyce tablic decyzyjnych jest fakt - na nasze potrzeby możemy zdefiniować to pojęcie jako obiekt Javowy umieszczony w pamięci roboczej (working memory) silnika reguł w trakcie jego uruchamiania, lub też powstały "wewnątrz silnika" jako rezultat działania którejś reguły. W naszym przykładzie występują tylko fakty umieszczone w pamięci roboczej "z zewnątrz". Fakty posiadają atrybuty, czyli w naszym przypadku właściwości (properties) obiektów Javowych. Drools umożliwia tworzenie warunków na konkretną wartość pola obiektu - oczywiście musimy trzymać się konwencji JavaBeans.

Definicja tabeli zaczyna się w komórce oznaczonej tekstem RuleTable . W kolejnym wierszu wpisujemy nagłówki oznaczające rolę danej kolumny w tabeli - condition (warunek) lub action (konsekwencja, akcja). Kolejne dwa wiersze służą do definiowania szczegółów warunku lub akcji. Warunkiem może być np. istnienie jakiegoś faktu (komórka B9) lub konkretna wartość atrybutu faktu (komórki C8 i C9 - tutaj odnosimy się do wartości atrybutu name faktu typu Activity a kolejne wiersze są potencjalnymi wartościami tego pola). Tabela zawiera dwie reguły (wiersze 11 i 12):
  1. Istnieje Student oraz istnieje Activity o nazwie fun
  2. Istnieje Student oraz istnieje Activity o nazwie learning
Dla obu reguł istnieje wspólna akcja, zdefiniowana jako fragment kodu Javy - dodanie Stringa do listy. $param oznacza wartość z komórki wybranej jako przecięcie bieżącej kolumny (akcji) i wiersza uruchomionej reguły. Jeśli więc silnik reguł zostanie zasilony faktem Student oraz faktem Activity o atrybucie name równym learning - wówczas zostanie uruchomiona akcja pierwszej reguły. Jeśli dodatkowo pojawi się fakt Activity o atrybucie name=fun, zostanie również uruchomiona akcja drugiej reguły. Kilka faktów umieszczonych w pamięci roboczej (working memory) silnika reguł może spowodować uruchomienie wielu reguł. Bardziej szczegółowe informacje można znaleźć w dokumentacji. Na uwagę zasługuje jeszcze sekcja Variables, która umożliwia zdefiniowanie zmiennych. Pozwala to na bardzo proste zwracanie wyników działania reguł - uruchamiając silnik reguł można za pomocą metody setGlobal przekazać referencję do obiektu Javowego, który będzie reprezentował daną zmienną zdefiniowaną w regułach. W naszym przykładzie do zwrócenia listy jako rezultatu działania reguł stosujemy konstrukcję:
...
List rulesEvaluationResult = new ArrayList();
statelessDroolsSession.setGlobal("resultList", rulesEvaluationResult);
Uruchom_reguły

Po jej wykonaniu rulesEvaluationResult zawiera wynik działania reguł czyli to co wewnątrz tablicy decyzyjnej wkładamy do zmiennej resultList.

Mając już gotową tablicę decyzyjną możemy przystąpić do tworzenia aplikacji. Zaczynamy od stworzenia projektu wykorzystując Maven'a:
mvn archetype:create -DgroupId=pl.kadamczyk.droolssample -DartifactId=DroolsSample

Edytujemy plik pom.xml tak aby znajdowały się w nim następujące zależności:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.kadamczyk.droolssample</groupId>
<artifactId>DroolsSample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>DroolsSample</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>4.0.7</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>4.0.7</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>4.0.7</version>
</dependency>
</dependencies>
</project>


Jeszcze tylko
mvn install
oraz
mvn eclipse:eclipse
i importujemy projekt do Eclipse.

Dodajemy do projektu klasę, której zadaniem jest stworzenie bazy reguł (RuleBase) na podstawie dostarczonego do niej pliku XLS (jego nazwy):
package pl.kadamczyk.droolssample;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.Properties;

import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.compiler.DroolsParserException;
import org.drools.compiler.PackageBuilder;
import org.drools.compiler.PackageBuilderConfiguration;
import org.drools.decisiontable.InputType;
import org.drools.decisiontable.SpreadsheetCompiler;
import org.drools.rule.Package;

public class DecisionTableXlsCompiler {

public RuleBase compileToRuleBase(final String decisionTablesXlsFile) throws Exception {
RuleBase result = RuleBaseFactory.newRuleBase();

final InputStream resourceAsStream = DecisionTableXlsCompiler.class.getResourceAsStream(decisionTablesXlsFile);
final String drl = compileXlsToDlr(resourceAsStream);
Package rulePackage = this.buildPackageFromDrl(drl);
result.addPackage(rulePackage);
return result;
}

private Package buildPackageFromDrl(final String drlString) throws DroolsParserException, IOException {
Properties properties = new Properties();
properties.setProperty("drools.dialect.java.compiler", "JANINO");
properties.setProperty("drools.dialect.java.lngLevel", "1.5");

final PackageBuilderConfiguration pkgBuilderCfg = new PackageBuilderConfiguration(properties);
final PackageBuilder builder = new PackageBuilder(pkgBuilderCfg);

Reader drlReader = new StringReader(drlString);
builder.addPackageFromDrl(drlReader);

Package result = builder.getPackage();

return result;
}

private String compileXlsToDlr(final InputStream xlsStream) {
final SpreadsheetCompiler compiler = new SpreadsheetCompiler();
final String drl = compiler.compile(xlsStream, InputType.XLS);
return drl;
}

}

Oraz klasę, która uruchamia silnik reguł ze skompilowaną wcześniej bazą reguł, zasilając go faktami:
package pl.kadamczyk.droolssample;

import java.util.List;

import org.drools.RuleBase;
import org.drools.StatelessSession;

public class DroolsEvaluator {

public <T> void run(RuleBase ruleBase, final String outParamName, T outParamRef, final List<Object> facts) {
final StatelessSession statelessDroolsSession = ruleBase.newStatelessSession();
statelessDroolsSession.setGlobal(outParamName, outParamRef);
statelessDroolsSession.execute(facts);
}

}

I już możemy tą aplikację uruchomić:
package pl.kadamczyk.droolssample;

import java.util.ArrayList;
import java.util.List;

import org.drools.RuleBase;

import pl.kadamczyk.droolssample.model.Activity;
import pl.kadamczyk.droolssample.model.Student;

public class Runner {

public static void main(String[] args) throws Exception {
DecisionTableXlsCompiler compiler = new DecisionTableXlsCompiler();
DroolsEvaluator evaluator = new DroolsEvaluator();

List<Object> rulesResult = new ArrayList<Object>();

RuleBase ruleBase = compiler.compileToRuleBase("decisiontable.xls");
evaluator.run(ruleBase, "resultList", rulesResult, prepareFacts());

for (Object obj : rulesResult) {
System.out.println(obj);
}
}

private static List<Object> prepareFacts() {
List<Object> facts = new ArrayList<Object>();
Activity learningActivity = new Activity();
learningActivity.setName("learning");
facts.add(learningActivity);
Activity funActivity = new Activity();
funActivity.setName("fun");
facts.add(funActivity);
facts.add(new Student());

return facts;
}
}

Uruchomienie powyższego przykładu spowoduje wypisanie na konsoli napisu:
Student is having fun
Student is learning


co jest zgodne z oczekiwaniami, ponieważ przekazane do silnika reguł fakty (obiekty utworzone w metodzie prepareFacts() ) spełniają obie reguły.