<?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>The Code-House Blog &#187; Consulting</title>
	<atom:link href="http://blog.code-house.org/category/code-house/consulting/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.code-house.org</link>
	<description>Blog niewielkiej firmy z branży IT.</description>
	<lastBuildDate>Fri, 10 Jun 2011 14:33:25 +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>OSGi-fikacja oraz nowe bundle w repozytorium ServiceMix</title>
		<link>http://blog.code-house.org/2010/03/osgi-new-bundles-servicemix-repository/</link>
		<comments>http://blog.code-house.org/2010/03/osgi-new-bundles-servicemix-repository/#comments</comments>
		<pubDate>Wed, 24 Mar 2010 15:26:52 +0000</pubDate>
		<dc:creator>Łukasz Dywicki</dc:creator>
				<category><![CDATA[Camel]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[ServiceMix]]></category>
		<category><![CDATA[Moved]]></category>

		<guid isPermaLink="false">http://blog.code-house.org/?p=249</guid>
		<description><![CDATA[W tym wpisie zostanie omówiony proces OSGi-fikacji artefaktów, który przechodziłem gdy uruchamiałem prostą usługę na ServiceMix, która miała śledzić zewnętrzny RSS i pobierać z niego wpisy. Postanowiłem skorzystać z camel-rss. Przykłady które były do niego załączone są wystarczające by stworzyć odpowiedniego konsumenta&#8230; Problem zaczął się gdy usiłowałem uruchomić endpoint camela w OSGi. Mimo poprawnej konfiguracji, [...]]]></description>
			<content:encoded><![CDATA[<p>W tym wpisie zostanie omówiony proces OSGi-fikacji artefaktów, który przechodziłem gdy uruchamiałem prostą usługę na ServiceMix, która miała śledzić zewnętrzny RSS i pobierać z niego wpisy. Postanowiłem skorzystać z camel-rss. Przykłady które były do niego załączone są wystarczające by stworzyć odpowiedniego konsumenta&#8230;<br />
<!-- more --><br />
Problem zaczął się gdy usiłowałem uruchomić endpoint camela w OSGi. Mimo poprawnej konfiguracji, rozwiązanych zależności otrzymywałem wyjątek:</p>
<pre class="brush: plain; title: ; notranslate">java.lang.NoClassDefFoundError: Could not initialize class com.sun.syndication.feed.synd.SyndFeedImpl
        at com.sun.syndication.io.SyndFeedInput.build(SyndFeedInput.java:123)
        at org.apache.camel.component.rss.RssUtils.createFeed(RssUtils.java:34)
        at org.apache.camel.component.rss.RssEntryPollingConsumer.createFeed(RssEntryPollingConsumer.java:54)
        at org.apache.camel.component.feed.FeedEntryPollingConsumer.poll(FeedEntryPollingConsumer.java:42)
        at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:106)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
        at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:619)
</pre>
<p>Naturalnie, strasznie zirytowany, wziąłem się za dochodzenie &#8211; początkowo byłem przekonany że brakuje importów w camel-rss jednakże krótkie googlowanie <a href="http://js.jipiju.com/2009/08/04/osgi-jumping-through-classoading-hoops/">wskazało rozwiązanie</a>. Winne było kilka linii w klasie PluginManager:</p>
<pre class="brush: java; title: ; notranslate">
    private Class[] getClasses() throws ClassNotFoundException {
        // Ten ClassLoader wskazuje na bundle w którym jest zdefiniowany endpoint!
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        List classes = new ArrayList();
        boolean useLoadClass = Boolean.valueOf(System.getProperty(&quot;rome.pluginmanager.useloadclass&quot;, &quot;false&quot;)).booleanValue();
        for (int i = 0; i &lt;_propertyValues.length; i++) {
            // Naturalnie tutaj leciał ClassNotFoundException
            Class mClass = (useLoadClass ?  classLoader.loadClass(_propertyValues[i]) :
                Class.forName(_propertyValues[i], true, classLoader));
            classes.add(mClass);
        }
        Class[] array = new Class[classes.size()];
        classes.toArray(array);
        return array;
    }
</pre>
<p>Po przeróbce metoda wygląda następująco.</p>
<pre class="brush: java; title: ; notranslate">
    private Class[] getClasses() throws ClassNotFoundException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        List classes = new ArrayList();
        boolean useLoadClass = Boolean.valueOf(System.getProperty(&quot;rome.pluginmanager.useloadclass&quot;, &quot;false&quot;)).booleanValue();
        for (int i = 0; i &lt;_propertyValues.length; i++) {
            Class mClass = null;
            try {
                if (useLoadClass) {
                    mClass = classLoader.loadClass(_propertyValues[i]);
                } else {
                    mClass = Class.forName(_propertyValues[i], true, classLoader);
                }
            } catch (ClassNotFoundException e) {
                // Jeśli zewnętrzny class loader zgłosi wyjątek usiłujemy załadować klasę
                // z bieżącej paczki
                mClass = getClass().getClassLoader().loadClass(_propertyValues[i]);
            }
            classes.add(mClass);
        }
        Class[] array = new Class[classes.size()];
        classes.toArray(array);
        return array;
    }
</pre>
<p>Naturalnie, można się zastanawiać po co bibliotece do obsługi RSS zabiegi z ClassLoaderami. Otóż ROME wykorzystuje plik .properties do konfiguracji &#8222;pluginów&#8221; (poors man DI). W określonych miejscach możemy dodać własne klasy które obsłużą jakiś niestandardowy format. Problem w tym, że &#8222;patent&#8221; z plikiem properties świetnie sprawdza się przy płaskim classloaderze, niestety zawodzi w OSGi. Należy pamiętać o tym, że w OSGi nasz class loader ma dostęp do tego, do czego mu pozwalają importy i nie wszystko to, co widzi nasze oko w archiwum musi być dostępne dla naszego programu.</p>
<p>Przy okazji stworzenia <a href="https://issues.apache.org/activemq/browse/SMX4-510">bundle z ROME 1.0</a> postanowiłem również stworzyć bundle dla <a href="https://issues.apache.org/activemq/browse/SMX4-511">Apache POI 3.6</a>. Bibliotekę tą wykorzystywałem wspólnie z <a href="http://nurkiewicz.blogspot.com/">Tomkiem Nurkiewiczem</a> podczas prezentacji &#8222;Mule ESB vs ServiceMix&#8221;.</p>
<h2>OSGi-fikacja</h2>
<p>Bardzo swobodna definicja:</p>
<blockquote><p><a name="OSGi-fikacja">OSGi-fikacja</a> to proces mający na celu stworzenie działającego bundle z istniejącej już biblioteki. Wiele z projektów nie dostarczają poprawnych z punktu widzenia frameworku OSGi manifestów, czasami są budowane poprzez Ant bądź w ogóle są dostępne tylko ich binarne wersje co utrudnia analizę. Proces ten w większości przypadków sprowadza się do analizy zależności klas (importów) oraz zadeklarowanych klas (eksportów). W skrajnych wypadkach konieczna jest dodanie kodu bądź podmiana jego fragmentów tak by nie powodowały problemów po uruchomieniu. W celu zachowania porządku w publicznych repozytoriach Mavena stworzone w ten sposób archiwa są zapisywane z innym ArtifactId bądź GroupId, natomiast z zachowaniem oryginalnej wersji.</p></blockquote>
<p>Nie aspiruję do miana człowieka który tworzy nowe pojęcia. Ten nieco przydługi wywód ma na celu jedynie przybliżenie działań które czasami są konieczne do uzyskania biblioteki działającej w OSGi.</p>
<p>Na potrzeby przykładu OSGi-fikacji wybrałem <a href="http://logging.apache.org/log4j/1.2/index.html">log4j</a>, jako popularną bibliotekę z małym zbiorem zależności. Wersja 1.2.12 nie zawiera poprawnego manifestu OSGi przez co nie można jej użyć pod Equinoxem czy Felixem.<br />
Zależności które ma log4j takie jak:</p>
<ul>
<li>javax.mail</li>
<li>javax.swing</li>
<li>javax.naming</li>
<li>javax.activation</li>
<li>javax.management</li>
<li>com.sun.jdmk.comm</li>
</ul>
<p>Są opcjonalne, co znaczy że biblioteka bez problemów uruchomi się jeśli nie uda się zaimportować wyżej wymienionych paczek. Określimy zatem ich <strong>resolution</strong> na <em>optional</em>. </p>
<p>Pozostałe zależności wymienione poniżej są wymagane by móc odczytać plik log4j.xml:</p>
<ul>
<li>org.w3c.dom</li>
<li>javax.xml.parsers</li>
<li>org.xml.sax</li>
</ul>
<p>Poniżej znajduje się pom.xml który przygotowałem po to by zaprezentować użycie wcześniej wspomnianych pluginów. Pom ten ma skutkować stworzeniem artefaktu OSGi gotowego do uruchomienia pod Kara-fem.</p>
<pre class="brush: xml; title: ; notranslate">&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;parent&gt;
      &lt;groupId&gt;org.apache.servicemix.bundles&lt;/groupId&gt;
      &lt;artifactId&gt;bundles-pom&lt;/artifactId&gt;
      &lt;version&gt;4&lt;/version&gt;
    &lt;/parent&gt;

    &lt;groupId&gt;org.apache.servicemix.bundles&lt;/groupId&gt;
    &lt;artifactId&gt;org.apache.servicemix.bundles.log4j&lt;/artifactId&gt;
    &lt;version&gt;1.2.12-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;bundle&lt;/packaging&gt;
    &lt;name&gt;Apache ServiceMix Bundles: ${pkgArtifactId}-${pkgVersion}&lt;/name&gt;
    &lt;description&gt;
        This bundle simply wraps ${pkgArtifactId}-${pkgVersion}.jar.
    &lt;/description&gt;

    &lt;properties&gt;
        &lt;!-- Zmienne dla maven-bundle-plugin --&gt;
        &lt;servicemix.osgi.export.pkg&gt;
            org.apache.log4j*;version=${pkgVersion}
        &lt;/servicemix.osgi.export.pkg&gt;
        &lt;servicemix.osgi.import.pkg&gt;
            &lt;!-- Zależności opcjonalne --&gt;
            com.sun.jdmk.comm;resolution:=optional,
            javax.jms;resolution:=optional,
            javax.mail*;resolution:=optional,
            javax.management;resolution:=optional,
            javax.naming;resolution:=optional,
            javax.swing*;resolution:=optional,
            * &lt;!-- Wszystkie inne zależności jakie doda analizator --&gt;
        &lt;/servicemix.osgi.import.pkg&gt;
        &lt;!-- Zmienne artefaktu --&gt;
        &lt;pkgGroupId&gt;log4j&lt;/pkgGroupId&gt;
        &lt;pkgArtifactId&gt;log4j&lt;/pkgArtifactId&gt;
        &lt;pkgVersion&gt;1.2.12&lt;/pkgVersion&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;
        &lt;!-- zależność do log4j --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;${pkgGroupId}&lt;/groupId&gt;
            &lt;artifactId&gt;${pkgArtifactId}&lt;/artifactId&gt;
            &lt;version&gt;${pkgVersion}&lt;/version&gt;
            &lt;optional&gt;true&lt;/optional&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;!-- Kopiowanie plików .class --&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;phase&gt;package&lt;/phase&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;shade&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;configuration&gt;
                            &lt;artifactSet&gt;
                                &lt;includes&gt;
                                    &lt;include&gt;${pkgGroupId}:${pkgArtifactId}&lt;/include&gt;
                                &lt;/includes&gt;
                            &lt;/artifactSet&gt;
                            &lt;filters&gt;
                                &lt;filter&gt;
                                    &lt;artifact&gt;${pkgGroupId}:${pkgArtifactId}&lt;/artifact&gt;
                                    &lt;excludes&gt;
                                        &lt;exclude&gt;**&lt;/exclude&gt;
                                    &lt;/excludes&gt;
                                &lt;/filter&gt;
                            &lt;/filters&gt;
                            &lt;promoteTransitiveDependencies&gt;true&lt;/promoteTransitiveDependencies&gt;
                            &lt;createDependencyReducedPom&gt;true&lt;/createDependencyReducedPom&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;
&lt;/project&gt;
</pre>
<p>Teraz pora na instalację bundla na szynie:</p>
<pre class="listing">
<span class="startup">
 ____                  _          __  __ _
/ ___|  ___ _ ____   _(_) ___ ___|  \/  (_)_  __
\___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ /
 ___) |  __/ |   \ V /| | (_|  __/ |  | | |&gt;  &lt;
|____/ \___|_|    \_/ |_|\___\___|_|  |_|_/_/\_\
</span><span class="bold">
  Apache ServiceMix</span> (4.2.0-fuse-01-00)

Hit '<span class="bold">&lt;tab&gt;</span>' for a list of available commands
and '<span class="bold">[cmd] --help</span>' for help on a specific command.
<span class="bold">karaf</span>@root&gt;

<span class="bold">karaf</span>@root&gt; <span class="command">install mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.log4j/1.2.12-SNAPSHOT</span>
Bundle ID: 186
<span class="bold">karaf</span>@root&gt; <span class="command">list|grep log4j</span>
[ 186] [Resolved   ] [            ] [       ] [   60] Apache ServiceMix Bundles: <span class="grep">log4j</span>-1.2.12 (1.2.12.SNAPSHOT)
<span class="bold">karaf</span>@root&gt; <span class="command">start 186</span>
<span class="bold">karaf</span>@root&gt; <span class="command">list|grep log4j</span>
[ 186] [Active     ] [            ] [       ] [   60] Apache ServiceMix Bundles: <span class="grep">log4j</span>-1.2.12 (1.2.12.SNAPSHOT)
<span class="bold">karaf</span>@root&gt; <span class="command">packages:imports 186</span>
OSGi System Bundle (0): javax.management; version="0.0.0"
OSGi System Bundle (0): javax.naming; version="0.0.0"
OSGi System Bundle (0): javax.swing; version="0.0.0"
OSGi System Bundle (0): javax.swing.border; version="0.0.0"
OSGi System Bundle (0): javax.swing.event; version="0.0.0"
OSGi System Bundle (0): javax.swing.table; version="0.0.0"
OSGi System Bundle (0): javax.swing.text; version="0.0.0"
OSGi System Bundle (0): javax.swing.tree; version="0.0.0"
OSGi System Bundle (0): javax.xml.parsers; version="0.0.0"
OSGi System Bundle (0): org.w3c.dom; version="0.0.0"
OSGi System Bundle (0): org.xml.sax; version="0.0.0"
OSGi System Bundle (0): org.xml.sax.helpers; version="0.0.0"
OPS4J Pax Logging - API (3): org.apache.log4j.spi; version="1.2.15"
OPS4J Pax Logging - API (3): org.apache.log4j.xml; version="1.2.15"
OPS4J Pax Logging - API (3): org.apache.log4j; version="1.2.15"
geronimo-jms_1.1_spec (64): javax.jms; version="1.1.0"
Apache ServiceMix Bundles: mail-1.4.1 (86): javax.mail.internet; version="1.4.1"
Apache ServiceMix Bundles: mail-1.4.1 (86): javax.mail; version="1.4.1"
<span class="bold">karaf</span>@root&gt; <span class="command">packages:exports 186</span>
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5.util; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.net; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5.viewer; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.jmx; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.jdbc; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.config; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.helpers; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5.config; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.or.jms; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.nt; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.or.sax; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5.viewer.categoryexplorer; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.or; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.chainsaw; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.varia; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5.viewer.configure; version="1.2.12"
Apache ServiceMix Bundles: log4j-1.2.12 (186): org.apache.log4j.lf5.viewer.images; version="1.2.12"
<span class="bold">karaf</span>@root&gt;
</pre>
<p>Jak widać wszystko działa i ma się dobrze. :) Jedyna uwaga jaką mam to by nie używać tak spreparowanego log4j. W specyfikacji OSGi R4 V4.2 Enterprise jest opisana usługa logująca. Oprócz niej jest jeszcze <a href="http://wiki.ops4j.org/display/paxlogging/Pax+Logging">Pax Logging</a> (używany przez Karafa) wspierająca kilka różnych bibliotek od log4j poprzez slf4j po wspomnianą usługę OSGi.</p>
<p>Pozdrawiam i życzę miłej OSGi-fikacji! :)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.code-house.org/2010/03/osgi-new-bundles-servicemix-repository/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Wprowadzenie do Apache ServiceMix 4 cz. 1</title>
		<link>http://blog.code-house.org/2010/03/introduction-to-apache-servicemix4-part-1/</link>
		<comments>http://blog.code-house.org/2010/03/introduction-to-apache-servicemix4-part-1/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 11:19:50 +0000</pubDate>
		<dc:creator>Łukasz Dywicki</dc:creator>
				<category><![CDATA[Camel]]></category>
		<category><![CDATA[Consulting]]></category>
		<category><![CDATA[FUSE Source]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[ServiceMix]]></category>
		<category><![CDATA[Moved]]></category>

		<guid isPermaLink="false">http://blog.code-house.org/?p=179</guid>
		<description><![CDATA[Dnia 23 lutego w ramach Warszawa JUG miałem przyjemność wraz z Tomkiem Nurkiewiczem prezentować narzędzia integracyjne z otwartym kodem źródłowym. Tomek przedstawił Mule ESB, podczas gdy ja zająłem się Apache ServiceMix i Apache Camel. Ze względu na objętość przykładu ten wpis będzie jedynie wprowadzeniem do konsoli. Niestety podczas prezentacji nie udało mi się uruchomić przykładu [...]]]></description>
			<content:encoded><![CDATA[<p>Dnia 23 lutego w ramach Warszawa JUG miałem przyjemność wraz z <a href="http://nurkiewicz.blogspot.com/">Tomkiem Nurkiewiczem</a> prezentować narzędzia integracyjne z otwartym kodem źródłowym. Tomek przedstawił Mule ESB, podczas gdy ja zająłem się Apache ServiceMix i Apache Camel. Ze względu na objętość przykładu ten wpis będzie jedynie wprowadzeniem do konsoli.<br />
<!-- more --><br />
Niestety podczas prezentacji nie udało mi się uruchomić przykładu na &#8222;szynie&#8221; &#8211; ponieważ uniemożliwiły to zależności do bibliotek których nie miałem zapisanych lokalnie. Drugim mym przeciwnikiem był czas &#8211; nie było wielu chętnych by słuchać po 2h tłumaczeń dlaczego się nie udało :-) Na problem z zależnościami stworzyłem rozwiązanie i zgłosiłem je do Karaf-a (<a href="https://issues.apache.org/jira/browse/FELIX-2141">FELIX 2141</a>). W przyszłej wersji &#8211; 1.6 &#8211; wszyscy będą mogli skorzystać z polecenia <tt>features:info -t</tt> które wyświetli całe drzewko zależności potrzebnych do zainstalowania nowych funkcjonalności.</p>
<h3>Przygotowanie środowiska</h3>
<p>Do uruchomienia przykładów potrzebować będziemy dwóch paczek &#8211; pierwsza to <a href="http://servicemix.apache.org">Apache ServiceMix</a>, druga to <a href="http://maven.apache.org">Apache Maven</a>. Ze swojej strony polecam pobranie <a href="http://fusesource.com/downloads/">FUSE ESB 4.2</a>, produktu który jest oparty o ServiceMix. Zgodnie z moimi zapowiedziami od tej wersji FUSE Source wprowadza pełne wsparcie produkcyjne dla ServiceMix 4. Jeśli nie masz zainstalowanego Mavena i nigdy tego nie robiłeś zajrzyj na wiki <a href="http://inside.code-house.org/confluence/">Code-House</a>: <a href="http://inside.code-house.org/confluence/display/MVN/Wprowadzenie+do+Maven+2">Wprowadzenie do Maven 2</a></p>
<p>Po pobraniu odpowiedniej wersji należy ją rozpakować do wybranego folderu. Szynę uruchamiamy skryptem servicemix.bat. Jeśli wszystko przebiegło poprawnie naszym oczom powinien ukazać się obrazek jak poniżej:</p>
<pre class="listing">
<span class="command">E:\tools\progress\fuse-esb\4.2.0-b\bin>servicemix.bat</span>
 ____                  _          __  __ _
/ ___|  ___ _ ____   _(_) ___ ___|  \/  (_)_  __
\___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ /
 ___) |  __/ |   \ V /| | (_|  __/ |  | | |>  <
|____/ \___|_|    \_/ |_|\___\___|_|  |_|_/_/\_\

  Apache ServiceMix (4.2.0-fuse-01-00)

Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
karaf@root&gt;
</pre>
<p>Od tej chwili mamy do dyspozycji konsolę administracyjną. Aby zwiększyć jej użyteczność wykonujemy następujące polecenia:</p>
<pre class="listing">
karaf@root&gt; <span class="command">osgi:install wrap:mvn:http://download.java.net/maven/2!net.java.dev.jna/jna/3.1.0</span>
Bundle ID: 134
</pre>
<p>Spowoduje to pobranie z repozytorium Mavena (http://download.java.net/maven/2) biblioteki JNA w wersji 3.1.0. Nie musimy oczywiście określać za każdym razem adresu repozytoriów, ale o tym nieco później. Prefix wrap: spowoduje wygenerowanie manifestu OSGi na podstawie zawartości pobranej biblioteki. Jest on konieczny ponieważ JNA nie dostarcza potrzebnych danych do uruchomienia w środowisku OSGi.</p>
<pre class="listing">
karaf@root&gt; <span class="command">osgi:install mvn:http://jansi.fusesource.org/repo/release!org.fusesource.jansi/jansi/1.2</span>
Bundle ID: 135
</pre>
<p>Druga biblioteka wykorzystuje JNA i umożliwia kolorowanie tekstu w konsoli windowsowej zgodnie z ANSI, czyli tak jak w standardowych terminalach Unix-a. Po zainstalowaniu tych dwóch rzeczy pora zaprząc je do pracy. Poniżej filtrujemy listę zainstalowanych rzeczy po słowie Console.</p>
<pre class="listing">
karaf@root&gt; <span class="command">list|grep Console</span>
[  10] [Active     ] [Created     ] [       ] [   30] Apache Felix Karaf :: Shell Console (1.4.0.fuse-01-00)
karaf@root&gt; <span class="command">refresh 10</span>
</pre>
<p>Numer 10 oznacza id paczki OSGi, tekst Active to stan paczki a tekst Created informuje o stanie kontekstu blueprint, czwarty bloczek to stan kontekstu Springa, numer 30 to start level paczki a w ostatnim nawiasie mamy wersję. Sporo informacji jak na jedną linijkę, nieprawdaż? Blueprint to standaryzowanie tego czym jest Spring i Spring DM, także można korzystać zamiennie bądź z jednego bądź z drugiego rozwiązania. Ciekawe porównanie funkcjonalności obu rozwiązań &#8211; Spring DM oraz Blueprint opublikował kilka dni temu Guillaume Nodet na swoim blogu we wpisie <a href="http://gnodet.blogspot.com/2010/03/spring-dm-aries-blueprint-and-custom.html">Spring-DM, Aries Blueprint and custom namespaces</a>. Apache Camel od wersji 2.3 będzie wspierał Blueprint (<a href="https://issues.apache.org/activemq/browse/CAMEL-2022">CAMEL-2022</a>).</p>
<pre class="listing">
<span class="startup">
 ____                  _          __  __ _
/ ___|  ___ _ ____   _(_) ___ ___|  \/  (_)_  __
\___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ /
 ___) |  __/ |   \ V /| | (_|  __/ |  | | |>  <
|____/ \___|_|    \_/ |_|\___\___|_|  |_|_/_/\_\
</span><span class="bold">
  Apache ServiceMix</span> (4.2.0-fuse-01-00)

Hit '<span class="bold">&lt;tab&gt;</span>' for a list of available commands
and '<span class="bold">[cmd] --help</span>' for help on a specific command.
<span class="bold">karaf</span>@root&gt;
</pre>
<p>Teraz wykonanie poleceń z filtrem <strong>grep</strong> spowoduje podświetlenie szukanej frazy:</p>
<pre class="listing">
<span class="bold">karaf</span>@root&gt; <span class="command">list |grep Console</span>
[  10] [Active     ] [Created     ] [       ] [   30] Apache Felix Karaf :: Shell <span class="grep">Console</span> (1.4.0.fuse-01-00)
</pre>
<p>Takie małe udogodnienie przy przeglądaniu dłuższych rezultatów jest nieocenione.</p>
<h3>Podstawowe polecenia konsoli</h3>
<p>Polecenia w Apache Karaf są podzielone na kilka grup, które ułatwiają zarządzanie. Pierwszą grupą jest OSGi.</p>
<h4>Polecenia OSGi</h4>
<table class="listing">
<tr>
<th>Polecenie</th>
<th>Przeznaczenie</th>
</tr>
<tr>
<td>list</td>
<td>Wyświetlenie listy zainstalowanych paczek</td>
</tr>
<tr>
<td>ls [bundle id]</td>
<td>Wyświetlenie usług eksportowanych przez paczkę.</td>
</tr>
</tr>
<tr>
<td>ls -u [bundle id]</td>
<td>Wyświetlenie usług używanych przez paczkę.</td>
</tr>
<tr>
<td>headers [bundle id]</td>
<td>Wyświetlenie manifestu paczki.</td>
</tr>
<tr>
<td>start [bundle id]</td>
<td>Uruchomienie paczki o danym ID.</td>
</tr>
<tr>
<td>stop [bundle id]</td>
<td>Zatrzymanie paczki o danym ID.</td>
</tr>
<tr>
<td>restart [bundle id]</td>
<td>Zatrzymanie i wystartowanie paczki o danym ID.</td>
</tr>
<tr>
<td>update [bundle id]</td>
<td>Aktualizacja paczki.</td>
</tr>
<tr>
<td>refresh [bundle id]</td>
<td>Odświeżenie importów paczki a także przeładowanie kontekstu Spring-DM.</td>
</tr>
<tr>
<td>install [url]</td>
<td>Zainstalowanie nowej paczki.</td>
</tr>
<tr>
<td>uninstall [bundle id]</td>
<td>Odinstalowanie paczki.</td>
</tr>
<tr>
<td>shutdown</td>
<td>Zatrzymanie kontenera.</td>
</tr>
<tr>
<td>bundle-level [bundle id] [startLevel]</td>
<td rowspan="2">Ustawienie start levelu dla paczki.</td>
</tr>
<tr>
<td>start-level</td>
</tr>
</table>
<p>Kiedy znamy już listę poleceń nie pozostaje nic innego jak je wypróbować. :-) Checkout <a href="http://svn.code-house.org/wjug/">przykładowego kodu</a> z SVN pozwoli wykonać nam kilka ćwiczeń. Po wykonaniu polecenia <strong>mvn clean install</strong> w repozytorium Mavena są JARy które, naturalnie, chcemy zainstalować. Rezultat jaki powinniśmy zobaczyć w konsoli to:</p>
<pre class="listing">
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Money transfer ServiceMix example ..................... SUCCESS [2.028s]
[INFO] Money transfer :: API ................................. SUCCESS [3.182s]
[INFO] Money transfer :: POI bundle .......................... SUCCESS [7.504s]
[INFO] Money transfer :: Internal ............................ SUCCESS [0.093s]
[INFO] Money transfer :: Internal :: CSV ..................... SUCCESS [4.399s]
[INFO] Money transfer :: Internal :: XLS ..................... SUCCESS [2.823s]
[INFO] Money transfer :: Internal :: Mail .................... SUCCESS [2.309s]
[INFO] Money transfer :: Internal :: Splitter ................ SUCCESS [0.936s]
[INFO] Money transfer :: Internal :: Routes .................. SUCCESS [1:21.241s]
[INFO] Money transfer :: External ............................ SUCCESS [0.016s]
[INFO] Money transfer :: External :: Customer ................ SUCCESS [3.182s]
[INFO] Money transfer :: External :: Bank .................... SUCCESS [2.059s]
[INFO] Money transfer :: External :: Validator ............... SUCCESS [2.918s]
[INFO] Money transfer :: Features ............................ SUCCESS [0.171s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 54 seconds
[INFO] Finished at: Mon Mar 22 10:47:27 CET 2010
[INFO] Final Memory: 127M/341M
[INFO] ------------------------------------------------------------------------
</pre>
<p>Może teraz kilka słów o modułach które są widoczne w Mavenie.</p>
<table class="listing">
<tr>
<th width="28%">Moduł</th>
<th width="32%">Ścieżka<br />Maven ID</th>
<th>Przeznaczenie</th>
</tr>
<tr>
<td>Money transfer :: API</td>
<td>api<br />org.code-house.samples/api</td>
<td>API systemów zewnętrznych oraz POJO wykorzystywane do komunikacji.</td>
</tr>
<tr>
<td>Money transfer :: POI bundle</td>
<td>poi<br />org.code-house.samples/poi</td>
<td>Bundle zawierający bibliotekę Apache POI oraz wszystkie jej zależności z Manifestem OSGi pozwalającym na jej uruchomienie na szynie.</td>
</tr>
<tr>
<td>Money transfer :: Internal :: CSV</td>
<td>internal/csv<br />org.code-house.samples.internal/csv</td>
<td>Paczka zawierająca implementację procesora przetwarzającego pliki CSV na POJO MoneyTransfer.</td>
</tr>
<tr>
<td>Money transfer :: Internal :: XLS</td>
<td>internal/xls<br />org.code-house.samples.internal/xls</td>
<td>Paczka zawierająca implementację procesora przetwarzającego pliki XLS na POJO MoneyTransfer.</td>
</tr>
<tr>
<td>Money transfer :: Internal :: Mail</td>
<td>internal/mail<br />org.code-house.samples.internal/mail</td>
<td>Paczka z kodem dzielącym przychodzący mail z załącznikami na pojedyncze wiadomości które można przetworzyć jako XLS bądź CSV.</td>
</tr>
<tr>
<td>Money transfer :: Internal :: Splitter</td>
<td>internal/splitter<br />org.code-house.samples.internal/splitter</td>
<td>Paczka z kodem odpowiedzialnym za rozdzielanie listy obiektów MoneyTransfer na listę wiadomości.</td>
</tr>
<tr>
<td><strong>Money transfer :: Internal :: Routes</strong></td>
<td>internal/routes<br />org.code-house.samples.internal/routes</td>
<td><strong>Główna paczka z definicjami routingu</strong></td>
</tr>
<tr>
<td>Money transfer :: External :: Customer</td>
<td>external/customer<br />org.code-house.samples.external/customer</td>
<td>Implementacja WebService odpowiedzialnego za pobieranie danych klienta na podstawie numeru rachunku bankowego.</td>
</tr>
<tr>
<td>Money transfer :: External :: Bank</td>
<td>external/bank<br />org.code-house.samples.external/bank</td>
<td>Implementacja usługi zwracającej informację o nazwie banku na podstawie numeru rachunku.</td>
</tr>
<tr>
<td>Money transfer :: External :: Validator</td>
<td>external/validator<br />org.code-house.samples.external/validator</td>
<td>Usługa weryfikująca czy MoneyTransfer jest poprawny.</td>
</tr>
<tr>
<td>Money transfer :: Features</td>
<td>features<br />org.code-house.samples/features</td>
<td>Moduł zawierający opcjonalny deskryptor do uruchomienia modułów.</td>
</tr>
</table>
<p>Jak widać dwa główne obszary projektu są skupione w katalogach internal oraz external. Ten pierwszy zawiera implementacje ściśle związaną z usługami natomiast drugi to &#8222;zatyczki&#8221; emulujące działanie systemów zewnętrznych. Drobna nota &#8211; kolumna Maven ID nie zawiera informacji o wersji &#8211; w każdym module jest to <strong>1.0.0.SNAPSHOT</strong>.</p>
<p>Aby zainstalować któryś bundle przechodzimy do konsoli ServiceMix&#8217;a i wykonujemy takie polecenia:</p>
<pre class="listing">
<span class="bold">karaf</span>@root&gt; <span class="command">install -s mvn:org.code-house.samples/api/1.0.0.SNAPSHOT</span>
Bundle ID: 210
<span class="bold">karaf</span>@root&gt; <span class="command">features:install camel-jetty</span>
<span class="bold">karaf</span>@root&gt; <span class="command">install -s mvn:org.code-house.samples.external/customer/1.0.0.SNAPSHOT</span>
Bundle ID: 211
</pre>
<p>Po wykonaniu tych poleceń powinien być uruchomiony Web Service którego WSDL znajduje się pod adresem http://localhost:9001/CustomerWs?wsdl. Przełącznik <strong>-s</strong> w przypadku polecenia install powoduje że po zainstalowaniu bundle zostanie wystartowany. Polecenie <strong>features-install camel-jetty</strong> jest potrzebne nie ze względu na to że kolejna paczka korzysta z Camela, dzięki jego wykonaniu zostanie zainstalowane Jetty, z którego korzysta CXF.</p>
<p>Kolejne paczki instalujemy analogicznie:</p>
<pre class="listing">
<span class="bold">karaf</span>@root&gt; <span class="command">features:install camel-activemq</span>
<span class="bold">karaf</span>@root&gt; <span class="command">install -s mvn:org.code-house.samples.external/validator/1.0.0.SNAPSHOT</span>
Bundle ID: 215
<span class="bold">karaf</span>@root&gt; <span class="command">install -s mvn:org.code-house.samples.external/bank/1.0.0.SNAPSHOT</span>
Bundle ID: 217
</pre>
<p>Rozszerzenie <a href="http://camel.apache.org/activemq.html">camel-activemq</a> jest rozszerzeniem modułu <a href="http://camel.apache.org/jms.html">camel-jms</a> które pozwala na nieco wydajniejszą pracę z <a href="http://activemq.apache.org">ActiveMQ</a>.</p>
<h4>Integracja ServiceMix z repozytoriami Mavena</h4>
<p>Maven jako narzędzie do budowania korzysta z określonego schematu składowania bibliotek które następnie są automatycznie pobierane. Karaf, który jak wspomniałem podczas prezentacji, wyłonił się z projektu ServiceMix Kernel korzysta z biblioteki <a href="http://wiki.ops4j.org/display/paxurl/Documentation">Pax URL</a>. Dzięki temu z marszu mamy dostęp do standardowych repozytoriów Mavena, co jednak gdy mamy swoje repozytorium, które zawiera tylko nasze artefakty?<br />
Otwieramy plik etc/org.ops4j.pax.url.mvn.cfg i dodajemy w nim co trzeba. Moja standardowa konfiguracja wygląda następująco:</p>
<pre class="brush: plain; title: ; notranslate">
org.ops4j.pax.url.mvn.settings=E:/tools/maven-2.2.1/conf/settings.xml
org.ops4j.pax.url.mvn.localRepository=E:/repository
org.ops4j.pax.url.mvn.defaultRepositories=file:${karaf.home}/${karaf.default.repository}@snapshots
org.ops4j.pax.url.mvn.repositories= \
    http://repo1.maven.org/maven2, \
    http://repo.fusesource.com/maven2, \
    http://repo.fusesource.com/maven2-snapshot@snapshots@noreleases, \
    http://repository.apache.org/content/groups/snapshots-group@snapshots@noreleases, \
    http://repository.ops4j.org/maven2, \
    http://svn.apache.org/repos/asf/servicemix/m2-repo, \
    http://repository.springsource.com/maven/bundles/release, \
    http://repository.springsource.com/maven/bundles/external, \
    http://repository.code-house.org/content/groups/release, \
    http://repository.code-house.org/content/groups/snapshot@snapshots@noreleases, \

http://jansi.fusesource.org/repo/release
</pre>
<p>Dzięki temu PAX w pierwszej kolejności będzie skanował katalog E:/repository zamiast standardowego ~/.m2/repository. Jeśli któreś z repozytoriów wymaga autoryzacji adres powinien wyglądać następująco:</p>
<pre class="brush: plain; title: ; notranslate">http://user:pass@jansi.fusesource.org/repo/release</pre>
<h3>Podsumowanie</h3>
<p>Mam nadzieję że wpis ten przybliży chociaż w niewielkim stopniu ServiceMix 4 oraz Karafa. W przyszłym wpisie, którego daty publikacji nie sposób przewidzieć zostaną dokładniej omówione polecenia z grupy <strong>features</strong>. Póki co życzę miłej zabawy z konsolą. :-) W razie pytań, niejasności i problemów &#8211; proszę o komentarze.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.code-house.org/2010/03/introduction-to-apache-servicemix4-part-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

