You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@karaf.apache.org by Cameleer <ka...@gmail.com> on 2014/12/07 23:13:52 UTC

spring's NamespaceHandler again

Yes, OSGi is not officially supported by spring anymore or at least not
outside of eclipse virgo…
Yes, just use blueprint, if you have no legacy applications and like doing
dependency injection as in
the good old days with a lot of xml metadata…
Or just wait until CDI is an overall supported technology…


In the meantime you have to solve spring related problems :-)

I had a working camel cxf spring rest bundle application example that I
initialized
via the following spring xml configuration:

<?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:cxf="http://cxf.apache.org/core"
       xmlns:camel-cxf="http://camel.apache.org/schema/cxf"
       xmlns:camel="http://camel.apache.org/schema/spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                          
http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd
                           http://camel.apache.org/schema/cxf
http://camel.apache.org/schema/cxf/camel-cxf.xsd
                           http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
    <cxf:bus>
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>

    <camel-cxf:rsServer id="helloService" address="/rs"
                        serviceClass="com.rwe.negotiator.rest.SayHello"/>

    <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
        <route id="sayHello">
            <from uri="cxfrs:bean:helloService"/>
            <transform>
                <constant>hello</constant>
            </transform>
        </route>
    </camelContext>
</beans>

But: The same application does not work anymore with karaf-3.0.2 and
cxf-3.0.1.
During the start of the application you'll find the following excpeption in
the logs:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: Unable to locate Spring NamespaceHandler for XML
schema namespace [http://cxf.apache.org/core]
Offending resource: URL [bundle://297.0:0/META-INF/spring/camel-context.xml]

The error has already been discussed in this forum
(http://karaf.922171.n3.nabble.com/Spring-4-0-2-and-spring-dm-tp4033093.html),
but it did not yield a solution.

No it's not a problem with its osgi bundle meta data, like a missing import
statement.
Spring's OsgiBundleXmlApplicationContext tries to parse the xml
configuration file and encounters a few unknown namespaces, like
http://camel.apache.org/schema/cxf.
To see what is going on here just increase the log level for spring's
PluggableSchemaResolver class:

karaf@local()> log:set TRACE org.springframework.beans.factory.xml

Now the log file tells us, what namespaces spring could resolve, e.g.:
TRACE | ExtenderThread-2 | PluggableSchemaResolver          | 43 -
org.apache.servicemix.bundles.spring-beans - 3.2.11.RELEASE_1 | Trying to
resolve XML entity with public id [null] and system id
[http://camel.apache.org/schema/cxf/camel-cxf.xsd]
DEBUG | ExtenderThread-2 | PluggableSchemaResolver          | 43 -
org.apache.servicemix.bundles.spring-beans - 3.2.11.RELEASE_1 | Found XML
schema [http://camel.apache.org/schema/cxf/camel-cxf.xsd] in classpath:
schema/cxfEndpoint.xsd

I looked through the complete log file and as it turns out, it didn't find a
NamespaceHandler for http://cxf.apache.org/core.

It's not a problem with my application, the NamespaceHandler is really
missing in karaf, although the cxf-core bundle is installed.

karaf@local()> list -t 0 | grep -i cxf
166 | Active   |  40 | 3.0.1                              | Apache CXF Core

So what happend?
Every possible spring NamespaceHandler gets registered by the
spring-osgi-extender module. This module has a class named NamespaceManager.
(By the way the original source code is still available from
http://docs.spring.io/downloads/nightly/release-download.php?project=OSGI in
the file spring-osgi-1.2.1-with-dependencies.zip from the year 2009)
Let's increase the log level for this class in karaf's logging configuration
'org.ops4j.pax.logging.cfg' with this extra line and restart karaf:

log4j.logger.org.springframework.osgi.extender.internal.support=DEBUG,out

The log file reveals the real problem now:

DEBUG | FelixStartLevel  | NamespaceManager                 | 91 -
org.springframework.osgi.extender - 1.2.1 | Bundle [Apache CXF Core
(org.apache.cxf.cxf-core)] declares namespace handlers but is not compatible
with extender [org.springframework.osgi.extender|1.2.1]; ignoring...
DEBUG | FelixStartLevel  | NamespaceManager                 | 91 -
org.springframework.osgi.extender - 1.2.1 | Bundle [Apache CXF Core
(org.apache.cxf.cxf-core)] declares namespace handlers but is not compatible
with extender [org.springframework.osgi.extender|1.2.1]; ignoring...

Namespace handlers of some bundles just get ignored :-)
Inside the source code of this NamespaceManager you find:

// check type compatibility between the bundle's and spring-extender's
spring version
if (hasCompatibleNamespaceType(bundle)) {
	addHandler(bundle);
} else {
	if (log.isDebugEnabled())
		log.debug("Bundle [" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
				+ "] declares namespace handlers but is not compatible with extender ["
+ extenderInfo
				+ "]; ignoring...");
}

So we have a problem if two spring versions are installed in parallel. 
The spring-osgi-extender module might have imported the spring 3.x packages
and cxf-core has imported spring 4.x packages.
At the time the extender module scans cxf's NamespaceHandlers it compares if
the classloaders are the same inside the hasCompatibleNamespaceType method.

Both the osgi-extender bundle and the cxf bundle have a wide version range
of spring package imports. None of them explicitly references a specific
version.
They are just capable of working with all spring versions. At runtime each
chooses the highest (I think) version of spring packages that are available.
In the end, every module might have imported a different version and are not
compatible to each other. 

As a result not all spring namespace handlers are registered.

Everything works perfectly again if you just install only one spring version
in karaf.

By the way, it's not easy to exclude a spring version, since karaf's spring
feature lists them all.
It would be great if someone can split the spring-features.xml in multiple
files like spring3.2-features and spring-4.0-features, so that
you can reference the features repository independently?


Is there a real solution to this version hell?

Better restrict karaf to install only one spring version?



--
View this message in context: http://karaf.922171.n3.nabble.com/spring-s-NamespaceHandler-again-tp4037036.html
Sent from the Karaf - Dev mailing list archive at Nabble.com.