Strongly consistent application is an application whose database writings will be reflected immediately in the database queries. In the case of eventually consistent applications, it is not necessary that the recently stored data be reflected in the immediate database queries.
Google App engine provides both strongly and eventually consistent modes for their applications. By default all the Google App engine applications are strongly consistent provided they should use ancestor queries in the applications.
A query that fetches data from a single entity group is called ancestor query. Entity group is a group of entities who share same parent key.
In this application we will develop a Java based web application whose database writings will be in strongly consistent mode. In this application, we are using low level datastore api for database operations.
We are developing this application using Eclipse 4.2.0. Please ensure that, you have installed Google Plugin for Eclipse. If you have not installed Google Plugin for Eclipse, you can follow this article for Google Plugin for Eclipse.
Some of the screenshots of this application are given below :
![]() |
| Lists of all the products added |
![]() |
| Add Form |
Now we are going to see, how to develop this application in step by step.
1. Create new Web Application Project
File -> New -> Web Application Project
Note : Ensure that, the checkboxes "Use Google Web Toolkit" and "Generate project sample code" are unchecked.
2. Create a css file namely main.css in the directory inventory/war/css
3. Create a javascript file namely main.js in the directory inventory/war/js
1. Create new Web Application Project
File -> New -> Web Application Project
Note : Ensure that, the checkboxes "Use Google Web Toolkit" and "Generate project sample code" are unchecked.
2. Create a css file namely main.css in the directory inventory/war/css
inventory/war/css/main.css
form,table {
background: -webkit-gradient(linear, bottom, left 175px, from(#CCCCCC), to(#EEEEEE));
background: -moz-linear-gradient(bottom, #CCCCCC, #EEEEEE 175px);
margin:auto;
font-family: Tahoma, Geneva, sans-serif;
font-size: 14px;
font-style: italic;
line-height: 24px;
font-weight: bold;
color: #09C;
text-decoration: none;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
padding:10px;
border: 1px solid #999;
border: inset 1px solid #333;
-webkit-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
}
form{
position:relative;
width:400px;
height:400px;
}
table {
min-width:450px;
}
tr,td{
border : 1px solid #999;
}
input ,textarea {
width:375px;
display:block;
border: 1px solid #999;
height: 25px;
-webkit-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
}
textarea#remarks {
width:375px;
height:150px;
}
textarea {
display:block;
}
button {
width:140px;
position:absolute;
bottom:20px;
background:#09C;
color:#fff;
font-family: Tahoma, Geneva, sans-serif;
height:30px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
border: 1p solid #999;
}
button:hover {
background:#fff;
color:#09C;
}
button#cancel{
right:60px;
}
button#submit{
right:220px;
}
textarea:focus, input:focus {
border: 1px solid #09C;
}
#add_link {
position: relative;
left:120px
}
3. Create a javascript file namely main.js in the directory inventory/war/js
inventory/war/js/main.js
function home(){
window.location = "/productslist.jsp"
}
4. Create a jsp file namely productslist.jsp in the directory inventory/war
This file displays a list of all the added products.
5. Create a jsp file namely product.jsp in the directory inventory/war
6. Create a java class namely ProductServlet.java in the directory inventory/src/in/wptrafficanalyzer/inventory
7. Updating the file application descriptor file web.xml in the directory war/WEB-INF
In eclipse, click the menu "Run -> Debug as -> Web Application". Now the local Google App Engine server will be started in the port 8888.
9. Open the application
In a web browser, enter the address http://localhost:8888. Now a web page , with list of products will be opened. Click on "Add Product" link to add new products to the list.
10. Deploying this application
Please refer this article to deploy this application to the real world Google App Engine.
This file displays a list of all the added products.
inventory/war/productslist.jsp
<%@page import="com.google.appengine.api.datastore.FetchOptions"%>
<%@page import="com.google.appengine.api.datastore.DatastoreServiceFactory"%>
<%@page import="com.google.appengine.api.datastore.DatastoreService"%>
<%@page import="com.google.appengine.api.datastore.Query"%>
<%@page import="com.google.appengine.api.datastore.KeyFactory"%>
<%@page import="com.google.appengine.api.datastore.Key" %>
<%@page import="com.google.appengine.api.datastore.Entity" %>
<%@page import="java.util.List" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<link rel="stylesheet" href="css/main.css"></link>
</head>
<body>
<%
String productCategory = "general";
// Parent key for entity group
Key productCategoryKey = KeyFactory.createKey("ProductCategory", productCategory);
// An ancestor query
Query query = new Query("Product",productCategoryKey);
// Getting datastore service for querying datastore
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// Fetching entities from datastore
List<Entity> products = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
%>
<!-- Displaying fetched entities in a table format -->
<table>
<caption>List of Products<span id="add_link"><a href="/product.jsp?action=add">Add Product</a></span></caption>
<tr>
<th>Sl.No</th><th>Code</th><th>Name</th><th>Remarks</th><th></th><th></th>
</tr>
<%
int i=0;
for(Entity product : products){
pageContext.setAttribute("product_id", product.getKey().getId());
pageContext.setAttribute("product_code", product.getProperty("code"));
pageContext.setAttribute("product_name", product.getProperty("name"));
pageContext.setAttribute("product_remarks", product.getProperty("remarks"));
i++;
%>
<tr>
<td><%= i %></td>
<td>${fn:escapeXml(product_code)}</td>
<td>${fn:escapeXml(product_name)}</td>
<td>${fn:escapeXml(product_remarks) }</td>
<td><a href="/product.jsp?id=${product_id }&action=edit">Edit</a></td>
<td><a href="/product?id=${product_id }&action=del">Delete</a></td>
</tr>
<%
}
%>
</table>
</body>
</html>
5. Create a jsp file namely product.jsp in the directory inventory/war
inventory/war/product.jsp
<%@page import="com.google.appengine.api.datastore.FetchOptions"%>
<%@page import="com.google.appengine.api.datastore.DatastoreServiceFactory"%>
<%@page import="com.google.appengine.api.datastore.DatastoreService"%>
<%@page import="com.google.appengine.api.datastore.Query"%>
<%@page import="com.google.appengine.api.datastore.KeyFactory"%>
<%@page import="com.google.appengine.api.datastore.Key" %>
<%@page import="com.google.appengine.api.datastore.Entity" %>
<%@page import="com.google.appengine.api.datastore.EntityNotFoundException" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<link rel="stylesheet" href="css/main.css"></link>
<script language="javascript" src="js/main.js"></script>
</head>
<body>
<%
String action = request.getParameter("action");
pageContext.setAttribute("action", action);
String formTitle = "Add Product:";
String buttonTitle = "Add Product";
if(action.equals("edit")){ // For editing existing entity
formTitle = "Edit Product:";
buttonTitle = "Update Product";
String productCategory = "general";
String id = request.getParameter("id");
// Parent key
Key productCategoryKey = KeyFactory.createKey("ProductCategory", productCategory);
// Key of entity to be edited
Key key = KeyFactory.createKey(productCategoryKey,"Product", Long.parseLong(id));
// Getting datastore service
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
try {
// Fetching the entity to be edited
Entity product = datastore.get(key);
pageContext.setAttribute("product_id", key.getId());
pageContext.setAttribute("product_code", product.getProperty("code"));
pageContext.setAttribute("product_name", product.getProperty("name"));
pageContext.setAttribute("product_remarks", product.getProperty("remarks"));
} catch (EntityNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
pageContext.setAttribute("form_title", formTitle);
pageContext.setAttribute("button_title", buttonTitle);
%>
<form action="/product" method="post">
<div>
<h1>${form_title}</h1>
<label>
<input type="hidden" name="id" value="${product_id}" />
<input type="hidden" name="action" value="${action}" />
<span>Product Code</span>
<input type="text" name="code" value="${fn:escapeXml(product_code)}" />
</label>
<label>
<span>Product Name</span>
<input type="text" name="name" value="${fn:escapeXml(product_name)}" />
</label>
<label>
<span>Remarks</span>
<textarea id="remarks" name="remarks">${fn:escapeXml(product_remarks)}</textarea>
<button type="submit" id="submit" >${button_title}</button>
<button type="button" id="cancel" onclick="home()" >Cancel</button>
</label>
</div>
</form>
</body>
</html>
6. Create a java class namely ProductServlet.java in the directory inventory/src/in/wptrafficanalyzer/inventory
inventory/src/in/wptrafficanalyzer/inventory/ProductServlet.java
package in.wptrafficanalyzer.inventory;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
public class ProductServlet extends HttpServlet{
// Name of parent entity
private final String productCategoryKind = "ProductCategory";
private final String productCategory = "general";
private final String productKind = "Product";
// Get Parent Key
private Key getParentKey(){
Key parentKey = KeyFactory.createKey(productCategoryKind, productCategory);
return parentKey;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String action = req.getParameter("action");
String id = req.getParameter("id");
if(action.equals("del")){
// Delete the entity
delProduct(id);
// Redirecting to the products lists
resp.sendRedirect("/productslist.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String action = req.getParameter("action");
String id = req.getParameter("id");
// Get the code entered in the form
String code = req.getParameter("code");
// Get the name entered in the form
String name = req.getParameter("name");
// Get the remarks entered in the form
String remarks = req.getParameter("remarks");
if(action.equals("add")){
// Add new entity
addProduct(code, name, remarks);
}else if(action.equals("edit")){
// Update existing entity
updateProduct(id,code,name,remarks);
}
// Redirecting to the products lists
resp.sendRedirect("/productslist.jsp");
}
private void addProduct(String code,String name,String remarks){
// Getting datastore service
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// Creating a product entity
Entity product = new Entity("Product", getParentKey());
product.setProperty("code", code);
product.setProperty("name", name);
product.setProperty("remarks", remarks);
// Storing the new entity to the datastore
datastore.put(product);
}
// Update the existing entity
private void updateProduct(String id,String code,String name,String remarks){
// Getting key of the existing entity
Key key = KeyFactory.createKey(getParentKey(),"Product", Long.parseLong(id));
// Getting datastore service
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
try {
Entity product = datastore.get(key);
product.setProperty("code", code);
product.setProperty("name", name);
product.setProperty("remarks", remarks);
// Overwrite the existing entity
datastore.put(product);
} catch (EntityNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Delete the entity
private void delProduct(String id){
Key key = KeyFactory.createKey(getParentKey(),"Product", Long.parseLong(id));
// Getting datastore service
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// Delete the entity
datastore.delete(key);
}
}
7. Updating the file application descriptor file web.xml in the directory war/WEB-INF
inventory/war/WEB-INF/web.xml
8. Start the local Google App Engine serverproduct in.wptrafficanalyzer.inventory.ProductServlet product /product productslist.jsp
In eclipse, click the menu "Run -> Debug as -> Web Application". Now the local Google App Engine server will be started in the port 8888.
9. Open the application
In a web browser, enter the address http://localhost:8888. Now a web page , with list of products will be opened. Click on "Add Product" link to add new products to the list.
10. Deploying this application
Please refer this article to deploy this application to the real world Google App Engine.


