Sunday, August 14, 2016

Writing a multi-tenant web app with Java and Spring

Hello everyone.

The goal for this post is to discuss how to develop and deploy to Tomcat an example of a multi-tenant Java web application.

Before we start, here's a couple of links that discuss the principles and challenges involved:
Here's the list of software you'll need for this project:

1. Java 1.8
2. Spring 4
3. Tomcat 8
4. PostgreSQL 9.4
5. Maven 2
6. Eclipse IDE 4.5
7. EclipseLink 2.6.3

First, let's consider the major steps needed to finish the project:

1. Install and configure the server environment where the Java app will be deployed to
2. Choose the data separation architecture at the database level
3. Write the application
4. Deploy to Tomcat

Now, let's consider the details of each of the above steps:

1. Install and configure the server
Because item number 1 above is time-consuming and may be new to a number of developers, I actually wrote a companion article dealing specifically with that: Setting up Tomcat + PostgreSQL for multi-tenant web apps in Linux.

2. Choose the data segregation architecture
Data segregation can be achieved in a number of ways for multi-tenancy apps. One of them is by creating different database "schemas", where each tenant's data set is stored in a different schema of the same database. That's the approach I've chosen for the sample application we'll discuss.

Using this technique, the database is organized as depicted in the following screenshot:

This allows the application to preface the table name by the tenant's identification name as the schema. For example, for tenant1's PRODUCT table, the application refers to it as tenant1.PRODUCT.

3. Write the application
I used Java + Spring + JPA + PostgreSQL to develop this application.

Please keep in mind that this application is contrived in some ways because my goal was to experiment with some concepts and get a refresher on others. For example, I wanted to find out how well - and how much coding would be required for - JPA to handle one-to-many relationships for database records; it actually require little extra code but there is definitely a learning curve to anyone new to this.

And especially I wanted to find out how much change would be required to migrate a single-tenant web app to a multi-tenant one. The design I chose is simple but works very well: One single database with multiple schemas (one per tenant) as shown in the picture above.

Here's the screenshot of the database structure showing 2 tenants:


So, here's a list of different techniques and technologies I employed in this app:

AJAX: nothing too fancy. In this app, I used it to invoke a web service and update only a portion of the page; who could possibly tolerate a full page refresh every time?
Spring: I used multiple modules of Spring: Spring MVC, Spring Security, Java only Spring configuration through Java annotations.
Pictures: I wanted to get a refresher on multi-part picture upload and handling of response in JavaScript.
JPA: I chose EclipseLink, but could very easily have chosen Hibernate, which is another JPA provider.
Restful web services: Spring allows you to easily create RESTful webservice. You just need to correctly configure your "controller" through Java annotations.
JSON: JSON is used in most - if not all - responses from the web services.
Multi-tenancy: Take a look at the RepositoryUtilityImpl class, which is a Singleton, and you'll see that I use the tenant's name string as schema name, also known as table qualifer.
Database: I used PostgreSQL, but you could easily migrate it to another DB by making a few changes to persistence.xml and the DB.properties file where the driver name is read from.

Again, I have to stress that this is just a contrived demo web app that I wrote in my spare time; hence, much can be improved. For example, of course a USER table would have to be created; will be working on that next. However, the multi-tenancy principle is there: data is securely separate from one tenant to the next.

4. Deploy the app to Tomcat
After this is all finished and tested locally as a single instance, the application can finally be copied to multiple directories in Tomcat and renamed to ROOT.war. There will be one directory for each of the tenants we have in our portfolio of clients.

Here's a screenshot of what tenant1 sees on the Menu page of the application:


And here's what tenant2 sees on the Menu page:

You haven't even started yet and already got 2 big clients?!!! Wow! 

Having a sub-domain named after its company's name gives the client/tenant a sense of ownership; he will also be able to change some aspects of the tenant's custom data at the Tenant Info page.

Is that sub-domain strategy and data segregation what you had in mind when you thought about multi-tenancy? Please share your comments below.

And lastly, and very important!, here's the link for the source code and the WAR file:
https://github.com/blueriversys/SpringMvcJpaApp


Thanks.
Joe


Saturday, August 13, 2016

Setting up Tomcat + PostgreSQL for multi-tenant web apps in Linux


Have you ever been frustrated with those hard to set up cloud services? Ever been hit by those service's surprise fees? How about their feature limitations? Ever wondered how to setup Tomcat for a multi-tenancy web app? 

Well, my friend, this is your lucky day. Today I'll show you how I setup a local app server with Tomcat + PostgreSQL + Linux to host my Java web applications on a small ASUS machine that I made to be my "server". 

You can actually use similar technique to host your own websites (rather than web apps) out of your bedroom as well. There are quite a bit of small computers, which you can transform into a server. 

Remember, my goal was to host a multi-tenant Java web app on Tomcat, so that an user could type something like this on his browser:
http://tenant1.yourdomain.com

while another user - actually another tenant - could type something like this: 
http://tenant2.yourdomain.com

The companion article showing how to write the Java app itself is Writing a multi-tenancy web app with Spring.

The advantage of this kind of architecture for the developer is that he'll  maintain only one set of source code and deploy (or provision) an independent instance of the app for each of his clients. For a description of the multi-tenancy architecture, please follow these links:



So, here's what you'll need to complete this project:
. Linux 16 LTC
. Java 8
. Tomcat 8.0.30
. PostgreSQL 9.4
. OpenSSH
. WinSCP

If you don't want to install Linux, it's OK, you could easily adapt the steps to install everything on a Windows machine.

For some of the steps you'll may need to Google up for details, but here's the essence of it:

1. Install Ubuntu Linux 16 LTS
There are multiple ways of doing that, but I copied the image structure of files into a USB flash disk and start the install process from there.

2. Install Java 8
a) I don't remember whether or not Ubuntu installs Java automatically, but you can check by opening a terminal window and issuing this command:
java -version
The link to install 

3. Set the JAVA_HOME environment variable
gedit is the graphical editor for Linux, so if you installed Java 8 on /usr/lib/jvm/java-1.8.0-openjdk-amd64 as I did, then issue these commands:
a) open a terminal window
b) sudo gedit /etc/environment
c) insert these lines: 
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64
export JAVA_HOME
d) save and exit
e) now reload by issuing this command:
. /etc/environment

4. Install Tomcat 8
You'll need both to install Tomcat 8 and configure it such that the HTTP server listen on port 80, so your visitors don't have to specify the port number from the outside of your network (Tomcat by default listens on port 8080).
a) follow this link to install Tomcat
https://www.digitalocean.com/community/tutorials/how-to-install-apache-tomcat-8-on-ubuntu-16-04
b) http://www.2ality.com/2010/07/running-tomcat-on-port-80-in-user.html

5. Configure Tomcat for multi-tenancy
In order for Tomcat to correctly respond appropriately to multiple web address, one for each tenant, you'll need to configure the file server.xml
a) sudo gedit /opt/tomcat/conf/server.xml
b) insert these 2 Host entries:
<host name ="tenant1.yourdomain.com" appBase="webapps_tenant1" unpackwars="true" autoDeploy="true" />
<host name ="tenant2.yourdomain.com" appBase="webapps_tenant1" unpackwars="true" autoDeploy="true" />
c) create the 2 folders accordingly
/opt/tomcat/webapps_tenant1
/opt/tomcat/webapps_tenant2

Here's the folder structure after this step:


6. Configure the "hosts" file
The hosts file contains the mapping table used by the browser to find your app or website. It comes with a single line usually "127.0.0.1 localhost", but you need to add these 2 extra lines, assuming the ip address of your Tomcat machine is 192.168.2.17:
192.168.2.17 tenant1.yourdomain.com
192.168.2.17 tenant2.yourdomain.com

7. Change the DNS for your domain name
This step varies from domain provider to domain provider, so it will require some trial and error, but essentially you'll need to specify the IP address your browser will connect to when the user types a web address such as http://tenant1.blueriversys.com.

8. Configure your Router's routing table
This step varies from router to router, but essentially it tells your router which is the machine that will handle the requests to port 80. 

In my case, it looks like this screenshot:


9. Install and configure SSH (optional)
SSH stands for Secure Shell and it allows you to create a Terminal connection to your Linux machine from your Windows dev machine. This is what will allow you to issue basic commands from Windows as well as use an SCP software for file transfer.
Here's a link that shows how to install and configure an SSH server:
https://help.ubuntu.com/community/SSH/OpenSSH/Configuring

10. Install WindowsSCP in Windows for file transfer (optional)
This step is optional but very handy because, if you take it, you'll be able to transfer the WAR files to the newly installed Linux machine right from your Windows dev machine. This is the only software in this procedure that you'll install in the Windows machine.
The following is a link that contains the install procedure as well as the guide on how to use WindowsSCP for file transfer:
https://winscp.net/eng/docs/guides

11. Copy the WAR files
Now, all that remains is for you to copy the WAR file from your dev machine to the tenant folders you created in step 5.  Make sure you rename the WAR file to ROOT.war as expected by Tomcat for this type of configuration. 

Here's the folder content for "tenant1":


Note: the ROOT folder itself is automatically created by Tomcat when you restart it.

And that's basically it, folks. For testing, just go anywhere outside your LAN network and type in the browser the web address you added to your "hosts" file.

Good luck and let me know in the comments if I can help you any further.

Thanks.

Joe