Architecture · ATG · ATG External Cache · Cache · RESTFul

ATG Cache Using JBOSS Data Grid/Infinispan

ATG Cache Using JBOSS Data Grid/Infinispan

 

As performance is really important in retail Or web commerce applications, the caching plays an important role in improve the performance. ATG Commerce servers are loaded with lot of components and functionality. And top of that, repository caching will increase enormous memory consumption on ATG JVM’s. Hence, externalizing this cache is an important aspect to reduce the memory foot prints and also reduce the  overall load on ATG servers.

        JBoss data grid internally uses infinispan cache stores to handle the data. On top of infinispan, JDG has provided some more wrappers to include grid features like map/reduce and search functionalities.

Infinispan an open source version of JBoss Data Grid

Infinispan works in 4 caching modes.

·         Local Mode

·         Replicated Mode

·         Invalidation Mode

·         Distribution Mode (Preferred)

 

Where Distributed caching is more appropriate in most of the scenarios. And Replication mode provides an very high available cluster and consumes huge RAM .

 

ATG and JBoss Data Grid Integration

 

JBoss Data Grid/Infinispan works with TCP connections (at Base) between the clusters nodes. And it depends  onJgroups” as the communication configuration to form the Clusters. Jgroups will use TCP Or UDP to form clusters.

 

Cache grid Cluster

 

Using JBoss Cache Servers (Preferred)

·         Hotrod is an effective protocol to communicate with JBOSS data grids.

·         Clients like ATG App servers can connect to data grids using hotrod protocol.

·         We can host a cluster of cache servers using JBoss infinispan servers. These servers can form a cluster using “Jgroups” module which part of JBoss inbuilt modules.

4.       These jboss cache instances are deployed in a domain, so that they can be managed and configured accordingly.

5.       And jgroups use the multicast discovery protocols to find and add related  cache instances to a cluster.

6.       Each JBoss cache server instance start an individual embedded infinispan instance and form a cluster with rest of the instances.

7.       An integrated dashboard is available to check the health and performance of cluster. This dashboard can be used to configure Or fine tune the cache stores installed as part of data grids.

 

The following diagram depicts the 4 cache server instances On 2 hosts And an inbuilt load balancer and A controller.

 

 

image002

  

 

Using embedded Jar files

 

The above described clustered configuration can be achieved by embedded cache application instances. Multiple instances of a simple embedded cache applications are started to form a cluster. These instances use Jgroups to communicate and form a cluster.

 

This grid can be formed on any application servers independent of JBoss

However, JBoss servers provide an integrated dashboard as part of JBoss admin console.  This console will not be available in embedded cache clusters.

 

 

 

ATG Servers to Data grid

 

ATG Servers communicating to data grid using hotrod protocol (Preferred)

 

1.       ATG App serves use HotRod protocol to communicate with Infinispan data grid as depicted in following diagram

2.       This type of communication is essentially powerful if both client and server are JVM based.

3.       Here ATG Server can establish a  communication with cache grid over HotRod protocol.

 

image004

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Repository Cache ingestion into data grid

 

ATG Repositories can externalize its caches to Data grids.

 

Daily refresh/weekly

1.       A complete data refresh can be performed on daily basis/weekly basis by using ATG Scheduler. This activity can be triggered at an off peak time to refresh complete cache data.

2.       This is just to maintain consistence across DB and cache grids.

 

ATG Servers Communicating over REST HTTP

1.       Infinispan data grid also exposes REST end points to communicate over HTTP.

2.       Here, the client can be in any language. And any client can connect to infinispan data grids over http.

3.       This may increase HTTP communication protocol overhead.

4.   And also Object serialization and deserialization is an extra activity as part of this communication.

 

 

PLP/Search

 

1.       Fire a search query to endeca to fetch the relevant product id’s.

2.       Get the complete product data from cache grid using product id’s.

3.       Aggregate the product data and send it to Search/PLP pages.

 

PDP

 

The above search result set can be used to display PDP or else we can re-fetch again from cache grid to paint in PDP

 

Other Pages

It is better to rely on existing database to get the product details.

 

 

*Note: JBoss Data Grid is the licensed version of Infinispan Cache Grid.

 

Java · RESTFul · Spring · spring boot · Swagger

Swagger docs for Spring Boot

Spring boot is becoming famous and famous due to microservice architecture and advantage of spring framework support in it.As REST services are playing a huge role in microservice architecture, swagger introduces a better way to publish these REST services so that they can be tested, published as living documents.

Here is a simple spring boot application having a controlled on it. This controlled exposes a REST services. And this RESt service has been documented using SWAGGER with some simple annotations.

Most of the code is self-explanatory.

Git Link for Code

Run the code using >mvn spring-boot:run

and Access the swagger UI at http://localhost:8080/swagger-ui.html

Java · Servlet3.0

Asynchronous Servlet in 3.0

Async servlet is a new feature added in servlet 3.0 specification. This servlet works in a non-blocking mode. Each request is processed in a new thread which is independent of request thread. The request is temporarily suspended by application till the business logic is executed. Once the application is ready with result, the request will be resumed and the response will be pushed to browser.

The request is temporarily suspended and later resumed or re-dispatched through filters for further processing. This is completely dependent on persistent connection between a browser and server. And all the event which are generated while executing the request are relayed on existing persistent connection.

Required Environment:

Jetty9.x version server Or Tomcat Latest Version.

And example of AyncServlet

package com.servlets;

import java.io.IOException;

import javax.servlet.AsyncContext;
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 AsyncServletDis
 */
@WebServlet(asyncSupported = true, urlPatterns = { "/asyncservletdis" })
public class AsyncServletDis extends HttpServlet {
 private static final long serialVersionUID = 1L;
 int instanceVariable =1;

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

 /**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 */
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 /*
 * This is an important step to start asynchronous nature of servlet
 * Get the AsyncContext
 */

 AsyncContext aCtx = request.startAsync();
 // add a listener to this context.
 aCtx.addListener(new AsyncListener());
 //aCtx.setTimeout(5000);
 aCtx.start(new Runnable() {

 @Override
 public void run() {
 // TODO Auto-generated method stub

 String sleep = request.getParameter("sleep");
 if(sleep!=null){
 try {
 Thread.sleep(10000);
 } catch (InterruptedException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 }

 try {
 aCtx.getResponse().getWriter().write("Request Processed");
 System.out.println("Print instance variable#####"+instanceVariable);
 instanceVariable+=1;
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 /*
 * Once completed call the complete method to close asynch process.
 * Either call complete or dispatch to end thread.
 */

 aCtx.complete();
 //aCtx.dispatch("/result.jsp");

 }
 });
 }

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

}

And Listener

package com.servlets;

import javax.servlet.AsyncEvent;
import javax.servlet.annotation.WebListener;

import com.sun.media.jfxmedia.logging.Logger;

/**
 * Application Lifecycle Listener implementation class AsyncListener
 *
 */
@WebListener
public class AsyncListener implements javax.servlet.AsyncListener {

 /**
 * Default constructor. 
 */
 public AsyncListener() {
 // TODO Auto-generated constructor stub
 }

 /**
 * @see AsyncListener#onComplete(AsyncEvent)
 */
 public void onComplete(AsyncEvent arg0) throws java.io.IOException { 
 // TODO Auto-generated method stub
 System.out.println("Asyn proces completed..");
 }

 /**
 * @see AsyncListener#onError(AsyncEvent)
 */
 public void onError(AsyncEvent arg0) throws java.io.IOException { 
 // TODO Auto-generated method stub
 }

 /**
 * @see AsyncListener#onStartAsync(AsyncEvent)
 */
 public void onStartAsync(AsyncEvent arg0) throws java.io.IOException { 
 // TODO Auto-generated method stub
 System.out.println("Async process started..."+arg0.getAsyncContext());

 }

 /**
 * @see AsyncListener#onTimeout(AsyncEvent)
 */
 public void onTimeout(AsyncEvent arg0) throws java.io.IOException { 
 // TODO Auto-generated method stub
 }

}
Java · Java8

Recursive Action Task in Fork/Join Framework

Recursive Task is useful where the tasks are independent and caller is not expecting any return result from the task.

Note: make sure that you are waiting to complete the first task. i.e (action.isDone() check)

RecursiveTask

Here is the example which illustrates the Recursive Task

A Main program to start pool and first task,

/**
 * 
 */
package forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;

/**
 * @author prabhu kvn
 *
 */
public class EvenNumberFinderMain_Action {

 public static void main(String args[]) {

 // Mock Data: crate an array of 100 numbers
 List a = new ArrayList();

 for (int i = 0; i < 100; i++) {
 a.add(i);
 }
 // Initialize the Thread Pool
 ForkJoinPool pool = new ForkJoinPool(12);
 EvenNumberFinderAction action = new EvenNumberFinderAction(a);
 pool.execute(action);

 do {
 /*System.out.println("****************Pool****************");
 System.out.println("Parallesim:" + pool.getParallelism());
 System.out.println("Pool size:" + pool.getPoolSize());
 System.out.println("Active Thread count:" + pool.getActiveThreadCount());
 System.out.println("Queed Submission count:" + pool.getQueuedSubmissionCount());
 System.out.println("Qued Task count:" + pool.getQueuedTaskCount());
 System.out.println("Running Thread count:" + pool.getRunningThreadCount());
 System.out.println("Seal count:" + pool.getStealCount());*/

 } while (!action.isDone());
 System.out.println("Main thread One");
 pool.shutdown();
 System.out.println("Main thread Two");

 }
}

And RecusriveAction Class implementation,

package forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveAction;
import java.util.stream.Collectors;

public class EvenNumberFinderAction extends RecursiveAction{

/**
*
*/
private static final long serialVersionUID = 1L;

List a=null;

public EvenNumberFinderAction() {
}

public EvenNumberFinderAction(List a) {
this.a=a;
}
@Override
protected void compute() {
// TODO Auto-generated method stub
List taskList = new ArrayList();
List subList=null;
List evenList = new ArrayList();
/*
* See if the list is greater than 10. if so divide the task.
*/
if(a.size()>10){
subList = a.subList(0, 10);
List remaining = a.subList(10, a.size());
EvenNumberFinderAction task = new EvenNumberFinderAction(remaining);
task.fork();
taskList.add(task);
}else{
subList=a;
}

if(subList!=null){
evenList=subList.parallelStream().filter(element -> {return element%2==0;}).collect(Collectors.toList());
}
System.out.println(“Sub Result:”+evenList);

}
}

Output:
Sub Result:[40, 42, 44, 46, 48]
Sub Result:[90, 92, 94, 96, 98]
Sub Result:[10, 12, 14, 16, 18]
Sub Result:[50, 52, 54, 56, 58]
Sub Result:[30, 32, 34, 36, 38]
Sub Result:[60, 62, 64, 66, 68]
Sub Result:[20, 22, 24, 26, 28]
Sub Result:[70, 72, 74, 76, 78]
Sub Result:[0, 2, 4, 6, 8]
Main thread One
Main thread Two
Sub Result:[80, 82, 84, 86, 88]

Sequence of above task,

forkjoinwithaction

Java · Java8

ForkJoin Demonstration in JAVA

Fork/Join Framework which is introduced in java7 is an important framework to achieve parallel processing in java.This is very useful if you have to execute recursive operations.

There are different kind of tasks which can be executed as part of fork join framework.

  1. RecursiveTask: A task which returns something after the execution
  2. RecursiveAction: A task which will not return anything
  3. CountedCompleter: A task can trigger other tasks on completion of some set of tasks.

RecursiveTask

The following program demonstrates the fork join concept with RecursiveTask. And attached sequence diagram which is best viewed in MS Paint gives the execution mechanism of this framework.

Aim of the program is to find even numbers from a given list.

Execution Environment: JDK8 and Windows 7

A main program to initialize pool and start the task.

/**
 * 
 */
package forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

/**
 * @author prabhu kvn
 *
 */
public class EvenNumberFinderMain {

 public static void main(String args[]) {

 // Mock Data: crate an array of 100 numbers
 List a = new ArrayList();
 List evenNumbers = new ArrayList();
 for (int i = 0; i < 100; i++) {
 a.add(i);
 }
 // Initialize the Thread Pool
 ForkJoinPool pool = new ForkJoinPool(12);
 EvenNumberFinderTask task = new EvenNumberFinderTask(a);
 pool.execute(task);

 do {
 System.out.println("****************Pool****************");
 System.out.println("Parallesim:" + pool.getParallelism());
 System.out.println("Pool size:" + pool.getPoolSize());
 System.out.println("Active Thread count:" + pool.getActiveThreadCount());
 System.out.println("Queed Submission count:" + pool.getQueuedSubmissionCount());
 System.out.println("Qued Task count:" + pool.getQueuedTaskCount());
 System.out.println("Running Thread count:" + pool.getRunningThreadCount());
 System.out.println("Seal count:" + pool.getStealCount());

 } while (!task.isDone());
 pool.shutdown();
 // wait for 
 evenNumbers = task.join();
 System.out.println("Result:" + evenNumbers);

 }
}

Actual Task program

/**
*
*/
package forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;

public class EvenNumberFinderTask extends RecursiveTask{

List a=null;

public EvenNumberFinderTask() {
}

public EvenNumberFinderTask(List a) {
this.a=a;
}
@Override
protected List compute() {
// TODO Auto-generated method stub
List taskList = new ArrayList();
List subList=null;
List evenList = new ArrayList();
/*
* See if the list is greater than 10. if so divide the task.
*/
if(a.size()>10){
subList = a.subList(0, 10);
List remaining = a.subList(10, a.size());
EvenNumberFinderTask task = new EvenNumberFinderTask(remaining);
task.fork();
taskList.add(task);
}else{
subList=a;
}

if(subList!=null){
evenList=subList.parallelStream().filter(element -> {return element%2==0;}).collect(Collectors.toList());
}
System.out.println(“Sub Result:”+evenList);

// wait for all the threads to join
for(EvenNumberFinderTask t: taskList){
evenList.addAll(t.join());
}

return evenList;
}
}

And check the out put of the program which is very interesting. And also sequence diagram

forkjoinseg1

Java · Java8

File Reading Using Java8 Streams

Here we can use Java8 streams to read a file content.

/**
 * 
 */
package java8pract.streams;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author prabhu kvn
 *
 */
public class StreamsInIO {

 /**
 * Using Java8 Streams to read the file
 */
 public StreamsInIO() {
 // TODO Auto-generated constructor stub
 }

 /**
 * @param args
 */
 public static void main(String[] args) {

 try {
 FileReader freader = new FileReader(new File("d:/text1.txt"));
 BufferedReader bReader = new BufferedReader(freader);
 Stream fileStream = bReader.lines();
 List fileContent = fileStream.collect(Collectors.toList());
 System.out.println(fileContent.size());
 System.out.println(fileContent);

 } catch (FileNotFoundException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }

 }

}
Java

StringJoiner and String.join() in jdk8

StringJoiner is a new class in jdk8 which can be used to format data in string format. In the same way String.join() also format the string data with a different use case. Here is an example


public class StringJoinerDemo {

/**
*
*/
public StringJoinerDemo() {
// Default Constructor
}

public static void main(String[] args) {

StringJoiner stringJoiner = new StringJoiner(":", "{", "}");
stringJoiner.add("prabhu").add("kvn");
stringJoiner.add("bangalore").add("560066");
System.out.println("Joined String: "+stringJoiner.toString());

//String join functionality.
List listOfChars = new ArrayList();
for(int i=0;i<20;i++){
listOfChars.add(Integer.toString(i));
}

System.out.println(String.join(" | ", listOfChars));

}
}

Output
Joined String: {prabhu:kvn:bangalore:560066}
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19

Java

Integer Cache in Java

There is an integer caching introduced in java which is similar to String constant pool. this inetgere cache by default cache all the numbers from -128 to 127. That means, if you try to use any number between -128 to 127, it will be fetched from cache and you will see the same integer instance. Having said that, here is the small program to demonstarate the same and observer the out put of this program after 127.

Apart from this we can even increase this limit by using, –XXAutoBoxCacheMax=1024. But this will also consume equal amount of memory though you use these numbers or not.

/**
* @author prabhu kvn
*
*/
public class IntegerCacheDemoInHotSpot {</code>

/**
*
*/
public IntegerCacheDemoInHotSpot() {
}

/**
* @param args
*/
public static void main(String[] args) {
System.out.println("Integer Testing");
for (int i = 0; i &lt; 255; i++) {
Integer firstInt = i;
Integer secondInt = i;
System.out.println(firstInt + &quot; == &quot; + secondInt + &quot; : &quot; + (firstInt == secondInt));

}

}

}

Out Put:

Integer Testing
0 == 0 : true
1 == 1 : true
2 == 2 : true
3 == 3 : true
4 == 4 : true
5 == 5 : true
6 == 6 : true
7 == 7 : true
8 == 8 : true
9 == 9 : true
10 == 10 : true
11 == 11 : true
12 == 12 : true
13 == 13 : true
14 == 14 : true
15 == 15 : true
16 == 16 : true
17 == 17 : true
18 == 18 : true
19 == 19 : true
20 == 20 : true
21 == 21 : true
22 == 22 : true
23 == 23 : true
24 == 24 : true
25 == 25 : true
26 == 26 : true
27 == 27 : true
28 == 28 : true
29 == 29 : true
30 == 30 : true
31 == 31 : true
32 == 32 : true
33 == 33 : true
34 == 34 : true
35 == 35 : true
36 == 36 : true
37 == 37 : true
38 == 38 : true
39 == 39 : true
40 == 40 : true
41 == 41 : true
42 == 42 : true
43 == 43 : true
44 == 44 : true
45 == 45 : true
46 == 46 : true
47 == 47 : true
48 == 48 : true
49 == 49 : true
50 == 50 : true
51 == 51 : true
52 == 52 : true
53 == 53 : true
54 == 54 : true
55 == 55 : true
56 == 56 : true
57 == 57 : true
58 == 58 : true
59 == 59 : true
60 == 60 : true
61 == 61 : true
62 == 62 : true
63 == 63 : true
64 == 64 : true
65 == 65 : true
66 == 66 : true
67 == 67 : true
68 == 68 : true
69 == 69 : true
70 == 70 : true
71 == 71 : true
72 == 72 : true
73 == 73 : true
74 == 74 : true
75 == 75 : true
76 == 76 : true
77 == 77 : true
78 == 78 : true
79 == 79 : true
80 == 80 : true
81 == 81 : true
82 == 82 : true
83 == 83 : true
84 == 84 : true
85 == 85 : true
86 == 86 : true
87 == 87 : true
88 == 88 : true
89 == 89 : true
90 == 90 : true
91 == 91 : true
92 == 92 : true
93 == 93 : true
94 == 94 : true
95 == 95 : true
96 == 96 : true
97 == 97 : true
98 == 98 : true
99 == 99 : true
100 == 100 : true
101 == 101 : true
102 == 102 : true
103 == 103 : true
104 == 104 : true
105 == 105 : true
106 == 106 : true
107 == 107 : true
108 == 108 : true
109 == 109 : true
110 == 110 : true
111 == 111 : true
112 == 112 : true
113 == 113 : true
114 == 114 : true
115 == 115 : true
116 == 116 : true
117 == 117 : true
118 == 118 : true
119 == 119 : true
120 == 120 : true
121 == 121 : true
122 == 122 : true
123 == 123 : true
124 == 124 : true
125 == 125 : true
126 == 126 : true
127 == 127 : true
128 == 128 : false
129 == 129 : false
130 == 130 : false
131 == 131 : false
132 == 132 : false
133 == 133 : false
134 == 134 : false
135 == 135 : false
136 == 136 : false
137 == 137 : false
138 == 138 : false
139 == 139 : false
140 == 140 : false
141 == 141 : false
142 == 142 : false
143 == 143 : false
144 == 144 : false
145 == 145 : false
146 == 146 : false
147 == 147 : false
148 == 148 : false
149 == 149 : false
150 == 150 : false
151 == 151 : false
152 == 152 : false
153 == 153 : false
154 == 154 : false
155 == 155 : false
156 == 156 : false
157 == 157 : false
158 == 158 : false
159 == 159 : false
160 == 160 : false
161 == 161 : false
162 == 162 : false
163 == 163 : false
164 == 164 : false
165 == 165 : false
166 == 166 : false
167 == 167 : false
168 == 168 : false
169 == 169 : false
170 == 170 : false
171 == 171 : false
172 == 172 : false
173 == 173 : false
174 == 174 : false
175 == 175 : false
176 == 176 : false
177 == 177 : false
178 == 178 : false
179 == 179 : false
180 == 180 : false
181 == 181 : false
182 == 182 : false
183 == 183 : false
184 == 184 : false
185 == 185 : false
186 == 186 : false
187 == 187 : false
188 == 188 : false
189 == 189 : false
190 == 190 : false
191 == 191 : false
192 == 192 : false
193 == 193 : false
194 == 194 : false
195 == 195 : false
196 == 196 : false
197 == 197 : false
198 == 198 : false
199 == 199 : false
200 == 200 : false
201 == 201 : false
202 == 202 : false
203 == 203 : false
204 == 204 : false
205 == 205 : false
206 == 206 : false
207 == 207 : false
208 == 208 : false
209 == 209 : false
210 == 210 : false
211 == 211 : false
212 == 212 : false
213 == 213 : false
214 == 214 : false
215 == 215 : false
216 == 216 : false
217 == 217 : false
218 == 218 : false
219 == 219 : false
220 == 220 : false
221 == 221 : false
222 == 222 : false
223 == 223 : false
224 == 224 : false
225 == 225 : false
226 == 226 : false
227 == 227 : false
228 == 228 : false
229 == 229 : false
230 == 230 : false
231 == 231 : false
232 == 232 : false
233 == 233 : false
234 == 234 : false
235 == 235 : false
236 == 236 : false
237 == 237 : false
238 == 238 : false
239 == 239 : false
240 == 240 : false
241 == 241 : false
242 == 242 : false
243 == 243 : false
244 == 244 : false
245 == 245 : false
246 == 246 : false
247 == 247 : false
248 == 248 : false
249 == 249 : false
250 == 250 : false
251 == 251 : false
252 == 252 : false
253 == 253 : false
254 == 254 : false

We have similar kind of cache for long values too,check below


Long j= 0L;

for(;j<4000;j++){
Long firstLong=Long.valueOf(j);
Long secondLong=Long.valueOf(j);
System.out.println(firstLong+" == "+secondLong+" : "+(firstLong==secondLong));

}