GitXplorerGitXplorer
v

runtime-api-switcher-osgi-based

public
0 stars
0 forks
0 issues

Commits

List of commits on branch master.
Unverified
3a266faf0ade3a39519670b48227d43d35b3b382

incorporated spring in different version than in web application into adapter version 1.0

vventh committed 10 years ago
Unverified
35c53d41a2f956eb7b9df945ea5257882ad90868

bundled different spring version

vventh committed 10 years ago
Unverified
ba94143182db65c7278bb76d497e746204a27ce1

Corrected integration tests launching; Introduced integration test; described osgi properties

vventh committed 10 years ago
Unverified
af8bffd5eecba341e719343bdf9fe4c8bb7cc735

introduced separation on unit and integration tests; used tomcat7 plugin to easier integration testing

vventh committed 10 years ago
Unverified
c900bbd01bfd188e4020d7e80773dc5fa9c632e8

Simplified service declaration,

vventh committed 10 years ago
Unverified
c5a4047391f84e9ff3a4a0efac613fac410a8a86

Expanded project's description by adding HowTo ;P

vventh committed 10 years ago

README

The README file for this repository.

runtime-api-switcher

Runtime API Switcher is a proof of concept that an OSGI container may be embedded in a web application and provide support for different adapter versions.

Thanks of the different version of an adapter, there is possibility to switch between contracts at runtime.

Rules of engagement: Because, it's a PoC I wrote only three test scenarios to verify, if the switching will work. These scenarios are contained in RuntimeApiSwitcherTest.

mvn clean integration-test

Adapter bundles are copied to /WEB-INF/bundles directory of Web Application during pre-package phase.

Once, the web application is built, deliver it, please, to a standalone tomcat running on localhost:8080. Then you may run the integration test against working Web Application hosted on your tomcat.

The container's lifecycle is handled by org.venth.poc.runtimeapiswitcher.webapp.osgi.OsgiFrameworkBootstraper declared as osgiContainer. The class bootstraps felix container, loads bundles and exposes stopFramework method.

<bean
        id="osgiContainer"
        class="org.venth.poc.runtimeapiswitcher.webapp.osgi.OsgiFrameworkBootstraper"
        destroy-method="stopFramework"
        p:bundlesLocation="/WEB-INF/bundles"
>
    <property name="extraPackages">
        <list>
            <value>org.venth.poc.runtimeapiswitcher.api.adapter</value>
        </list>
    </property>
</bean>

Exported services are available by usage of OsgiServiceProxyFactoryBean class. The factory creates a proxy bean, which encapsulates all calls to osgi service in order to use a indicated service version. Note that, if an application publishes the event AdapterVersionSwitchRequested, the proxy will react on this event by trying switching osgi service on the fly.

The proxy bean is also responsible for releasing a service, when the application is about to shutdown.

In spring descriptor there is parent bean declaration (shorthand decreasing typing):

<bean id="osgiServiceProxy" class="org.venth.poc.runtimeapiswitcher.webapp.osgi.OsgiVersionSwitchableServiceProxyFactoryBean"
          destroy-method="releaseService"
          abstract="true"
          p:context-ref="osgiContainer"
          p:defaultVersion="1.0"
/>

and an instance declaration:

<bean parent="osgiServiceProxy" 
    p:serviceType="org.venth.poc.runtimeapiswitcher.api.adapter.AdaptedService"
/>

In the application's code the declared service could be injected for example by @Autowire annotation.

Bundling Spring isn't easy task, still is doable.

Issues:

  • Bundled spring cannot find any beans declared by annotations (found solution for that ;)
  • spring has a lot of different dependencies... some of them are unnecessary. The bundling process makes the dependencies to be mandatory.

The solution for many spring dependencies is usage of an optional resolution directive provided by osgi.

<Import-Package>
    *;resolution:=optional
</Import-Package>

Classpath scanning seems to be handled only for equinox platform. Please see class: org.springframework.core.io.support.PathMatchingResourcePatternResolver

static {
    try {
        // Detect Equinox OSGi (e.g. on WebSphere 6.1)
        Class<?> fileLocatorClass = ClassUtils.forName("org.eclipse.core.runtime.FileLocator",
                PathMatchingResourcePatternResolver.class.getClassLoader());
        equinoxResolveMethod = fileLocatorClass.getMethod("resolve", URL.class);
        logger.debug("Found Equinox FileLocator for OSGi bundle URL resolution");
    }
    catch (Throwable ex) {
        equinoxResolveMethod = null;
    }
}

Spring cannot handle Felix used in this PoC, because Felix doesn't provide any FileLocator. I wrote a simple class looking for pattern classpath*:**.class. The implemented pattern resolver doesn't look inside bundled jars. It enumerates only classes located direclty on bundled classpath. org.venth.poc.runtimeapiswitcher.osgi.OsgiBundleResourceResolver

To use this resolver I simply created a anonymous class from ClassPathXmlApplicationContext.

springContext = new ClassPathXmlApplicationContext("classpath:/context-ver_1.xml") {
    @Override
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new OsgiBundleResourceResolver();
    }
};

Test "RuntimeApiSwitcherTest" proves, that spring annotation scanning is working. To run integration tests use:

mvn integration-test