Hello
I've been working on integrating a registry/repository support into
CAMEL. The current implementation uses XML files, later it should also
be linked with real-life repositories (Galaxy, OW2 Registry, ...). The
implementation is now complete, and here's how I've done it:
* To use the registry, I use the Spring camel-context XML file and
map the "registry:" protocol to the lookup class:
<!-- The registry component, configured as a File Registry -->
<bean id="registry" class="test.FileRegistryComponent">
<property name="file" value="registry.xml"/>
</bean>
* The file-based registry/repository is an XML file:
<?xml version="1.0" encoding="UTF-8"?>
<registry xmlns="custom:FileRegistry"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="custom:FileRegistry FileRegistry.xsd">
<entry>
<logicalName>queue</logicalName>
<technicalName>
joram:queue:sampleQueue
</technicalName>
</entry>
<entry>
<logicalName>topic</logicalName>
<technicalName>
joram:topic:sampleTopic
</technicalName>
</entry>
<entry>
<logicalName>sampleWebService</logicalName>
<technicalName>
<![CDATA[
cxf://
http://localhost:9000/CxfService_1/SayHello
?serviceClass=test.ISayHello
&wsdlURL=http://localhost:9000/CxfService_1/SayHello?wsdl
&serviceName={http://test/}SayHello
&portName={http://test/}SayHelloPort
&dataFormat=POJO
]]>
</technicalName>
</entry>
</registry>
The XSD for the XML is attached.
* Finally, you simply prefix your endpoint with "registry:" to point
it to a registry/repository entry. For example, in DSL:
from("registry:queue").process(new Processor() {
public void process(Exchange e) {
// Convert JMS message content into WS request
final List<String> params = new ArrayList<String>();
e.getIn().setHeader(CxfConstants.OPERATION_NAME, "hello");
String body = e.getIn().getBody(String.class);
params.add(body);
e.getIn().setBody(params);
}
}).to("registry:sampleWebService").to("registry:topic");
I'm attaching the registry/repository's Java implementation. Any
comments are welcome.
PS: I know that based on the fact that I'm using an XSD schema I could
have also used the JAXB APIs to match XML files to Java classes (tools
automatically do it, so why bother!). If you think that's better, I
could well switch to that as well.
PPS: When CAMEL 1.5.1 will be out, the parent class that's used for the
registry will be RefComponent. The modification is minor, but neat.
Do you think this can be commited into the CAMEL examples?
Thanks
--
S. Ali Tokmen
[EMAIL PROTECTED]
Office: +33 4 76 29 76 19
GSM: +33 66 43 00 555
Bull, Architect of an Open World TM
http://www.bull.com
package test;
import org.apache.camel.CamelContext;
import org.apache.camel.Component;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
public abstract class AbstractRegistryComponent implements Component<Exchange> {
private CamelContext context;
public CamelContext getCamelContext() {
return this.context;
}
public void setCamelContext(CamelContext context) {
this.context = context;
}
protected abstract String lookup(String name) throws Exception;
@SuppressWarnings("unchecked")
public Endpoint<Exchange> createEndpoint(final String name) throws
Exception {
final String logicalAddress = name.substring(name.indexOf(':') + 1);
final String technicalAddress = lookup(logicalAddress);
final String scheme;
final int schemeStart = technicalAddress.indexOf(':');
if (schemeStart > 0) {
scheme = technicalAddress.substring(0, schemeStart);
} else {
scheme = technicalAddress;
}
System.out.println("AbstractRegistryComponent creating endpoint: name
is " + name + ", logicalAddress is "
+ logicalAddress + ", technicalAddress is " + technicalAddress + ",
scheme is " + scheme);
return context.getComponent(scheme).createEndpoint(technicalAddress);
}
}
package test;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class FileRegistryComponent extends AbstractRegistryComponent {
private String file;
private Map<String, String> registry;
private Pattern whitespace = Pattern.compile("\\s");
public String getFile() {
return this.file;
}
public void setFile(String file) {
try {
this.file = file;
this.registry = new HashMap<String, String>();
DocumentBuilderFactory docBuilderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc;
ClassLoader cl = this.getClass().getClassLoader();
if (cl.getResource(file) != null) {
InputStream resource = cl.getResourceAsStream(file);
doc = docBuilder.parse(resource);
resource.close();
} else {
doc = docBuilder.parse(new File(file));
}
doc.getDocumentElement().normalize();
NodeList listOfEntries = doc.getElementsByTagName("entry");
for (int i = 0; i < listOfEntries.getLength(); i++) {
String name = null;
String value = null;
NodeList entry = listOfEntries.item(i).getChildNodes();
for (int j = 0; j < entry.getLength(); j++) {
Node entryDetail = entry.item(j);
if ("logicalName".equals(entryDetail.getNodeName())) {
name = getValueAndRemoveAllWhitespace(entryDetail);
} else if
("technicalName".equals(entryDetail.getNodeName())) {
value = getValueAndRemoveAllWhitespace(entryDetail);
}
}
this.registry.put(name, value);
}
} catch (Exception e) {
this.file = null;
this.registry = null;
throw new IllegalArgumentException("Cannot read file \"" + file +
"\"", e);
}
}
private String getValueAndRemoveAllWhitespace(Node node) {
StringBuilder result = new StringBuilder();
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
result.append(children.item(i).getNodeValue());
}
return this.whitespace.matcher(result.toString()).replaceAll("");
}
@Override
protected String lookup(String name) {
if (registry == null) {
throw new IllegalStateException("FileRegistryComponent doesn't have
a valid file specified");
}
return this.registry.get(name);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="custom:FileRegistry" elementFormDefault="qualified"
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="custom:FileRegistry">
<element name="registry" type="tns:registry"></element>
<complexType name="registry">
<sequence maxOccurs="unbounded" minOccurs="0">
<element name="entry" type="tns:entry"></element>
</sequence>
</complexType>
<complexType name="entry">
<sequence maxOccurs="1" minOccurs="1">
<element name="logicalName" type="string"></element>
<element name="technicalName" type="string"></element>
</sequence>
</complexType>
</schema>