Overview

Automatic Proxy Selection for Mule ESB Webservices

2 Comments

When configuring mule, you might find out that some of your services need to call external parties. Depending on your deployment scenario there needs to be a proxy server involved. However this might change for various test stages, some need, some don’t, some need them only for specific domains and like that.
To reduce configuration overhead we have created an automatic proxy selector used for our services. Because I think its neat, I want to share it with you.

<https:connector name="autoProxy">
  <spring:property name="proxyHostname">
    <spring:bean class="org.springframework.jndi.JndiObjectFactoryBean">
      <spring:property name="jndiName" value="/jndi/config/proxyHost" />
      <spring:property name="defaultObject" value="" />
    </spring:bean>
  </spring:property>
  <spring:property name="proxyPort">
    <spring:bean class="org.springframework.jndi.JndiObjectFactoryBean">
      <spring:property name="jndiName" value="/jndi/config/proxyPort" />
      <spring:property name="defaultObject" value="0" />
    </spring:bean>
  </spring:property>
  <service-overrides dispatcherFactory="de.codecentric.mule.HttpAutoProxyMessageDispatcherFactory" />
  <https:tls-key-store path="/mule.keystore" keyPassword="changeit" storePassword="changeit"/>
  <https:tls-server path="/mule.keystore" storePassword="changeit"/>
</https:connector>

As you can see we configured a Connector which creates this MessageDispatcherFactory, it passes the configuration obtained from JNDI to it and also adds a keystore for ssl connections to it (with the great default password changeit :-))
Using it is then straightforward:

  <outbound-endpoint address="https://external.service/endpoint" synchronous="true" connector-ref="autoProxy">

The Factory itself is dead simple:

public class HttpAutoProxyMessageDispatcherFactory
  extends AbstractMessageDispatcherFactory {
  public MessageDispatcher create(OutboundEndpoint endpoint) throws MuleException {
    return new HttpAutoProxyMessageDispatcher(endpoint);
  }
}

The HttpAutoProxyMessageDispatcher implementation is easy was well. And contains a few hardcoded hosts that should not be proxied. Feel free to improve that part:

public class HttpAutoProxyMessageDispatcher
  extends HttpClientMessageDispatcher {
 
  private final boolean hasProxy;
  private final String proxyHost;
  private final int proxyPort;
 
  public HttpAutoProxyMessageDispatcher(OutboundEndpoint endpoint) {
    super(endpoint);
    this.proxyHost = ((HttpConnector) endpoint.getConnector()).getProxyHostname();
    this.proxyPort = ((HttpConnector) endpoint.getConnector()).getProxyPort();
    this.hasProxy = StringUtils.isNotBlank(proxyHost);
  }
 
  @Override
  protected HostConfiguration getHostConfig(URI uri) throws URISyntaxException {
    String host = uri.getHost();
    HostConfiguration config = new HostConfiguration();
    config.setHost(host, uri.getPort(), Protocol.getProtocol(uri.getScheme().toLowerCase()));
    if (hasProxy && !isLocalhost(host)) {
      config.setProxy(proxyHost, proxyPort);
    }
    return config;
  }
 
  private boolean isLocalhost(String host) {
    return "localhost".equals(host) || "127.0.0.1".equals(host);
  }
 
}

When you applied this pattern you only need to make sure JNDI information regarding the proxy is correct on each environment, and the mule configuration will automatically adapt to it.

Update: Mule 3.2

Recent Versions of Mule made it even easier to implement the HttpAutoProxyMessageDispatcher:

public class HttpAutoProxyMessageDispatcher extends
    HttpClientMessageDispatcher implements MessageDispatcher {
 
  public HttpAutoProxyMessageDispatcher(OutboundEndpoint endpoint) {
    super(endpoint);
  }
 
  @Override
  protected HostConfiguration getHostConfig(URI uri) throws Exception {
    Protocol protocol = Protocol.getProtocol(uri.getScheme().toLowerCase());
    String host = uri.getHost();
    int port = uri.getPort();
    HostConfiguration config = new HostConfiguration();
    config.setHost(host, port, protocol);
    if (!isLocalhost(host) && StringUtils.isNotBlank(connector.getProxyHostname())) {
      config.setProxy(connector.getProxyHostname(), connector.getProxyPort());
    }
    return config;
  }
 
  private boolean isLocalhost(String host) {
    return "localhost".equals(host) || "127.0.0.1".equals(host); 
  }
}

Kommentare

  • Chris

    2. August 2011 von Chris

    Hi there… first of all thank you very much for this information!

    I am very curious about a topics kinda related to this as well. I am basically trying to figure out if by default the community open source edition of Mule allows you to create multiple headless mule servers on different cloud servers and then write a mule script which can then be deployed through those headless servers.

    I am next to positive that the enterprise version of Mule provides a web based management interface and allows for multiple servers but I don’t know if this is possible through the open source version.

    Also, are you aware of anyone who has created an open source or cheap management interface to monitor such Mule servers.

    I just can’t afford the enterprise version but would like to create a script which can be run on multiple mule servers.

    Thanks in advance!

  • Sagnik

    2. July 2014 von Sagnik

    Hi how to use autoproxy in mule-flow….
    can u describe with example??

Comment

Your email address will not be published. Required fields are marked *