13 października 2008

Spring-DM 1.2.0 M1 z Jetty na Equinox z pomocą pax-runner

Wczoraj, w pax-runner w akcji - uruchamianie aplikacji webowych jako pakunków OSGi, opisałem uruchamianie aplikacji webowych korzystając z dobrodziejstw pax-runner. Przykładowa aplikacja spring-osgi-webapp uruchomiona została w ramach Jetty, który był zanurzony w Equinoksie za pomocą pakunku org.ops4j.pax.web.service. Prosta aplikacja, więc i proste środowisko wystarczyło (przez "proste" rozumiem wyłącznie łatwość zestawienia gotowego do działania środowiska, a nie funkcjonalność niskiej jakości). Kiedy jednak chcielibyśmy skorzystać z dobrodziejstw oferowanych przez Spring Framework na scenę wchodzi Spring Dynamic Modules for OSGi(tm) Service Platforms (Spring-DM).

Rolą Spring-DM jest monitorowanie środowiska uruchomieniowego OSGi i reagowanie na instalację pakunków korzystających z funkcjonalności Spring Framework, tak aby bardziej restrykcyjne środowisko javowe, jakim jest OSGi, nie powodowało zbyt wielu komplikacji podczas tworzenia i uruchamiania aplikacji. Skoncentrowałem swoje wysiłki na aplikacjach webowych, ale nie ma to w zasadzie wielkiego znaczenia, czy są to aplikacje webowe, czy niewebowe. Chodzi jedynie o połączenie cech Spring Framework i OSGi (potencjalnie z Java EE). Marzenie ściętej głowy? Już przekonałem się, że nie (bagatela, na chwilę przed moim wystąpieniem Wprowadzenie do OSGi i Spring Dynamic Modules (Spring-DM) podczas tegorocznej konferencji Java Developers Day 2008 w Krakowie za...3 dni!). Przekonaj się samemu, że idzie gładko. Zapraszam również na konferencję, abyśmy mogli omówić szczegóły.

Rozpoczynamy od zebrania wymaganych pakunków OSGi do uruchomienia Spring-DM (zakładam, że sam pax-runner jest już gotowy. Nie?! Zajrzyj do wspomnianego pax-runner w akcji - uruchamianie aplikacji webowych jako pakunków OSGi). Posiłkuję się plikami dystrybuowanymi w ramach Spring-DM 1.2.0 M1 oraz dostępnych w repozytoriach Spring-DM OSGified Artifacts Repository i SpringSource Enterprise Bundle Repository. Cały zestaw pakunków to następująca lista:
  • com.springsource.javax.el-2.1.0.jar
  • com.springsource.javax.servlet.jsp-2.1.0.jar
  • com.springsource.javax.servlet.jsp.jstl-1.1.2.jar
  • com.springsource.junit-3.8.2.jar
  • com.springsource.net.sf.cglib-2.1.3.jar
  • com.springsource.org.aopalliance-1.0.0.jar
  • com.springsource.org.apache.taglibs.standard-1.1.2.jar
  • com.springsource.org.objectweb.asm-2.2.3.jar
  • jetty-6.1.9.jar
  • jetty-util-6.1.9.jar
  • jetty.start.osgi-1.0.0.jar
  • jetty.web.extender.fragment.osgi-1.0.0.jar
  • servlet-api.osgi-2.5-SNAPSHOT.jar
  • spring-aop-2.5.5.jar
  • spring-beans-2.5.5.jar
  • spring-context-2.5.5.jar
  • spring-context-support-2.5.5.jar
  • spring-core-2.5.5.jar
  • spring-osgi-core-1.2.0-m1.jar
  • spring-osgi-extender-1.2.0-m1.jar
  • spring-osgi-io-1.2.0-m1.jar
  • spring-osgi-web-1.2.0-m1.jar
  • spring-osgi-web-extender-1.2.0-m1.jar
  • spring-web-2.5.5.jar
  • spring-webmvc-2.5.5.jar
Umieszczam pakunki w wybranym katalogu, powiedzmy springdm-jetty, i uruchamiam pax-runner.
 C:\apps\equinox-springdm\pax-runner-profiles\springdm-jetty
> pax-run "--platform=equinox" "--log=DEBUG" "--profiles=log" springdm-jetty
Po chwili, kiedy przewinie się mnóstwo komunikatów (dzięki --log=DEBUG, który jest dla celów poznawczych, jak działa Spring-DM pod spodem) można podejść do wdrożenia aplikacji webowej korzystającej ze Spring Framework.
 osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 ACTIVE org.eclipse.osgi.util_3.1.300.v20080303
2 ACTIVE org.eclipse.osgi.services_3.1.200.v20070605
3 ACTIVE org.ops4j.pax.logging.pax-logging-api_1.1.1
4 ACTIVE org.ops4j.pax.logging.pax-logging-service_1.1.1
5 ACTIVE com.springsource.javax.el_2.1.0
6 ACTIVE com.springsource.javax.servlet.jsp_2.1.0
7 ACTIVE com.springsource.javax.servlet.jsp.jstl_1.1.2
8 ACTIVE com.springsource.junit_3.8.2
9 ACTIVE com.springsource.net.sf.cglib_2.1.3
10 ACTIVE com.springsource.org.aopalliance_1.0.0
11 ACTIVE com.springsource.org.apache.taglibs.standard_1.1.2
12 ACTIVE com.springsource.org.objectweb.asm_2.2.3
13 ACTIVE org.mortbay.jetty.server_6.1.9
14 ACTIVE org.mortbay.jetty.util_6.1.9
15 ACTIVE org.springframework.osgi.jetty.start.osgi_1.0.0
16 RESOLVED org.springframework.osgi.jetty.web.extender.fragment.osgi_1.0.0
Master=27
17 ACTIVE org.springframework.osgi.servlet-api.osgi_2.5.0.SNAPSHOT
18 ACTIVE org.springframework.bundle.spring.aop_2.5.5
19 ACTIVE org.springframework.bundle.spring.beans_2.5.5
20 ACTIVE org.springframework.bundle.spring.context_2.5.5
21 ACTIVE org.springframework.bundle.spring.context.support_2.5.5
22 ACTIVE org.springframework.bundle.spring.core_2.5.5
23 ACTIVE org.springframework.bundle.osgi.core_1.2.0.m1
24 ACTIVE org.springframework.bundle.osgi.extender_1.2.0.m1
25 ACTIVE org.springframework.bundle.osgi.io_1.2.0.m1
26 ACTIVE org.springframework.bundle.osgi.web_1.2.0.m1
27 ACTIVE org.springframework.bundle.osgi.web.extender_1.2.0.m1
Fragments=16
28 ACTIVE org.springframework.bundle.spring.web_2.5.5
29 ACTIVE org.springframework.bundle.spring.webmvc_2.5.5
Najlepiej skorzystać z przykładów dystrybuowanych w ramach samego Spring-DM. Musimy je zbudować lokalnie za pomocą Apache Maven 2 (nie udało mi się znaleźć ich dostępnych binarnie w Sieci). W katalogu src Spring-DM wykonujemy polecenie mvn package -Pequinox,samples -Dmaven.test.skip=true.
 jlaskowski@work /cygdrive/c/apps/spring-osgi/src
$ mvn package -Pequinox,samples -Dmaven.test.skip=true
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Spring Dynamic Modules ................................ SUCCESS [2.203s]
[INFO] Spring OSGi Mocks ..................................... SUCCESS [8.578s]
[INFO] Spring OSGi IO ........................................ SUCCESS [0.188s]
[INFO] Spring OSGi Core ...................................... SUCCESS [1.343s]
[INFO] Spring OSGi Extender .................................. SUCCESS [0.438s]
[INFO] Spring OSGi Testing Framework ......................... SUCCESS [22.281s]
[INFO] Spring OSGi Web Support ............................... SUCCESS [0.516s]
[INFO] Spring OSGi Web Extender .............................. SUCCESS [0.218s]
[INFO] Spring OSGi Archetype ................................. SUCCESS [1.188s]
[INFO] Spring OSGi Annotations ............................... SUCCESS [0.156s]
[INFO] Spring OSGi Samples ................................... SUCCESS [0.078s]
[INFO] Spring OSGi Samples: Simple Service ................... SUCCESS [0.016s]
[INFO] Spring OSGi Samples: Simple Service Provider .......... SUCCESS [0.062s]
[INFO] Spring OSGi Samples: Simple Service Integration Tests . SUCCESS [0.063s]
[INFO] Spring OSGi Samples: Weather Service .................. SUCCESS [0.000s]
[INFO] Spring OSGi Samples: Weather Service DAO .............. SUCCESS [0.109s]
[INFO] Spring OSGi Samples: Weather Service Extension ........ SUCCESS [0.172s]
[INFO] Spring OSGi Samples: Weather Service Provider ......... SUCCESS [0.109s]
[INFO] Spring OSGi Samples: Weather Service Client ........... SUCCESS [0.125s]
[INFO] Spring OSGi Samples: Weather Service Wiring Bundle .... SUCCESS [0.078s]
[INFO] Spring OSGi Samples: Weather Service Integration Test . SUCCESS [0.125s]
[INFO] Spring OSGi Samples: Simple Web Application ........... SUCCESS [0.000s]
[INFO] Spring OSGi Samples: SimpleWebApp - Log4j Fragment .... SUCCESS [0.438s]
[INFO] Spring OSGi Samples: SimpleWebApp - War Bundle ........ SUCCESS [0.578s]
[INFO] Spring OSGi Samples: SimpleWebApp - Integration Test .. SUCCESS [0.281s]
[INFO] Spring OSGi Samples: OSGi Web Console ................. SUCCESS [0.016s]
[INFO] Spring OSGi Samples: OSGi Web Console - Log4j Fragment SUCCESS [0.359s]
[INFO] Spring OSGi Samples: OSGi Web Console - War Bundle .... SUCCESS [0.719s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47 seconds
Następnie, w ramach konsoli Equinoksa wdrażamy aplikację Simple Web Application (katalog samples/simple-web-app).

Najpierw instalacja pakunku war-1.2.0-m1.war.
 osgi> install file:c:/apps/spring-osgi/src/samples/simple-web-app/war/target/war-1.2.0-m1.war
[OSGi Console] DEBUG org.springframework.osgi.extender.internal.activator.ContextLoaderListener -
Processing bundle event [INSTALLED] for bundle [org.springframework.osgi.samples.simplewebapp]
[OSGi Console] DEBUG org.springframework.osgi.extender.internal.activator.ContextLoaderListener -
Processing bundle event [INSTALLED] for bundle [org.springframework.osgi.samples.simplewebapp]
Bundle id is 30
[Framework Event Dispatcher] INFO org.springframework.osgi.samples.simplewebapp - BundleEvent INSTALLED
Jak można zauważyć instalacja aplikacji (będącej pakunkiem OSGi) wzbudziła słuchacza org.springframework.osgi.extender.internal.activator.ContextLoaderListener, który odpowiedzialny jest za zestawienie środowiska (kontekstu) springowego dla aplikacji korzystających z/opartych o Spring Framework.

Teraz pozostaje już tylko uruchomić pakunek poleceniem start 30 (może być wymagane wciśnięcie ENTER dwukrotnie - raz, aby zatwierdzić polecenie, a drugi w połowie przetwarzania polecenia start). Z komunikatem
 [Timer-3] INFO org.springframework.osgi.web.deployer.jetty.JettyWarDeployer - 
Successfully deployed bundle [Simple OSGi War (org.springframework.osgi.samples.simplewebapp)]
at [/simple-web-app] on server Jetty-6.1.x
pozostaje jedynie odwiedzić stronę aplikacji - http://localhost:8080/spring-osgi-webapp/.

Działa! Kolejny krok to pomysł na ciekawą aplikację webową demonstrującą siłę środowiska OSGi z Spring-DM, czyli mieszankę funkcjonalności OSGi, Spring Framework i Java EE. Wciąż pamiętam komentarze Daniela (zebrane w Pora na łyk OSGi - rozdział 1. Wprowadzenie). I uwierzyć, że gość stosuje Spring Framework z OSGi od tak dawna. Musi mieć niezłą zabawę czytając kolejne wpisy z moimi poczynaniami ;-)