SyncRemoting cookbook

Posted 4 June 2008 @ 6:17 pm by Owen Taylor

I 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...

Comments are closed.