Monday, 26 July 2010

Spring Schemas

I ran into an interesting problem with Spring and ActiveMQ a few days ago. To make use of the ActiveMQ namespace in our Spring contexts, I had the following beans element:
  xmlns="http://www.springframework.org/schema/beans"
amq="http://activemq.apache.org/schema/core"
xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemalocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.1.0.xsd">

...

This seemed fairly sensible since we're using version 5.1.0 of ActiveMQ and there IS a schema at http://activemq.apache.org/schema/core/activemq-core-5.1.0.xsd.

However, when this was deployed to one of our test environments that does NOT have access to the internet, it fell over with the following exception:
Offending resource: class path resource [appContext.xml];
nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
Line 10 in XML document from class path resource [messagingContext.xml] is invalid;
nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.4.c:
The matching wildcard is strict, but no declaration can be found for element 'amq:connectionFactory'
This led me to discover a feature that I was previously unaware of - the spring.schemas file. The documentation says this:
The properties file called 'spring.schemas' contains a mapping of XML Schema locations (referred to along with the schema declaration in XML files that use the schema as part of the 'xsi:schemaLocation' attribute) to classpath resources. This file is needed to prevent Spring from absolutely having to use a default EntityResolver that requires Internet access to retrieve the schema file.
In fact, the default spring.schemas file contains the following entries:
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
So both those URL's are mapped to schemas on the classpath, ie. Spring doesn't need to download them from the internet.

However, the spring.schemas file bundled with ActiveMQ contains these entries:
http\://activemq.org/config/1.0=activemq.xsd
http\://activemq.org/config/1.0/1.0.xsd=activemq.xsd
http\://activemq.apache.org/schema/core=activemq.xsd
http\://activemq.apache.org/schema/core/activemq-core.xsd=activemq.xsd
So although mappings are provided, the mappings are for URL's that don't actually exist. (To be honest, I can't see how/why you would use these mappings unless you were already aware of this feature!)

Nonetheless, I fixed the issue by changing the beans declaration as follows:
  xmlns="http://www.springframework.org/schema/beans"
amq="http://activemq.apache.org/schema/core"
xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemalocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">

...

Note that the URL for the ActiveMQ namespace now matches a URL in spring.schemas.

1 comment:

pcleary said...

Thanks! HUGE help, got me past that error.