package org.jboss.soa.esb.listeners.config.mappers120;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.util.ClassUtil;
import org.jboss.soa.esb.dom.YADOMUtil;
import org.jboss.soa.esb.listeners.ListenerTagNames;
import org.jboss.soa.esb.listeners.gateway.http.HttpGatewayServlet;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.PropertyDocument.Property;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.HttpBusDocument.HttpBus;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.HttpGatewayDocument.HttpGateway;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.HttpProviderDocument.HttpProvider;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.PayloadAs;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.HttpExceptionMappings;
import org.jboss.soa.esb.listeners.config.xbeanmodel120.AsyncHttpResponse;
import org.jboss.internal.soa.esb.listeners.war.HttpGatewayDeploymentFactory;
import org.jboss.internal.soa.esb.assertion.AssertArgument;
import org.w3c.dom.Element;
import org.apache.log4j.Logger;
import java.util.*;
import java.io.InputStream;
import java.io.IOException;
/**
* Http gateway mapper.
* @author <a href="mailto:ema@redhat.com">Jim Ma</a>
*/
public class HttpGatewayMapper {
private static final Logger logger = Logger.getLogger(HttpGatewayMapper.class);
/**
* Perform the Http listener mapping.
* @param root The "ConfigTree" configuration root node.
* @param listener http listener config.
* @param model The configuration model from which the mapping is being performed.
* @return The ConfigTree listener configuration node.
* @throws org.jboss.soa.esb.ConfigurationException Invalid listener configuration.
*/
public static Element map(Element root, HttpGateway listener, XMLBeansModel model) throws ConfigurationException {
Element listenerNode = YADOMUtil.addElement(root, "listener");
HttpBus bus;
HttpProvider provider;
listenerNode.setAttribute("name", listener.getName());
try {
bus = (HttpBus) model.getOptionalBus(listener.getBusidref());
} catch (ClassCastException e) {
throw new ConfigurationException("Invalid busid reference [" + listener.getBusidref() + "] on listener [" + listener.getName() + "]. A <http-listener> must reference a <http-bus>.");
}
// Map the standard listener attributes - common across all listener types...
MapperUtil.mapDefaultAttributes(listener, listenerNode, model);
String urlPattern = listener.getUrlPattern();
PayloadAs.Enum payloadAs = listener.getPayloadAs();
if(listener.getAsyncResponseList() != null && !listener.getAsyncResponseList().isEmpty()) {
AsyncHttpResponse asyncResponse = listener.getAsyncResponseList().get(0);
listenerNode.setAttribute(HttpGatewayServlet.ASYNC_SERVICE_INVOKE, "true");
listenerNode.setAttribute(HttpGatewayServlet.ASYNC_STATUS_CODE, Integer.toString(asyncResponse.getStatusCode()));
AsyncHttpResponse.Payload payload = asyncResponse.getPayload();
if(payload != null) {
listenerNode.setAttribute(HttpGatewayServlet.ASYNC_PAYLOAD, payload.getClasspathResource());
listenerNode.setAttribute(HttpGatewayServlet.ASYNC_PAYLOAD_CONTENT_TYPE, payload.getContentType());
if(payload.getCharacterEncoding() != null) {
listenerNode.setAttribute(HttpGatewayServlet.ASYNC_PAYLOAD_CHARACTER_ENCODING, payload.getCharacterEncoding());
}
}
} else {
listenerNode.setAttribute(HttpGatewayServlet.ASYNC_SERVICE_INVOKE, "false");
}
if(bus != null) {
try {
provider = (HttpProvider) model.getProvider(bus);
} catch (ClassCastException e) {
throw new ConfigurationException("Invalid bus config [" + listener.getBusidref() + "]. Should be contained within a <http-provider> instance. Unexpected exception - this should have caused a validation error!");
}
// Map the <property> elements targeted at the listener - from the listener itself.
//MapperUtil.mapProperties(provider.getPropertyList(), listenerNode);
for(Property property : provider.getPropertyList()) {
Element propertyElement = listenerNode.getOwnerDocument().createElement("property");
MapperUtil.serialize(property, propertyElement);
listenerNode.appendChild(propertyElement);
}
List<HttpBus.ProtectedMethods> protectedMethodsList = bus.getProtectedMethodsList();
List<HttpBus.AllowedRoles> rolesList = bus.getAllowedRolesList();
HttpBus.TransportGuarantee.Enum transportGuarantee = bus.getTransportGuarantee();
MapperUtil.mapProperties(bus.getPropertyList(), listenerNode);
mapStandardSettings(listenerNode, urlPattern, payloadAs, listener.getPropertyList());
if(protectedMethodsList != null && !protectedMethodsList.isEmpty()) {
HttpBus.ProtectedMethods methods = protectedMethodsList.get(0);
StringBuilder methodsString = new StringBuilder();
for(HttpBus.ProtectedMethods.Method method : methods.getMethodList()) {
if(methodsString.length() > 0) {
methodsString.append(",");
}
methodsString.append(method.getName().toString());
}
listenerNode.setAttribute(HttpGatewayDeploymentFactory.PROTECTED_METHODS, methodsString.toString());
}
if(rolesList != null && !rolesList.isEmpty()) {
HttpBus.AllowedRoles roles = rolesList.get(0);
StringBuilder rolesString = new StringBuilder();
for(HttpBus.AllowedRoles.Role role : roles.getRoleList()) {
if(rolesString.length() > 0) {
rolesString.append(",");
}
rolesString.append(role.getName());
}
listenerNode.setAttribute(HttpGatewayDeploymentFactory.ALLOWED_ROLES, rolesString.toString());
}
if(transportGuarantee != null) {
listenerNode.setAttribute(HttpGatewayDeploymentFactory.TRANSPORT_GUARANTEE, transportGuarantee.toString());
}
// Exception status mappings...
mapExceptionStatusMappings(listenerNode, provider, listener);
} else {
// Use the "default" http bus....
mapStandardSettings(listenerNode, urlPattern, payloadAs, listener.getPropertyList());
// Exception status mappings...
mapExceptionStatusMappings(listenerNode, (HttpProvider) model.getProvider(HttpProvider.class), listener);
}
return listenerNode;
}
private static void mapStandardSettings(Element listenerNode, String urlPattern, PayloadAs.Enum payloadAs, List<Property> listenerProps) {
MapperUtil.mapProperties(listenerProps, listenerNode);
listenerNode.setAttribute(ListenerTagNames.GATEWAY_CLASS_TAG, HttpGatewayDeploymentFactory.class.getName());
listenerNode.setAttribute(ListenerTagNames.IS_GATEWAY_TAG, "true");
if(urlPattern != null) {
listenerNode.setAttribute(HttpGatewayDeploymentFactory.URL_PATTERN, urlPattern);
}
if(payloadAs != null) {
listenerNode.setAttribute(HttpGatewayServlet.PAYLOAD_AS, payloadAs.toString());
}
}
private static void mapExceptionStatusMappings(Element listenerNode, HttpProvider provider, HttpGateway listener) throws ConfigurationException {
StringBuilder exceptionMappingsAttrBuilder = new StringBuilder();
if(provider != null) {
HttpExceptionMappings providerExceptionConfig = provider.getException();
if(providerExceptionConfig != null) {
buildExceptionMappingCSV(exceptionMappingsAttrBuilder, providerExceptionConfig);
}
}
if(listener != null && listener.getExceptionList() != null && !listener.getExceptionList().isEmpty()) {
HttpExceptionMappings listenerExceptionConfig = listener.getExceptionList().get(0);
buildExceptionMappingCSV(exceptionMappingsAttrBuilder, listenerExceptionConfig);
}
if(exceptionMappingsAttrBuilder.length() > 0) {
listenerNode.setAttribute(org.jboss.soa.esb.listeners.gateway.http.HttpGatewayServlet.EXCEPTION_MAPPINGS, exceptionMappingsAttrBuilder.toString());
}
}
private static void buildExceptionMappingCSV(StringBuilder exceptionMappingsAttrBuilder, HttpExceptionMappings exceptionConfig) throws ConfigurationException {
// The mappings file is a .properties file containing exception-to-status-code mappings...
String mappingsFile = exceptionConfig.getMappingsFile();
if(mappingsFile != null) {
exceptionMappingsAttrBuilder.append(mappingsFile);
exceptionMappingsAttrBuilder.append(",");
}
// We add the exception mappings as a CSV list of exception class name and status
// code key value pairs...
List<HttpExceptionMappings.Mapping> mappings = exceptionConfig.getMappingList();
if(mappings != null && !mappings.isEmpty()) {
for(HttpExceptionMappings.Mapping mapping : mappings) {
exceptionMappingsAttrBuilder.append(mapping.getClass1().trim());
exceptionMappingsAttrBuilder.append("=");
exceptionMappingsAttrBuilder.append(mapping.getStatus());
exceptionMappingsAttrBuilder.append(",");
}
}
}
public static Map<String, Integer> decodeExceptionMappingsCSV(String exceptionMappingsCSV) throws ConfigurationException {
AssertArgument.isNotNullAndNotEmpty(exceptionMappingsCSV, "exceptionMappingsCSV");
Map<String, Integer> mappings = new HashMap<String, Integer>();
String[] mappingDecls = exceptionMappingsCSV.split(",");
for(String mappingDecl : mappingDecls) {
String[] mappingTokens = mappingDecl.split("=");
if(mappingTokens.length == 1) {
loadExceptionMappings(mappingTokens[0], mappings);
} else if(mappingTokens.length == 2) {
try {
mappings.put(mappingTokens[0], Integer.valueOf(mappingTokens[1]));
} catch(NumberFormatException e) {
throw new ConfigurationException("Invalid Exception Status Mapping mapping declaration '" + mappingDecl + "'. Status code value '" + mappingTokens[1] + "' not a valid integer.");
}
} else {
throw new ConfigurationException("Invalid Exception Status Mapping mapping declaration '" + mappingDecl + "'. Expected either an exception mapping file name, or a '<exception>=<status>' Key Value Pair.");
}
}
return mappings;
}
private static void loadExceptionMappings(String mappingsFile, Map<String, Integer> mappings) throws ConfigurationException {
Properties mappingProperties = new Properties();
InputStream stream = ClassUtil.getResourceAsStream(mappingsFile, HttpGatewayMapper.class);
if(stream == null) {
throw new ConfigurationException("Failed to find Exception to HTTP Status code mappings file '" + mappingsFile + "' on classpath.");
}
try {
mappingProperties.load(stream);
} catch (IOException e) {
throw new ConfigurationException("Error reading Exception to HTTP Status code mappings file '" + mappingsFile + "'.", e);
} finally {
try {
stream.close();
} catch (IOException e) {
logger.debug("Error closing Exception to HTTP Status code mappings file '" + mappingsFile + "'.", e);
}
}
Set<Map.Entry<Object, Object>> entries = mappingProperties.entrySet();
for(Map.Entry<Object, Object> entry : entries) {
try {
mappings.put((String) entry.getKey(), Integer.valueOf((String) entry.getValue()));
} catch(NumberFormatException e) {
throw new ConfigurationException("Invalid Exception Status Mapping mapping '" + entry.getKey() + "=" + entry.getValue() + "'. Status code value '" + entry.getValue() + "' not a valid integer.");
}
}
}
}