<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sławomir Czerwiński</title>
	<atom:link href="http://czerwinski.info.pl/feed/" rel="self" type="application/rss+xml" />
	<link>http://czerwinski.info.pl</link>
	<description>o mnie, mojej pracy, moich zainteresowaniach</description>
	<lastBuildDate>Sat, 28 Jan 2012 21:40:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Fabryki testów</title>
		<link>http://czerwinski.info.pl/2011/02/fabryk-testow/</link>
		<comments>http://czerwinski.info.pl/2011/02/fabryk-testow/#comments</comments>
		<pubDate>Sat, 05 Feb 2011 11:00:16 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[TestNG]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=871</guid>
		<description><![CDATA[Długo nosiłem się z&#160;zamiarem napisania czegoś na temat fabryk testów w&#160;TestNG. W&#160;końcu napisałem&#8230; Zapraszam do pobrania Software Developer&#8217;s Journal&#160;3-2011 i&#160;przeczytania artykułu ze strony&#160;50.]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Długo nosiłem się z&nbsp;zamiarem napisania czegoś na temat fabryk testów w&nbsp;TestNG. W&nbsp;końcu napisałem&hellip;</p>
<p>Zapraszam do pobrania <a target="_blank" href="http://sdjournal.org/magazine/1637-cucumber-rspec">Software Developer&#8217;s Journal&nbsp;3-2011</a> i&nbsp;przeczytania artykułu ze strony&nbsp;50.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2011/02/fabryk-testow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>O Java Killerach słów kilka</title>
		<link>http://czerwinski.info.pl/2010/08/o-java-killerach-slow-kilka/</link>
		<comments>http://czerwinski.info.pl/2010/08/o-java-killerach-slow-kilka/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 08:00:32 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[BlackBeltFactory]]></category>
		<category><![CDATA[JavaBlackBelt]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=855</guid>
		<description><![CDATA[Okres letni oznacza lepszą pogodę. Zamiast siedzieć przed komputerem, w&#160;wolnym czasie można pójść na spacer do parku albo wyjechać gdzieś nad wodę. Niestety oznacza to mniej wpisów na blogu. Już się poprawiam&#8230; Pod moim ostatnim wpisem bardzo szybko pojawiło się kilka komentarzy. Okazuje się, że zdania na temat tzw.&#160;Java Killers są podzielone. Dla tych, którzy [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Okres letni oznacza lepszą pogodę. Zamiast siedzieć przed komputerem, w&nbsp;wolnym czasie można pójść na spacer do parku albo wyjechać gdzieś nad wodę. Niestety oznacza to mniej wpisów na blogu.</p>
<p>Już się poprawiam&hellip;</p>
<p>Pod moim ostatnim wpisem bardzo szybko pojawiło się kilka <a href="http://czerwinski.info.pl/2010/06/ile-wynosi-100/#respond">komentarzy</a>. Okazuje się, że zdania na temat tzw.&nbsp;<em>Java Killers</em> są podzielone.</p>
<p>Dla tych, którzy nie mieli jeszcze okazji zetknąć się z&nbsp;omawianym pojęciem &ndash; <em>Java Killers</em> to pytania mające na celu udowodnić programiście Java, że właściwie nie zna języka Java.</p>
<p>Dla większości komentujących, pytania takie nie są niczym trudnym. Jednak szczególnie zainteresowała mnie następująca wypowiedź:</p>
<blockquote><p>No coż, ja wolę pracować z&nbsp;dobrym programistą niż z&nbsp;nawet wybitnym specjalistą od języka :] ale co kto lubi</p>
</blockquote>
<p>Od razu napiszę, że ja też. Z&nbsp;doświadczenia wiem, że dobry programista szybko nauczy się nowego języka. Z&nbsp;kolei wybitny specjalista od języka potrafi być fatalnym i&nbsp;niereformowalnym programistą. A&nbsp;jednak&hellip;</p>
<p>Jednak są powody, dla których warto być wybitnym specjalistą od języka.</p>
<p>Po pierwsze, specjalista od języka czasem się przydaje w&nbsp;zespole. Wprawdzie wydajność nie jest najważniejszą cechą napisanego kodu, ale przychodzi taki moment, kiedy trzeba przyspieszyć algorytm z&nbsp;kilku minut do jednej sekundy. Wówczas można np.&nbsp;zastąpić proste dodawanie <code>String</code>ów obiektem klasy <code>StringBuilder</code>.</p>
<p>Ale doraźna optymalizacja nie jest jedynym obszarem do wykorzystania specjalisty od języka. Taki człowiek przydaje się także w&nbsp;sytuacji, gdy trzeba doszkolić niedoświadczonego programistę albo na bieżąco wspomagać zespół w&nbsp;problematycznych sytuacjach. Nauczyciel, konsultant czy też coach musi być wybitnym specjalistą, żeby móc uczyć innych.</p>
<p>Na sam koniec pozostawiłem argument, który może stanowić najlepszą motywację dla sceptyków. Aplikując na stanowisko programisty Java należy się przygotować na testy, które często składają się z&nbsp;pytań, jakie można odnaleźć wśród <em>Java Killers</em>. Może nie są to pytania podchwytliwe, ale dotyczą dobrej znajomości języka.</p>
<p>Co można zrobić, by poszerzyć swoją wiedzę? Na początek dobra może być jakaś książka o&nbsp;SCJP. Jednak wszystkim tym, którzy poważnie myślą o&nbsp;programowaniu w&nbsp;języku Java, polecam stronę <a target="_blank" href="http://www.blackbeltfactory.com/ui/ref=sczerwinski">BlackBeltFactory</a>. Dlaczego?</p>
<ul>
<li>Przeglądając pytania w&nbsp;wersji beta i&nbsp;zdając kolejne egzaminy nauczyłem się kilku rzeczy, na które zapewne nigdy nie natknąłbym się jedynie programując.</li>
<li>Dzięki <a target="_blank" href="http://www.blackbeltfactory.com/ui/ref=sczerwinski">BlackBeltFactory</a> dobrze przygotowałem się do testów rekrutacyjnych z&nbsp;języka Java.</li>
<li>Zdobywszy niebieski pas, mogłem zapisać się do grupy JavaBlackBelt na LinkedIn.</li>
<li>Podczas nauki, w&nbsp;każdej chwili mogę skorzystać z&nbsp;pomocy któregoś z&nbsp;wielu coachów. Mogę też sam uczyć innych.</li>
<li>Materiał dostępny na <a target="_blank" href="http://www.blackbeltfactory.com/ui/ref=sczerwinski">BlackBeltFactory</a> nie ogranicza się jedynie do programowania w&nbsp;języku Java. Są tam też egzaminy z&nbsp;Groovy, Ruby, .NET czy też zagadnień ogólnych, jak programowanie obiektowe.</li>
</ul>
<p>Każdego, kto chciałby się zarejestrować na BlackBeltFactory, zapraszam <a target="_blank" href="http://www.blackbeltfactory.com/ui/#Register/recruiter=sczerwinski/ref=sczerwinski">na tę stronę</a>.</p>
<p>Chyba dzisiaj wyszedł mi wpis reklamowy, ale trudno. Strona naprawdę jest warta polecenia.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/08/o-java-killerach-slow-kilka/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ile wynosi $100?</title>
		<link>http://czerwinski.info.pl/2010/06/ile-wynosi-100/</link>
		<comments>http://czerwinski.info.pl/2010/06/ile-wynosi-100/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 11:30:05 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[BlackBeltFactory]]></category>
		<category><![CDATA[JavaBlackBelt]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=842</guid>
		<description><![CDATA[Przeczytałem dzisiaj ciekawy wpis dotyczący egzaminu na technika informatyka. Zawarte w&#160;nim informacje zainspirowały mnie do napisania takiego oto fragmentu kodu: public class Dollars { public static void main(String... args) { int $100 = 50; System.out.println($100); } } Pytanie brzmi: &#8222;Co się stanie?&#8221; Wystąpi błąd kompilacji? Program skompiluje się, ale wystąpi błąd podczas uruchamiania? Program wyświetli [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Przeczytałem dzisiaj ciekawy <a target="_blank" href="http://gynvael.coldwind.pl/?id=318">wpis</a> dotyczący egzaminu na technika informatyka. Zawarte w&nbsp;nim informacje zainspirowały mnie do napisania takiego oto fragmentu kodu:</p>
<pre name="code" class="java">
public class Dollars {
    public static void main(String... args) {
        int $100 = 50;
        System.out.println($100);
    }
}
</pre>
<p>Pytanie brzmi: &bdquo;Co się stanie?&rdquo;</p>
<ol>
<li>Wystąpi błąd kompilacji?</li>
<li>Program skompiluje się, ale wystąpi błąd podczas uruchamiania?</li>
<li>Program wyświetli <code>$100</code>?</li>
<li>Program wyświetli <code>50</code>?</li>
</ol>
<p>Każdy kto przeczyta wspomniany <a target="_blank" href="http://gynvael.coldwind.pl/?id=318">artykuł</a> z&nbsp;pewnością od razu będzie znał odpowiedź. Jednak wszystkim polecam empiryczne przetestowanie powyższego kodu &ndash; to naprawdę ciekawe doświadczenie.</p>
<p>PS.&nbsp;Próbowałem też z&nbsp;<code>$</code>, <code>$$</code> i&nbsp;<code>$_$</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/06/ile-wynosi-100/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Aspektowe warunkowanie algorytmu</title>
		<link>http://czerwinski.info.pl/2010/06/aspektowe-warunkowanie-algorytmu/</link>
		<comments>http://czerwinski.info.pl/2010/06/aspektowe-warunkowanie-algorytmu/#comments</comments>
		<pubDate>Mon, 07 Jun 2010 11:00:32 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Adnotacje]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[AspectJ]]></category>
		<category><![CDATA[Parametr]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[TestNG]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=781</guid>
		<description><![CDATA[W&#160;programach, z&#160;których korzysta wielu różnych użytkowników, moduł ustawień potrafi być bardziej skomplikowany niż sama aplikacja. Większość opcji przyjmuje postać wartości logicznych. W&#160;naszym zespole powstał nawet termin Single Checkbox Requirement (albo Single Checkbox Apocalypse), oznaczający funkcję programu, która może być włączona lub wyłączona i&#160;wpływa na wiele różnych elementów systemu (np.&#160;powiadomienia email). Wprowadzenie jednego SCR do projektu [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>W&nbsp;programach, z&nbsp;których korzysta wielu różnych użytkowników, moduł ustawień potrafi być bardziej skomplikowany niż sama aplikacja. Większość opcji przyjmuje postać wartości logicznych. W&nbsp;naszym zespole powstał nawet termin <em>Single Checkbox Requirement</em> (albo <em>Single Checkbox Apocalypse</em>), oznaczający funkcję programu, która może być włączona lub wyłączona i&nbsp;wpływa na wiele różnych elementów systemu (np.&nbsp;powiadomienia email).</p>
<p>Wprowadzenie jednego <acronym title="Single Checkbox Requirement">SCR</acronym> do projektu generuje kilka(naście/dziesiąt) dodatkowych instrukcji warunkowych. Większa ilość takich wymagań powoduje, że kod źródłowy staje się całkowicie nieczytelny (niezależnie od zastosowanych zabiegów poprawiających jego jakość) &ndash; zwłaszcza, gdy pojawiają się one po pół roku (sic!) pisania aplikacji.</p>
<p>Programowanie aspektowe pozwoliło mi rozwiązać opisany problem szybko i&nbsp;w&nbsp;elegancki sposób.</p>
<p>W&nbsp;przykładzie wykorzystam plik <code>pom.xml</code> opracowany w&nbsp;jednym z&nbsp;wcześniejszych <a target="_blank" href="http://czerwinski.info.pl/2010/05/projekt-maven-z-aspectj/">wpisów</a>. Struktura projektu będzie wyglądać następująco:</p>
<ul class="dir-tree">
<li class="dir">src
<ul>
<li class="dir">main
<ul>
<li class="dir">java
<ul>
<li class="package">pl.info.czerwinski.conditional
<ul>
<li class="file-java"><a href="#Conditional.java">Conditional.java</a></li>
<li class="file-java"><a href="#ConditioningAspect.java">ConditioningAspect.java</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="dir">test
<ul>
<li class="dir">java
<ul>
<li class="package">pl.info.czerwinski.conditional
<ul>
<li class="file-java"><a href="#Calculation.java">Calculation.java</a></li>
<li class="file-java"><a href="#CalculationTests.java">CalculationTests.java</a></li>
<li class="file-java"><a href="#ConditionalCalculation.java">ConditionalCalculation.java</a></li>
<li class="file-java"><a href="#FullCalculation.java">FullCalculation.java</a></li>
</ul>
</li>
</ul>
</li>
<li class="dir">resources
<ul>
<li class="file"><a href="#parameters.properties">parameters.properties</a></li>
<li class="file-xml"><a href="#testng.xml">testng.xml</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="file-xml"><a target="_blank" href="http://czerwinski.info.pl/2010/05/projekt-maven-z-aspectj/">pom.xml</a></li>
</ul>
<p><a name="Conditional.java"></a><strong>Adnotacja <code>@Conditional</code></strong></p>
<p>Aby w&nbsp;prosty sposób włączać i&nbsp;wyłączać wykonywanie określonych metod, oznaczę je adnotacją <code>@Conditional</code>:</p>
<pre name="code" class="java">
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Conditional {
    String value();
}
</pre>
<p>Wartością atrybutu <code>value</code> będzie nazwa parametru warunkującego wykonanie danej metody.</p>
<p><a name="Calculation.java"></a><strong>Interfejs <code>Calculation</code></strong></p>
<p>Aby ułatwić sobie zadanie, do testów wykorzystam dwie implementacje prostego algorytmu:</p>
<pre name="code" class="java">
interface Calculation {
    double calculate();
}
</pre>
<p>Metoda <code>calculate</code> będzie wykonywać pewne operacje arytmetyczne, po czym zwróci ich wynik.</p>
<p><a name="FullCalculation.java"></a><strong>Pełna implementacja</strong></p>
<p>Najpierw utworzę klasę <code>FullCalculation</code>, której wszystkie metody będą zawsze wykonywane:</p>
<pre name="code" class="java">
class FullCalculation implements Calculation {

    public double calculate() {
        initValue();
        multiply();
        divide();
        add();
        subtract();
        return value;
    }

    private void initValue() {
        value = 1.0;
    }

    private void multiply() {
        value *= 2.0;
    }

    private void divide() {
        value /= 2.0;
    }

    private void add() {
        value += 1.0;
    }

    private void subtract() {
        value -= 1.0;
    }

    private double value;
}
</pre>
<p>Algorytm składa się z&nbsp;kilku atomowych operacji:</p>
<ul>
<li>ustawienie wartości na&nbsp;1,</li>
<li>pomnożenie wartości przez&nbsp;2,</li>
<li>podzielenie wartości przez&nbsp;2,</li>
<li>dodanie&nbsp;1 do wartości,</li>
<li>odjęcie&nbsp;1 od wartości,</li>
<li>zwrócenie wartości.</li>
</ul>
<p>Jeżeli żaden etap obliczeń nie zostanie pominięty, wynik powinien wynosić&nbsp;1.</p>
<p><a name="ConditionalCalculation.java"></a><strong>Implementacja warunkowana</strong></p>
<p>Klasa <code>ConditionalCalculation</code> jest niemalże dokładną kopią pełnej implementacji. Tym razem metody <code>multiply</code>, <code>divide</code>, <code>add</code> i&nbsp;<code>subtract</code> oznaczone są adnotacją <code>@Conditional</code> z&nbsp;odpowiednimi parametrami:</p>
<pre name="code" class="java">
class ConditionalCalculation implements Calculation {

    public double calculate() {
        initValue();
        multiply();
        divide();
        add();
        subtract();
        return value;
    }

    private void initValue() {
        value = 1.0;
    }

    @Conditional("MULTIPLY")
    private void multiply() {
        value *= 2.0;
    }

    @Conditional("DIVIDE")
    private void divide() {
        value /= 2.0;
    }

    @Conditional("ADD")
    private void add() {
        value += 1.0;
    }

    @Conditional("SUBTRACT")
    private void subtract() {
        value -= 1.0;
    }

    private double value;
}
</pre>
<div class="postmetadata"><strong>UWAGA:</strong> Celowo pominąłem dziedziczenie (wzorzec metody szablonu aż się prosi o&nbsp;zastosowanie) i&nbsp;utworzyłem drugą, taką samą klasę, aby wyraźnie zaakcentować, że jedyną różnicą jest adnotacja <code>@Conditional</code>.</div>
<p><a name="parameters.properties"></a><strong>Parametry warunkujące</strong></p>
<p>Działanie przykładowego aspektu oprę na ustawieniach pobieranych z&nbsp;pliku <code>parameters.properties</code>. W&nbsp;typowej aplikacji będą to raczej wielkości pobierane z&nbsp;bazy danych.</p>
<p>Spośród obliczeń warunkowych włączę tylko mnożenie i&nbsp;dodawanie. Teraz rezultat powinien wynieść&nbsp;3:</p>
<pre name="code" class="properties">
# ConditionalCalculation properties:
MULTIPLY=true
DIVIDE=false
ADD=true
SUBTRACT=false
</pre>
<p><a name="CalculationTests.java"></a><strong>Testy</strong></p>
<p>Metody testowe dla obu algorytmów są raczej oczywiste:</p>
<pre name="code" class="java">
public class CalculationTests {

    @Test
    public void testCalculateFull() {
        Calculation calculation = new FullCalculation();

        assertEquals(calculation.calculate(), 1.0,
                "Full calculation value");
    }

    @Test
    public void testCalculateParameterized() {
        Calculation calculation = new ConditionalCalculation();

        assertEquals(calculation.calculate(), 3.0,
                "Conditional calculation value");
    }
}
</pre>
<p><a name="testng.xml"></a><strong>Konfiguracja testów</strong></p>
<p>Aby testy się wykonywały, muszę jeszcze utworzyć plik <code>testng.xml</code>, wskazujący właściwy pakiet:</p>
<pre name="code" class="xml">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"&gt;
&lt;suite name="AspectJ" verbose="2"&gt;
  &lt;test name="Conditional"&gt;
    &lt;packages&gt;
      &lt;package name="pl.info.czerwinski.conditional"/&gt;
    &lt;/packages&gt;
  &lt;/test&gt;
&lt;/suite&gt;
</pre>
<p>W&nbsp;tej chwili wywołanie <code>mvn test</code> powinno zakończyć się jedną porażką przy dwóch wykonanych testach. Nieprawidłowy rezultat wystąpi w&nbsp;metodzie <code>testCalculateParameterized</code>, gdzie zamiast oczekiwanej wartości&nbsp;3.0 pojawi się&nbsp;1.0.</p>
<p><a name="ConditioningAspect.java"></a><strong>Aspekt warunkujący</strong></p>
<p>Pora przejść do najważniejszego elementu całego przykładu, czyli do aspektu. Pojawia się tu kilka nowości:</p>
<pre name="code" class="java">
@Aspect
public class ConditioningAspect {

    @Around("call(@Conditional * *.*(..)) &#038;&#038; @annotation(conditional)")
    public Object condition(
            ProceedingJoinPoint joinPoint,
            Conditional conditional) throws Throwable {
        String parameterName = conditional.value();
        if (Boolean.parseBoolean(parameters.getString(parameterName))) {
            return joinPoint.proceed();
        }
        return null;
    }

    private ResourceBundle parameters =
        ResourceBundle.getBundle("parameters");
}
</pre>
<p><a target="_blank" href="http://czerwinski.info.pl/2010/05/wywolanie-i-wykonanie-metody/">Poprzednio</a> omówiłem adnotacje <code>@Before</code> oraz <code>@After</code>, wskazujące rady <em>przed</em> i&nbsp;<em>po</em>. Adnotacja <code>@Around</code> służy to utworzenia rady &bdquo;otaczającej&rdquo; punkt przecięcia, czyli takiej, która kontroluje dalsze wykonanie programu. Standardowo metoda taka pobiera parametr klasy <code>ProceedingJoinPoint</code> i&nbsp;zwraca dowolny obiekt. Aby rada pozostała bez wpływu na wykonanie programu, powinna składać się z&nbsp;jednej instrukcji:</p>
<pre name="code" class="java">
return joinPoint.proceed();
</pre>
<p>Innymi słowy, brak tej instrukcji oznacza, że metoda, której rada dotyczy, nie zostanie w&nbsp;ogóle wykonana.</p>
<p>Definicja punktu przecięcia w&nbsp;przykładzie jest dość złożona:</p>
<pre>
<acronym title="wywołanie metody">call</acronym>(<acronym title="oznaczonej adnotacją @Conditional">@Conditional</acronym> <acronym title="zwracającej wynik dowolnego typu">*</acronym> <acronym title="należącej do dowolnej klasy">*</acronym>.<acronym title="o&nbsp;dowolnej nazwie">*</acronym>(<acronym title="przyjmującej dowolną ilość dowolnych argumentów">..</acronym>)) &#038;&#038; <acronym title="posiada adnotację przekazaną jako parametr do metody rady">@annotation(conditional)</acronym>
</pre>
<p>Powyższy zapis oznacza wywołanie dowolnej metody oznaczonej adnotacją <code>@Conditional</code>. Rada przyjmuje tę adnotację jako parametr <code>conditional</code>, dzięki czemu można uzależnić dalsze działanie programu od atrybutu <code>value</code>.</p>
<p>Po dodaniu aspektu, wszystkie testy powinny zakończyć się sukcesem.</p>
<p><a name="summary"></a><strong>Podsumowanie</strong></p>
<p>Opisane rozwiązanie daje możliwość szybkiego i&nbsp;łatwego warunkowania kolejnych metod, z&nbsp;zachowaniem czytelności kodu.</p>
<p>Przypuszczam, że do zaproponowanego przeze mnie aspektu można wprowadzić dalsze poprawki (czekam na konstruktywne komentarze). Mam tylko nadzieję, że duża ilość kodu nie zmniejszy czytelności niniejszego wpisu.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/06/aspektowe-warunkowanie-algorytmu/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Drzewo katalogów w CSS</title>
		<link>http://czerwinski.info.pl/2010/05/drzewo-katalogow-w-css/</link>
		<comments>http://czerwinski.info.pl/2010/05/drzewo-katalogow-w-css/#comments</comments>
		<pubDate>Fri, 28 May 2010 12:00:35 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Katalog]]></category>
		<category><![CDATA[Plik]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=757</guid>
		<description><![CDATA[Pracując nad nowym artykułem, po raz kolejny doszedłem do momentu, gdzie powinienem przedstawić strukturę plików i&#160;katalogów w&#160;projekcie. Do tej pory radziłem sobie przy pomocy znacznika pre oraz odpowiednio umieszczonych spacji. Problem polega na tym, że przy większej liczbie plików lub większym zagnieżdżeniu katalogów, lista staje się nieczytelna. Uznałem, że najlepszym wyjściem będzie dodanie do bloga [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Pracując nad nowym artykułem, po raz kolejny doszedłem do momentu, gdzie powinienem przedstawić strukturę plików i&nbsp;katalogów w&nbsp;projekcie. Do tej pory radziłem sobie przy pomocy znacznika <code>pre</code> oraz odpowiednio umieszczonych spacji. Problem polega na tym, że przy większej liczbie plików lub większym zagnieżdżeniu katalogów, lista staje się nieczytelna.</p>
<p>Uznałem, że najlepszym wyjściem będzie dodanie do bloga arkusza stylów oraz odpowiednich ikonek, z&nbsp;pomocą których utworzę całkiem zgrabne drzewko. Zanim dorobię się własnych obrazków, skorzystam z&nbsp;udostępnionego na licencji&nbsp;GPL zestawu <a target="_blank" href="http://www.paolocampitelli.com/gnome-icons/">Gnome Crystal Diamond Icons&nbsp;1.0b</a>.</p>
<p>W&nbsp;pliku&nbsp;CSS dodaję styl całej listy. Chciałbym, aby nazwy plików i&nbsp;katalogów napisane były <a target="_blank" href="http://pl.wikipedia.org/wiki/Kr%C3%B3j_pisma#Sta.C5.82e_i_proporcjonalne">stałym krojem pisma</a>:</p>
<pre name="code" class="css">
.dir-tree {
  font-family: monospace;
}
</pre>
<p>Następnie wskazuję ikony użyte przy wypunktowaniu różnych elementów listy. W&nbsp;tej chwili rozróżniam katalogi, pakiety oraz pliki: Java, XML i&nbsp;pozostałe:</p>
<pre name="code" class="css">
.dir {
  list-style: url("dir.png");
}

.package {
  list-style: url("package.png");
}

.file {
  list-style: url("file.png");
}

.file-java {
  list-style: url("file-java.png");
}

.file-xml {
  list-style: url("file-xml.png");
}
</pre>
<p>Na samym końcu postanowiłem dodać kropkowane linie, w&nbsp;celu zwiększenia czytelności:</p>
<pre name="code" class="css">
.dir-tree ul {
  border-left: 1px dotted #ccc;
}
</pre>
<p>Przykładowa struktura katalogów w&nbsp;pliku&nbsp;HTML wygląda następująco:</p>
<pre name="code" class="html">
&lt;ul class="dir-tree"&gt;
  &lt;li class="dir"&gt;src
    &lt;ul&gt;
      &lt;li class="dir"&gt;main
        &lt;ul&gt;
          &lt;li class="dir"&gt;java
            &lt;ul&gt;
              &lt;li class="package"&gt;pl.info.czerwinski
                &lt;ul&gt;
                  &lt;li class="file-java"&gt;FooClass.java&lt;/li&gt;
                  &lt;li class="file-java"&gt;FooEntity.java&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li class="dir"&gt;resources
            &lt;ul&gt;
              &lt;li class="file"&gt;project.properties&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li class="dir"&gt;test
        &lt;ul&gt;
          &lt;li class="dir"&gt;java
            &lt;ul&gt;
              &lt;li class="package"&gt;pl.info.czerwinski
                &lt;ul&gt;
                  &lt;li class="file-java"&gt;FooTest.java&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li class="dir"&gt;resources
            &lt;ul&gt;
              &lt;li class="file"&gt;testing.properties&lt;/li&gt;
              &lt;li class="file-xml"&gt;testng.xml&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li class="file-xml"&gt;pom.xml&lt;/li&gt;
&lt;/ul&gt;
</pre>
<p>W&nbsp;rezultacie otrzymuję drzewo podobne do poniższego:</p>
<ul class="dir-tree">
<li class="dir">src
<ul>
<li class="dir">main
<ul>
<li class="dir">java
<ul>
<li class="package">pl.info.czerwinski
<ul>
<li class="file-java">FooClass.java</li>
<li class="file-java">FooEntity.java</li>
</ul>
</li>
</ul>
</li>
<li class="dir">resources
<ul>
<li class="file">project.properties</li>
</ul>
</li>
</ul>
</li>
<li class="dir">test
<ul>
<li class="dir">java
<ul>
<li class="package">pl.info.czerwinski
<ul>
<li class="file-java">FooTest.java</li>
</ul>
</li>
</ul>
</li>
<li class="dir">resources
<ul>
<li class="file">testing.properties</li>
<li class="file-xml">testng.xml</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="file-xml">pom.xml</li>
</ul>
<p>Od tej pory każdą strukturę plików w&nbsp;projekcie będę przedstawiał za pomocą powyższego rozwiązania. Mam nadzieję, że opisany przykład przysłuży się też komuś poza mną.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/05/drzewo-katalogow-w-css/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wywołanie i wykonanie metody</title>
		<link>http://czerwinski.info.pl/2010/05/wywolanie-i-wykonanie-metody/</link>
		<comments>http://czerwinski.info.pl/2010/05/wywolanie-i-wykonanie-metody/#comments</comments>
		<pubDate>Wed, 26 May 2010 11:00:36 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Adnotacje]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[AspectJ]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=728</guid>
		<description><![CDATA[Przygotowałem ostatnio plik pom.xml dla projektu korzystającego z&#160;AspectJ. Zanim przejdę do omawiania rzeczywistych problemów, przedstawię pokrótce budowę prostego aspektu. Żeby uzyskać jak najwięcej szczegółów, zamiast testów, użyję raczej niezbyt eleganckiego rozwiązania opartego o&#160;System.out. Przygotowania Na początek utworzę klasę, której dotyczyć będą punkty przecięcia użyte przy tworzeniu aspektu. Wystarczy mi jedna metoda, wyświetlająca komunikat: public class [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Przygotowałem <a href="http://czerwinski.info.pl/2010/05/projekt-maven-z-aspectj/">ostatnio</a> plik <code>pom.xml</code> dla projektu korzystającego z&nbsp;AspectJ. Zanim przejdę do omawiania rzeczywistych problemów, przedstawię pokrótce budowę prostego aspektu. Żeby uzyskać jak najwięcej szczegółów, zamiast testów, użyję raczej niezbyt eleganckiego rozwiązania opartego o&nbsp;<code>System.out</code>.</p>
<p><strong>Przygotowania</strong></p>
<p>Na początek utworzę klasę, której dotyczyć będą <em><a target="_blank" href="http://pl.wikipedia.org/wiki/AspectJ#Punkty_przeci.C4.99cia_.28pointcuts.29">punkty przecięcia</a></em> użyte przy tworzeniu aspektu. Wystarczy mi jedna metoda, wyświetlająca komunikat:</p>
<pre name="code" class="java">
public class FooClass {
    public void fooMethod() {
        System.out.println("FooClass.fooMethod() says \"Hello\".");
    }
}
</pre>
<p>Metodę <code>fooMethod</code> wywoływać będę wewnątrz metody innej klasy. Dla uproszczenia będzie to główna klasa programu:</p>
<pre name="code" class="java">
public class MethodExample {
    public static void main(String... args) {
        new MethodExample();
    }

    public MethodExample() {
        new FooClass().fooMethod();
    }
}
</pre>
<p><strong>Aspekt</strong></p>
<p>Pora utworzyć pierwszy aspekt. Nie będę tutaj omawiał starego podejścia, gdzie aspekty pisane były w&nbsp;specjalnym języku (przykłady można znaleźć w&nbsp;<a target="_blank" href="http://pl.wikipedia.org/wiki/AspectJ">Wikipedii</a>). Zamiast tego utworzę najzwyklejszą klasę, oznaczoną adnotacją <code>@Aspect</code>:</p>
<pre name="code" class="java">
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class MethodLogger {
}
</pre>
<p><strong>Wykonanie metody</strong></p>
<p>Na początku zajmę się <em><a target="_blank" href="http://pl.wikipedia.org/wiki/AspectJ#Punkty_z.C5.82.C4.85cze.C5.84_.28joinpoints.29">punktem złączenia</a></em>, odpowiadającym wykonaniu metody <code>fooMethod</code>, nie przyjmującej żadnych parametrów oraz nie zwracającej żadnej wartości. W&nbsp;AspectJ możemy go zapisać:</p>
<pre name="code" class="java">
execution(void fooMethod())
</pre>
<p>Punkt przecięcia może składać się po prostu z&nbsp;jednego punktu złączenia. Tak też będzie w&nbsp;omawianym przykładzie. Ze względu na prostotę, nie będę definiował osobnego punktu przecięcia (może w&nbsp;kolejnych przykładach), ale przejdę od razu do <em><a target="_blank" href="http://pl.wikipedia.org/wiki/AspectJ#Rady">rad</a></em>.</p>
<p>Utworzę dwie rady dla omawianego punktu przecięcia &ndash; <em>przed</em> oraz <em>po</em>. Będą to metody klasy aspektu, przyjmujące jako parametr konkretny punkt złączenia, przy którym rada została wywołana. Aby wskazać, że metoda jest radą, użyję odpowiednich adnotacji:</p>
<pre name="code" class="java">
@Before("execution(void fooMethod())")
public void beforeExecution(JoinPoint joinPoint) {
    System.out.println("Before execution");
}

@After("execution(void fooMethod())")
public void afterExecution(JoinPoint joinPoint) {
    System.out.println("After execution");
}
</pre>
<p>Po uruchomieniu programu, otrzymuję chyba oczywisty rezultat:</p>
<pre>
Before execution
FooClass.fooMethod() says "Hello".
After execution
</pre>
<p><strong>Wywołanie metody</strong></p>
<p>Nieco innym punktem złączenia jest wywołanie metody. Jego definicja będzie wyglądała następująco:</p>
<pre name="code" class="java">
call(void fooMethod())
</pre>
<p>Do aspektu dodaję dwie nowe rady &nbsp; przed wywołaniem metody oraz po wywołaniu metody:</p>
<pre name="code" class="java">
@Before("call(void fooMethod())")
public void beforeCall(JoinPoint joinPoint) {
    System.out.println("Before call");
}

@After("call(void fooMethod())")
public void afterMethodCall(JoinPoint joinPoint) {
    System.out.println("After call");
}
</pre>
<p>Tym razem rezultat może nie być już tak oczywisty (przynajmniej na pierwszy rzut oka):</p>
<pre>
Before call
Before execution
FooClass.fooMethod() says "Hello".
After execution
After call
</pre>
<p>Z&nbsp;powyższego przykładu płynie wniosek, że metoda jest najpierw wywoływana, a&nbsp;dopiero potem wykonywana.</p>
<p><strong>Porównanie punktów złączenia</strong></p>
<p>Aby dokładniej porównać omawiane punkty złączeń, utworzę dodatkową metodę, wywoływaną z&nbsp;poziomu każdej rady:</p>
<pre name="code" class="java">
private void printJoinPointInfo(JoinPoint joinPoint) {
    System.out.println("======== Join point: ========");
    System.out.println("Signature: " +
        joinPoint.getSignature().toShortString());
    System.out.println("Kind: " + joinPoint.getKind());
    System.out.println("This: " +
        joinPoint.getThis().getClass().getSimpleName());
    System.out.println("Target: " +
        joinPoint.getTarget().getClass().getSimpleName());
    System.out.println("=============================");
}
</pre>
<p>Tym razem na konsoli powinny pojawić się następujące komunikaty:</p>
<pre>
Before call
======== Join point: ========
Signature: FooClass.fooMethod()
Kind: method-call
This: MethodExample
Target: FooClass
=============================
Before execution
======== Join point: ========
Signature: FooClass.fooMethod()
Kind: method-execution
This: FooClass
Target: FooClass
=============================
FooClass.fooMethod() says "Hello".
After execution
======== Join point: ========
Signature: FooClass.fooMethod()
Kind: method-execution
This: FooClass
Target: FooClass
=============================
After call
======== Join point: ========
Signature: FooClass.fooMethod()
Kind: method-call
This: MethodExample
Target: FooClass
=============================
</pre>
<p>Jak widać, dla tej samej metody obiekt docelowy (<em>target</em>) jest zawsze ten sam &ndash; jest to obiekt, w&nbsp;którym dana metoda się znajduje. Ale wskazanie obiektu bieżącego (<em>this</em>) nie jest już takie proste. W&nbsp;przypadku wykonania metody, jest to ten sam obiekt, co docelowy (zawierający daną metodę). Jednak przy wywołaniu metody, obiekt bieżący jest tym, z&nbsp;poziomu którego metoda jest wywoływana.</p>
<p><strong>Podsumowanie</strong></p>
<p>Omówiony przykład pokazuje, ile potencjalnych błędów może spowodować prosta obsługa wywołania lub wykonania metody. Wewnątrz konstruktora klasy <code>MethodExample</code> została wywołana metoda <code>fooMethod</code>, ale jej wykonanie odbywa się dla obiektu klasy <code>FooClass</code>. Czytelnikom polecam ponowne przeanalizowanie całego kodu.</p>
<p>Następnym razem spróbuję opisać jakieś realne zastosowanie AspectJ. Podam też przykłady innych rad i&nbsp;punktów złączenia.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/05/wywolanie-i-wykonanie-metody/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Projekt Maven z AspectJ</title>
		<link>http://czerwinski.info.pl/2010/05/projekt-maven-z-aspectj/</link>
		<comments>http://czerwinski.info.pl/2010/05/projekt-maven-z-aspectj/#comments</comments>
		<pubDate>Fri, 21 May 2010 11:00:55 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[AspectJ]]></category>
		<category><![CDATA[Maven]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=705</guid>
		<description><![CDATA[Programowaniem aspektowym (ang.&#160;Aspect-oriented programming) zainteresowałem się ponad rok temu. Niestety od tamtej pory nie znalazłem dość czasu, aby zająć się tym zagadnieniem na poważnie. Nadszedł moment, kiedy nie jestem już całkowicie pochłonięty pracą z&#160;Seam Framework. Teraz nareszcie mogę zagłębić się w&#160;tajniki biblioteki AspectJ. Niniejszy wpis nie będzie zawierał żadnych przykładowych aspektów. Na początku postaram się [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Programowaniem aspektowym (ang.&nbsp;<em>Aspect-oriented programming</em>) zainteresowałem się ponad rok temu. Niestety od tamtej pory nie znalazłem dość czasu, aby zająć się tym zagadnieniem na poważnie. Nadszedł moment, kiedy nie jestem już całkowicie pochłonięty pracą z&nbsp;Seam Framework. Teraz nareszcie mogę zagłębić się w&nbsp;tajniki biblioteki AspectJ.</p>
<p>Niniejszy wpis nie będzie zawierał żadnych przykładowych aspektów. Na początku postaram się omówić konfigurację projektu w&nbsp;pliku <code>pom.xml</code>.</p>
<p>Ponieważ zamierzam wykorzystać aspekty oparte o&nbsp;adnotacje, potrzebuję kompilacji kodu przynajmniej w&nbsp;wersji Java&nbsp;1.5:</p>
<pre name="code" class="xml">
&lt;project&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  [&hellip;]

  &lt;build&gt;
    &lt;plugins&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.3&lt;/version&gt;
        &lt;configuration&gt;
          &lt;source&gt;1.5&lt;/source&gt;
          &lt;target&gt;1.5&lt;/target&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
[&hellip;]
</pre>
<p>W&nbsp;następnej kolejności, dodaję wtyczkę <code>aspectj-maven-plugin</code>, która będzie kompilować aspekty razem z&nbsp;kodem oraz testami:</p>
<pre name="code" class="xml">
[&hellip;]
      &lt;plugin&gt;
        &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
        &lt;artifactId&gt;aspectj-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;1.3&lt;/version&gt;
        &lt;configuration&gt;
          &lt;complianceLevel&gt;1.5&lt;/complianceLevel&gt;
        &lt;/configuration&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;goals&gt;
              &lt;goal&gt;compile&lt;/goal&gt;
              &lt;goal&gt;test-compile&lt;/goal&gt;
            &lt;/goals&gt;
          &lt;/execution&gt;
        &lt;/executions&gt;
      &lt;/plugin&gt;
[&hellip;]
</pre>
<p>Na sam koniec muszę wskazać wtyczce <code>maven-surefire-plugin</code> położenie pliku&nbsp;XML zawierającego konfigurację TestNG:</p>
<pre name="code" class="xml">
[&hellip;]
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.5&lt;/version&gt;
        &lt;configuration&gt;
          &lt;suiteXmlFiles&gt;
            &lt;suiteXmlFile&gt;src/test/resources/testng.xml&lt;/suiteXmlFile&gt;
          &lt;/suiteXmlFiles&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;
[&hellip;]
</pre>
<p>Aby móc tworzyć aspekty, do zależności muszę dodać bibliotekę <code>aspectjrt</code>:</p>
<pre name="code" class="xml">
[&hellip;]
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.aspectj&lt;/groupId&gt;
      &lt;artifactId&gt;aspectjrt&lt;/artifactId&gt;
      &lt;version&gt;1.6.8&lt;/version&gt;
    &lt;/dependency&gt;
[&hellip;]
</pre>
<p>Na sam koniec, do zależności dodaję bibliotekę TestNG:</p>
<pre name="code" class="xml">
[&hellip;]
    &lt;dependency&gt;
      &lt;groupId&gt;org.testng&lt;/groupId&gt;
      &lt;artifactId&gt;testng&lt;/artifactId&gt;
      &lt;version&gt;5.11&lt;/version&gt;
      &lt;classifier&gt;jdk15&lt;/classifier&gt;
      &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;

  [&hellip;]
&lt;/project&gt;
</pre>
<p>Oczywiście należałoby ustawić pozostałe parametry projektu, jak <code>groupId</code>, <code>artifactId</code>, <code>version</code>, <code>packaging</code> czy <code>version</code>. Przydadzą się także raporty <code>maven-surefire-report-plugin</code> oraz <code>maven-javadoc-plugin</code>, o&nbsp;których pisałem przy okazji <a href="http://czerwinski.info.pl/2010/03/strona-wtyczki-maven/">strony wtyczki Maven</a>.</p>
<p>Następnym razem postaram się omówić pierwszy przykład prostego aspektu wraz z&nbsp;testami.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/05/projekt-maven-z-aspectj/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Seam: Pobieranie konfiguracji poczty z bazy</title>
		<link>http://czerwinski.info.pl/2010/05/seam-pobieranie-konfiguracji-poczty-z-bazy/</link>
		<comments>http://czerwinski.info.pl/2010/05/seam-pobieranie-konfiguracji-poczty-z-bazy/#comments</comments>
		<pubDate>Thu, 06 May 2010 10:00:37 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Seam Framework]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Encje]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[Uwierzytelnienie]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=668</guid>
		<description><![CDATA[Gdy już udało mi się wysłać wiadomość email z&#160;poziomu aplikacji Seam, postanowiłem przenieść konfigurację serwera poczty wychodzącej do bazy danych &#8211; tak aby użytkownik (administrator) systemu mógł ją zmieniać w&#160;dowolnym momencie. Realizacja tego zadania wymagała rozszerzenia funkcjonalności komponentu org.jboss.seam.mail.mailSession. Na początek tworzę nową klasę, dziedziczącą po&#160;MailSession: @Name("org.jboss.seam.mail.mailSession") @Install( precedence = Install.APPLICATION, classDependencies = "javax.mail.Session") @Scope(ScopeType.APPLICATION) [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Gdy już udało mi się <a href="http://czerwinski.info.pl/2010/04/seam-powiadomienia-email/">wysłać wiadomość email</a> z&nbsp;poziomu aplikacji Seam, postanowiłem przenieść konfigurację serwera poczty wychodzącej do bazy danych &ndash; tak aby użytkownik (administrator) systemu mógł ją zmieniać w&nbsp;dowolnym momencie.</p>
<p>Realizacja tego zadania wymagała rozszerzenia funkcjonalności komponentu <code>org.jboss.seam.mail.mailSession</code>. Na początek tworzę nową klasę, dziedziczącą po&nbsp;<code>MailSession</code>:</p>
<pre name="code" class="java">
@Name("org.jboss.seam.mail.mailSession")
@Install(
        precedence = Install.APPLICATION,
        classDependencies = "javax.mail.Session")
@Scope(ScopeType.APPLICATION)
public class JpaMailSession extends org.jboss.seam.mail.MailSession {
    @In
    private EntityManager entityManager;
}
</pre>
<p>Pobieranie danych serwera poczty z&nbsp;bazy wymaga przeciążenia kilku metod. Na początku zajmę się tworzeniem właściwego obiektu sesji:</p>
<pre name="code" class="java">
@Override
@Unwrap
public javax.mail.Session getSession() throws NamingException {
    setSessionJndiName(null);
    create();
    return super.getSession();
}
</pre>
<p>Ustawienie nazwy sesji na <code>null</code> (linia&nbsp;4) spowoduje, że metoda <code>create()</code> (linia&nbsp;5) faktycznie utworzy nową sesję. Domyślnie dane serwera poczty są stałe (pochodzą z&nbsp;pliku <code>components.xml</code>), więc wystarczy jednorazowe utworzenie sesji. W&nbsp;wypadku konfiguracji zapisanej w&nbsp;bazie wszelkie niezbędne dane mogą ulec zmianie w&nbsp;trakcie działania aplikacji, co powoduje konieczność przeładowania sesji.</p>
<p>Powyższe operacje można wykonywać w&nbsp;odpowiednio przygotowanej metodzie obserwatora zdarzenia związanego ze zmianą danych serwera pocztowego&hellip; może w&nbsp;następnym artykule.</p>
<p>Kolejną przeciążaną metodą będzie <code>getHost()</code> &ndash; odpowiedzialna za pobieranie nazwy serwera pocztowego:</p>
<pre name="code" class="java">
@Override
public String getHost() {
    if (entityManager != null) {
        super.setHost(loadHostFromDB());
    }
    return super.getHost();
}
</pre>
<p>Implementację prywatnej metody <code>loadHostFromDB()</code> pozostawiam czytelnikom, ponieważ dane serwera pocztowego można przechowywać w&nbsp;bazie na wiele sposobów &ndash; wszystko zależy od konkretnej sytuacji i&nbsp;kontekstu.</p>
<p>Przed pobraniem nazwy hosta z&nbsp;bazy sprawdzam, czy istnieje <code>entityManager</code> (linia&nbsp;3). Nie chodzi o&nbsp;to, że komponent może nie istnieć w&nbsp;kontekście &ndash; on mógł nie zostać wstrzyknięty. Powodem takiej sytuacji jest adnotacja <code>@BypassInterceptors</code> przy klasie <code>org.jboss.seam.mail.MailSession</code> &ndash; bez interceptorów nie ma wstrzykiwania zależności.</p>
<p>Analogicznie przeciążam metody pobierające pozostałe dane serwera pocztowego:</p>
<pre name="code" class="java">
@Override
public Integer getPort() {
    if (entityManager != null) {
        super.setPort(loadPortFromDB());
    }
    return super.getPort();
}

@Override
public String getUsername() {
    if (entityManager != null) {
        super.setUsername(loadUsernameFromDB());
    }
    return super.getUsername();
}

@Override
public String getPassword() {
    if (entityManager != null) {
        super.setPassword(loadPasswordFromDB());
    }
    return super.getPassword();
}
</pre>
<p>Teraz już można usunąć znacznik <code>mail:mail-session</code> z&nbsp;pliku <code>components.xml</code>. Wysyłanie wiadomości będzie się odbywać w&nbsp;oparciu o&nbsp;konfigurację zapisaną w&nbsp;bazie danych.</p>
<p>Opisany wyżej mechanizm można poddać wielu dalszym ulepszeniom. Być może opiszę swoje propozycje w&nbsp;przyszłości.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/05/seam-pobieranie-konfiguracji-poczty-z-bazy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Seam: Powiadomienia email</title>
		<link>http://czerwinski.info.pl/2010/04/seam-powiadomienia-email/</link>
		<comments>http://czerwinski.info.pl/2010/04/seam-powiadomienia-email/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 11:00:00 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Seam Framework]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[JSF]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=666</guid>
		<description><![CDATA[Dzisiejszy artykuł stanowi jedynie wstęp do bardziej zaawansowanych zagadnień dotyczących poczty elektronicznej w&#160;Seam Framework. Opiszę tutaj podstawową konfigurację oraz wysyłanie prostej wiadomości email &#8211; kwestie kluczowe z&#160;punktu widzenia tematyki kolejnych wpisów. Obsługa poczty w&#160;Seam realizowana jest za pośrednictwem biblioteki JavaMail. Dlatego do projektu (albo do bibliotek serwera) należy dodać archiwum mail.jar. Podstawowa konfiguracja serwera poczty [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Dzisiejszy artykuł stanowi jedynie wstęp do bardziej zaawansowanych zagadnień dotyczących poczty elektronicznej w&nbsp;Seam Framework. Opiszę tutaj podstawową konfigurację oraz wysyłanie prostej wiadomości email &ndash; kwestie kluczowe z&nbsp;punktu widzenia tematyki kolejnych wpisów.</p>
<p>Obsługa poczty w&nbsp;Seam realizowana jest za pośrednictwem biblioteki JavaMail. Dlatego do projektu (albo do bibliotek serwera) należy dodać archiwum <code>mail.jar</code>.</p>
<p>Podstawowa konfiguracja serwera poczty wychodzącej powinna znaleźć się w&nbsp;pliku <code>components.xml</code>:</p>
<pre name="code" class="xml">
&lt;mail:mail-session
    host="smtp.foo.com"
    port="25"
    username="fooUser"
    password="fooPassword"/&gt;
</pre>
<p>Wysłanie wiadomości odbywa się poprzez przetworzenie odpowiedniego widoku zawartego w&nbsp;pliku&nbsp;XHTML. Poniżej przedstawiam przykładowy widok <code>mail.xhtml</code>:</p>
<pre name="code" class="xhtml">
&lt;!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;m:message
    charset="UTF-8"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:m="http://jboss.com/products/seam/mail"&gt;

  &lt;m:from name="#{mailBean.fromName}" address="#{mailBean.fromEmail}"/&gt;
  &lt;m:to name="#{mailBean.toName}"&gt;#{mailBean.toEmail}&lt;/m:to&gt;

  &lt;m:subject&gt;#{mailBean.subject}&lt;/m:subject&gt;

  &lt;m:body&gt;
    &lt;p&gt;
      #{mailBean.body}
    &lt;/p&gt;
    &lt;p&gt;--&lt;/p&gt;
    &lt;p&gt;&lt;small&gt;#{mailBean.signature}&lt;/small&gt;&lt;/p&gt;
  &lt;/m:body&gt;

&lt;/m:message&gt;
</pre>
<p>Zawarte w&nbsp;przykładzie dane nadawcy i&nbsp;adresata oraz temat i&nbsp;treść wiadomości pobierane są z&nbsp;komponentu <code>mailBean</code>, ale nic nie stoi na przeszkodzie, aby zostały wpisane na stałe do widoku. Tak jak w&nbsp;przypadku zwykłych stron&nbsp;JSF czy <a href="http://czerwinski.info.pl/2010/01/seam-itext-i-zapis-do-pliku/">dokumentów&nbsp;PDF</a>, także w&nbsp;wiadomościach email można dowolnie łączyć czysty tekst z&nbsp;wyrażeniami Expression Language&nbsp;(<code>#{&hellip;}</code>).</p>
<p>Przekierowanie na stronę <code>mail.seam</code> powinno zakończyć się wysłaniem przygotowanej wcześniej wiadomości. Wówczas jednak w&nbsp;przeglądarce pojawi się pusta strona. Aby temu zapobiec, można przetworzyć widok używając komponentu <code>renderer</code> (<code>org.jboss.seam.faces.Renderer</code>):</p>
<pre name="code" class="java">
@In(create=true)
private Renderer renderer;
</pre>
<p>Wysłanie wiadomości odbywa się poprzez wywołanie metody <code>render()</code>:</p>
<pre name="code" class="java">
public void send() {
  // &hellip;
  renderer.render("/mail.xhtml");
}
</pre>
<p>Oczywiście przed dokonaniem wysyłki należy pamiętać, aby ustawić prawidłowe wartości odpowiednich właściwości komponentu <code>mailBean</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/04/seam-powiadomienia-email/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Odwracanie kolejności elementów tabeli</title>
		<link>http://czerwinski.info.pl/2010/04/odwracanie-tabeli/</link>
		<comments>http://czerwinski.info.pl/2010/04/odwracanie-tabeli/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 10:00:23 +0000</pubDate>
		<dc:creator>Sławomir Czerwiński</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Generics]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://czerwinski.info.pl/?p=645</guid>
		<description><![CDATA[Potrzebowałem utworzyć tabelę, zawierającą elementy tabeli źródłowej, lecz w&#160;odwrotnej kolejności. Zadanie jest dziecinnie proste, jednak chciałem się upewnić, czy nie ma już specjalnie dla tego celu przygotowanej metody &#8211; na przykład w&#160;klasie java.util.Arrays. Wówczas natrafiłem na ciekawe rozwiązanie problemu: public static Object[] reverse(Object[] arr) { List&#60;Object&#62; list = Arrays.asList(arr); Collections.reverse(list); return list.toArray(); } Oczywiście! Przecież [...]]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=b0dd47ca3172170af85075220a17d98f&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Potrzebowałem utworzyć tabelę, zawierającą elementy tabeli źródłowej, lecz w&nbsp;odwrotnej kolejności. Zadanie jest dziecinnie proste, jednak chciałem się upewnić, czy nie ma już specjalnie dla tego celu przygotowanej metody &ndash; na przykład w&nbsp;klasie <code>java.util.Arrays</code>. Wówczas natrafiłem na <a target="_blank" href="http://answers.yahoo.com/question/index?qid=20070904201231AAIwpJv" rel="nofollow">ciekawe rozwiązanie problemu</a>:</p>
<pre name="code" class="java">
public static Object[] reverse(Object[] arr) {
    List&lt;Object&gt; list = Arrays.asList(arr);
    Collections.reverse(list);
    return list.toArray();
}
</pre>
<p>Oczywiście! Przecież metoda, której szukam, została zaimplementowana dla kolekcji.</p>
<p>Na wszelki wypadek postanowiłem przetestować znaleziony algorytm:</p>
<pre name="code" class="java">
@Test
public void testReverse() {
    Object[] objects = new Object[] {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    };

    Object[] reversed = ArrayHandle.reverse(objects);

    assertEquals(reversed[0], (Object) 10,
            "First element of reversed array");
}
</pre>
<p>Tak! Działa!</p>
<p>Jeszcze tylko upewnię się, że tabela źródłowa pozostaje niezmieniona:</p>
<pre name="code" class="java">
@Test
public void testReverse() {
    // &hellip;
    assertEquals(objects[0], (Object) 1,
            "First element of original array");
}
</pre>
<p>Uruchamiam testy i&hellip;&nbsp;otrzymuję błąd:</p>
<pre>
java.lang.AssertionError: First element of original array expected:<1> but was:<10>
</pre>
<p>Co się stało?</p>
<p>Przeanalizujmy metodę <code>reverse</code>.</p>
<p>Na samym początku tworzony jest interfejs <code>java.util.List</code> dla tablicy źródłowej. Zauważmy przy tym, że lista zwrócona przez <code>Arrays.asList()</code> odwołuje się bezpośrednio do wskazanej tablicy &ndash; <strong>nie kopiuje jej elementów</strong>.</p>
<p>Dzięki metodzie <code>Collections.reverse()</code> odwrócona zostaje kolejność elementów listy, czyli <em>de facto</em> elementów <strong>tablicy źródłowej</strong>.</p>
<p>Na samym końcu, przy użyciu metody <code>List.toArray()</code> tworzona jest <strong>nowa tablica</strong>, która zostaje następnie zwrócona jako wynik działania metody.</p>
<p>Czyli metoda <code>reverse</code> zmienia kolejność elementów wewnątrz tablicy podanej jako parametr na odwrotną, po czym zwraca kopię tej tablicy? Przypuszczam (albo przynajmniej mam nadzieję), że nie taka była intencja autora. Jeżeli widzę metodę o&nbsp;sygnaturze <code>Object[] reverse(Object[])</code>, to spodziewam się, że parametr pozostanie niezmieniony (już lepiej by było, gdyby ta metoda nie zwracała nic).</p>
<p>Postanowiłem nieco ulepszyć algorytm &ndash; tak aby kopia tablicy tworzona była przed zmianą kolejności elementów:</p>
<pre name="code" class="java">
public static &lt;T&gt; T[] reverse(T[] arr) {
    T[] reversed = arr.clone();
    List&lt;T&gt; list = Arrays.asList(reversed);
    Collections.reverse(list);
    return reversed;
}
</pre>
<p>W&nbsp;ten sposób kolejność elementów tablicy wejściowej pozostaje bez zmian; ponadto unikam tworzenia nadmiarowej kopii.</p>
<p>Istnieje jeszcze jeden atut nowej implementacji &ndash; jest to metoda generyczna. Aby odwrócić kolejność elementów tablicy liczb całkowitych, nie muszę już korzystać z&nbsp;rzutowania:</p>
<pre name="code" class="java">
Integer[] reversed = (Integer[]) ArrayHandle.reverse(integers);
</pre>
<p>Teraz mogę zwyczajnie wywołać tę metodę dla tablicy <code>Integer[]</code>, jak w&nbsp;poniższej metodzie testowej:</p>
<pre name="code" class="java">
@Test
public void testReverseForIntegers() {
    Integer[] integers = new Integer[] {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    };

    Integer[] reversed = ArrayHandle.reverse(integers);

    assertEquals(reversed[0], (Integer) 10,
            "First element of reversed array");
    assertEquals(integers[0], (Integer) 1,
            "First element of original array");
}
</pre>
<p>Oczywiście można ograniczyć odpowiedzialność metody <code>reverse</code> do zmiany kolejności elementów tablicy <em>in situ</em>:</p>
<pre name="code" class="java">
public static &lt;T&gt; void reverse(T[] arr) {
    List&lt;T&gt; list = Arrays.asList(arr);
    Collections.reverse(list);
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://czerwinski.info.pl/2010/04/odwracanie-tabeli/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

