Java application and database backup

In the world of web it is important to take backup of our site and database frequently. We don’t know when we’d come accross unexpected error which causes our site stop working. Here I have developed an application in Java, Servlet and JSP which will help you to take backup as per your wish whenever you want to take backup. This application takes backup from your workspace for the current web application. While taking backup it creates zip files in the workspace and you will be given choice whether you want to download or delete once the backup is successfully done. You can select what type of backup you want to take like site, database or site & database together. You can also see the backup files are saved to the physical workspace location of your hard drive.

If you have any query please feel free to send a query in comment section of the article or you can also contact me through Contact page.

Prerequisites
Eclipse or any JEE based IDE
Tomcat v7
JDK 1.6
MySQL 5.x
Jar files – jstl-1.2.jar, mysql-connector-java-5.1.23-bin.jar
Final output
Home page
Java application and database backup
Select option for which you want backup – database, site or both
Java application and database backup
Database backup
Java application and database backup
Site Backup
Java application and database backup
Database and Site backup
Java application and database backup
 

This tutorial shows step by step how you can write code and make it works. Put the jar files under WEB-INF/lib directory.

Step 1. Create a Dynamic Web Project or Web Application according to your IDE. All the required project structure gets created.

Step 2. Now we will modify our deployment descriptor – web.xml as below. We won’t make any entry for Servlets in this file because Tomcat v7 supports Servlet 3.x version and we will get benefits of using annotations. We have only welcome file in web.xml file for our home page.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>backup</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

 

Step 3. We need a properties file or you may also hardcode the configuration values in Java class itself but it’s a good practice to put the configuration related properties in the property files.

application.properties – put this under src dirctory

dbhost=jdbc:mysql://localhost
dbport=3306
dbname=ci_post
dbdriver=com.mysql.jdbc.Driver
dbusername=root
dbpassword=

 
Step 4. We will have some constants which will be used in our application.
Constants.java

package in.webtuts.backup.utils;
public class Constants {
private Constants() {
}
public static final int BUFFER_SIZE = 1024;
public static final String DATE_FORMAT = "yyyy-MM-dd_hh-mm-ss";
public static final String FILE_EXT_SQL = ".sql";
public static final String FILE_EXT_ZIP = ".zip";
public static final String MYSQL_BASE_DIR_Q = "SELECT @@basedir";
public static final String MYSQL_BIN_DIR = "/bin/";
}

 

Step 5. We will have one class AppUtils.java for various utility methods like getting all the files from a directory recursively, adding files one by one to ZipEntry, writing to zip file. This file basically takes backup for application.

package in.webtuts.backup.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class AppUtils {
public static void getAllFiles(File dir, List<File> fileList) {
File[] files = dir.listFiles();
for (File file : files) {
fileList.add(file);
if (file.isDirectory()) {
getAllFiles(file, fileList);
}
}
}
public static String writeWebAppZipFile(String fileName,
File directoryToZip, String projectWorkspace, List<File> fileList) {
FileOutputStream fos = null;
ZipOutputStream zos = null;
String filePath = "";
boolean isError = false;
try {
Format formatter = new SimpleDateFormat(Constants.DATE_FORMAT);
filePath = projectWorkspace + fileName
+ formatter.format(new Date()) + Constants.FILE_EXT_ZIP;
fos = new FileOutputStream(filePath);
zos = new ZipOutputStream(fos);
for (File file : fileList) {
if (!file.isDirectory()) { // we only zip files, not directories
boolean isSuccess = addToZip(directoryToZip, file, zos);
if (!isSuccess) {
break;
}
}
}
} catch (FileNotFoundException e) {
isError = true;
e.printStackTrace();
} finally {
try {
if (zos != null) {
zos.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (isError) {
return null;
}
return filePath;
}
private static boolean addToZip(File directoryToZip, File file,
ZipOutputStream zos) {
FileInputStream fis = null;
boolean isSuccess = true;
try {
fis = new FileInputStream(file);
// we want the zipEntry's path to be a relative path that is
// relative
// to the directory being zipped, so chop off the rest of the path
String zipFilePath = file.getCanonicalPath().substring(
directoryToZip.getCanonicalPath().length() + 1,
file.getCanonicalPath().length());
ZipEntry zipEntry = new ZipEntry(zipFilePath);
zos.putNextEntry(zipEntry);
byte[] bytes = new byte[Constants.BUFFER_SIZE];
int length;
while ((length = fis.read(bytes)) >= 0) {
zos.write(bytes, 0, length);
}
} catch (Exception e) {
isSuccess = false;
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (zos != null) {
zos.closeEntry();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return isSuccess;
}
}

 

Step 6. Next we will have one class DBUtils.java for various utility methods like database connection, querying database, getting database dump, writing to zip file. This file basically takes backup for database.

package in.webtuts.backup.utils;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class DBUtils {
/**
* to load the database driver
*
* @return a database connection
* @throws SQLException
* throws an exception if an error occurs
*/
public static Connection getDBConnection() throws SQLException {
Connection conn = null;
try {
Class.forName(PropertiesUtils.DB_DRIVER);
conn = DriverManager.getConnection(PropertiesUtils.DB_HOST + ":"
+ PropertiesUtils.DB_PORT + "/" + PropertiesUtils.DB_NAME,
PropertiesUtils.DB_USERNAME, PropertiesUtils.DB_PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* to get a result set of a query
*
* @param query
* custom query
* @return a result set of custom query
* @throws SQLException
* throws an exception if an error occurs
*/
public static ResultSet getDBResultSet(Connection conn, String query)
throws SQLException {
ResultSet rs = null;
if (null != conn) {
PreparedStatement st = conn.prepareStatement(query);
rs = st.executeQuery();
}
return rs;
}
/**
* to run an update query such as update, delete
*
* @param query
* custom query
* @throws SQLException
* throws an exception if an error occurs
*/
public static void runQuery(Connection conn, String query)
throws SQLException {
if (null != conn) {
PreparedStatement st = conn.prepareStatement(query);
st.executeUpdate();
} else {
System.out.println("Query execution failed!");
}
}
/**
* close an opened PreparedStatement
*
* @return a void
* @throws SQLException
* throws an exception if an error occurs
*/
public static void closePreparedStatement(PreparedStatement ps)
throws SQLException {
if (null != ps) {
ps.close();
}
}
/**
* close an opened ResultSet
*
* @return a void
* @throws SQLException
* throws an exception if an error occurs
*/
public static void closeResultSet(ResultSet rs) throws SQLException {
if (null != rs) {
rs.close();
}
}
/**
* close an opened database connection
*
* @return a void
* @throws SQLException
* throws an exception if an error occurs
*/
public static void closeDBConnection(Connection conn) throws SQLException {
if (null != conn) {
conn.close();
}
}
public static String writeDBZipFile(String fileName, String projectWorkspace) {
FileOutputStream fos = null;
ZipOutputStream zos = null;
String filePath = "";
boolean isError = false;
try {
byte[] data = getMySQLDBData();
Format formatter = new SimpleDateFormat(Constants.DATE_FORMAT);
filePath = projectWorkspace + fileName
+ formatter.format(new Date()) + Constants.FILE_EXT_ZIP;
fos = new FileOutputStream(filePath);
zos = new ZipOutputStream(fos);
zos.putNextEntry(new ZipEntry(PropertiesUtils.DB_NAME
+ Constants.FILE_EXT_SQL));
zos.write(data);
} catch (FileNotFoundException e) {
isError = true;
e.printStackTrace();
} catch (IOException e) {
isError = true;
e.printStackTrace();
} finally {
try {
if (zos != null) {
zos.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (isError) {
return null;
}
return filePath;
}
private static byte[] getMySQLDBData() {
String mySQLBinPath = getMySQLBinPath();
StringBuilder stringBuilder = new StringBuilder();
boolean isComplete = true;
if (mySQLBinPath != null) {
String execCommand = "";
if (PropertiesUtils.DB_PASSWORD.trim().length() > 0) {
execCommand = mySQLBinPath + "mysqldump -u "
+ PropertiesUtils.DB_USERNAME + " -p"
+ PropertiesUtils.DB_PASSWORD + " --database "
+ PropertiesUtils.DB_NAME;
} else {
execCommand = mySQLBinPath + "mysqldump -u "
+ PropertiesUtils.DB_USERNAME + " --database "
+ PropertiesUtils.DB_NAME;
}
Runtime runtime = Runtime.getRuntime();
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
final Process process = runtime.exec(execCommand);
inputStream = process.getInputStream();
if (inputStream != null) {
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
int count;
char[] cs = new char[Constants.BUFFER_SIZE];
while ((count = bufferedReader.read(cs, 0,
Constants.BUFFER_SIZE)) != -1) {
stringBuilder.append(cs, 0, count);
}
} else {
isComplete = false;
}
} catch (IOException e) {
isComplete = false;
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (isComplete) {
return stringBuilder.toString().getBytes();
}
return null;
}
private static String getMySQLBinPath() {
try {
Connection connection = getDBConnection();
ResultSet resultSet = getDBResultSet(connection,
Constants.MYSQL_BASE_DIR_Q);
if (resultSet != null) {
if (resultSet.next()) {
return resultSet.getString(1) + Constants.MYSQL_BIN_DIR;
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}

 

Step 7. We need to read the property file, so for this we have one class PropertiesUtils.java

package in.webtuts.backup.utils;
import java.util.ResourceBundle;
public class PropertiesUtils {
public static String DB_HOST;
public static String DB_PORT;
public static String DB_NAME;
public static String DB_DRIVER;
public static String DB_USERNAME;
public static String DB_PASSWORD;
public static void readProperties() {
ResourceBundle rb = ResourceBundle.getBundle("application");
DB_HOST = rb.getString("dbhost");
DB_PORT = rb.getString("dbport");
DB_NAME = rb.getString("dbname");
DB_DRIVER = rb.getString("dbdriver");
DB_USERNAME = rb.getString("dbusername");
DB_PASSWORD = rb.getString("dbpassword");
}
}

 

Step 8. We want that our properties get read automatically when the application starts up so that we can avoid overhead for manual reading of the key/value pairs from the property file. So for this we need a Servlet Listener class. You can also achieve the same thing using Servlet by using configuration.

package in.webtuts.backup.listeners;
import in.webtuts.backup.utils.PropertiesUtils;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* Application Lifecycle Listener implementation class AppListener
*
*/
@WebListener
public class AppListener implements ServletContextListener {
/**
* Default constructor.
*/
public AppListener() {
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
@Override
public void contextInitialized(ServletContextEvent event) {
PropertiesUtils.readProperties();
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
}
}

 

Step 9. We need some servlet classes for backup the application and download or delete the backup files. So here we will create one BackupServlet for taking the backup.

package in.webtuts.backup.servlets;
import in.webtuts.backup.utils.AppUtils;
import in.webtuts.backup.utils.DBUtils;
import java.io.File;
import java.io.IOException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class BackupServlet
*/
@WebServlet("/BackupServlet")
public class BackupServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BackupServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
String backupInput = request.getParameter("backup");
String backupSubmit = request.getParameter("getBackup");
if (null != backupSubmit && null != backupInput) {
Class cls = this.getClass();
ProtectionDomain pDomain = cls.getProtectionDomain();
String filePath = pDomain.getCodeSource().toString();
String projectWorkspace = filePath.substring(
filePath.indexOf('/') + 1,
filePath.lastIndexOf(".metadata") - 1);
String contextPath = getServletContext().getContextPath();
String projLoc = projectWorkspace + contextPath;
String backupFileName = "";
if (backupInput.equals("1")) {
backupFileName = contextPath + "_database_";
String dbZipPath = DBUtils.writeDBZipFile(backupFileName,
projectWorkspace);
request.setAttribute("dbZipPath", dbZipPath);
request.setAttribute("success", "Database Backup Successful.");
} else if (backupInput.equals("2")) {
backupFileName = contextPath + "_site_";
File directoryToZip = new File(projLoc);
List<File> fileList = new ArrayList<File>();
AppUtils.getAllFiles(directoryToZip, fileList);
String webZipPath = AppUtils.writeWebAppZipFile(backupFileName,
directoryToZip, projectWorkspace, fileList);
request.setAttribute("webZipPath", webZipPath);
request.setAttribute("success", "Web App Backup Successful.");
} else if (backupInput.equals("3")) {
backupFileName = contextPath + "_site_";
File directoryToZip = new File(projLoc);
List<File> fileList = new ArrayList<File>();
AppUtils.getAllFiles(directoryToZip, fileList);
String webZipPath = AppUtils.writeWebAppZipFile(backupFileName,
directoryToZip, projectWorkspace, fileList);
request.setAttribute("webZipPath", webZipPath);
backupFileName = "";
backupFileName = contextPath + "_database_";
String dbZipPath = DBUtils.writeDBZipFile(backupFileName,
projectWorkspace);
request.setAttribute("dbZipPath", dbZipPath);
request.setAttribute("success",
"Web App and Database Backup Successful.");
} else {
request.setAttribute("error", "Please select Backup Type.");
}
} else {
request.setAttribute("error", "Something wrong occurred.");
}
request.setAttribute("backupInput", backupInput);
RequestDispatcher requestDispatcher = request
.getRequestDispatcher("/index.jsp");
requestDispatcher.forward(request, response);
}
}

 
Step 10. We need another Servlet for downloading the backup.
DownloadServlet.java

package in.webtuts.backup.servlets;
import in.webtuts.backup.utils.Constants;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class DownloadServlet
*/
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public DownloadServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fname = request.getParameter("fname");
if (fname != null && fname.trim().length() > 0) {
File file = new File(fname);
FileInputStream fileInputStream = new FileInputStream(file);
ServletContext context = getServletContext();
String mimeType = context.getMimeType(fname);
if (mimeType == null) {
mimeType = "application/octet-stream";
}
response.setContentType(mimeType);
response.setContentLength((int) file.length());
// show the file save dialog
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",
file.getName());
response.setHeader(headerKey, headerValue);
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[Constants.BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
fileInputStream.close();
outputStream.close();
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

 
Step 11. We need one more servlet for deleting the backup from user interface.
DeleteServlet.java

package in.webtuts.backup.servlets;
import java.io.File;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class DeleteServlet
*/
@WebServlet("/DeleteServlet")
public class DeleteServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public DeleteServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fname = request.getParameter("fname");
if (fname != null && fname.trim().length() > 0) {
File file = new File(fname);
if (file.exists()) {
boolean success = file.delete();
if (success) {
request.setAttribute("success",
"Backup Successfully deleted.");
} else {
request.setAttribute("error",
"Error occurred during backup deletion.");
}
}
}
RequestDispatcher requestDispatcher = request
.getRequestDispatcher("/index.jsp");
requestDispatcher.forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

 
Step 12. View part – index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Site and Database backup</title>
</head>
<body>
<div style="width: 600px;">
<c:if test="${!empty error}">
<p style="color: red;">
<c:out value="${error}" />
</p>
</c:if>
<c:if test="${!empty success}">
<p style="color: green;">
<c:out value="${success}" />
</p>
</c:if>
<c:if test="${!empty dbZipPath}">
<p style="color: green;">
<c:out value="Backup Path: ${dbZipPath}" />
<span> <a
href="${pageContext.request.contextPath}/DownloadServlet?fname=${dbZipPath}">Download</a>
&nbsp;&nbsp; <a
href="${pageContext.request.contextPath}/DeleteServlet?fname=${dbZipPath}"
onclick="return confirm('Are you sure want to delete ?');">Delete</a>
</span>
</p>
</c:if>
<c:if test="${!empty webZipPath}">
<p style="color: green;">
<c:out value="Backup Path: ${webZipPath}" />
<span> <a
href="${pageContext.request.contextPath}/DownloadServlet?fname=${webZipPath}">Download</a>
&nbsp;&nbsp; <a
href="${pageContext.request.contextPath}/DeleteServlet?fname=${webZipPath}"
onclick="return confirm('Are you sure want to delete ?');">Delete</a>
</span>
</p>
</c:if>
<form method="post" action="BackupServlet">
<fieldset>
<legend>Backup</legend>
<p>
<label>Select Backup Type</label><br /> <select name="backup"
id="backup">
<option value="0"
<c:if test="${backupInput != null || backupInput == 0}">
<c:out value="selected='selected'" />
</c:if>>--
Select --</option>
<option value="1"
<c:if test="${backupInput != null && backupInput == 1}">
<c:out value="selected='selected'" />
</c:if>>Database</option>
<option value="2"
<c:if test="${backupInput != null && backupInput == 2}">
<c:out value="selected='selected'" />
</c:if>>Site</option>
<option value="3"
<c:if test="${backupInput != null && backupInput == 3}">
<c:out value="selected='selected'" />
</c:if>>Both</option>
</select>
</p>
<p>
<input type="submit" name="getBackup" value="Get Backup" />
</p>
</fieldset>
</form>
</div>
</body>
</html>

 

I am done. If you have better idea or if you feel that you want to improve the article please let me know.

Thanks for your reading. Please do not forget to leave a comment.

Leave a Reply

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