SyncRemoting cookbook
Posted 4 June 2008 @ 6:17 pm by Owen TaylorI wrote up a cheat sheet for myself when building scatter-gather or map reduce apps with GigaSpacesXAP.
It goes like this:
Create business interface (as part of shared classes)
Space-side stuff:
Create the Space-side implementation (logic) [ This may use a GigaSpace reference ]
Configure the implementation on the Space-Side:
Declare the business implementation as a [bean]
Declare a filter as part of the space
The filter references a ServiceExporter
Declare the os-remoting:service-exporter
The exporter references the business implementation [the bean]
If impl uses space: Declare the giga-space-context
Client-side stuff
Declare os-remoting:sync-proxy with its attributes:
The business interface it implements
The giga-space it uses as a transport layer
Whether broadcast is true or false
If necessary –declare the reducer for the proxy
Inject the client with the service proxy (ie: public void setMyService(MyService ref){} )
Let's say we want to do a Map reduce exercise where each node in the cluster will process its share in parallel and return a total result for my digestion...
Let's say I want to know the average price for all my widgets in all my inventory, but my inventory is scattered across a dozen servers because I do so much business...
I have my widgets:
package com.test.common;
import com.gigaspaces.annotation.pojo.SpaceRouting;
public class Widget {
private Double price;
private String description;
private Integer routingValue;
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@SpaceRouting
public Integer getRoutingValue() {
return routingValue;
}
public void setRoutingValue(Integer routingValue) {
this.routingValue = routingValue;
}
}
My Service needs an interface such as:
package com.test.common;
public interface PricingService{
public Double getAveragePriceOfAllWidgets();
}
Next, I need to implement the service:
package com.test;
import org.openspaces.core.GigaSpace;
import org.openspaces.core.context.GigaSpaceContext;
import com.j_spaces.core.client.SQLQuery;
import com.test.common.PricingService;
import com.test.common.Widget;
public class PricingServiceImpl implements PricingService{
@GigaSpaceContext
GigaSpace space;
public Double getAveragePriceOfAllWidgets() {
Object[] allWidgets = space.readMultiple(new Widget(), Integer.MAX_VALUE);
double priceTotal = 0.0d;
for(int x=0;x<allWidgets.length;x++){
priceTotal=priceTotal+((Widget)allWidgets[x]).getPrice().doubleValue();
}
double averagePrice = priceTotal/allWidgets.length;
return new Double(averagePrice);
}
}
Now I need a client that uses this service:
package com.test;
import java.util.TimerTask;
import com.test.common.PricingService;
public class WidgetSurfingClient extends TimerTask{
private PricingService service;
public void setPricingService(PricingService ref){
this.service=ref;
}
public void run(){
System.out.println(
"The average price of all widgets is now: $"+
service.getAveragePriceOfAllWidgets());
}
}
Now I need something to do the "reduce" side of the map-reduce: (it also performs the final average calculation because I am looking for the average price...
package com.test;
import org.openspaces.remoting.RemoteResultReducer;
import org.openspaces.remoting.SpaceRemotingInvocation;
import org.openspaces.remoting.SpaceRemotingResult;
public class AveragingDoubleResultReducer implements RemoteResultReducer<Double,Double>{
public Double reduce(SpaceRemotingResult<Double>[] results,
SpaceRemotingInvocation remotingInvocation) throws Exception {
double totalDouble = 0.0d;
int size = results.length;
for (int x=0;x<size;x++){
if(results[x]!=null){
if(results[x].getResult()!=null){
totalDouble += (Double) results[x].getResult();
}
}
}
double averageDouble=totalDouble/size;
return new Double(averageDouble);
}
}
That takes care of the Java code, now we have to configure this system:
First: the Space-side configuration:
<beans ... XML namespace declaration stuff not shown...>
<!-- bootstrap the construction of the serviceCluster: -->
<os-core:space id="widgetTransport" url="/./widgetsystem">
<!-- setup the PricingServiceExporter to handle calls -->
<os-core:filter-provider ref="PricingServiceExporter"/>
</os-core:space>
<!-- wrap the serviceCluster in Spring-ready OpenSpaces API -->
<os-core:giga-space id="gigaspace" space="widgetTransport"
tx-manager="transactionManager" />
<!-- declare the transaction manager -->
<os-core:local-tx-manager id="transactionManager"
space="widgetTransport"/>
<bean id="PricingService" class="com.test.PricingServiceImpl"/>
<!-- provide a gigaspace context to the pricing service -->
<os-core:giga-space-context/>
<!--
Provide the binding to the Space-side
transport for the PricingService :
-->
<os-remoting:service-exporter id="PricingServiceExporter">
<os-remoting:service ref="PricingService"/>
</os-remoting:service-exporter>
<!-- configure a big or small cluster
(here we have 20 partitions with 1 backup for each) -->
<os-sla:sla cluster-schema="partitioned-sync2backup"
number-of-instances="20" number-of-backups="1"
max-instances-per-vm="1">
</os-sla:sla>
</beans>
Next: the client-side configuration:
<beans ... XML namespace declaration stuff not shown...>
<!-- bootstrap the basic proxy for the serviceCluster: -->
<os-core:space id="widgetTransport" url="jini://*/*/widgetsystem" />
<!-- wrap the proxy in Spring-ready OpenSpaces API -->
<os-core:giga-space id="gigaspace" space="widgetTransport" />
<!-- WidgetSurfer Service -->
<bean id="WidgetSurfer" class="com.test.WidgetSurfingClient">
<property name="pricingService" ref="PricingService"/>
</bean>
<bean id="AveragingDoubleResultReducer" class="com.test.AveragingDoubleResultReducer"/>
<os-remoting:sync-proxy id="PricingService"
giga-space="gigaspace"
broadcast="true"
interface="com.test.common.PricingService">
<os-remoting:result-reducer ref="AveragingDoubleResultReducer"/>
</os-remoting:sync-proxy>
<!-- this is regular Spring TimerTask configuration stuff: -->
<bean id="widgetClientTask" class="org.springframework.scheduling.timer.ScheduledTimerTask" >
<!-- wait 1 seconds before starting repeated execution -->
<property name="delay" value="1000" />
<!-- run every 5 seconds -->
<property name="period" value="5000" />
<property name="timerTask" ref="WidgetSurfer" />
</bean>
<bean id="widgetClientTimer" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<!-- This wires the factory to the scheduledTask bean above -->
<ref bean="widgetClientTask" />
</list>
</property>
</bean>
</beans>
Cheers,
Owen.
Read more...







