-
1. Re: CBR on SOAP and Transport Headers
asankha Aug 24, 2011 7:07 AM (in response to asankha)I managed to solve this question myself after some effort - and I'd like to share it here for the benefit of others in future
For Case #1 a normal XPath based CBR was sufficient as a better solution does not seem to exist out of the box
<action name="proxy_cbr_soap_header"
class="org.jboss.soa.esb.actions.ContentBasedRouter">
<property name="cbrAlias" value="XPath"/>
<!-- This is what the documentation [Services_Guide.pdf Section 3.2.4 Namespaces] says - but it does not work
<property name="namespaces">
<route-to prefix="s" uri="http://schemas.xmlsoap.org/soap/envelope/" />
<route-to prefix="ns" uri="http://someuri" />
</property-->
<property name="destinations">
<namespace prefix="s" uri="http://schemas.xmlsoap.org/soap/envelope/"/>
<namespace prefix="ns" uri="http://someuri"/>
<route-to service-category="service"
service-name="RealService" expression="/s:Envelope/s:Header/ns:routing = 'xadmin;server1;community#1.0##'" />
<route-to service-category="service"
service-name="ReturnFault" expression="true()"/>
</property>
</action>
Note: the documentation asks you to specify the namespaces in one way, but what works is a different configuration
For case #2 I wrote a custom action as follows:
Class TransportHeaderBasedRouter.java
import java.util.*;
import org.jboss.soa.esb.message.*;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.actions.*;
import org.jboss.soa.esb.Service;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.services.registry.RegistryException;
import org.jboss.soa.esb.services.routing.MessageRouterException;
import org.jboss.soa.esb.message.mapping.ObjectMapper;
import org.jboss.soa.esb.message.mapping.ObjectMappingException;
import org.jboss.soa.esb.http.HttpRequest;
import org.jboss.soa.esb.client.MessageMulticaster;
import org.jboss.soa.esb.listeners.ListenerTagNames;
import java.util.regex.Pattern;
/**
* Based on JBoss ESB samples and code base
*/
public class TransportHeaderBasedRouter extends ContentBasedWiretap {
private Map<Pattern, Service> regexToServiceMap = new HashMap<Pattern, Service>();
protected List<Service> executeRules(Message message) throws MessageRouterException {
String value = HttpRequest.getRequest(message).getHeaderValue(_config.getAttribute("name"));
List<Service> outgoingDestinations = new ArrayList<Service>();
for (Map.Entry<Pattern, Service> e : regexToServiceMap.entrySet()) {
if (e.getKey().matcher(value).matches()) {
outgoingDestinations.add(e.getValue());
break;
}
}
return outgoingDestinations;
}
public TransportHeaderBasedRouter(ConfigTree _config) throws ConfigurationException, RegistryException, MessageRouterException {
super(_config);
ConfigTree[] destList = _config.getChildren(ROUTE_TO_TAG);
if (destList != null) {
for (ConfigTree curr : destList) {
try {
String key = curr.getAttribute("regex");
String category = curr.getAttribute(ListenerTagNames.SERVICE_CATEGORY_NAME_TAG, "");
String name = curr.getRequiredAttribute(ListenerTagNames.SERVICE_NAME_TAG);
Service service = new Service(category, name);
regexToServiceMap.put(Pattern.compile(key), service);
} catch (Exception e) {
throw new ConfigurationException("Problems with destination list", e);
}
}
}
}
public Message process(Message message) throws ActionProcessingException {
super.process(message) ;
return null ;
}
}
Invocation Snippet
<action name="proxy_cbr_transport_header" class="TransportHeaderBasedRouter">
<property name="name" value="routing"/>
<property name="destinations">
<route-to service-category="service" service-name="TrpRealService" regex="xadmin;server1;community#1.0##"/>
<route-to service-category="service" service-name="TrpReturnFault" regex=".*"/>
</property>
</action>
The "routing" in the above example is the HTTP header name, which is matched as a regular expression against the regex values under destinations. The first matching service is selected
For case #3 - the easiest way I found was to write another custom action as follows:
Class SOAPFaultAction.java
import org.jboss.soa.esb.actions.AbstractActionLifecycle;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.message.*;
import org.jboss.soa.esb.actions.ActionProcessingException;
import java.util.Set;
public class SOAPFaultAction extends AbstractActionLifecycle {
protected ConfigTree _config;
public SOAPFaultAction(ConfigTree config) { _config = config; }
public Message process(Message msg) throws ActionProcessingException {
msg.getBody().add("<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body><SOAP-ENV:Fault xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><faultcode xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns=\"\">SOAP-ENV:Server</faultcode><faultstring xmlns=\"\">" + _config.getAttribute("faultText") + "</faultstring></SOAP-ENV:Fault></S:Body></S:Envelope>");
return msg;
}
}
Invocation Snippet
<action name="fault" class="SOAPFaultAction">
<property name="faultText" value="Invalid routing header"/>
</action>
The "value" will be inserted into the custom SOAP fault specified as a String - I know its not elegant , maybe a better solution exists