Java tutorial
/* * $Id$ * -------------------------------------------------------------------------------------- * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.transport.as2; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HeaderElement; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpVersion; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.cookie.MalformedCookieException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mule.DefaultMuleMessage; import org.mule.MessageExchangePattern; import org.mule.api.MuleContext; import org.mule.api.MuleMessage; import org.mule.api.transformer.TransformerException; import org.mule.api.transport.MessageTypeNotSupportedException; import org.mule.transport.as2.transformers.ByteArraytoSMIME; import org.mule.transport.http.CookieHelper; import org.mule.transport.http.HttpConnector; import org.mule.transport.http.HttpConstants; import org.mule.transport.http.HttpMuleMessageFactory; import org.mule.transport.http.HttpRequest; import org.mule.transport.http.ReleasingInputStream; import org.mule.util.CaseInsensitiveHashMap; import org.mule.util.IOUtils; import org.mule.util.PropertiesUtils; import org.mule.util.StringUtils; /** * <code>As2MuleMessageFactory</code> TODO document */ public class As2MuleMessageFactory extends HttpMuleMessageFactory { private static Log log = LogFactory.getLog(As2MuleMessageFactory.class); private static final String DEFAULT_ENCODING = "UTF-8"; /* They come from Http Message Factory*/ private boolean enableCookies = false; private String cookieSpec; private MessageExchangePattern exchangePattern = MessageExchangePattern.REQUEST_RESPONSE; private ByteArraytoSMIME byteArrayToSMIMETransf; public As2MuleMessageFactory(MuleContext context) { super(context); byteArrayToSMIMETransf = new ByteArraytoSMIME(); } @Override protected Class<?>[] getSupportedTransportMessageTypes() { // TODO return the supported message types. This is typically the class name of the // underlying transport message // throw new UnsupportedOperationException("getSupportedTransportMessageTypes"); return new Class[] { HttpRequest.class, HttpMethod.class }; } @Override protected Object extractPayload(Object transportMessage, String encoding) throws Exception { if (transportMessage instanceof HttpRequest) { return extractPayloadFromHttpRequest((HttpRequest) transportMessage); } else if (transportMessage instanceof HttpMethod) { return extractPayloadFromHttpMethod((HttpMethod) transportMessage); } else { // This should never happen because of the supported type checking throw new MessageTypeNotSupportedException(transportMessage, getClass()); } } @Override protected Object extractPayloadFromHttpRequest(HttpRequest httpRequest) throws IOException { log.debug("DBG: inside extractPayloadFromHttpRequest"); Object body = httpRequest.getBody(); // If http method is GET we use the request uri as the payload. if (body == null) { log.debug("DBG: body is null"); body = httpRequest.getRequestLine().getUri(); } else { // If we are running async we need to read stream into a byte[]. // Passing along the InputStream doesn't work because the // HttpConnection gets closed and closes the InputStream, often // before it can be read. if (!exchangePattern.hasResponse()) { log.debug("Reading HTTP POST InputStream into byte[] for asynchronous messaging."); body = IOUtils.toByteArray((InputStream) body); } } /* Create a Mime based on the Content Type of the request from a byte stream and return the payload */ try { //body = createMIME(body httpRequest.getContentType())); body = byteArrayToSMIMETransf.transformMimeMessage(body, "multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha1;"); } catch (TransformerException e) { throw new IOException("Transformer Exception"); } return body; } protected Object extractPayloadFromHttpMethod(HttpMethod httpMethod) throws IOException { InputStream body = httpMethod.getResponseBodyAsStream(); if (body != null) { return new ReleasingInputStream(body, httpMethod); } else { return StringUtils.EMPTY; } } @Override protected void addProperties(DefaultMuleMessage message, Object transportMessage) throws Exception { String method; HttpVersion httpVersion; String uri; String statusCode = null; Map<String, Object> headers; Map<String, Object> httpHeaders = new HashMap<String, Object>(); Map<String, Object> queryParameters = new HashMap<String, Object>(); if (transportMessage instanceof HttpRequest) { HttpRequest httpRequest = (HttpRequest) transportMessage; method = httpRequest.getRequestLine().getMethod(); httpVersion = httpRequest.getRequestLine().getHttpVersion(); uri = httpRequest.getRequestLine().getUri(); headers = convertHeadersToMap(httpRequest.getHeaders(), uri); convertMultiPartHeaders(headers); } else if (transportMessage instanceof HttpMethod) { HttpMethod httpMethod = (HttpMethod) transportMessage; method = httpMethod.getName(); httpVersion = HttpVersion.parse(httpMethod.getStatusLine().getHttpVersion()); uri = httpMethod.getURI().toString(); statusCode = String.valueOf(httpMethod.getStatusCode()); headers = convertHeadersToMap(httpMethod.getResponseHeaders(), uri); } else { // This should never happen because of the supported type checking in our superclass throw new MessageTypeNotSupportedException(transportMessage, getClass()); } rewriteConnectionAndKeepAliveHeaders(headers); headers = processIncomingHeaders(headers); httpHeaders.put(HttpConnector.HTTP_HEADERS, new HashMap<String, Object>(headers)); String encoding = getEncoding(headers); queryParameters.put(HttpConnector.HTTP_QUERY_PARAMS, processQueryParams(uri, encoding)); //Make any URI params available ans inbound message headers addUriParamsAsHeaders(headers, uri); headers.put(HttpConnector.HTTP_METHOD_PROPERTY, method); headers.put(HttpConnector.HTTP_REQUEST_PROPERTY, uri); headers.put(HttpConnector.HTTP_VERSION_PROPERTY, httpVersion.toString()); if (enableCookies) { headers.put(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY, cookieSpec); } if (statusCode != null) { headers.put(HttpConnector.HTTP_STATUS_PROPERTY, statusCode); } message.addInboundProperties(headers); message.addInboundProperties(httpHeaders); message.addInboundProperties(queryParameters); // The encoding is stored as message property. To avoid overriding it from the message // properties, it must be initialized last initEncoding(message, encoding); } protected Map<String, Object> processIncomingHeaders(Map<String, Object> headers) throws Exception { Map<String, Object> outHeaders = new HashMap<String, Object>(); for (Map.Entry<String, Object> header : headers.entrySet()) { String headerName = header.getKey(); // fix Mule headers? if (headerName.startsWith("X-MULE")) { headerName = headerName.substring(2); } // accept header & value outHeaders.put(headerName, header.getValue()); } return outHeaders; } Map<String, Object> convertHeadersToMap(Header[] headersArray, String uri) throws URISyntaxException { Map<String, Object> headersMap = new CaseInsensitiveHashMap(); for (int i = 0; i < headersArray.length; i++) { final Header header = headersArray[i]; // Cookies are a special case because there may be more than one // cookie. if (HttpConnector.HTTP_COOKIES_PROPERTY.equals(header.getName()) || HttpConstants.HEADER_COOKIE.equals(header.getName())) { putCookieHeaderInMapAsAServer(headersMap, header, uri); } else if (HttpConstants.HEADER_COOKIE_SET.equals(header.getName())) { putCookieHeaderInMapAsAClient(headersMap, header, uri); } else { if (headersMap.containsKey(header.getName())) { if (headersMap.get(header.getName()) instanceof String) { // concat headersMap.put(header.getName(), headersMap.get(header.getName()) + "," + header.getValue()); } else { // override headersMap.put(header.getName(), header.getValue()); } } else { headersMap.put(header.getName(), header.getValue()); } } } return headersMap; } protected void convertMultiPartHeaders(Map<String, Object> headers) { // template method } private void rewriteConnectionAndKeepAliveHeaders(Map<String, Object> headers) { // rewrite Connection and Keep-Alive headers based on HTTP version String headerValue; if (!isHttp11(headers)) { String connection = (String) headers.get(HttpConstants.HEADER_CONNECTION); if ((connection != null) && connection.equalsIgnoreCase("close")) { headerValue = Boolean.FALSE.toString(); } else { headerValue = Boolean.TRUE.toString(); } } else { headerValue = (headers.get(HttpConstants.HEADER_CONNECTION) != null ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); } headers.put(HttpConstants.HEADER_CONNECTION, headerValue); headers.put(HttpConstants.HEADER_KEEP_ALIVE, headerValue); } private boolean isHttp11(Map<String, Object> headers) { String httpVersion = (String) headers.get(HttpConnector.HTTP_VERSION_PROPERTY); return !HttpConstants.HTTP10.equalsIgnoreCase(httpVersion); } private String getEncoding(Map<String, Object> headers) { String encoding = DEFAULT_ENCODING; Object contentType = headers.get(HttpConstants.HEADER_CONTENT_TYPE); if (contentType != null) { // use HttpClient classes to parse the charset part from the Content-Type // header (e.g. "text/html; charset=UTF-16BE") Header contentTypeHeader = new Header(HttpConstants.HEADER_CONTENT_TYPE, contentType.toString()); HeaderElement values[] = contentTypeHeader.getElements(); if (values.length == 1) { NameValuePair param = values[0].getParameterByName("charset"); if (param != null) { encoding = param.getValue(); } } } return encoding; } protected Map<String, Object> processQueryParams(String uri, String encoding) throws UnsupportedEncodingException { Map<String, Object> httpParams = new HashMap<String, Object>(); int i = uri.indexOf("?"); if (i > -1) { String queryString = uri.substring(i + 1); for (StringTokenizer st = new StringTokenizer(queryString, "&"); st.hasMoreTokens();) { String token = st.nextToken(); int idx = token.indexOf('='); if (idx < 0) { addQueryParamToMap(httpParams, unescape(token, encoding), null); } else if (idx > 0) { addQueryParamToMap(httpParams, unescape(token.substring(0, idx), encoding), unescape(token.substring(idx + 1), encoding)); } } } return httpParams; } protected void addUriParamsAsHeaders(Map headers, String uri) { int i = uri.indexOf("?"); String queryString = ""; if (i > -1) { queryString = uri.substring(i + 1); headers.putAll(PropertiesUtils.getPropertiesFromQueryString(queryString)); } headers.put(HttpConnector.HTTP_QUERY_STRING, queryString); } private void initEncoding(MuleMessage message, String encoding) { message.setEncoding(encoding); } private void putCookieHeaderInMapAsAClient(Map<String, Object> headersMap, final Header header, String uri) throws URISyntaxException { try { final Cookie[] newCookies = CookieHelper.parseCookiesAsAClient(header.getValue(), cookieSpec, new URI(uri)); final Object preExistentCookies = headersMap.get(HttpConstants.HEADER_COOKIE_SET); final Object mergedCookie = CookieHelper.putAndMergeCookie(preExistentCookies, newCookies); headersMap.put(HttpConstants.HEADER_COOKIE_SET, mergedCookie); } catch (MalformedCookieException e) { log.warn("Received an invalid cookie: " + header, e); } } private void putCookieHeaderInMapAsAServer(Map<String, Object> headersMap, final Header header, String uri) throws URISyntaxException { if (enableCookies) { Cookie[] newCookies = CookieHelper.parseCookiesAsAServer(header.getValue(), new URI(uri)); if (newCookies.length > 0) { Object oldCookies = headersMap.get(HttpConnector.HTTP_COOKIES_PROPERTY); Object mergedCookies = CookieHelper.putAndMergeCookie(oldCookies, newCookies); headersMap.put(HttpConnector.HTTP_COOKIES_PROPERTY, mergedCookies); } } } private String unescape(String escapedValue, String encoding) throws UnsupportedEncodingException { if (escapedValue != null) { return URLDecoder.decode(escapedValue, encoding); } return escapedValue; } private void addQueryParamToMap(Map<String, Object> httpParams, String key, String value) { Object existingValue = httpParams.get(key); if (existingValue == null) { httpParams.put(key, value); } else if (existingValue instanceof List) { List<String> list = (List<String>) existingValue; list.add(value); } else if (existingValue instanceof String) { List<String> list = new ArrayList<String>(); list.add((String) existingValue); list.add(value); httpParams.put(key, list); } } /* If the transport message supports message properties implement this method to transfer all message properties from the transport message to the MuleMessage. @Override protected void addProperties(DefaultMuleMessage message, Object transportMessage) throws Exception { } */ /* If the transport message supports attachments implement this method to transfer all attachments to from the transport message to the MuleMessage. @Override protected void addAttachments(DefaultMuleMessage message, Object transportMessage) throws Exception { } */ public void setEnableCookies(boolean enableCookies) { this.enableCookies = enableCookies; } public void setCookieSpec(String cookieSpec) { this.cookieSpec = cookieSpec; } public void setExchangePattern(MessageExchangePattern mep) { exchangePattern = mep; } }