Running CouchDB and JBoss Application Server in Reverse Proxy mode

In my previous post, Transforming XML Data into JSON documents using JQuery, I had to parse KJV.xml, using  jQuery, to retrive all the verses of the bible in a separate JSON document. There were 31,102 documents in total. What I left out of that post was that I had to move all these documents into CouchDB. Preferably, also using jQuery AJAX. Before I continue, I’d like to say a few words about CouchDB.

CouchDB is a robust, scalable and high performance document oriented database server which is accessible over a RESTful JSON API. It is schemaless and ad hoc which allows your domain objects to evolve independently of one another. It implements incremental replication with bidirectional conflict detection. It is also indexable and queryable. Just like replication, indexing is also incremental. Which means as your data gets bigger, the time to access particular indexes takes roughly the same time. CouchDB uses a table oriented reporting engine, MapReduce for CouchDB, which uses javascript as the query engine.

If you are like me, and running a Windows machine, then you can find an exe build of CouchDB 1.1.0 with all of its dependencies, Erlang and so on, here.

After installing, go to http://localhost:5984 and you should see the welcome message

        {"couchdb":"Welcome","version":"1.1.0"}

Go to  http://localhost:5984/_utils/index.html to visit Futon, the administration interface for CouchDB.

Now fast forward to the AJAX part. In my javascript, I have just created a javascript object containing the text, verse number, chapter, book and testament of a particular verse of the bible. Now I would like to save this object as a document in CouchDB. For this, you can use the jQuery.Couch plugin.

The entire javascript for this parsing and couchdb initializing with the data from KJV.xml is in the code snippet below.

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script src="http://localhost:5984/_utils/script/json2.js"></script>
    <script src="http://localhost:5984/_utils/script/sha1.js"></script>
    <script src="http://localhost:5984/_utils/script/jquery.js?1.4.2"></script>
    <script src="http://localhost:5984/_utils/script/jquery.couch.js?0.11.0"></script>
    <script src="http://localhost:5984/_utils/script/jquery.dialog.js?0.11.0"></script>

</head>

<body>

	<script type="text/javascript">

	jQuery(window).load( function() {

	});

	jQuery(document).ready( function(){

		$.couch.urlPrefix = "http://localhost:5984";

		$.couch.login({
		    name: "yourusername",
		    password: "yourpassword",
		    success: function(data) {

		    },
		    error: function(status) {

		    }
		});

       $.ajax({
	        type: "GET",
			url: "KJV.xml",
			dataType: "xml",
			success: function(xml) {
				var count = 0;
				var doc = {};

				$(xml).find('bible').each(function(){
					var translation = $(this).attr('translation');

					$(this).find('testament').each( function(){
						var testament = $(this).attr( 'name');

						$(this).find('book').each( function() {
							var book = $(this).attr('name');

							$(this).find('chapter').each( function(){
								var chapternumber = $(this).attr('number');

								$(this).find('verse').each( function(){
									var versenumber = $(this).attr('number');

									var versetext = $(this).text();
									count++;

									var doc = {};
									doc["_id"] = count.toString();
									doc["translation"] = translation;
									doc["testament"] = testament;
									doc["book"] = book;
									doc["chapter"] = parseInt(chapternumber);
									doc["versenumber"] = parseInt(versenumber);
									doc["versetext"] = versetext;

									$.couch.db("bibleverses").saveDoc(doc, {
									    success: function(data) {

									    },
									    error: function(status) {

									    }
									});

								});
							});
						});

					});
				});
	}
		});

	});
	</script>
</body>
</html>

But now there is a problem. The html file containing the javascript xml parser, is in a web app running on JBoss Application Server 6. The html file is accessible on my local machine at http://localhost:8080/bibleverses/index.html. But browsers enforce the Same-Origin Policy for AJAX requests. This means that to perform an AJAX request, the page from which the request is made and the target of the request must be within the same domain. So since our couchdb resdes on localhost:5984 and jboss on localhost:8080, AJAX requests are not successful.

This problem can be solved using the mod_proxy module of Apache httpd to enable Reverse Proxying for CouchDB and JBoss. This means we will be able to access our jboss web app under, for example, http://www.bibleverses.org/site and couchdb under http://www.bibleverses.org/couch. Both of them would have the same origin and thus ajax requests from the web app would be consumed successfully by the couchdb server.

The names you choose to use must either be registered as a domain name and have requests for www cname forwarded to the IP of your server or you can do local dns mapping if you are on windows.

Just add

192.168.2.123  www.bibleverses.org

to your %SYSTEMROOT%\System32\drivers\etc\hosts file. Of course you can choose any name here but whatever name you choose is what you must use when the time for the reverse proxy configuration arises.

Now you need to install Apache Http and make sure it listens on port 80.

The next step is the installation of the mod_proxy, mod_proxy_http and mod_proxy_ajp modules of apache. To do that, open the config file for Apache, %APACHEHOME%\conf\httpd.conf. By the way I am using version 2.2.19 of apache for my tests.

Make sure the following lines are not commented out in the configuration file:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Make sure Apache is listening on port 80 of the external network interface and create a named virtual host with the same values

Listen 192.168.2.123:80
NameVirtualHost 192.168.2.123:80

For security, make sure that the proxy is accessible by only IPs in my local area network. This can be adjusted later in a production environment. In addition, I create a VirtualHost directive, specifying the value of the NameVirtualHost we talked about earlier. A server name is the minimum requirement for a Virtual Host directive and in my example, http://www.bibleverses.org was used. This means that when a request is sent to http://www.bibleverses.org, use the virtual hosting information defined in this directive. The ProxyPass just means that when /site subfolder of the ServerName is requested, forward that to the web app on JBoss and when /couch is requested, forward that to couchdb.

<Proxy *>
	Order Deny,Allow
	Deny from all
	Allow from 192.168.2
</Proxy>

<VirtualHost 192.168.2.123:80>
    ServerName www.bibleverses.org
    ProxyPass /site http://127.0.0.1:8080/bibleverses
    ProxyPass /couch http://127.0.0.1:5984
</VirtualHost>

This means we can access couchdb as http://www.bibleverses.org/couch and the site with the javascript at http://www.bibleverses.org/site/index.html. The AJAX requests will now work from the web app to couchdb.

An added advantage of the Reverse Proxy setup is that now, we only need to open one port 80 on our NAT device. No need anymore to open 5984 and 8080 to direct access to the internet. All requests for couchdb and jboss stuff will come through port 80 of apache httpd. In addition, it can be used as a load balancer to balance load among several back-end servers such as jboss servers (in conjunction with JBoss mod_cluster), or to provide caching for a back-end server such as couchdb.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s