Some of posts from this blog has been moved to dywicki.pl. You will be automatically redirected to new blog if you would submit comment.
New posts are published on dywicki.pl, this blog contains old content and it is not continued.
Niektóre posty z tego bloga zostały przeniesione do dywicki.pl. Zostaniesz automatycznie przekierowany jeśli bedzięsz chciał dodać komentarz.
Nowe posty sa publikowane na dywicki.pl, ten blog zawiera stare treści i nie jest kontynuowany.
Po dłuższym czasie braku aktywności na tym blogu – postanowiłem przenieść część z postów, które zostały na nim opublikowane do nowego blogu, który tyczy się kwestii java, middleware itd. pod adresem dywicki.pl. Być może zawitają tam inne języki. :) Wszystkie pozostałe posty są i nadal będą dostępne. Zmiany są podyktowane tym, że jest mi trudno prowadzić blog jednoosobowej firmy i developerski zarazem. Stąd też decyzja o stworzeniu tylko jednego – developerskiego.
Dla osób, które jeszcze subskrybują kanały RSS z tego bloga – proszę o przepięcie na nowy adres – dywicki.pl, na pewno nie pożałujecie. Nowy blog z pewnością będzie aktualizowany częściej niż ten. :)
I work with Apache Karaf almost every day. There is a lot of commands provided by default and most of them are a bit anonymous. In this post I would like introduce these commands.
Common command executed in Karaf shell is list. There is few switches which makes this command more usable. First of them is -l which shows bundle locations, second is -t. Second switch is available from Karaf 2.1.
Below example output of these commands:
__ __ ____ / //_/____ __________ _/ __/ / ,< / __ `/ ___/ __ `/ /_ / /| |/ /_/ / / / /_/ / __/ /_/ |_|\__,_/_/ \__,_/_/ Apache Karaf (2.1.2) Hit '<tab>' for a list of available commands and '[cmd] --help' for help on a specific command. Hit '<ctrl-d>' or 'osgi:shutdown' to shutdown Karaf. karaf@root> list -l START LEVEL 100 , List Threshold: 50 ID State Blueprint Spring Level Location [ 34] [Resolved ] [ ] [ ] [ 60] mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/1.1.2 [ 39] [Active ] [ ] [ ] [ 60] mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jetty/6.1.25_1 karaf@root> list -l -t 0 START LEVEL 100 , List Threshold: 0 ID State Blueprint Spring Level Location [ 0] [Active ] [ ] [ ] [ 0] System Bundle [ 1] [Active ] [ ] [ ] [ 5] mvn:org.ops4j.pax.url/pax-url-mvn/1.2.1 [ 2] [Active ] [ ] [ ] [ 5] mvn:org.ops4j.pax.url/pax-url-wrap/1.2.1 [ 3] [Active ] [ ] [ ] [ 8] mvn:org.ops4j.pax.logging/pax-logging-api/1.5.3 [ 4] [Active ] [ ] [ ] [ 8] mvn:org.ops4j.pax.logging/pax-logging-service/1.5.3 [ 5] [Active ] [ ] [ ] [ 10] mvn:org.apache.felix/org.apache.felix.configadmin/1.2.4 [ 6] [Active ] [ ] [ ] [ 11] mvn:org.apache.felix/org.apache.felix.fileinstall/3.0.2 [ 7] [Active ] [Created ] [ ] [ 20] mvn:org.apache.aries.blueprint/org.apache.aries.blueprint/0.2-incubating [ 8] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.jaas/org.apache.karaf.jaas.config/2.1.2 [ 9] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.1.2 [ 10] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf/org.apache.karaf.management/2.1.2 [ 11] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/2.1.2 [ 12] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.features/org.apache.karaf.features.core/2.1.2 [ 13] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.packages/2.1.2 [ 14] [Active ] [ ] [ ] [ 30] mvn:org.apache.aries.jmx/org.apache.aries.jmx.blueprint/0.2-incubating [ 15] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.jaas/org.apache.karaf.jaas.modules/2.1.2 [ 16] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.1.2 [ 17] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.features/org.apache.karaf.features.management/2.1.2 [ 18] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.features/org.apache.karaf.features.command/2.1.2 [ 19] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.log/2.1.2 [ 20] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.1.2 [ 21] [Active ] [ ] [ ] [ 30] mvn:org.apache.aries.jmx/org.apache.aries.jmx/0.2-incubating [ 22] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.blueprint/2.1.2 [ 23] [Active ] [ ] [ ] [ 30] mvn:org.apache.mina/mina-core/2.0.0-RC1 [ 24] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.dev/2.1.2 [ 25] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.osgi/2.1.2 [ 26] [Active ] [ ] [ ] [ 30] mvn:org.apache.sshd/sshd-core/0.4.0 [ 27] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.commands/2.1.2 [ 28] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.features/2.1.2 [ 29] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.console/2.1.2 [ 30] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.admin/org.apache.karaf.admin.management/2.1.2 [ 32] [Active ] [Created ] [ ] [ 30] mvn:org.apache.karaf.shell/org.apache.karaf.shell.config/2.1.2 [ 34] [Resolved ] [ ] [ ] [ 60] mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/1.1.2 [ 39] [Active ] [ ] [ ] [ 60] mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jetty/6.1.25_1
As you see first comman returns short list which contains bundles installed by me (servlet api and jetty). Second list contains bundles default installed also by Karaf. Another usefull switch is -s which shows symbolic names:
karaf@root> list -s START LEVEL 100 , List Threshold: 50 ID State Blueprint Spring Level Symbolic name [ 34] [Resolved ] [ ] [ ] [ 60] org.apache.geronimo.specs.geronimo-servlet_2.5_spec (1.1.2) [ 39] [Active ] [ ] [ ] [ 60] org.apache.servicemix.bundles.jetty (6.1.25.1)
Switch -t may be mixed with both -s and -l.
After first impression with OSGi and bundles as modules most of us moving to using OSGi services. That’s really cool stuff and gives a lot of fun, but without helper commands we may stuck. Karaf provides command named ls which shows services exported by given bundle.
karaf@root> ls 132 Apache Karaf :: Web Console :: Admin Plugin (132) provides: ----------------------------------------------------------- osgi.service.blueprint.compname = adminPlugin felix.webconsole.label = admin objectClass = javax.servlet.Servlet service.id = 176 ---- osgi.blueprint.container.version = 2.1.2 osgi.blueprint.container.symbolicname = org.apache.karaf.webconsole.admin objectClass = org.osgi.service.blueprint.container.BlueprintContainer service.id = 178
If we would check which services are in use by our bundle we have very usefull switch -u.
karaf@root> ls -u 21 Apache Aries JMX Bundle (21) uses: ---------------------------------- service.vendor = Apache Software Foundation service.pid = org.apache.felix.cm.ConfigurationAdmin service.description = Configuration Admin Service Specification 1.2 Implementation objectClass = org.osgi.service.cm.ConfigurationAdmin service.id = 33
When you work under OSGi it’s important which packages you import and export. The two commands packages:imports and packages:exports will simply show what’s comes and goes from your bundle. I’ll not show how these commands work but I have little trick for you. When you’re unable to resolve bundle because you have missing import packages and you have ClassNotFoundException type dev:dynamic-import bundleid command. This command add DynamicImport-Package: * entry to bundle manifest. After that, when you’ll resolve bundle type packages:imports and check complete list of import you missed in your headers.
All commands shown above are strictly related to OSGi. But Karaf is a little bigger and allow you do more than OSGi execution environment. One of tools which Karaf build on top of OSGi framework is features mechanism. You may define list of things to install and add dependencies between them instead typing install command line after line. But sometimes you would like to check what given feature contains. To do that type features:info command. This command requires feature name as argument.
karaf@root> features:info webconsole Description of webconsole 2.1.2 feature ---------------------------------------------------------------- Feature has no configuration Feature depends on: webconsole-base 2.1.2 Feature contains followed bundles: mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.1.2 mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.1.2 mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.1.2
You may use few additional switches: -b, -d, -c. First shows bundles in feature, second bundle dependencies and last feature configuration. We have also another switch -t which shows all these informations plus tree of features and it’s bundles.
karaf@root> features:info -t webconsole Description of webconsole 2.1.99-SNAPSHOT feature ---------------------------------------------------------------- Feature has no configuration Feature depends on: webconsole-base 2.1.99-SNAPSHOT Feature contains followed bundles: mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.1.99-SNAPSHOT mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.1.99-SNAPSHOT mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.1.99-SNAPSHOT Feature tree webconsole 2.1.99-SNAPSHOT + mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.1.99-SNAPSHOT + mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.1.99-SNAPSHOT \ mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.1.99-SNAPSHOT webconsole-base 2.1.99-SNAPSHOT + mvn:org.apache.felix/org.apache.felix.metatype/1.0.4 + mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.branding/2.1.99-SNAPSHOT \ mvn:org.apache.felix/org.apache.felix.webconsole/3.1.6 http 2.1.99-SNAPSHOT + mvn:org.ops4j.pax.web/pax-web-api/0.8.1 + mvn:org.ops4j.pax.web/pax-web-spi/0.8.1 + mvn:org.ops4j.pax.web/pax-web-runtime/0.8.1 \ mvn:org.ops4j.pax.web/pax-web-jetty/0.8.1 jetty [7.0,8.0) * Tree contains 1 unresolved dependencies * means that node declares dependency but the dependant feature is not available.
I mentioned dev:dynamic-import command before. But Karaf have few more commands which makes development easier. First of all is dev:show-tree which shows bundles tree, for example:
karaf@root> dev:show-tree 39 Bundle dump [39] is currently ACTIVE dump [39] +- org.apache.karaf.diagnostic.core [16] +- org.apache.aries.blueprint [7] +- org.apache.felix.configadmin [5] | +- org.ops4j.pax.logging.pax-logging-api [3] +- org.ops4j.pax.logging.pax-logging-api [3]
Another command you may use is dev:framework which allows you change OSGi framework used by Karaf. I don’t use this command to often.
Last command I would introduce is dev:create-dump commited to Karaf trunk by me. This command creates zip archive which contains diagnostic stuff you may attach to JIRA or send to developers in your company to check what was wrong. By default dumps contains log entries from $KARAF_BASE/data/log, list of installed bundles and features. You may also create new diagnostic providers. Sample code is available in SVN: demo, provider class, blueprint config.
Remember that every Karaf command can be executed with –help switch which shows all arguments and switches. In this post you was introduced to following commands:
Tegoroczna edycja konferencji Javarsovia jest bez wątpienia największym wydarzeniem tej kategorii w Polsce. Grono sponsorów i partnerów nafaszerowane gigantycznymi korporacjami (IBM, Oracle, Microsoft, Adobe, Google). Pomyśleć, że Code-House w zeszłym roku był sponsorem tej niewielkiej konferencji a w tym roku nie przyszło by nam rywalizować nawet o ławkę sponsorów rezerwowych. :-) Moje gratulacje dla kapituły przekazuję już teraz.
Wróćmy jednak do meritum – a mianowicie czego brakuje na Javarsovii. :-) Brakuje prelekcji o OSGi, które mimo porządnego wieku (10 lat) jest w dalszym ciągu nowością dla wielu developerów. Szczęśliwie, w ramach spotkań Warszawa JUG było zaplanowane spotkanie pt. Springowe spojrzenie na OSGi – Spring Dynamic Modules for OSGi(tm) – które miał poprowadzić Jacek Lis. Niestety, Jacek w planowanym terminie (15 czerwiec) będzie poza Warszawą. Aby obronić OSGi i załatać deficyt tego tematu na Javarsovii (zgłaszałem się z OSGi R4.2 Enterprise do C4P), postanowiłem zastąpić Jacka i poprowadzić prezentację – której temat również ewoluował na Spring Dynamic Modules, Blueprint, OSGi – deklaratywne.
Podsumowując, czego można się spodziewać w najbliższy wtorek:
Serdecznie zapraszam wszystkich zainteresowanych jak i zawiedzionych tym, że OSGi nie będzie na Javarsovii. :-)
1 Trwają negocjacje, czy Apache Felix Karaf zostanie projektem wysokiego poziomu (TLP) fundacji Apache.
Jakiś czas temu Jacek Laskowski wspominał o praktykach studenckich w IBM.
Celem praktyk w IBM jest zapoznanie się z produktami korporacji, praktyki w Code-House mają nieco inny wymiar – przede wszystkim technologiczny. Część z dziedzin, w których obracamy się obecnie przy okazji ServiceMixa jest nieco futurystyczna (OSGi R 4.2, dOSGi), część za to bardzo praktyczna np. szerokie użycie Mavena oraz Spring Framework czy JAX-WS/JAX-RS. Cały kod, który powstanie w wyniku praktyk będzie opublikowany na licencji Apache 2.0 i udostępniony publicznie.
Pula tematów dla praktykantów obejmuje następujące projekty fundacji Apache:
Praktyki są bezpłatne (niestety), odbywają się w trybie zdalnym i trwają do 3 miesięcy – termin rozpoczęcia praktyk jest uzgadniany ze studentem. Nie ma konieczności przebywania w naszym biurze – cały proces naboru aplikacji odbywa się przy pomocy Internetu i dopiero ostatni etap – rozmowa kwalifikacyjna – wymaga spotkania. Na co dzień konsultacje będziemy odbywać przy pomocy komunikatorów – Skype, GTalk, w skrajnym wypadku Gadu-Gadu. ;-) Co dwa tygodnie podsumowujemy minioną „iterację” oraz planujemy następną.
Po wprowadzeniu do narzędzi i projektów studenci będą wypływać na głębokie wody – czyli samodzielną realizację zadań.
Do zarządzania, koordynacji zadań oraz dokumentacji i weryfikacji kodu wykorzystujemy narzędzia Atlassian:
Jedyną wymaganą cechą jest znajomość języka Java – która zostanie zweryfikowana testem. Jeśli dysponujesz tą cechą i jesteś miłośnikiem technologii zapraszamy do wysyłania aplikacji pod adres rekrutacja@code-house.org z tematem Praktyki 2010. Nabór aplikacji na najbliższą edycję praktyk prowadzimy do 20 kwietnia. W zależności od rezultatów będą organizowane kolejne.
Nieco więcej informacji znajdziecie na stronie Praktyki Studenckie 2010.
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…
Problem zaczął się gdy usiłowałem uruchomić endpoint camela w OSGi. Mimo poprawnej konfiguracji, rozwiązanych zależności otrzymywałem wyjątek:
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)
Naturalnie, strasznie zirytowany, wziąłem się za dochodzenie – początkowo byłem przekonany że brakuje importów w camel-rss jednakże krótkie googlowanie wskazało rozwiązanie. Winne było kilka linii w klasie PluginManager:
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("rome.pluginmanager.useloadclass", "false")).booleanValue(); for (int i = 0; i <_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; }
Po przeróbce metoda wygląda następująco.
private Class[] getClasses() throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); List classes = new ArrayList(); boolean useLoadClass = Boolean.valueOf(System.getProperty("rome.pluginmanager.useloadclass", "false")).booleanValue(); for (int i = 0; i <_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; }
Naturalnie, można się zastanawiać po co bibliotece do obsługi RSS zabiegi z ClassLoaderami. Otóż ROME wykorzystuje plik .properties do konfiguracji „pluginów” (poors man DI). W określonych miejscach możemy dodać własne klasy które obsłużą jakiś niestandardowy format. Problem w tym, że „patent” 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.
Przy okazji stworzenia bundle z ROME 1.0 postanowiłem również stworzyć bundle dla Apache POI 3.6. Bibliotekę tą wykorzystywałem wspólnie z Tomkiem Nurkiewiczem podczas prezentacji „Mule ESB vs ServiceMix”.
Bardzo swobodna definicja:
OSGi-fikacja 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.
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.
Na potrzeby przykładu OSGi-fikacji wybrałem log4j, 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.
Zależności które ma log4j takie jak:
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 resolution na optional.
Pozostałe zależności wymienione poniżej są wymagane by móc odczytać plik log4j.xml:
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.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.servicemix.bundles</groupId> <artifactId>bundles-pom</artifactId> <version>4</version> </parent> <groupId>org.apache.servicemix.bundles</groupId> <artifactId>org.apache.servicemix.bundles.log4j</artifactId> <version>1.2.12-SNAPSHOT</version> <packaging>bundle</packaging> <name>Apache ServiceMix Bundles: ${pkgArtifactId}-${pkgVersion}</name> <description> This bundle simply wraps ${pkgArtifactId}-${pkgVersion}.jar. </description> <properties> <!-- Zmienne dla maven-bundle-plugin --> <servicemix.osgi.export.pkg> org.apache.log4j*;version=${pkgVersion} </servicemix.osgi.export.pkg> <servicemix.osgi.import.pkg> <!-- Zależności opcjonalne --> 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, * <!-- Wszystkie inne zależności jakie doda analizator --> </servicemix.osgi.import.pkg> <!-- Zmienne artefaktu --> <pkgGroupId>log4j</pkgGroupId> <pkgArtifactId>log4j</pkgArtifactId> <pkgVersion>1.2.12</pkgVersion> </properties> <dependencies> <!-- zależność do log4j --> <dependency> <groupId>${pkgGroupId}</groupId> <artifactId>${pkgArtifactId}</artifactId> <version>${pkgVersion}</version> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <!-- Kopiowanie plików .class --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <artifactSet> <includes> <include>${pkgGroupId}:${pkgArtifactId}</include> </includes> </artifactSet> <filters> <filter> <artifact>${pkgGroupId}:${pkgArtifactId}</artifact> <excludes> <exclude>**</exclude> </excludes> </filter> </filters> <promoteTransitiveDependencies>true</promoteTransitiveDependencies> <createDependencyReducedPom>true</createDependencyReducedPom> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Teraz pora na instalację bundla na szynie:
____ _ __ __ _ / ___| ___ _ ____ _(_) ___ ___| \/ (_)_ __ \___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ / ___) | __/ | \ 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> karaf@root> install mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.log4j/1.2.12-SNAPSHOT Bundle ID: 186 karaf@root> list|grep log4j [ 186] [Resolved ] [ ] [ ] [ 60] Apache ServiceMix Bundles: log4j-1.2.12 (1.2.12.SNAPSHOT) karaf@root> start 186 karaf@root> list|grep log4j [ 186] [Active ] [ ] [ ] [ 60] Apache ServiceMix Bundles: log4j-1.2.12 (1.2.12.SNAPSHOT) karaf@root> packages:imports 186 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" karaf@root> packages:exports 186 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" karaf@root>
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 Pax Logging (używany przez Karafa) wspierająca kilka różnych bibliotek od log4j poprzez slf4j po wspomnianą usługę OSGi.
Pozdrawiam i życzę miłej OSGi-fikacji! :)
Dnia dzisiejszego została wydana finalna wersja specyfikacji OSGi R4 V4.2 Enterprise. Wersja jest gotowa do pobrania pod adresem http://www.osgi.org/Download/Release4V42. Dokument ma 483 strony. :-)
Do opublikowania tego postu zachęcił mnie Jacek Laskowski swym postem pod tytułem W piątek 4Developers ze mną z Enterprise OSGi i in.
Bardzo się cieszę że na 4Developers (na którym niestety mnie nie będzie) temat Enterprise OSGi będzie poruszony, ponieważ jak się zdaje jest to nieuchronny kierunek rozwoju Javy. Pod wpływem słów Jacka zacząłem się zastanawiać nad długofalowymi efektami jakie OSGi ma wnieść do developmentu.
Hałas który obecnie jest wokół OSGi w przybiera konkretne kształty w postaci projektów takich jak Aries czy Gemini. Obydwa projekty skupiają się nad ostatnimi draftami OSGi R4 V4.2 i mają na celu udostępnienie technologii takich jak JNDI, JPA i JMX wewnątrz kontenerów OSGi. Zacznijmy jednak od początku..
JAR-hell occurs when software is deployed into a runtime environment which is unsuitable, but nothing other than full integration testing would detect this. Having multiple software packages dependent upon the same piece of software, with unpredictable incompatibilities, is pure hell. Ensuring the compatibility of a variety of dependent packages is duanting, doing it amongst the variety supported by a hierarchy of complex class loaders, is inhuman.
Źródło Apache Depot
Czyli w skrócie – piekło zaczyna się robić gdy pojawiają się niekompatybilności między bibliotekami w poprawnym środowisku. Co więcej owe niekompatybilności można wykryć dopiero po dogłębnych testach we wszystkich środowiskach w których ma działać aplikacja.
W przypadku OSGi wszystkie zależności są przewidywalne, co więcej nie uda się nam uruchomić paczki bez jej zależności – stąd teoretycznie nigdy nie powinniśmy widzieć ClassNotFoundException. Nie uda nam się również uruchomić naszego bundle jeśli powstanie konflikt w używanych zależnościach. Przykład z życia wzięty – mamy bundle zależące od camel-activemq oraz activemq-core. Pierwszy z nich pozwala na import spring-jms w wersji < 4.0, natomiast drugi w wersji < 2.6. Jeśli do tego mamy dwie wersje bundle spring-jms: 2.5.6 oraz 3.0.0 to mamy klapę. Naszej paczki nie da się wystartować ponieważ otrzymamy "Packages usage conflict". Zostaliśmy ochronieni przed JAR Hellem kosztem zablokowania kodu nawet jeśli zależność była opcjonalna.
Problem wydaje się trywialny – teoretycznie to są dwie różne wersje Springa, nie da się zaprzeczyć że 2.5.6 != 3.0.0. W praktyce jednak zmiany w spring-jms były tak niewielkie że można bez problemu uruchomić activemq-core z nową wersją. W takim wypadku jesteśmy zmuszeni do czekania na nową wersję ActiveMQ, która będzie pozwalała na korzystanie ze Springa 3.0 bądź samodzielnie zmodyfikować manifesty. Obydwa rozwiązania są równie złe – jedno to czekanie, drugie to tworzenie nowej dystrybucji ActiveMQ.
Co w takim wypadku możemy zrobić? Możemy użyć serwisów OSGi, które pozwalają na oddzielenie implementacji od interfejsu, dzięki czemu możemy połączyć dwie wersje bibliotek za fasadą w postaci ServiceReference. Tutaj jednak może pojawić się inny problem – mianowicie część bibliotek które lubią dostęp do ClassLoaderów może skutecznie protestować – na przykład Hibernate czy Open JPA. Dla przykładu diagram obrazujący kolejny z życia wzięty przypadek:
W tym przypadku usiłowałem stworzyć działającą usługę która zapisywała by przychodzące komunikaty w bazie danych. Może parę słów o tym, który bundle co robi:
Całość komunikacji odbywała się z JMS w trybie request-reply dzięki Apache Camel. Po bardzo długich „walkach” poniższą strukturę udało się uruchomić pod OSGi. Ostatecznie całość działa z Hibernate w układzie takim jak poniżej.
Z diagramu wyrzuciłem paczki które nie są istotne takie jak driver JDBC czy Commons ConnectionPool. Jedyny mankament na jaki trafiłem wiąże się z DAO Service, mianowicie bundle który go eksportuje poprzez Spring-DM musi zadeklarować widoczność wszystkich swoich klas dla paczki która będzie korzystać z usługi co jak by nie patrzeć jest drobnym wypaczeniem fasady jaką ma być ServiceReference. Niestety po 2 tygodniach poświęconych na uruchomienie JPA w OSGi nie siliłem się na elegancję.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd "> <osgi:reference id="dataSource" interface="javax.sql.DataSource" /> <osgi:service id="exchangeDAOExporter" ref="exchangeDAO" context-class-loader="service-provider" interface="org.code_house.dataaccess.ExchangeDAO" /> </beans>
Problem jaki powstaje z OSGi to metadane. Do tej pory – jeśli zarządzałem zależnościami do bibliotek robiłem to przez dependencyManagement Mavena, dzięki któremu rozwiązywałem wszystkie konflikty. OSGi jednak nie wiąże się z Mavenem ponieważ są to dwa różne obszary o zgoła innym funkcjonowaniu – OSGi to runtime, Maven to build time. Dopóki nie zapanuje harmonia pomiędzy tymi dwoma uruchamianie czegokolwiek w OSGi będzie katorgą. Należy do tego dodać jeszcze jeden element związany z OSGi – mianowicie OSGi Bundle Repository (OBR), a OBR nijak się ma do repozytoriów Mavena przez co rozbieżności tylko się nasilają.
Aby temu zapobiegać najpopularniejsze istniejące repozytoria SpringSource Enterprise Bundle Repository oraz ServiceMix 4 Bundles repository – publikują artefakty w repozytoriach Mavena. Problem w tym, że część artefaktów jest powielona. Tak jak kiedyś były 3 wersje Java Persistence API tak teraz dochodzą kolejne dwie – z manifestami OSGi. Czy ktoś wspominał o piekle?
Należy również dodać że nie każdy JAR który ląduje w OSGi jest traktowany tak samo – oprócz standardowych bundli są również fragmenty, które są świetnym rozwiązaniem, jednakże początkowo potrafią przysporzyć wielu problemów. Cały trik sprowadza się do tego, że fragmenty mają wspólny class loader z paczką do której są przypięte.
Po całych tych wywodach na temat problemów z OSGi pora na to co ma ono nam dać – przenośność. Podobnie jak Java EE 6 z profilami tak OSGi ma zapewnić większą przenośność klocków pomiędzy środowiskami. Wyobrażacie sobie, że można przenieść aplikację z kontenera servletów na serwer aplikacyjny bez modyfikacji? Albo usługę z szyny integracyjnej na kontener servletów? Niedorzeczne, ale z OSGi możliwe do wykonania. Wystarczy zainstalować wszystkie wymagane bundle i całość będzie działać.
Oczywiście naiwna była by wiara w to, że tak będzie. Każda specyfikacja która powstaje dla Javy ma standaryzować i ujednolicać środowiska. W praktyce jednak każda z nich staje się punktem wyjściowym do rozwoju nowych produktów. Każdy dostawca oferuje zgodność ze specyfikacją plus coś. Nie twierdzę, że to złe, ponieważ polaryzacja rynku oprogramowania jest tak samo potrzebna jak wolny rynek, należy się jednak wystrzegać monopolistów a w przypadku oprogramowania również vendor locków.
Patrzę na OSGi z nadzieją ponieważ w moim mniemaniu jest to przedłużenie idei jaką niosła specyfikacja Java Business Integration. Propozycja JBI 2.0 spotkała się z krytyką ze strony IBM oraz BEA Systems zasłaniających się tym, że istnieje SCA. Problem w tym, że obydwie specyfikacje traktują o innych warstwach integracji – SCA gwarantuje przenośność usług, podczas gdy JBI miało zapewnić przenośność komponentów i komunikacji między nimi. SCA i JBI mogą a nawet powinny iść w parze. Teoria JBI mówiła o możliwości uruchomienia servicemix-cxf-bc (zgodnego z JBI) na Open ESB, w praktyce okazywało się to jednak bardzo trudne. Dzięki OSGi/Enterprise OSGi stanie się to łatwiejsze.
W ciągu kilku najbliższych lat trend OSGi dzięki zainteresowaniu wielkich korporacji będzie rósł w siłę. Trzymam kciuki by Enterprise OSGI przyniosło więcej korzyści niż tylko zbawienie od JAR Hella.
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 na „szynie” – ponieważ uniemożliwiły to zależności do bibliotek których nie miałem zapisanych lokalnie. Drugim mym przeciwnikiem był czas – 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 (FELIX 2141). W przyszłej wersji – 1.6 – wszyscy będą mogli skorzystać z polecenia features:info -t które wyświetli całe drzewko zależności potrzebnych do zainstalowania nowych funkcjonalności.
Do uruchomienia przykładów potrzebować będziemy dwóch paczek – pierwsza to Apache ServiceMix, druga to Apache Maven. Ze swojej strony polecam pobranie FUSE ESB 4.2, 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 Code-House: Wprowadzenie do Maven 2
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:
E:\tools\progress\fuse-esb\4.2.0-b\bin>servicemix.bat ____ _ __ __ _ / ___| ___ _ ____ _(_) ___ ___| \/ (_)_ __ \___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ / ___) | __/ | \ V /| | (_| __/ | | | |> < |____/ \___|_| \_/ |_|\___\___|_| |_|_/_/\_\ Apache ServiceMix (4.2.0-fuse-01-00) Hit '' for a list of available commands and '[cmd] --help' for help on a specific command. karaf@root>
Od tej chwili mamy do dyspozycji konsolę administracyjną. Aby zwiększyć jej użyteczność wykonujemy następujące polecenia:
karaf@root> osgi:install wrap:mvn:http://download.java.net/maven/2!net.java.dev.jna/jna/3.1.0
Bundle ID: 134
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.
karaf@root> osgi:install mvn:http://jansi.fusesource.org/repo/release!org.fusesource.jansi/jansi/1.2
Bundle ID: 135
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.
karaf@root> list|grep Console [ 10] [Active ] [Created ] [ ] [ 30] Apache Felix Karaf :: Shell Console (1.4.0.fuse-01-00) karaf@root> refresh 10
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ń – Spring DM oraz Blueprint opublikował kilka dni temu Guillaume Nodet na swoim blogu we wpisie Spring-DM, Aries Blueprint and custom namespaces. Apache Camel od wersji 2.3 będzie wspierał Blueprint (CAMEL-2022).
____ _ __ __ _ / ___| ___ _ ____ _(_) ___ ___| \/ (_)_ __ \___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| | \ \/ / ___) | __/ | \ 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>
Teraz wykonanie poleceń z filtrem grep spowoduje podświetlenie szukanej frazy:
karaf@root> list |grep Console [ 10] [Active ] [Created ] [ ] [ 30] Apache Felix Karaf :: Shell Console (1.4.0.fuse-01-00)
Takie małe udogodnienie przy przeglądaniu dłuższych rezultatów jest nieocenione.
Polecenia w Apache Karaf są podzielone na kilka grup, które ułatwiają zarządzanie. Pierwszą grupą jest OSGi.
Polecenie | Przeznaczenie |
---|---|
list | Wyświetlenie listy zainstalowanych paczek |
ls [bundle id] | Wyświetlenie usług eksportowanych przez paczkę. |
ls -u [bundle id] | Wyświetlenie usług używanych przez paczkę. |
headers [bundle id] | Wyświetlenie manifestu paczki. |
start [bundle id] | Uruchomienie paczki o danym ID. |
stop [bundle id] | Zatrzymanie paczki o danym ID. |
restart [bundle id] | Zatrzymanie i wystartowanie paczki o danym ID. |
update [bundle id] | Aktualizacja paczki. |
refresh [bundle id] | Odświeżenie importów paczki a także przeładowanie kontekstu Spring-DM. |
install [url] | Zainstalowanie nowej paczki. |
uninstall [bundle id] | Odinstalowanie paczki. |
shutdown | Zatrzymanie kontenera. |
bundle-level [bundle id] [startLevel] | Ustawienie start levelu dla paczki. |
start-level |
Kiedy znamy już listę poleceń nie pozostaje nic innego jak je wypróbować. :-) Checkout przykładowego kodu z SVN pozwoli wykonać nam kilka ćwiczeń. Po wykonaniu polecenia mvn clean install w repozytorium Mavena są JARy które, naturalnie, chcemy zainstalować. Rezultat jaki powinniśmy zobaczyć w konsoli to:
[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] ------------------------------------------------------------------------
Może teraz kilka słów o modułach które są widoczne w Mavenie.
Moduł | Ścieżka Maven ID |
Przeznaczenie |
---|---|---|
Money transfer :: API | api org.code-house.samples/api |
API systemów zewnętrznych oraz POJO wykorzystywane do komunikacji. |
Money transfer :: POI bundle | poi org.code-house.samples/poi |
Bundle zawierający bibliotekę Apache POI oraz wszystkie jej zależności z Manifestem OSGi pozwalającym na jej uruchomienie na szynie. |
Money transfer :: Internal :: CSV | internal/csv org.code-house.samples.internal/csv |
Paczka zawierająca implementację procesora przetwarzającego pliki CSV na POJO MoneyTransfer. |
Money transfer :: Internal :: XLS | internal/xls org.code-house.samples.internal/xls |
Paczka zawierająca implementację procesora przetwarzającego pliki XLS na POJO MoneyTransfer. |
Money transfer :: Internal :: Mail | internal/mail org.code-house.samples.internal/mail |
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. |
Money transfer :: Internal :: Splitter | internal/splitter org.code-house.samples.internal/splitter |
Paczka z kodem odpowiedzialnym za rozdzielanie listy obiektów MoneyTransfer na listę wiadomości. |
Money transfer :: Internal :: Routes | internal/routes org.code-house.samples.internal/routes |
Główna paczka z definicjami routingu |
Money transfer :: External :: Customer | external/customer org.code-house.samples.external/customer |
Implementacja WebService odpowiedzialnego za pobieranie danych klienta na podstawie numeru rachunku bankowego. |
Money transfer :: External :: Bank | external/bank org.code-house.samples.external/bank |
Implementacja usługi zwracającej informację o nazwie banku na podstawie numeru rachunku. |
Money transfer :: External :: Validator | external/validator org.code-house.samples.external/validator |
Usługa weryfikująca czy MoneyTransfer jest poprawny. |
Money transfer :: Features | features org.code-house.samples/features |
Moduł zawierający opcjonalny deskryptor do uruchomienia modułów. |
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 „zatyczki” emulujące działanie systemów zewnętrznych. Drobna nota – kolumna Maven ID nie zawiera informacji o wersji – w każdym module jest to 1.0.0.SNAPSHOT.
Aby zainstalować któryś bundle przechodzimy do konsoli ServiceMix’a i wykonujemy takie polecenia:
karaf@root> install -s mvn:org.code-house.samples/api/1.0.0.SNAPSHOT Bundle ID: 210 karaf@root> features:install camel-jetty karaf@root> install -s mvn:org.code-house.samples.external/customer/1.0.0.SNAPSHOT Bundle ID: 211
Po wykonaniu tych poleceń powinien być uruchomiony Web Service którego WSDL znajduje się pod adresem http://localhost:9001/CustomerWs?wsdl. Przełącznik -s w przypadku polecenia install powoduje że po zainstalowaniu bundle zostanie wystartowany. Polecenie features-install camel-jetty 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.
Kolejne paczki instalujemy analogicznie:
karaf@root> features:install camel-activemq karaf@root> install -s mvn:org.code-house.samples.external/validator/1.0.0.SNAPSHOT Bundle ID: 215 karaf@root> install -s mvn:org.code-house.samples.external/bank/1.0.0.SNAPSHOT Bundle ID: 217
Rozszerzenie camel-activemq jest rozszerzeniem modułu camel-jms które pozwala na nieco wydajniejszą pracę z ActiveMQ.
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 Pax URL. 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?
Otwieramy plik etc/org.ops4j.pax.url.mvn.cfg i dodajemy w nim co trzeba. Moja standardowa konfiguracja wygląda następująco:
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
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:
http://user:pass@jansi.fusesource.org/repo/release
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 features. Póki co życzę miłej zabawy z konsolą. :-) W razie pytań, niejasności i problemów – proszę o komentarze.
Od dłuższego czasu pracuję z następującymi narzędziami: Maven, Eclipse, Jetty. Nigdy nie starałem się na to by moje projekty dobrze współgrały z Eclipse ponieważ wszystko i tak uruchamiam przez Mavena. Korzyścią jest przenośność tego rozwiązania, wadą brak klikalnej wygody, tj zakładki serwerów w Eclipse i aplikacji które są na nich uruchomione.
Read the rest of this entry »