January 2008
Using the GigaSpaces XAP product along with OpenSpaces and Spring allows the user the choice to receive both continuous queries through the configuration of a notify-container as well as snapshots of state returned according to either a specific or range query posed.
This allows the development of solutions utilizing a comfortably familiar query interface while attaining newfound throughput and low-latency due to the storing and retrieving of the information to and from memory.
An example would be nice so here goes:
Let us assume that a catalog of bicycles exists in a space and we have a customer interested in finding a bicycle with just the correct color and wheel diameter. We will show how that customer can both asynchronously receive notifications and synchronously receive a snapshot of the information available.
First, let's create a simple bicycle:
package gslabs.common;
public class Bicycle{
private Double wheelDiameter;
private String color;
private Integer numberOfGears;
public void setWheelDiameter(Double val){
this.wheelDiameter = val;
}
public Double getWheelDiameter(){
return wheelDiameter;
}
public void setColor(String val){
this.color = val;
}
public String getColor(){
return color;
}
public void setNumberOfGears(Integer val){
this.numberOfGears = val;
}
public Integer getNumberOfGears(){
return numberOfGears;
}
}
Next we will create a publisher of such Bicycles:
package gslabs;
import org.openspaces.core.GigaSpace;
import gslabs.common.*;
/**
* This TimerTask will be managed by the Spring container and the run method
* invoked over and over again according to the Spring configuration **/
public class BikeDeliveryService extends java.util.TimerTask{
private GigaSpace gigaspace;
public BikeDeliveryService(GigaSpace space){
gigaspace=space;
}
public void run(){
if(gigaspace != null){
Bicycle b = new Bicycle();
b.setColor("Red");
//there will be a variety of diameters: from 9 to 38 centimeters
b.setWheelDiameter(new Double(System.nanoTime()%30+9));
b.setNumberOfGears(new Integer(10));
gigaspace.write(b);
}
}
}
Now, we will create the Shopper that will be told when Bicycles that match the criteria specified are made available in the Space. Upon such notification, the Shopper takes a snapshot of up to 200 bikes that match a more specific criteria that falls within the range of the original notification.
package gslabs;
import net.jini.core.entry.UnusableEntryException;
import org.openspaces.events.adapter.SpaceDataEvent;
import com.j_spaces.core.client.ExternalEntry;
import org.openspaces.core.GigaSpace;
import gslabs.common.*;
public class Shopper{
/**
* This method facilitates the continuous receipt of matching Bicycles to
* this Shopper instance. The Criteria for matching is specified as a SQL
* query in the pu.xml file that defines the Shopper Spring bean.
**/
@SpaceDataEvent
public void dataProcessed(Object data, GigaSpace space){
Bicycle bike = (Bicycle)data;
System.out.println("Received Notification of new Bicycle with
wheel diameter == "+ bike.getWheelDiameter());
/*
* Next: we get a snapshot of up to 200 Bikes that currently exist and are
* Red, have 10 gears and a wheelDiameter of 17
*/
Bicycle template = new Bicycle();
template.setColor("Red");
template.setNumberOfGears(10);
template.setWheelDiameter(17d);
Object[] results = space.readMultiple(template, 200);
for(int x=0;x<results.length;x++){
System.out.println("Bicycle #"+(x+1)+" has wheel diameter == "+
((Bicycle)results[x]).getWheelDiameter());
}
}
}
Here follows the openSpaces Spring configuration file that allows the above two services to function within a Spring container. Specifically, it sets up a Timer to invoke the production of new Bicycles and the continuous query that feeds the Shopper with knowledge of only the bikes that match a particular query.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:os-core="http://www.openspaces.org/schema/core"
xmlns:os-events="http://www.openspaces.org/schema/events"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.openspaces.org/schema/core
http://www.openspaces.org/schema/core/openspaces-core.xsd
http://www.openspaces.org/schema/events
http://www.openspaces.org/schema/events/openspaces-events.xsd">
<!-- A bean representing a space (an IJSpace implementation)
if embedded use a /./ if not use jini://*/*/
-->
<os-core:space id="space" url="/./shoppingSpace"/>
<!-- OpenSpaces simplified space API built on top of IJSpace/JavaSpace. -->
<os-core:giga-space id="shoppingSpace" space="space"/>
<!-- Shopper Service -->
<bean id="Shopper" class="gslabs.Shopper">
</bean>
<!-- BikeDeliveryService Service -->
<bean id="BikeDeliveryService"
class="gslabs.BikeDeliveryService">
<constructor-arg ref="shoppingSpace"/>
</bean>
<!--
Defines a local Jini transaction manager - good to use anytime you do a take.
When using a polling-container you effectively are doing a take even though your
code doesn't show it.
-->
<os-core:local-tx-manager id="transactionManager" space="space"/>
<!--
A notify event container that performs (by default) notify registration operation against
the space using the provided template.
Once a match is found, the specified bean event listener is triggered using the
annotation adapter.
-->
<os-events:notify-container id="pollingEventContainer"
giga-space="shoppingSpace">
<os-events:tx-support tx-manager="transactionManager"/>
<os-core:sql-query where="wheelDiameter < 22 and wheelDiameter > 10 and color rlike 'Red|red|RED|Blue|blue|BLUE'"
class="gslabs.common.Bicycle" />
<os-events:listener>
<os-events:annotation-adapter>
<os-events:delegate ref="Shopper"/>
</os-events:annotation-adapter>
</os-events:listener>
</os-events:notify-container>
<bean id="scheduledTask"
class="org.springframework.scheduling.timer.ScheduledTimerTask" >
<!-- wait 1 seconds before starting repeated execution -->
<property name="delay" value="1000" />
<!-- run every 2 seconds -->
<property name="period" value="2000" />
<property name="timerTask" ref="BikeDeliveryService" />
</bean>
<bean id="timerFactory"
class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<!-- This wires the factory to the scheduledTask bean above
-->
<ref bean="scheduledTask" />
</list>
</property>
</bean>
</beans>
As the application runs, some bikes that match the SQL query will be produced and the output of our Shopper will look much like this:
Received Notification of new Bicycle with wheel diameter == 14.0
Received Notification of new Bicycle with wheel diameter == 12.0
Received Notification of new Bicycle with wheel diameter == 16.0
Received Notification of new Bicycle with wheel diameter == 15.0
Received Notification of new Bicycle with wheel diameter == 19.0
Received Notification of new Bicycle with wheel diameter == 17.0
Bicycle #1 has wheel diameter == 17.0
Received Notification of new Bicycle with wheel diameter == 21.0
Bicycle #1 has wheel diameter == 17.0
Received Notification of new Bicycle with wheel diameter == 15.0
Bicycle #1 has wheel diameter == 17.0
Received Notification of new Bicycle with wheel diameter == 17.0
Bicycle #1 has wheel diameter == 17.0
Bicycle #2 has wheel diameter == 17.0
PRINTER FRIENDLY VERSION
|