Changing the adapter host at runtime

HTTP adapters are a great way to connect your application to a backend system. You can set the hostname and port in the XML file and get started quickly.

However sometimes, your hostname is not "set in stone". Maybe you work with a staging server and a production server, maybe you have a list of alternate servers, or maybe your customers can choose the source from a list?

With MobileFirst Platform 7.0 and Java Adapters, this scenario is much easier to accomplish.

In this article, I will extend the RSS Reader built in the tutorial for Java HTTP Adapter to allow the user to choose the news source from a dropdown.

Requirements: IBM MobileFirst Platform Foundation 7.0 or above, knowledge of Java and Javascript development, Java Adapter and Java HTTP Adapter.

Concept

With JavaScript adapters, the connection policy (HTTP, SQL, etc) was set in the adapter's XML file and could not be altered without a new deployment. With Java adapter, there is no connection policy. Your custom Java code has free rein over the connection.

Starting point

I started with the sample attached to the Java HTTP Adapter tutorial.

This sample features a Hybrid application to read a CNN RSS feed. The feed comes from a Java adapter. The application has a dropdown to choose a topic from the CNN site.

This sample will be adapted to replace the concept of "topic" by one of "host".

Initialization

1
2
3
4
5
6
7
8
9
10
11
12
	private static CloseableHttpClient client;
	private static HashMap<String, HttpHost> hosts;
	private static HashMap<String, String> paths;
	public static void init() {
		client = HttpClients.createDefault();
		hosts = new HashMap<String, HttpHost>();
		hosts.put("cnn", new HttpHost("rss.cnn.com"));
		hosts.put("engadget", new HttpHost("www.engadget.com"));
		paths = new HashMap<String, String>();
		paths.put("cnn", "/rss/edition.rss");
		paths.put("engadget", "/rss.xml");
	}
As with the original sample, I've set the HTTP Client and the HTTP Hosts as static properties. The difference is instead of having one HttpHost, I have two HashMap of hosts and paths.

Both are initialized in the static init() method of RSSAdapterResource.java, which gets called by the init() method of RSSAdapterApplication.java.

If your application can connect to a longer list of backends, you could set this list in an array instead of a list of variables.

execute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
	public void execute(HttpUriRequest req, HttpServletResponse resultResponse, HttpHost host)
			throws ClientProtocolException, IOException,
			IllegalStateException, SAXException {
		HttpResponse RSSResponse = client.execute(host, req);
		ServletOutputStream os = resultResponse.getOutputStream();
		if (RSSResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
			resultResponse.addHeader("Content-Type", "application/json");
			String json = XML.toJson(RSSResponse.getEntity().getContent());
			os.write(json.getBytes(Charset.forName("UTF-8")));
	}else{
			resultResponse.setStatus(RSSResponse.getStatusLine().getStatusCode());
			RSSResponse.getEntity().getContent().close();
			os.write(RSSResponse.getStatusLine().getReasonPhrase().getBytes());
		}
		os.flush();
		os.close();
	}

As with the original sample, the execute() method is responsible for retrieving the RSS feed. The difference here is I pass a HttpHost since it will be different for each request.

GET procedure

1
2
3
4
5
6
7
8
9
10
11
12
	@GET
	@Produces("application/json")
	public void get(@Context HttpServletResponse response, @QueryParam("host") String hostKeyword)
			throws ClientProtocolException, IOException, IllegalStateException, SAXException {
		if(hostKeyword!=null && hosts.containsKey(hostKeyword) && paths.containsKey(hostKeyword)){
			execute(new HttpGet(paths.get(hostKeyword)), response, hosts.get(hostKeyword));
		}
		else{
			response.setStatus(404);
			response.flushBuffer();
		}
	}

This JAX-RS method is the only public endpoint of the adapter. It can be reached via a GET call to /IMFMultiHostAdapter/adapters/RSSAdapter.

It receives a query parameter host which in our example can either be "cnn" or "engadget". The methods retrieves the HttpHost and the path from the HashMaps, and calls the execute method.

Client-side code

index.html

I took the existing index.html from the original sample and changed the dropdown to show a list of RSS sources instead of topics.

1
2
3
4
<select id="host" style="width:90%; height:3em;">
	<option value="engadget" selected="selected">Engadget</option>
	<option value="cnn">CNN</option>
</select>

The id was changed to host as well, be careful to update any reference to it.

main.js

This file is almost the same as the original sample. The variable topic was changed to host, and it is initialized to var host = "engadget"; instead of keeping it empty.

Updated sample

The project described in this article can be downloaded or cloned from this URL: https://github.com/nasht00/IMFMultiHostAdapter

Last modified on May 01, 2016
Share this post: