Implementing Oracle Coherence Cache in WebApplications

Hi All, in past i have written one article regarding oracle coherence cache and its simple implementation. from past couple of months we are implementing coherence in our project and i thought to put its implementation here, so lets start with the topic. lets create a database table as below

create table product(product_id varchar2(5),product_name varchar2(50),unit_price varchar2(5),quantity varchar2(5));

prior to creating this example you need to have the coherence and weblogic installed here(code is tested with coherence 3.7 and weblogic 12c)

create a dynamic web project in eclipse and put coherence.jar as dependent lib, which acts as coherence server inside the weblogic application server.
proj_struct

Now lets design the form/page to insert the details
Note: here i am using the servlet 3.0 api and to get the database connection i used the @Resource injection(JSR specification)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!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>Insert title here</title>
<script scr="js/jquery.js"></script>
<script>
	$(document).ready(function() {
		if (!("autofocus" in document.createElement("input"))) {
			$("#q").focus();
		}
	});
</script>
</head>
<body>
	<form action="writetoCache" method="post">
	<table>
		<tr>
			<td>Product ID:</td>
			<td><input name="prod_id" id="prodid" autofocus required></td>
		</tr>
		<tr>
			<td>Product Name:</td>
			<td><input name="productName" id="name" required></td>
		</tr>
		<tr>
			<td>Unit Price:</td>
			<td><input name="unitPrice" id="unit_price"></td>
		</tr>
		<tr>
			<td>Total Quantity:</td>
			<td><input name="totQty" id="totQty"></td>
		</tr>
		<tr>
			<td>
				<input type="submit" value="SaveDetails">
			</td>
		</tr>
	</table>
		 
	</form>
</body>
</html>

Now lets write the controller for this above JSP, the aim of this controller is to write the data to database and cache server as well

package com.spark.coherence.cache.controller;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
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;
import javax.sql.DataSource;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

/**
 * Servlet implementation class WriteToCacheController
 */
@WebServlet("/writetoCache")
public class WriteToCacheController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Resource(name = "oracleDS")
	DataSource dataSource;

	Connection connection;
	PreparedStatement preparedStatement;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public WriteToCacheController() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub

		String productId = request.getParameter("prod_id");
		String productName = request.getParameter("productName");
		String unitPrice = request.getParameter("unitPrice");
		String Qunatity = request.getParameter("totQty");
		String sql = "insert into product values(?,?,?,?)";
		try {
			connection = dataSource.getConnection();
			System.out.println("-------------- Connection Closed Status: "
					+ connection.isClosed() + " ------------------");
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, productId);
			preparedStatement.setString(2, productName);
			preparedStatement.setString(3, unitPrice);
			preparedStatement.setString(4, Qunatity);

			preparedStatement.execute();
			writeToCache(productId, productName, unitPrice, Qunatity);
			
			RequestDispatcher requestDispatcher = request.getRequestDispatcher("getRecord.jsp");
			requestDispatcher.forward(request, response);

		} catch (SQLException e) {
			System.out
					.println("--------------------------Exception no record insert into Database !---------------------");
			e.printStackTrace();
		}
		
		
	}

	/**
	 * @param productId
	 * @param productName
	 * @param unitPrice
	 * @param Qunatity
	 */
	public void writeToCache(String productId, String productName,
			String unitPrice, String Qunatity) {

		CacheFactory.ensureCluster();
		NamedCache namedCache = CacheFactory.getCache("product");
		System.out.println("connected to cluster: "
				+ CacheFactory.getCluster().getClusterName()
				+ " With cache name " + namedCache.getCacheName());

		Map<String, String> dbObject = new HashMap<String, String>();
		dbObject.put("productId", productId);
		dbObject.put("productName", productName);
		dbObject.put("unitPrice", unitPrice);
		dbObject.put("quantity", Qunatity);

		if (namedCache.get(productId) == null) {
			namedCache.put(productId, dbObject);
		}

		System.out
				.println("------------- Object got cached ! -----------------");
		
	}
	
}

Once we are done with the insertion of data to database and cache, now its time to fetch the data either from database or cache. here the logic is if data is available in cache the controller pull data from cache if not it will pull from database and also update cache with the latest data so that next time it will from cache but not from database.

<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!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>Insert title here</title>
</head>
<body>
	<form action="readCache" method="post">
		<table>
			<tr>
				<td>Product ID:</td>
				<td><input name="prod_id" id="prodid" autofocus required></td>
			</tr>
			<tr>
				<td><input type="submit" value="getDetails"></td>
			</tr>
		</table>
	</form>

	<%
		Map cacheObject = (Map) session.getAttribute("cacheObj");
		if (cacheObject != null) {
	%>
	<table>
		<thead>
			<tr>
				<td>Product ID</td>
				<td>Product Name</td>
				<td>Unit Price</td>
				<td>Quantity Ordered</td>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td><%=cacheObject.get("productId")%></td>
				<td><%=cacheObject.get("productName")%></td>
				<td><%=cacheObject.get("unitPrice")%></td>
				<td><%=cacheObject.get("quantity")%></td>
			</tr>
		</tbody>
	</table>

	<%
		}
	%>
</body>
</html>

ReadFromCacheController.java:

/**
 * 
 */
package com.spark.coherence.cache.controller;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
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;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

/**
 * @author Sony
 * 
 */
@WebServlet("/readCache")
public class ReadFromCacheController extends HttpServlet {

	@Resource(name = "oracleDS")
	DataSource dataSource;

	Connection connection;
	PreparedStatement preparedStatement;
	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doGet(req, resp);
	}

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		CacheFactory.ensureCluster();
		NamedCache namedCache = CacheFactory.getCache("product");
		
		String productId = request.getParameter("prod_id");
		HttpSession httpSession = request.getSession();
		Map<String, String> cacheObject = (Map)namedCache.get(productId);
		
		if(cacheObject != null){
			System.out.println("----------- Read from cache -------------");
			httpSession.setAttribute("cacheObj", cacheObject);
			RequestDispatcher requestDispatcher = request.getRequestDispatcher("getRecord.jsp");
			requestDispatcher.forward(request, response);
		}else{
			System.out.println("----------- Read from db and update cache -------------");
			httpSession.setAttribute("cacheObj", readFromDatabase(productId));
			RequestDispatcher requestDispatcher = request.getRequestDispatcher("getRecord.jsp");
			requestDispatcher.forward(request, response);
		}
	}
	
	public Map<String, String> readFromDatabase(String productId){
		
		String sql = "select * from product where product_id = ?";
		Map<String, String> dbObject = new HashMap<String, String>();
		
		try {
			connection = dataSource.getConnection();
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, productId);
			ResultSet resultSet = preparedStatement.executeQuery();
			
			while (resultSet.next()) {
				dbObject.put("productId", resultSet.getString("product_id"));
				dbObject.put("productName", resultSet.getString("product_name"));
				dbObject.put("unitPrice", resultSet.getString("unit_price"));
				dbObject.put("quantity", resultSet.getString("quantity"));
			}
			
		}catch(SQLException sqlException){
			sqlException.printStackTrace();
		}
		writeToCache(dbObject,productId);
		return dbObject;
	}
	
	/**
	 * @param productId
	 * @param productName
	 * @param unitPrice
	 * @param Qunatity
	 */
	public void writeToCache(Map<String, String> dbObject,String productId) {

		CacheFactory.ensureCluster();
		NamedCache namedCache = CacheFactory.getCache("product");
		
		if (namedCache.get(productId) == null) {
			namedCache.put(productId, dbObject);
		}
		
	}
}

now that all coding is done now here is some config related to project, first i have implemented a ServletListener
for notifying contextDestroyed,contextInitialized events

now in order to connect with our coherence server the following two config files are required.

coherence-config.xml

<?xml version="1.0"?>
<!DOCTYPE cache-config SYSTEM "cache-config.dtd">
<cache-config>
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>product</cache-name>
            <scheme-name>example-distributed</scheme-name>
        </cache-mapping>
    </caching-scheme-mapping>
 
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>example-distributed</scheme-name>
            <service-name>DistributedCache</service-name>
            <backing-map-scheme>
                <local-scheme />
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
    </caching-schemes>
</cache-config>

tangosol-coherence-override.xml

<?xml version="1.0" encoding="UTF-8"?>
<coherence
	xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config http://xmlns.oracle.com/coherence/coherence-operational-config/1.2/coherence-operational-config.xsd">
	<cluster-config>
		<member-identity>
			<cluster-name>MyCluster</cluster-name>
		</member-identity>
		<unicast-listener>
			<address system-property="tangosol.coherence.localhost">192.168.0.100</address>
			<port system-property="tangosol.coherence.localport">8088</port>
		</unicast-listener>
		<multicast-listener>
			<time-to-live system-property="tangosol.coherence.ttl">60</time-to-live>
		</multicast-listener>
	</cluster-config>

	<configurable-cache-factory-config>
		<init-params>
			<init-param>
				<param-type>java.lang.String</param-type>
				<param-value system-property="tangosol.coherence.cacheconfig">
					coherence-cache-config.xml
				</param-value>
			</init-param>
		</init-params>
	</configurable-cache-factory-config>
</coherence>

Now as a final step lets run the application by deploying to weblogic server and below are the screen shots.

landing-page

now fill the details and submit the form and it should look as shown.

after-save

If suppose we query any record that is not available in cache it should get that from database and update cache as shown below.
read_and_update

if you query any record that is available in cache, it should directly read from cache and it will not hit database.
read_direct_cache

Advantage of implementing cache technology is, it will drastically improve the performance of the applications.
Happy cache 🙂

Advertisements

calling Oracle Coherence cache with Servlet

Hello all now then i was posted on to one of the projects in my organization which deals with large amount of data in the financial sector so the project has to be scaled in its performance and we started using “Oracle Coherence” as in memory cache, now in this post i want to discuss a small scenario how to install “Oracle Coherence R12” and use it.

What is Oracle Coherence ?
Oracle Coherence is the industry leading in-memory data grid solution that enables organizations to predictably scale mission-critical applications by providing fast access to frequently used data. As data volumes and customer expectations increase, driven by the “internet of things”, social, mobile, cloud and always-connected devices, so does the need to handle more data in real-time, offload over-burdened shared data services and provide availability guarantees.

Before starting this tutorial, you should:
1.Have access to or have installed the following software:

a. Oracle Coherence R12 for Java (or later)(Download)
b. Oracle WebLogic Server 11gR5 for Windows (Download)
c. Eclipse 3.8 (Juno) for Windows. please visit eclipse site for respective dowload.
Inside the eclipse please install the Weblogic version 11g or laterst.

Step1: Select File > New > Dynamic Web Project.
t20101

Step2:The Dynamic Runtime Module version automatically updates to 2.5 and the Configuration is set to Default Configuration for Oracle WebLogic Server 10gR3.No further configuration is needed. Click Finish.
t20105

Step3:the project structure should look as below.
prj_structure

Now its time to write the configuration and logic:
coherence-config.xml

<?xml version="1.0"?>

<!DOCTYPE cache-config SYSTEM "cache-config.dtd">

<cache-config>
	<caching-scheme-mapping>
		<cache-mapping>
			<cache-name>hello-example</cache-name>
			<scheme-name>distributed</scheme-name>
		</cache-mapping>
	</caching-scheme-mapping>

	<caching-schemes>
		<distributed-scheme>
			<scheme-name>distributed</scheme-name>
			<service-name>DistributedCache</service-name>
			<backing-map-scheme>
				<local-scheme />
			</backing-map-scheme>
			<autostart>true</autostart>
		</distributed-scheme>
	</caching-schemes>
</cache-config>

tangosol-coherence-override.xml

<?xml version='1.0'?>
 
<!DOCTYPE coherence SYSTEM "coherence.dtd">

<coherence>
	<cluster-config>
		<member-identity>
			<cluster-name>my-coherance-cluster</cluster-name>
		</member-identity>

		<multicast-listener>
			<address>224.12.1.0</address>
			<port>12100</port>
			<time-to-live>60</time-to-live>
		</multicast-listener>
	</cluster-config>

	<configurable-cache-factory-config>
		<init-params>
			<init-param>
				<param-type>java.lang.String</param-type>
				<param-value system-property="tangosol.coherence.cacheconfig">
					coherence-config.xml</param-value>
			</init-param>
		</init-params>
	</configurable-cache-factory-config>
</coherence>

coherance_put.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
	
<%@ page
	import="com.tangosol.net.CacheFactory,com.tangosol.net.NamedCache"%>
<!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>Insert title here</title>
</head>
<body>
	<%
		String key = "k2";
		String value = "Hello World!";

		CacheFactory.ensureCluster();
		NamedCache cache = CacheFactory.getCache("hello-example");

		cache.put(key, value);

	%>
</body>
</html>

coherance_get.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
	
<%@ page
	import="com.tangosol.net.CacheFactory,com.tangosol.net.NamedCache"%>
<!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>Insert title here</title>
</head>
<body>
	<%
		CacheFactory.ensureCluster();
		NamedCache cache = CacheFactory.getCache("hello-example");

		out.println((String) cache.get("k2"));
	%>
</body>
</html>

When the code is run on weblogic server and run the urls you should see the following o/p:

coherance_put

coherance_get

Happy Coherence 🙂
courtesy: http://www.oracle.com/webfolder/technetwork/tutorials/obe/fmw/coherence/obe34coherence_wls/coherence_wls_eclipse_setup/coherence_wls_eclipse_setup.htm

Will be posting when ever i get chance with new topic and content.