Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.servicemix.http.processors; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.servicemix.common.JbiConstants; import org.apache.servicemix.common.security.KeystoreManager; import org.apache.servicemix.http.HttpComponent; import org.apache.servicemix.http.HttpEndpoint; import org.apache.servicemix.http.monitoring.HttpConnectionListener; import org.apache.servicemix.soap.Context; import org.apache.servicemix.soap.SoapExchangeProcessor; import org.apache.servicemix.soap.SoapHelper; import org.apache.servicemix.soap.marshalers.SoapMessage; import org.apache.servicemix.soap.marshalers.SoapReader; import org.apache.servicemix.soap.marshalers.SoapWriter; import javax.jbi.messaging.*; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * * @author Guillaume Nodet * @version $Revision: 370186 $ * @since 3.0 */ public class ProviderProcessor extends AbstractProcessor implements SoapExchangeProcessor { private static Log log = LogFactory.getLog(ProviderProcessor.class); protected SoapHelper soapHelper; protected DeliveryChannel channel; private Map<String, PostMethod> methods; private Protocol protocol; private HttpConnectionListener listener; public ProviderProcessor(HttpEndpoint endpoint) { super(endpoint); this.soapHelper = new SoapHelper(endpoint); this.methods = new ConcurrentHashMap<String, PostMethod>(); } private String getRelUri(String locationUri) { java.net.URI uri = java.net.URI.create(locationUri); String relUri = uri.getPath(); if (!relUri.startsWith("/")) { relUri = "/" + relUri; } if (uri.getQuery() != null) { relUri += "?" + uri.getQuery(); } if (uri.getFragment() != null) { relUri += "#" + uri.getFragment(); } return relUri; } public void process(MessageExchange exchange) throws Exception { if (exchange.getStatus() == ExchangeStatus.DONE || exchange.getStatus() == ExchangeStatus.ERROR) { PostMethod method = methods.remove(exchange.getExchangeId()); if (method != null) { method.releaseConnection(); } return; } boolean txSync = exchange.isTransacted() && Boolean.TRUE.equals(exchange.getProperty(JbiConstants.SEND_SYNC)); txSync |= endpoint.isSynchronous(); NormalizedMessage nm = exchange.getMessage("in"); if (nm == null) { throw new IllegalStateException("Exchange has no input message"); } String locationURI = endpoint.getLocationURI(); // Incorporated because of JIRA SM-695 Object newDestinationURI = nm.getProperty(JbiConstants.HTTP_DESTINATION_URI); if (newDestinationURI != null) { locationURI = (String) newDestinationURI; log.debug("Location URI overridden: " + locationURI); } PostMethod method = new PostMethod(getRelUri(locationURI)); SoapMessage soapMessage = new SoapMessage(); soapHelper.getJBIMarshaler().fromNMS(soapMessage, nm); Context context = soapHelper.createContext(soapMessage); soapHelper.onSend(context); SoapWriter writer = soapHelper.getSoapMarshaler().createWriter(soapMessage); copyHeaderInformation(nm, method); RequestEntity entity = writeMessage(writer); // remove content-type header that may have been part of the in message if (!endpoint.isWantContentTypeHeaderFromExchangeIntoHttpRequest()) { method.removeRequestHeader(HEADER_CONTENT_TYPE); method.addRequestHeader(HEADER_CONTENT_TYPE, entity.getContentType()); } if (entity.getContentLength() < 0) { method.removeRequestHeader(HEADER_CONTENT_LENGTH); } else { method.setRequestHeader(HEADER_CONTENT_LENGTH, Long.toString(entity.getContentLength())); } if (endpoint.isSoap() && method.getRequestHeader(HEADER_SOAP_ACTION) == null) { if (endpoint.getSoapAction() != null) { method.setRequestHeader(HEADER_SOAP_ACTION, endpoint.getSoapAction()); } else { // method.setRequestHeader(HEADER_SOAP_ACTION, "\"\""); } } method.setRequestHeader(HEADER_X_CORRELATION_ID, (String) exchange.getProperty(JbiConstants.CORRELATION_ID)); String smxInstanceName = System.getProperty(SMX_INSTANCE_NAME_PROPERTY); if (smxInstanceName != null) { method.setRequestHeader(HEADER_X_POWERED_BY, smxInstanceName); } else { log.warn(SMX_INSTANCE_NAME_PROPERTY + " property was not set in servicemix.xml file"); } method.setRequestEntity(entity); boolean close = true; try { // Set the retry handler int retries = getConfiguration().isStreamingEnabled() ? 0 : getConfiguration().getRetryCount(); method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(retries, true)); // Set authentication if (endpoint.getBasicAuthentication() != null) { endpoint.getBasicAuthentication().applyCredentials(getClient(), exchange, nm); } // Execute the HTTP method //method.getParams().setLongParameter(HttpConnectionParams.CONNECTION_TIMEOUT, getClient().getParams().getSoTimeout()); int response = -1; try { response = getClient().executeMethod(getHostConfiguration(locationURI, exchange, nm), method); } catch (Exception ex) { try { if (listener != null) { if (ex instanceof SocketException) { log.error("Connection to address: " + locationURI + " was refused"); listener.onConnectionRefused(locationURI); } else if (ex instanceof SocketTimeoutException) { log.error("Connection to address: " + locationURI + " timed out"); listener.onTimeout(locationURI); } } } catch (Exception ex2) { log.warn("Error in HttpConnectionListener: " + ex2.getMessage()); } finally { throw ex; } } try { if (listener != null) { listener.onPostExecuted(locationURI, response); } } catch (Exception ex) { log.warn("Error in HttpConnectionListener: " + ex.getMessage()); } if (response != HttpStatus.SC_OK && response != HttpStatus.SC_ACCEPTED) { if (!(exchange instanceof InOnly)) { SoapReader reader = soapHelper.getSoapMarshaler().createReader(); Header contentType = method.getResponseHeader(HEADER_CONTENT_TYPE); String content = convertResponseBodyToString(method); logInOut(locationURI, response, method, soapMessage, content); soapMessage = reader.read(new ByteArrayInputStream(content.getBytes()), contentType != null ? contentType.getValue() : null); context.setFaultMessage(soapMessage); soapHelper.onAnswer(context); Fault fault = exchange.createFault(); fault.setProperty(JbiConstants.PROTOCOL_HEADERS, getHeaders(method)); soapHelper.getJBIMarshaler().toNMS(fault, soapMessage); exchange.setFault(fault); if (txSync) { channel.sendSync(exchange); } else { methods.put(exchange.getExchangeId(), method); channel.send(exchange); close = false; } return; } else { String content = convertResponseBodyToString(method); // even if it is InOnly, some out could come to us logInOut(locationURI, response, method, soapMessage, content); throw new Exception("Invalid status response: " + response); } } if (exchange instanceof InOut) { close = processInOut(exchange, method, context, txSync, close); } else if (exchange instanceof InOptionalOut) { close = processInOptionalOut(method, exchange, context, txSync, close); } else { exchange.setStatus(ExchangeStatus.DONE); channel.send(exchange); } } finally { if (close) { method.releaseConnection(); } } } // this method is created because getResponseBodyAsString log waringings private String convertResponseBodyToString(PostMethod method) throws IOException { InputStream responseBodyStream = method.getResponseBodyAsStream(); return streamToString(responseBodyStream); } private void logInOut(String locationURI, int responseCode, PostMethod method, SoapMessage requestSoapMessage, String responseContent) { if (log.isWarnEnabled()) { log.warn("Connections to address: " + locationURI + " ended with status: " + responseCode); log.warn("Request headers:"); for (int i = 0; i < method.getRequestHeaders().length; i++) { Header header = method.getRequestHeaders()[i]; log.warn(header.getName() + ": " + header.getValue()); } log.warn("Request content:"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { soapHelper.getSoapMarshaler().createWriter(requestSoapMessage).write(bos); log.warn(bos.toString()); } catch (Exception e) { log.warn("Cannot marshall request body"); } log.warn("Response headers:"); for (int i = 0; i < method.getResponseHeaders().length; i++) { Header header = method.getResponseHeaders()[i]; log.warn(header.getName() + ": " + header.getValue()); } log.warn("Response content:"); log.warn(responseContent); } } @SuppressWarnings("unchecked") private void copyHeaderInformation(NormalizedMessage nm, PostMethod method) { Map<String, String> headers = (Map<String, String>) nm.getProperty(JbiConstants.PROTOCOL_HEADERS); if (headers != null) { for (String name : headers.keySet()) { String value = headers.get(name); method.addRequestHeader(name, value); } } } private boolean processInOptionalOut(PostMethod method, MessageExchange exchange, Context context, boolean txSync, boolean close) throws Exception { if (method.getResponseContentLength() == 0) { exchange.setStatus(ExchangeStatus.DONE); channel.send(exchange); } else { NormalizedMessage msg = exchange.createMessage(); SoapReader reader = soapHelper.getSoapMarshaler().createReader(); SoapMessage soapMessage = reader.read(method.getResponseBodyAsStream(), method.getResponseHeader(HEADER_CONTENT_TYPE).getValue()); context.setOutMessage(soapMessage); soapHelper.onAnswer(context); if (getConfiguration().isWantHeadersFromHttpIntoExchange()) { msg.setProperty(JbiConstants.PROTOCOL_HEADERS, getHeaders(method)); } soapHelper.getJBIMarshaler().toNMS(msg, soapMessage); ((InOptionalOut) exchange).setOutMessage(msg); if (txSync) { channel.sendSync(exchange); } else { methods.put(exchange.getExchangeId(), method); channel.send(exchange); close = false; } } return close; } private boolean processInOut(MessageExchange exchange, PostMethod method, Context context, boolean txSync, boolean close) throws Exception { NormalizedMessage msg = exchange.createMessage(); SoapReader reader = soapHelper.getSoapMarshaler().createReader(); Header contentType = method.getResponseHeader(HEADER_CONTENT_TYPE); SoapMessage soapMessage = reader.read(method.getResponseBodyAsStream(), contentType != null ? contentType.getValue() : null); context.setOutMessage(soapMessage); soapHelper.onAnswer(context); if (getConfiguration().isWantHeadersFromHttpIntoExchange()) { msg.setProperty(JbiConstants.PROTOCOL_HEADERS, getHeaders(method)); } soapHelper.getJBIMarshaler().toNMS(msg, soapMessage); ((InOut) exchange).setOutMessage(msg); if (txSync) { channel.sendSync(exchange); } else { methods.put(exchange.getExchangeId(), method); channel.send(exchange); close = false; } return close; } private HostConfiguration getHostConfiguration(String locationURI, MessageExchange exchange, NormalizedMessage message) throws Exception { HostConfiguration host; URI uri = new URI(locationURI, false); if (uri.getScheme().equals("https")) { synchronized (this) { if (protocol == null) { ProtocolSocketFactory sf = new CommonsHttpSSLSocketFactory(endpoint.getSsl(), KeystoreManager.Proxy.create(endpoint.getKeystoreManager())); protocol = new Protocol("https", sf, 443); } } HttpHost httphost = new HttpHost(uri.getHost(), uri.getPort(), protocol); host = new HostConfiguration(); host.setHost(httphost); } else { host = new HostConfiguration(); host.setHost(uri.getHost(), uri.getPort()); } if (endpoint.getProxy() != null) { if ((endpoint.getProxy().getProxyHost() != null) && (endpoint.getProxy().getProxyPort() != 0)) { host.setProxy(endpoint.getProxy().getProxyHost(), endpoint.getProxy().getProxyPort()); } if (endpoint.getProxy().getProxyCredentials() != null) { endpoint.getProxy().getProxyCredentials().applyProxyCredentials(getClient(), exchange, message); } } else if ((getConfiguration().getProxyHost() != null) && (getConfiguration().getProxyPort() != 0)) { host.setProxy(getConfiguration().getProxyHost(), getConfiguration().getProxyPort()); } //host.getParams().setLongParameter(HttpConnectionParams.CONNECTION_TIMEOUT, getClient().getParams().getSoTimeout()); return host; } public void init() throws Exception { channel = endpoint.getServiceUnit().getComponent().getComponentContext().getDeliveryChannel(); if (listener != null) { listener.onProviderInit(endpoint.getLocationURI()); } } public void start() throws Exception { } public void stop() throws Exception { } public void shutdown() throws Exception { } protected Map<String, String> getHeaders(HttpServletRequest request) { Map<String, String> headers = new HashMap<String, String>(); Enumeration<?> enumeration = request.getHeaderNames(); while (enumeration.hasMoreElements()) { String name = (String) enumeration.nextElement(); String value = request.getHeader(name); headers.put(name, value); } return headers; } protected Map<String, String> getHeaders(HttpMethod method) { Map<String, String> headers = new HashMap<String, String>(); Header[] h = method.getResponseHeaders(); for (int i = 0; i < h.length; i++) { headers.put(h[i].getName(), h[i].getValue()); } return headers; } protected RequestEntity writeMessage(SoapWriter writer) throws Exception { if (getConfiguration().isStreamingEnabled()) { return new StreamingRequestEntity(writer); } else { ByteArrayOutputStream baos = new ByteArrayOutputStream(); writer.write(baos); return new ByteArrayRequestEntity(baos.toByteArray(), writer.getContentType()); } } protected HttpClient getClient() { HttpComponent comp = (HttpComponent) endpoint.getServiceUnit().getComponent(); HttpClient client = comp.getClient(); client.getParams().setSoTimeout(endpoint.getTimeout()); client.getParams().getDefaults().setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT, endpoint.getTimeout()); return client; } public void setListener(HttpConnectionListener listener) { this.listener = listener; } public static class StreamingRequestEntity implements RequestEntity { private SoapWriter writer; public StreamingRequestEntity(SoapWriter writer) { this.writer = writer; } public boolean isRepeatable() { return false; } public void writeRequest(OutputStream out) throws IOException { try { writer.write(out); out.flush(); } catch (Exception e) { throw (IOException) new IOException("Could not write request").initCause(e); } } public long getContentLength() { // not known so we send negative value return -1; } public String getContentType() { return writer.getContentType(); } } }