/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2010
*/
package org.jboss.soa.esb.listeners.config.mappers130;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.camel.util.UnsafeUriCharactersEncoder;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.dom.YADOMUtil;
import org.jboss.soa.esb.listeners.config.xbeanmodel130.CamelGatewayDocument;
import org.jboss.soa.esb.listeners.config.xbeanmodel130.CamelBusDocument.CamelBus;
import org.jboss.soa.esb.listeners.config.xbeanmodel130.FromDocument.From;
import org.jboss.soa.esb.listeners.config.xbeanmodel130.PropertyDocument.Property;
import org.jboss.soa.esb.listeners.config.xbeanmodel130.ServiceDocument.Service;
import org.jboss.soa.esb.listeners.gateway.camel.CamelGateway;
import org.jboss.soa.esb.listeners.gateway.camel.JBossESBComponent;
import org.w3c.dom.Element;
/**
* CamelGatewayMapper.
*
* @author dward at jboss.org
*/
public class CamelGatewayMapper {
/**
* ESB schedule timer scheme token.
*/
private static final String ESBSCHEDULE = "esbschedule";
private static final Logger logger = Logger.getLogger(CamelGatewayMapper.class);
public static Element map(final Element root, final CamelGatewayDocument.CamelGateway gateway, final XMLBeansModel model) throws ConfigurationException {
final Element gatewayNode = YADOMUtil.addElement(root, "listener");
gatewayNode.setAttribute("name", gateway.getName());
gatewayNode.setAttribute("gatewayClass", CamelGateway.class.getName());
final CamelBus bus;
try {
bus = (CamelBus)model.getOptionalBus(gateway.getBusidref());
} catch (ClassCastException e) {
throw new ConfigurationException("Invalid busid reference [" + gateway.getBusidref() + "] on gateway [" + gateway.getName() + "]. A <camel-gateway> must reference a <camel-bus>.");
}
List<String> routeXMLs = new ArrayList<String>();
URI toURI = createToURI(gateway, bus, model);
if (bus != null) {
try {
// <camel-bus from-uri="">
if (bus.isSetFromUri()) {
URI busFromURI = createURI(bus.getFromUri());
addRouteXML(busFromURI, toURI, routeXMLs);
}
// <camel-bus><from uri="">*
for (From busFrom : bus.getFromList()) {
URI fromURI = createURI(busFrom.getUri());
addRouteXML(fromURI, toURI, routeXMLs);
}
} catch (ClassCastException e) {
throw new ConfigurationException("Invalid bus config [" + gateway.getBusidref() + "]. Should be contained within a <camel-provider> instance. Unexpected exception - this should have caused a validation error!");
}
}
// <camel-gateway from-uri="">
if (gateway.isSetFromUri()) {
URI gatewayFromURI = createURI(gateway.getFromUri());
addRouteXML(gatewayFromURI, toURI, routeXMLs);
}
// <camel-gateway><from uri="">*
for (From gatewayFrom : gateway.getFromList()) {
URI fromURI = createURI(gatewayFrom.getUri());
addRouteXML(fromURI, toURI, routeXMLs);
}
// Map the standard listener attributes - common across all listener types...
MapperUtil.mapDefaultAttributes(gateway, gatewayNode, model);
// Map the <property> elements targeted at the listener - from the listener itself.
List<Property> propertyList = gateway.getPropertyList();
Iterator<Property> propertyIterator = propertyList.iterator();
while (propertyIterator.hasNext()) {
Property property = propertyIterator.next();
// Enforce adding routes the prescribed way
if (CamelGateway.ROUTES.equals(property.getName())) {
propertyIterator.remove();
}
}
MapperUtil.mapProperties(propertyList, gatewayNode);
// Map the routes <property>
if (routeXMLs.size() == 0) {
throw new ConfigurationException("no routes defined; add at least one route");
}
StringBuilder sb = new StringBuilder();
// Don't let the namespace fool you; there's no dependency on Spring at this level!
sb.append("<routes xmlns=\"http://camel.apache.org/schema/spring\">");
for (String routeXML : routeXMLs) {
sb.append(routeXML);
}
sb.append("</routes>");
String routesXML = sb.toString();
Element propertyElement = gatewayNode.getOwnerDocument().createElement("property");
propertyElement.setAttribute("name", CamelGateway.ROUTES);
propertyElement.setAttribute("value", routesXML);
gatewayNode.appendChild(propertyElement);
return gatewayNode;
}
private static URI createToURI(final CamelGatewayDocument.CamelGateway gateway, CamelBus bus, final XMLBeansModel model) throws ConfigurationException {
Map<String,Object> toParams = new LinkedHashMap<String,Object>();
Service service = model.getService(gateway);
toParams.put(JBossESBComponent.CATEGORY, service.getCategory());
toParams.put(JBossESBComponent.NAME, service.getName());
boolean async;
if (gateway.isSetAsync()) {
async = gateway.getAsync();
} else if (bus != null && bus.isSetAsync()) {
async = bus.getAsync();
} else {
async = false;
}
toParams.put(JBossESBComponent.ASYNC, String.valueOf(async));
long timeout;
if (gateway.isSetTimeout()) {
timeout = gateway.getTimeout();
} else if (bus != null && bus.isSetTimeout()) {
timeout = bus.getTimeout();
} else {
timeout = 30000L;
}
toParams.put(JBossESBComponent.TIMEOUT, String.valueOf(timeout));
try {
return JBossESBComponent.createEndpointURI(JBossESBComponent.SERVICE, toParams);
} catch (Exception e) {
throw new ConfigurationException("problem creating endpoint uri", e);
}
}
private static URI createURI(String str) throws ConfigurationException {
if (str != null) {
str = str.trim();
if (str.length() > 0) {
try {
return new URI(UnsafeUriCharactersEncoder.encode(str));
} catch (URISyntaxException e) {
throw new ConfigurationException("problem creating URI: " + str, e);
}
}
}
return null;
}
protected static void addRouteXML(URI fromURI, URI toURI, List<String> routeXMLs) throws ConfigurationException {
if (fromURI != null) {
StringBuilder sb = new StringBuilder();
String scheme = fromURI.getScheme();
StringBuilder timerURIBuilder = null;
sb.append("<route>");
if(scheme != null && scheme.equalsIgnoreCase(ESBSCHEDULE)) {
String[] tokens = fromURI.getSchemeSpecificPart().split(":");
if(tokens.length == 1) {
throw new ConfigurationException("Invalid use of esbschedule timer in from URI '" + scheme + "'. Must include a schedule timer value e.g. 'esbschedule:5000:file://etc'.");
}
try {
int timer = Integer.parseInt(tokens[0]);
timerURIBuilder = new StringBuilder();
timerURIBuilder.append("timer://" + fromURI.hashCode() + "?fixedRate=true&delay=0&period=" + timer);
} catch(NumberFormatException e) {
throw new ConfigurationException("Invalid esbschedule timer time '" + scheme + "'. Must be a valid integer.", e);
}
// Reconstruct the uri, excluding the esbschedule bits......
StringBuilder newFromURI = new StringBuilder();
for(int i = 1; i < tokens.length; i++) {
if(newFromURI.length() > 0) {
newFromURI.append(":");
}
newFromURI.append(tokens[i]);
}
fromURI = URI.create(newFromURI.toString());
}
if(timerURIBuilder != null) {
sb.append("<from uri=\"").append(timerURIBuilder.toString()).append("\"/>");
sb.append("<to uri=\"").append(fromURI).append("\"/>");
} else {
sb.append("<from uri=\"").append(fromURI).append("\"/>");
}
sb.append("<to uri=\"").append(toURI).append("\"/>");
sb.append("</route>");
routeXMLs.add(sb.toString());
}
}
}