If you are writing Camel routes using Spring to deploy to ServiceMix, you can’t use regular Spring properties, since ServiceMix is an OSGi container. Instead, you have to use OSGi properties. But if you try to start up your Spring context in a unit test, it will fail, since there is no OSGi environment. How can you get round this? One solution is for your tests to load the spring xml as an xml file before they instantiate the spring context. That way, they can replace the OSGi references with a regular spring property loader. Let’s see what this looks like.
In my Spring file I’ve got the OSGix namespace:
xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
Then an OSGix property loader, and a regular property placeholder that references it:
<osgix:cm-properties id="props" persistent-id="claimsExport"/>
<context:property-placeholder properties-ref="props"/>
In my test code, I have the following helper method:
public static String replaceOSGiPropertyLoader(String springXmlLocation)
throws ParserConfigurationException, IOException,
SAXException, XPathExpressionException, TransformerException {
log.info("Removing Spring osgix property loader");
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
File springFile = new File(springXmlLocation);
Document doc = builder.parse(new InputSource(new FileInputStream(springFile)));
// find the osgix properties bean
XPath xpath = XPathFactory.newInstance().newXPath();
Node osgiProps = (Node) xpath.evaluate("/beans/cm-properties",doc, XPathConstants.NODE);
// remove it
// first get the root node
Node beanNode = doc.getFirstChild();
// remove the child
beanNode.removeChild(osgiProps);
// now adjust the spring properties bean to load the props directly from the file
Element propertyPlaceholder = (Element) xpath.evaluate("/beans/property-placeholder",doc, XPathConstants.NODE);
// remove the ref to the osgi bean
propertyPlaceholder.removeAttribute("properties-ref");
// add a reference directly to the file that has the properties in
propertyPlaceholder.setAttribute("location","classpath:claimsExport.cfg");
// now write out the resultant xml
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc),new StreamResult(writer));
// return the string representation of the spring xml file
return writer.toString();
}
The OSGix property loader loads properties from a file with a name that matches its persistent id. In this case, the file is called claimsExport.cfg. You can see that the helper method simply updates the Spring property placeloader to load the properties directly from that file.
You can use the code as:
String springXml = replaceOSGiPropertyLoader("your-path/app-context.xml");
springContext = new GenericXmlApplicationContext(new ByteArrayResource(springXml.getBytes("utf-8")));
Thanks to
Ben Oday’s blog for telling me about the spring osgix property loader.
2 Responses to Testing Camel routes with Spring OSGi properties