Java tutorial
/* * Copyright (c) Mirth Corporation. All rights reserved. * * http://www.mirthcorp.com * * The software in this package is published under the terms of the MPL license a copy of which has * been included with this distribution in the LICENSE.txt file. */ package com.mirth.connect.connectors.ws; import java.io.ByteArrayInputStream; import java.io.File; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.net.ConnectException; import java.net.NoRouteToHostException; import java.net.URI; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import javax.xml.namespace.QName; import javax.xml.soap.AttachmentPart; import javax.xml.soap.SOAPMessage; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.BindingProvider; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.soap.SOAPBinding; import javax.xml.ws.soap.SOAPFaultException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.auth.AuthSchemeProvider; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.utils.HttpClientUtils; import org.apache.http.config.RegistryBuilder; import org.apache.http.config.SocketConfig; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.entity.ContentType; import org.apache.http.impl.auth.BasicSchemeFactory; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.apache.log4j.Logger; import com.mirth.connect.donkey.model.channel.ConnectorProperties; import com.mirth.connect.donkey.model.event.ConnectionStatusEventType; import com.mirth.connect.donkey.model.event.ErrorEventType; import com.mirth.connect.donkey.model.message.ConnectorMessage; import com.mirth.connect.donkey.model.message.Response; import com.mirth.connect.donkey.model.message.Status; import com.mirth.connect.donkey.model.message.attachment.AttachmentHandlerProvider; import com.mirth.connect.donkey.server.ConnectorTaskException; import com.mirth.connect.donkey.server.channel.DestinationConnector; import com.mirth.connect.donkey.server.event.ConnectionStatusEvent; import com.mirth.connect.donkey.server.event.ErrorEvent; import com.mirth.connect.donkey.util.DonkeyElement; import com.mirth.connect.donkey.util.DonkeyElement.DonkeyElementException; import com.mirth.connect.server.controllers.ConfigurationController; import com.mirth.connect.server.controllers.ControllerFactory; import com.mirth.connect.server.controllers.EventController; import com.mirth.connect.server.util.TemplateValueReplacer; import com.mirth.connect.util.ErrorMessageBuilder; import com.mirth.connect.util.HttpUtil; public class WebServiceDispatcher extends DestinationConnector { // The system property actually ends up being the maximum request count private static final int MAX_REDIRECTS = NumberUtils.toInt(System.getProperty("http.maxRedirects"), 20); private Logger logger = Logger.getLogger(this.getClass()); protected WebServiceDispatcherProperties connectorProperties; private EventController eventController = ControllerFactory.getFactory().createEventController(); private ConfigurationController configurationController = ControllerFactory.getFactory() .createConfigurationController(); private TemplateValueReplacer replacer = new TemplateValueReplacer(); private WebServiceConfiguration configuration; private RegistryBuilder<ConnectionSocketFactory> socketFactoryRegistry; private ExecutorService executor; private Set<DispatchTask<SOAPMessage>> dispatchTasks; private int timeout; /* * Dispatch object used for pooling the soap connection, and the current properties used to * create the dispatch object */ private Map<Long, DispatchContainer> dispatchContainers = new ConcurrentHashMap<Long, DispatchContainer>(); /* * CloseableHttpClient objects used to request the initial WSDL */ private Set<CloseableHttpClient> clients = Collections .newSetFromMap(new ConcurrentHashMap<CloseableHttpClient, Boolean>()); @Override public void onDeploy() throws ConnectorTaskException { this.connectorProperties = (WebServiceDispatcherProperties) getConnectorProperties(); // load the default configuration String configurationClass = configurationController.getProperty(connectorProperties.getProtocol(), "wsConfigurationClass"); try { configuration = (WebServiceConfiguration) Class.forName(configurationClass).newInstance(); } catch (Exception e) { logger.trace("could not find custom configuration class, using default"); configuration = new DefaultWebServiceConfiguration(); } try { socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()); configuration.configureConnectorDeploy(this); } catch (Exception e) { throw new ConnectorTaskException(e); } timeout = NumberUtils.toInt(connectorProperties.getSocketTimeout()); } @Override public void onUndeploy() throws ConnectorTaskException { configuration.configureConnectorUndeploy(this); } @Override public void onStart() throws ConnectorTaskException { if (timeout == 0) { executor = Executors.newCachedThreadPool(); dispatchTasks = Collections.newSetFromMap(new ConcurrentHashMap<DispatchTask<SOAPMessage>, Boolean>()); } } @Override public void onStop() throws ConnectorTaskException { for (CloseableHttpClient client : clients.toArray(new CloseableHttpClient[clients.size()])) { HttpClientUtils.closeQuietly(client); } clients.clear(); if (executor != null) { executor.shutdown(); } for (DispatchContainer dispatchContainer : dispatchContainers.values()) { for (File tempFile : dispatchContainer.getTempFiles()) { tempFile.delete(); } } dispatchContainers.clear(); } @Override public void onHalt() throws ConnectorTaskException { for (CloseableHttpClient client : clients.toArray(new CloseableHttpClient[clients.size()])) { HttpClientUtils.closeQuietly(client); } clients.clear(); if (executor != null) { boolean shutdown = executor.isShutdown(); executor.shutdownNow(); // Only log an error out if this is the first time the executor was shutdown if (!shutdown) { try { // Wait a bit for tasks to finish and remove themselves from the set executor.awaitTermination(100, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new ConnectorTaskException( "Halt task interrupted while waiting for executor to shutdown.", e); } int numTasks = dispatchTasks.size(); if (numTasks > 0) { String message = "Error halting Web Service Sender: " + numTasks + " request" + (numTasks == 1 ? "" : "s") + " failed to be halted. This can potentially lead to a thread leak if the requests continue to hang."; logger.error(message); eventController.dispatchEvent(new ErrorEvent(getChannelId(), getMetaDataId(), null, ErrorEventType.DESTINATION_CONNECTOR, getDestinationName(), connectorProperties.getName(), message, null)); } } } for (DispatchContainer dispatchContainer : dispatchContainers.values() .toArray(new DispatchContainer[dispatchContainers.size()])) { for (File tempFile : dispatchContainer.getTempFiles() .toArray(new File[dispatchContainer.getTempFiles().size()])) { tempFile.delete(); } } dispatchContainers.clear(); } private String sourceToXmlString(Source source) throws TransformerConfigurationException, TransformerException { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); Writer writer = new StringWriter(); transformer.transform(source, new StreamResult(writer)); return writer.toString(); } private void createDispatch(WebServiceDispatcherProperties webServiceDispatcherProperties, DispatchContainer dispatchContainer) throws Exception { String wsdlUrl = webServiceDispatcherProperties.getWsdlUrl(); String username = webServiceDispatcherProperties.getUsername(); String password = webServiceDispatcherProperties.getPassword(); String serviceName = webServiceDispatcherProperties.getService(); String portName = webServiceDispatcherProperties.getPort(); /* * The dispatch needs to be created if it hasn't been created yet (null). It needs to be * recreated if any of the above variables are different than what were used to create the * current dispatch object. This could happen if variables are being used for these * properties. */ if (dispatchContainer.getDispatch() == null || !StringUtils.equals(wsdlUrl, dispatchContainer.getCurrentWsdlUrl()) || !StringUtils.equals(username, dispatchContainer.getCurrentUsername()) || !StringUtils.equals(password, dispatchContainer.getCurrentPassword()) || !StringUtils.equals(serviceName, dispatchContainer.getCurrentServiceName()) || !StringUtils.equals(portName, dispatchContainer.getCurrentPortName())) { dispatchContainer.setCurrentWsdlUrl(wsdlUrl); dispatchContainer.setCurrentUsername(username); dispatchContainer.setCurrentPassword(password); dispatchContainer.setCurrentServiceName(serviceName); dispatchContainer.setCurrentPortName(portName); URL endpointUrl = getWsdlUrl(dispatchContainer); QName serviceQName = QName.valueOf(serviceName); QName portQName = QName.valueOf(portName); // create the service and dispatch logger.debug("Creating web service: url=" + endpointUrl.toString() + ", service=" + serviceQName + ", port=" + portQName); Service service = Service.create(endpointUrl, serviceQName); Dispatch<SOAPMessage> dispatch = service.createDispatch(portQName, SOAPMessage.class, Service.Mode.MESSAGE); if (timeout > 0) { dispatch.getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", timeout); dispatch.getRequestContext().put("com.sun.xml.internal.ws.request.timeout", timeout); dispatch.getRequestContext().put("com.sun.xml.ws.connect.timeout", timeout); dispatch.getRequestContext().put("com.sun.xml.ws.request.timeout", timeout); } Map<String, List<String>> requestHeaders = (Map<String, List<String>>) dispatch.getRequestContext() .get(MessageContext.HTTP_REQUEST_HEADERS); if (requestHeaders == null) { requestHeaders = new HashMap<String, List<String>>(); } dispatchContainer.setDefaultRequestHeaders(requestHeaders); dispatchContainer.setDispatch(dispatch); } } /** * Returns the URL for the passed in String. If the URL requires authentication, then the WSDL * is saved as a temp file and the URL for that file is returned. * * @param wsdlUrl * @param username * @param password * @return * @throws Exception */ private URL getWsdlUrl(DispatchContainer dispatchContainer) throws Exception { URI uri = new URI(dispatchContainer.getCurrentWsdlUrl()); // If the URL points to file, just return it if (!uri.getScheme().equalsIgnoreCase("file")) { BasicHttpClientConnectionManager httpClientConnectionManager = new BasicHttpClientConnectionManager( socketFactoryRegistry.build()); httpClientConnectionManager.setSocketConfig(SocketConfig.custom().setSoTimeout(timeout).build()); HttpClientBuilder clientBuilder = HttpClients.custom() .setConnectionManager(httpClientConnectionManager); HttpUtil.configureClientBuilder(clientBuilder); CloseableHttpClient client = clientBuilder.build(); try { clients.add(client); HttpClientContext context = HttpClientContext.create(); if (dispatchContainer.getCurrentUsername() != null && dispatchContainer.getCurrentPassword() != null) { CredentialsProvider credsProvider = new BasicCredentialsProvider(); AuthScope authScope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM); Credentials credentials = new UsernamePasswordCredentials( dispatchContainer.getCurrentUsername(), dispatchContainer.getCurrentPassword()); credsProvider.setCredentials(authScope, credentials); AuthCache authCache = new BasicAuthCache(); RegistryBuilder<AuthSchemeProvider> registryBuilder = RegistryBuilder .<AuthSchemeProvider>create(); registryBuilder.register(AuthSchemes.BASIC, new BasicSchemeFactory()); context.setCredentialsProvider(credsProvider); context.setAuthSchemeRegistry(registryBuilder.build()); context.setAuthCache(authCache); } RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout) .setSocketTimeout(timeout).setStaleConnectionCheckEnabled(true).build(); context.setRequestConfig(requestConfig); return getWsdl(client, context, dispatchContainer, new HashMap<String, File>(), dispatchContainer.getCurrentWsdlUrl()).toURI().toURL(); } finally { HttpClientUtils.closeQuietly(client); clients.remove(client); } } return uri.toURL(); } private File getWsdl(CloseableHttpClient client, HttpContext context, DispatchContainer dispatchContainer, Map<String, File> visitedUrls, String wsdlUrl) throws Exception { if (visitedUrls.containsKey(wsdlUrl)) { return visitedUrls.get(wsdlUrl); } String wsdl = null; StatusLine responseStatusLine = null; CloseableHttpResponse response = client.execute(new HttpGet(wsdlUrl), context); try { responseStatusLine = response.getStatusLine(); if (responseStatusLine.getStatusCode() == HttpStatus.SC_OK) { ContentType responseContentType = ContentType.get(response.getEntity()); if (responseContentType == null) { responseContentType = ContentType.TEXT_XML; } Charset responseCharset = responseContentType.getCharset(); if (responseContentType.getCharset() == null) { responseCharset = ContentType.TEXT_XML.getCharset(); } wsdl = IOUtils.toString(response.getEntity().getContent(), responseCharset); } } finally { HttpClientUtils.closeQuietly(response); } if (StringUtils.isNotBlank(wsdl)) { File tempFile = File.createTempFile("WebServiceSender", ".wsdl"); tempFile.deleteOnExit(); visitedUrls.put(wsdlUrl, tempFile); try { DonkeyElement element = new DonkeyElement(wsdl); for (DonkeyElement child : element.getChildElements()) { if (child.getLocalName().equals("import") && child.hasAttribute("location")) { String location = new URI(wsdlUrl).resolve(child.getAttribute("location")).toString(); child.setAttribute("location", getWsdl(client, context, dispatchContainer, visitedUrls, location).toURI().toURL() .toString()); } } wsdl = element.toXml(); } catch (Exception e) { logger.warn("Unable to cache imports for WSDL at URL: " + wsdlUrl, e); } FileUtils.writeStringToFile(tempFile, wsdl); dispatchContainer.getTempFiles().add(tempFile); return tempFile; } else { throw new Exception( "Unable to load WSDL at URL \"" + wsdlUrl + "\": " + String.valueOf(responseStatusLine)); } } @Override public void replaceConnectorProperties(ConnectorProperties connectorProperties, ConnectorMessage connectorMessage) { WebServiceDispatcherProperties webServiceDispatcherProperties = (WebServiceDispatcherProperties) connectorProperties; // Replace all values in connector properties webServiceDispatcherProperties .setWsdlUrl(replacer.replaceValues(webServiceDispatcherProperties.getWsdlUrl(), connectorMessage)); webServiceDispatcherProperties.setUsername( replacer.replaceValues(webServiceDispatcherProperties.getUsername(), connectorMessage)); webServiceDispatcherProperties.setPassword( replacer.replaceValues(webServiceDispatcherProperties.getPassword(), connectorMessage)); webServiceDispatcherProperties .setService(replacer.replaceValues(webServiceDispatcherProperties.getService(), connectorMessage)); webServiceDispatcherProperties .setPort(replacer.replaceValues(webServiceDispatcherProperties.getPort(), connectorMessage)); webServiceDispatcherProperties.setLocationURI( replacer.replaceValues(webServiceDispatcherProperties.getLocationURI(), connectorMessage)); webServiceDispatcherProperties.setSoapAction( replacer.replaceValues(webServiceDispatcherProperties.getSoapAction(), connectorMessage)); webServiceDispatcherProperties.setEnvelope( replacer.replaceValues(webServiceDispatcherProperties.getEnvelope(), connectorMessage)); Map<String, List<String>> headers = webServiceDispatcherProperties.getHeaders(); for (Map.Entry<String, List<String>> entry : headers.entrySet()) { replacer.replaceValuesInList(entry.getValue(), connectorMessage); } webServiceDispatcherProperties.setHeaders(headers); if (webServiceDispatcherProperties.isUseMtom()) { replacer.replaceValuesInList(webServiceDispatcherProperties.getAttachmentNames(), connectorMessage); replacer.replaceValuesInList(webServiceDispatcherProperties.getAttachmentContents(), connectorMessage); replacer.replaceValuesInList(webServiceDispatcherProperties.getAttachmentTypes(), connectorMessage); } } @Override public Response send(ConnectorProperties connectorProperties, ConnectorMessage connectorMessage) { WebServiceDispatcherProperties webServiceDispatcherProperties = (WebServiceDispatcherProperties) connectorProperties; eventController.dispatchEvent(new ConnectionStatusEvent(getChannelId(), getMetaDataId(), getDestinationName(), ConnectionStatusEventType.SENDING)); String responseData = null; String responseError = null; String responseStatusMessage = null; Status responseStatus = Status.QUEUED; boolean validateResponse = false; try { long dispatcherId = getDispatcherId(); DispatchContainer dispatchContainer = dispatchContainers.get(dispatcherId); if (dispatchContainer == null) { dispatchContainer = new DispatchContainer(); dispatchContainers.put(dispatcherId, dispatchContainer); } /* * Initialize the dispatch object if it hasn't been initialized yet, or create a new one * if the connector properties have changed due to variables. */ createDispatch(webServiceDispatcherProperties, dispatchContainer); Dispatch<SOAPMessage> dispatch = dispatchContainer.getDispatch(); configuration.configureDispatcher(this, webServiceDispatcherProperties, dispatch.getRequestContext()); SOAPBinding soapBinding = (SOAPBinding) dispatch.getBinding(); if (webServiceDispatcherProperties.isUseAuthentication()) { String currentUsername = dispatchContainer.getCurrentUsername(); String currentPassword = dispatchContainer.getCurrentPassword(); dispatch.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, currentUsername); dispatch.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, currentPassword); logger.debug("Using authentication: username=" + currentUsername + ", password length=" + currentPassword.length()); } // See: http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383528 String soapAction = webServiceDispatcherProperties.getSoapAction(); if (StringUtils.isNotEmpty(soapAction)) { dispatch.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, true); // MIRTH-2109 dispatch.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, soapAction); } // Get default headers Map<String, List<String>> requestHeaders = new HashMap<String, List<String>>( dispatchContainer.getDefaultRequestHeaders()); // Add custom headers if (MapUtils.isNotEmpty(webServiceDispatcherProperties.getHeaders())) { for (Entry<String, List<String>> entry : webServiceDispatcherProperties.getHeaders().entrySet()) { List<String> valueList = requestHeaders.get(entry.getKey()); if (valueList == null) { valueList = new ArrayList<String>(); requestHeaders.put(entry.getKey(), valueList); } valueList.addAll(entry.getValue()); } } dispatch.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders); // build the message logger.debug("Creating SOAP envelope."); AttachmentHandlerProvider attachmentHandlerProvider = getAttachmentHandlerProvider(); String content = attachmentHandlerProvider.reAttachMessage(webServiceDispatcherProperties.getEnvelope(), connectorMessage); Source source = new StreamSource(new StringReader(content)); SOAPMessage message = soapBinding.getMessageFactory().createMessage(); message.getSOAPPart().setContent(source); if (webServiceDispatcherProperties.isUseMtom()) { soapBinding.setMTOMEnabled(true); List<String> attachmentIds = webServiceDispatcherProperties.getAttachmentNames(); List<String> attachmentContents = webServiceDispatcherProperties.getAttachmentContents(); List<String> attachmentTypes = webServiceDispatcherProperties.getAttachmentTypes(); for (int i = 0; i < attachmentIds.size(); i++) { String attachmentContentId = attachmentIds.get(i); String attachmentContentType = attachmentTypes.get(i); String attachmentContent = attachmentHandlerProvider.reAttachMessage(attachmentContents.get(i), connectorMessage); AttachmentPart attachment = message.createAttachmentPart(); attachment.setBase64Content(new ByteArrayInputStream(attachmentContent.getBytes("UTF-8")), attachmentContentType); attachment.setContentId(attachmentContentId); message.addAttachmentPart(attachment); } } message.saveChanges(); if (StringUtils.isNotBlank(webServiceDispatcherProperties.getLocationURI())) { dispatch.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, webServiceDispatcherProperties.getLocationURI()); } boolean redirect = false; int tryCount = 0; /* * Attempt the invocation until we hit the maximum allowed redirects. The redirections * we handle are when the scheme changes (i.e. from HTTP to HTTPS). */ do { redirect = false; tryCount++; try { DispatchTask<SOAPMessage> task = new DispatchTask<SOAPMessage>(dispatch, message, webServiceDispatcherProperties.isOneWay()); SOAPMessage result; /* * If the timeout is set to zero, we need to do the invocation in a separate * thread. This is because there's no way to get a reference to the underlying * JAX-WS socket, so there's no way to forcefully halt the dispatch. If the * socket is truly hung and the user halts the channel, the best we can do is * just interrupt and ignore the thread. This means that a thread leak is * potentially introduced, so we need to notify the user appropriately. */ if (timeout == 0) { // Submit the task to an executor so that it's interruptible Future<SOAPMessage> future = executor.submit(task); // Keep track of the task by adding it to our set dispatchTasks.add(task); result = future.get(); } else { // Call the task directly result = task.call(); } if (webServiceDispatcherProperties.isOneWay()) { responseStatusMessage = "Invoked one way operation successfully."; } else { responseData = sourceToXmlString(result.getSOAPPart().getContent()); responseStatusMessage = "Invoked two way operation successfully."; } logger.debug("Finished invoking web service, got result."); // Automatically accept message; leave it up to the response transformer to find SOAP faults responseStatus = Status.SENT; } catch (Throwable e) { // Unwrap the exception if it came from the executor if (e instanceof ExecutionException && e.getCause() != null) { e = e.getCause(); } // If the dispatch was interrupted, make sure to reset the interrupted flag if (e instanceof InterruptedException) { Thread.currentThread().interrupt(); } Integer responseCode = null; String location = null; if (dispatch.getResponseContext() != null) { responseCode = (Integer) dispatch.getResponseContext() .get(MessageContext.HTTP_RESPONSE_CODE); Map<String, List<String>> headers = (Map<String, List<String>>) dispatch .getResponseContext().get(MessageContext.HTTP_RESPONSE_HEADERS); if (MapUtils.isNotEmpty(headers)) { List<String> locations = headers.get("Location"); if (CollectionUtils.isNotEmpty(locations)) { location = locations.get(0); } } } if (tryCount < MAX_REDIRECTS && responseCode != null && responseCode >= 300 && responseCode < 400 && StringUtils.isNotBlank(location)) { redirect = true; // Replace the endpoint with the redirected URL dispatch.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, location); } else { // Leave the response status as QUEUED for NoRouteToHostException and ConnectException, otherwise ERROR if (e instanceof NoRouteToHostException || ((e.getCause() != null) && (e.getCause() instanceof NoRouteToHostException))) { responseStatusMessage = ErrorMessageBuilder.buildErrorResponse("HTTP transport error", e); responseError = ErrorMessageBuilder.buildErrorMessage(connectorProperties.getName(), "HTTP transport error", e); eventController.dispatchEvent( new ErrorEvent(getChannelId(), getMetaDataId(), connectorMessage.getMessageId(), ErrorEventType.DESTINATION_CONNECTOR, getDestinationName(), connectorProperties.getName(), "HTTP transport error.", e)); } else if ((e.getClass() == ConnectException.class) || ((e.getCause() != null) && (e.getCause().getClass() == ConnectException.class))) { responseStatusMessage = ErrorMessageBuilder.buildErrorResponse("Connection refused.", e); eventController.dispatchEvent(new ErrorEvent(getChannelId(), getMetaDataId(), connectorMessage.getMessageId(), ErrorEventType.DESTINATION_CONNECTOR, getDestinationName(), connectorProperties.getName(), "Connection refused.", e)); } else { if (e instanceof SOAPFaultException) { try { responseData = new DonkeyElement(((SOAPFaultException) e).getFault()).toXml(); } catch (DonkeyElementException e2) { } } responseStatus = Status.ERROR; responseStatusMessage = ErrorMessageBuilder .buildErrorResponse("Error invoking web service", e); responseError = ErrorMessageBuilder.buildErrorMessage(connectorProperties.getName(), "Error invoking web service", e); eventController.dispatchEvent( new ErrorEvent(getChannelId(), getMetaDataId(), connectorMessage.getMessageId(), ErrorEventType.DESTINATION_CONNECTOR, getDestinationName(), connectorProperties.getName(), "Error invoking web service.", e)); } } } } while (redirect && tryCount < MAX_REDIRECTS); } catch (Exception e) { responseStatusMessage = ErrorMessageBuilder.buildErrorResponse("Error creating web service dispatch", e); responseError = ErrorMessageBuilder.buildErrorMessage(connectorProperties.getName(), "Error creating web service dispatch", e); eventController.dispatchEvent(new ErrorEvent(getChannelId(), getMetaDataId(), connectorMessage.getMessageId(), ErrorEventType.DESTINATION_CONNECTOR, getDestinationName(), connectorProperties.getName(), "Error creating web service dispatch.", e)); } finally { eventController.dispatchEvent(new ConnectionStatusEvent(getChannelId(), getMetaDataId(), getDestinationName(), ConnectionStatusEventType.IDLE)); } return new Response(responseStatus, responseData, responseStatusMessage, responseError, validateResponse); } private class DispatchContainer { /* * Dispatch object used for pooling the soap connection, and the current properties used to * create the dispatch object */ private Dispatch<SOAPMessage> dispatch = null; private String currentWsdlUrl = null; private String currentUsername = null; private String currentPassword = null; private String currentServiceName = null; private String currentPortName = null; private List<File> tempFiles = new ArrayList<File>(); private Map<String, List<String>> defaultRequestHeaders; public Dispatch<SOAPMessage> getDispatch() { return dispatch; } public void setDispatch(Dispatch<SOAPMessage> dispatch) { this.dispatch = dispatch; } public String getCurrentWsdlUrl() { return currentWsdlUrl; } public void setCurrentWsdlUrl(String currentWsdlUrl) { this.currentWsdlUrl = currentWsdlUrl; } public String getCurrentUsername() { return currentUsername; } public void setCurrentUsername(String currentUsername) { this.currentUsername = currentUsername; } public String getCurrentPassword() { return currentPassword; } public void setCurrentPassword(String currentPassword) { this.currentPassword = currentPassword; } public String getCurrentServiceName() { return currentServiceName; } public void setCurrentServiceName(String currentServiceName) { this.currentServiceName = currentServiceName; } public String getCurrentPortName() { return currentPortName; } public void setCurrentPortName(String currentPortName) { this.currentPortName = currentPortName; } public List<File> getTempFiles() { return tempFiles; } public Map<String, List<String>> getDefaultRequestHeaders() { return defaultRequestHeaders; } public void setDefaultRequestHeaders(Map<String, List<String>> defaultRequestHeaders) { this.defaultRequestHeaders = defaultRequestHeaders; } } public RegistryBuilder<ConnectionSocketFactory> getSocketFactoryRegistry() { return socketFactoryRegistry; } private class DispatchTask<T> implements Callable<T> { private Dispatch<T> dispatch; private T message; private boolean oneWay; public DispatchTask(Dispatch<T> dispatch, T message, boolean oneWay) { this.dispatch = dispatch; this.message = message; this.oneWay = oneWay; } @Override public T call() throws Exception { try { if (oneWay) { logger.debug("Invoking one way service..."); dispatch.invokeOneWay(message); return null; } else { logger.debug("Invoking web service..."); return dispatch.invoke(message); } } finally { if (dispatchTasks != null) { dispatchTasks.remove(this); } } } } }