Sample REST Applications

This topic provides examples that illustrate how multiple clients, both REST and native, can access the same VMware Tanzu GemFire region data.

Note: You must set PDX read-serialized to true when starting the cache server to achieve interoperability between different clients. See Setup and Configuration for instructions on starting up REST-enabled cache servers.

The following examples demonstrate the following:

  1. A Java REST client creates a Person object on key 1. This client references the following supporting examples (also provided):

    1. Tanzu GemFire cache client
    2. REST client utility
    3. Date Time utility
    4. Person class
    5. Gender class
  2. A Ruby REST client also gets data for key 1 and updates it.

  3. A Python REST Client demonstrates the creation and modification of objects. Note: An additional Python REST client reference application is available here: https://github.com/gemfire/py-gemfire-rest.

The following Java examples assume a project directory structure similar to the following:

Project directory structure. Top level folder 'JavaClient' contains 'src' folder. 'src' folder contains 'com.gemstone.gemfire.domains', 'com.gemstone.gemfire.javaclient', com.gemstone.gemfire.util' folders. Each of these 'com.' folder contain one or more .java' files.

#1. REST Java Client (RestClientApp.java)

package org.apache.geode.restclient;

 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;

 import org.apache.geode.util.RestClientUtils;

 import java.util.ArrayList;
 import java.util.List;

@SuppressWarnings( "unused")
 public class RestClientApp  {
   private static final String PEOPLE_REGION =  "/People";

   private static final String PERSON1_AS_JSON =  "{"
          +  "\"@type\ ": \"org.apache.geode.domain.Person\ "," +  "\"id\ ": 1,"
       +  " \"firstName\ ": \"Jane\ "," +  " \"middleName\ ": \"H\ ","
       +  " \"lastName\ ": \"Doe1\ "," +  " \"birthDate\ ": \"04/12/1983\ ","
       +  "\"gender\ ": \"MALE\ "" + "}";

   public static void main( final String... args)  throws Exception {
    doCreate(PEOPLE_REGION,  "1");
     System.out.println( "Programme has run successfully...!");
  }

   private static  HttpHeaders setAcceptAndContentTypeHeaders(){
    List<MediaType> acceptableMediaTypes =  new ArrayList<>();
    acceptableMediaTypes.add(MediaType.APPLICATION_JSON);

    HttpHeaders headers =  new HttpHeaders();
    headers.setAccept(acceptableMediaTypes);
    headers.setContentType(MediaType.APPLICATION_JSON);
     return headers;
  }

   private static void doCreate( final String regionNamePath,  final String key) {
    HttpHeaders headers =  setAcceptAndContentTypeHeaders();
    HttpEntity< String> entity =  new HttpEntity< String>(PERSON1_AS_JSON, headers);
     try {
      ResponseEntity< String> result = RestClientUtils.getRestTemplate().exchange(
             "http://localhost:8080/gemfire-api/v1/People?key=1" , HttpMethod.POST,
            entity,  String.class);

       System.out.println( "STATUS_CODE = " + result.getStatusCode().value());
       System.out.println( "HAS_BODY = " + result.hasBody());
       System.out.println( "LOCATION_HEADER = " + result.getHeaders().getLocation().toString());
    }  catch (HttpClientErrorException e) {
       System.out.println( "Http Client encountered error, msg:: " + e.getMessage());
    }  catch(HttpServerErrorException se) {
       System.out.println( "Server encountered error, msg::" + se.getMessage());
    }  catch (Exception e) {
       System.out.println( "Unexpected ERROR...!!");
    }
  }
}

#1a. Tanzu GemFire Cache Java Client (MyJavaClient.java)

package org.apache.geode.javaclient;

 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.Map;

 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.client.ClientCache;
 import org.apache.geode.cache.client.ClientCacheFactory;
 import org.apache.geode.cache.client.ClientRegionFactory;
 import org.apache.geode.cache.client.ClientRegionShortcut;
 import org.apache.geode.domain.Gender;
 import org.apache.geode.domain.Person;
 import org.apache.geode.pdx.PdxInstance;
 import org.apache.geode.util.DateTimeUtils;

 public class MyJavaClient {

   public static void main( String[] args) {
    ClientCacheFactory cf =  new ClientCacheFactory().addPoolServer( "localhost", 40405);
    ClientCache cache = cf.setPdxReadSerialized( true).create();
    ClientRegionFactory rf = cache.createClientRegionFactory(ClientRegionShortcut.PROXY);

    Region region = rf.create( "People");

     //Get data on key "1" , update it and put it again in cache
    Person actualObj =  null;
     Object obj = region.get( "1");
     if(obj  instanceof PdxInstance){
       System.out.println( "Obj is PdxInstance");
      PdxInstance pi = (PdxInstance)obj;
       Object obj2 = pi.getObject();
       if(obj2  instanceof Person){
        actualObj = (Person)obj2;
         System.out.println( "Received Person :" + actualObj.toString());
      } else {
         System.out.println( "Error: obj2 is expected to be of type Person");
      }
    } else {
       System.out.println( "Error: obj is expected to be of type PdxInstance");
    }

     //update the received object and put it in cache
 if(actualObj !=  null){
      actualObj.setFirstName( "Jane_updated");
      actualObj.setLastName( "Doe_updated");
      region.put( "1", actualObj);
    }

     //Add/putAll set of person objects
 final Person person2 =  new Person(102L,  "Sachin",  "Ramesh",  "Tendulkar", DateTimeUtils.createDate(1975, Calendar.DECEMBER, 14), Gender.MALE);
     final Person person3 =  new Person(103L,  "Saurabh",  "Baburav",  "Ganguly", DateTimeUtils.createDate(1972, Calendar.AUGUST, 29), Gender.MALE);
     final Person person4 =  new Person(104L,  "Rahul",  "subrymanyam",  "Dravid", DateTimeUtils.createDate(1979, Calendar.MARCH, 17), Gender.MALE);
     final Person person5 =  new Person(105L,  "Jhulan",  "Chidambaram",  "Goswami", DateTimeUtils.createDate(1983, Calendar.NOVEMBER, 25), Gender.FEMALE);
     final Person person6 =  new Person(101L,  "Rahul",  "Rajiv",  "Gndhi", DateTimeUtils.createDate(1970, Calendar.MAY, 14), Gender.MALE);
     final Person person7 =  new Person(102L,  "Narendra",  "Damodar",  "Modi", DateTimeUtils.createDate(1945, Calendar.DECEMBER, 24), Gender.MALE);
     final Person person8 =  new Person(103L,  "Atal",  "Bihari",  "Vajpayee", DateTimeUtils.createDate(1920, Calendar.AUGUST, 9), Gender.MALE);
     final Person person9 =  new Person(104L,  "Soniya",  "Rajiv",  "Gandhi", DateTimeUtils.createDate(1929, Calendar.MARCH, 27), Gender.FEMALE);
     final Person person10 =  new Person(104L,  "Priyanka",  "Robert",  "Gandhi", DateTimeUtils.createDate(1973, Calendar.APRIL, 15), Gender.FEMALE);
     final Person person11 =  new Person(104L,  "Murali",  "Manohar",  "Joshi", DateTimeUtils.createDate(1923, Calendar.APRIL, 25), Gender.MALE);
     final Person person12 =  new Person(104L,  "Lalkrishna",  "Parmhansh",  "Advani", DateTimeUtils.createDate(1910, Calendar.JANUARY, 01), Gender.MALE);
     final Person person13 =  new Person(104L,  "Shushma",  "kumari",  "Swaraj", DateTimeUtils.createDate(1943, Calendar.AUGUST, 10), Gender.FEMALE);
     final Person person14 =  new Person(104L,  "Arun",  "raman",  "jetly", DateTimeUtils.createDate(1942, Calendar.OCTOBER, 27), Gender.MALE);
     final Person person15 =  new Person(104L,  "Amit",  "kumar",  "shah", DateTimeUtils.createDate(1958, Calendar.DECEMBER, 21), Gender.MALE);
     final Person person16 =  new Person(104L,  "Shila",  "kumari",  "Dixit", DateTimeUtils.createDate(1927, Calendar.FEBRUARY, 15), Gender.FEMALE);

    Map< String,  Object> userMap =  new HashMap< String,  Object>();
    userMap.put( "2", person6);
    userMap.put( "3", person6);
    userMap.put( "4", person6);
    userMap.put( "5", person6);
    userMap.put( "6", person6);
    userMap.put( "7", person7);
    userMap.put( "8", person8);
    userMap.put( "9", person9);
    userMap.put( "10", person10);
    userMap.put( "11", person11);
    userMap.put( "12", person12);
    userMap.put( "13", person13);
    userMap.put( "14", person14);
    userMap.put( "15", person15);
    userMap.put( "16", person16);

     //putAll all person
    region.putAll(userMap);

     System.out.println( "successfully Put set of Person objects into the cache");
  }

}

#1b. REST Client Utilities (RestClientUtils.java)

package org.apache.geode.util;


 import java.net.URI;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.List;
 import org.springframework.http.converter.ByteArrayHttpMessageConverter;
 import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.StringHttpMessageConverter;
 import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;

 public class RestClientUtils {

   public static final String BASE_URL =  "http://192.0.2.0:8080" ;
   public static final String GEODE_REST_API_CONTEXT =  "/geode";
   public static final String GEODE_REST_API_VERSION =  "/v1";
   public static final URI GEODE_REST_API_WEB_SERVICE_URL = URI
      .create(BASE_URL + GEODE_REST_API_CONTEXT + GEODE_REST_API_VERSION);

   public static RestTemplate restTemplate;
   public static RestTemplate getRestTemplate() {
     if (restTemplate ==  null) {
      restTemplate =  new RestTemplate();
       final List<HttpMessageConverter<?>> messageConverters =  new ArrayList<HttpMessageConverter<?>>();

      messageConverters.add( new ByteArrayHttpMessageConverter());
      messageConverters.add( new StringHttpMessageConverter());
      messageConverters.add(createMappingJackson2HttpMessageConverter());

      restTemplate.setMessageConverters(messageConverters);
    }
     return restTemplate;
  }

   public static HttpMessageConverter< Object> createMappingJackson2HttpMessageConverter() {
     final Jackson2ObjectMapperFactoryBean objectMapperFactoryBean =  new Jackson2ObjectMapperFactoryBean();
    objectMapperFactoryBean.setFailOnEmptyBeans( true);
    objectMapperFactoryBean.setIndentOutput( true);
    objectMapperFactoryBean.setDateFormat( new SimpleDateFormat( "MM/dd/yyyy"));
    objectMapperFactoryBean
        .setFeaturesToDisable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    objectMapperFactoryBean
        .setFeaturesToEnable(
            com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_COMMENTS,
            com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES,
            com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    objectMapperFactoryBean.afterPropertiesSet();

     final MappingJackson2HttpMessageConverter httpMessageConverter =  new MappingJackson2HttpMessageConverter();
    httpMessageConverter.setObjectMapper(objectMapperFactoryBean.getObject());
     return httpMessageConverter;
  }

   public static URI toUri( final String... pathSegments) {
     return toUri(GEODE_REST_API_WEB_SERVICE_URL, pathSegments);
  }

   public static URI toUri( final URI baseUrl,  final String... pathSegments) {
     return UriComponentsBuilder.fromUri(baseUrl).pathSegment(pathSegments)
        .build().toUri();
  }
}

#1c. Date and Time Utilities (DateTimeUtils.java)

package org.apache.geode.util;


 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;

/**
 * The DateTimeUtils class is a utility class  for working with dates and times.
 */
@SuppressWarnings( "unused")
 public abstract class DateTimeUtils {

   public static Calendar createCalendar( final int year,  final int month,  final int day) {
     final Calendar dateTime = Calendar.getInstance();
    dateTime.clear();
    dateTime.set(Calendar.YEAR, year);
    dateTime.set(Calendar.MONTH, month);
    dateTime.set(Calendar.DAY_OF_MONTH, day);
     return dateTime;
  }

   public static Date createDate( final int year,  final int month,  final int day) {
     return createCalendar(year, month, day).getTime();
  }

   public static String format( final Date dateTime,  final String formatPattern) {
     return (dateTime !=  null ?  new SimpleDateFormat(formatPattern).format(dateTime) :  null);
  }

}

#1d. Person Class (Person.java)

package org.apache.geode.domain;


 import java.util.Date;

 import org.apache.geode.internal.lang.ObjectUtils;
 import org.apache.geode.pdx.PdxReader;
 import org.apache.geode.pdx.PdxSerializable;
 import org.apache.geode.pdx.PdxWriter;

 import org.apache.geode.util.DateTimeUtils;

/**
 * The Person class is an abstraction modeling a person.
 */

 public class Person  implements PdxSerializable /*ResourceSupport  implements DomainObject< Long>*/  {

   private static final long serialVersionUID = 42108163264l;

   protected static final String DOB_FORMAT_PATTERN =  "MM/dd/yyyy";

   private Long id;

   private Date birthDate;

   private Gender gender;

   private String firstName;
   private String middleName;
   private String lastName;

   public Person() {
  }

   public Person( final Long id) {
     this.id = id;
  }

   public Person( final String firstName,  final String lastName) {
     this.firstName = firstName;
     this.lastName = lastName;
  }

   public Person( final Long id,  final String firstName,  final String middleName,  final String lastName, Date date, Gender gender) {
     this.id = id;
     this.firstName = firstName;
     this.middleName = middleName;
     this.lastName = lastName;
     this.birthDate = date;
     this.gender = gender;
  }

   public Long getId() {
     return id;
  }

   public void setId( final Long id) {
     this.id = id;
  }

   public String getFirstName() {
     return firstName;
  }

   public void setFirstName( final String firstName) {
     this.firstName = firstName;
  }

   public String getLastName() {
     return lastName;
  }

   public void setLastName( final String lastName) {
     this.lastName = lastName;
  }

   public String getMiddleName() {
     return middleName;
  }

   public void setMiddleName( final String middleName) {
     this.middleName = middleName;
  }

   public Date getBirthDate() {
     return birthDate;
  }

   public void setBirthDate( final Date birthDate) {
     this.birthDate = birthDate;
  }

   public Gender getGender() {
     return gender;
  }

   public void setGender( final Gender gender) {
     this.gender = gender;
  }

  @Override
   public boolean equals( final Object obj) {
     if (obj ==  this) {
       return true;
    }

     if (!(obj  instanceof Person)) {
       return false;
    }

     final Person that = (Person) obj;

     return (ObjectUtils.equals( this.getId(), that.getId())
      || (ObjectUtils.equals( this.getBirthDate(), that.getBirthDate())
      && ObjectUtils.equals( this.getLastName(), that.getLastName())
      && ObjectUtils.equals( this.getFirstName(), that.getFirstName())));
  }

  @Override
   public int hashCode() {
     int hashValue = 17;
    hashValue = 37 * hashValue + ObjectUtils.hashCode(getId());
    hashValue = 37 * hashValue + ObjectUtils.hashCode(getBirthDate());
    hashValue = 37 * hashValue + ObjectUtils.hashCode(getLastName());
    hashValue = 37 * hashValue + ObjectUtils.hashCode(getFirstName());
     return hashValue;
  }

  @Override
   public String toString() {
     final StringBuilder buffer =  new StringBuilder( "{ type = ");
    buffer.append(getClass().getName());
    buffer.append( ", id = ").append(getId());
    buffer.append( ", firstName = ").append(getFirstName());
    buffer.append( ", middleName = ").append(getMiddleName());
    buffer.append( ", lastName = ").append(getLastName());
    buffer.append( ", birthDate = ").append(DateTimeUtils.format(getBirthDate(), DOB_FORMAT_PATTERN));
    buffer.append( ", gender = ").append(getGender());
    buffer.append( " }");
     return buffer.toString();
  }

  @Override
   public void fromData(PdxReader pr) {

    id = pr.readLong( "id");
    firstName = pr.readString( "firstName");
    middleName = pr.readString( "middleName");
    lastName = pr.readString( "lastName");
    birthDate = pr.readDate( "birthDate");
    gender = (Gender)pr.readObject( "gender");
  }

  @Override
   public void toData(PdxWriter pw) {
    pw.writeLong( "id", id);
    pw.writeString( "firstName", firstName);
    pw.writeString( "middleName", middleName);
    pw.writeString( "lastName", lastName);
    pw.writeDate( "birthDate", birthDate);
    pw.writeObject( "gender", gender);
  }

}

#1e. Gender Class (Gender.java)

package org.apache.geode.domain;

/**
 * The Gender  enum is a enumeration of genders (sexes).
 */

 public enum Gender {
  FEMALE,
  MALE
}

#2. Ruby REST Client (restClient.rb)

#!/usr/bin/ruby -w

puts "Hello, Ruby!";

# !/usr/bin/env ruby

require 'json'
require 'net/http'

class JsonSerializable

  def to_json
    hash = {}
    hash["@type"] = "org.apache.geode.web.rest.domain.Person"
    self.instance_variables.each do |var|
      if !var.to_s.end_with?("links")
        hash[var.to_s[1..-1]] = self.instance_variable_get var
      end
    end
    hash.to_json
  end

  def from_json! jsonString
    JSON.load(jsonString).each do |var, val|
      if !var.end_with?("type")
        self.instance_variable_set "@".concat(var), val
      end
    end
  end

end

class Person < JsonSerializable

  attr_accessor :id, :firstName, :middleName, :lastName, :birthDate, :gender

  def initialize(id = nil, firstName = nil, middleName = nil, lastName = nil )
    @id = id
    @firstName = firstName
    @middleName = middleName
    @lastName = lastName
    @birthDate = nil
    @gender = nil
  end

  def to_s
    s = "{ type = Person, id = #{@id}"
    s += ", firstName = #{@firstName}"
    s += ", middleName = #{@middleName}"
    s += ", lastName = #{@lastName}"
    s += ", birthDate = #{@birthDate}"
    s += ", gender = #{@gender}"
    s += "}"
  end

end

if __FILE__ == $0
  #p = Person.new(1, "Jon", "T", "Doe")
  #puts p
  #puts p.inspect
  #puts p.to_json

  uri = URI("http://localhost:8080/gemfire-api/v1/People/1");

  personJson = Net::HTTP::get(uri);

  # JSON from server
  puts "JSON read from Server for Person with ID 1...\n #{personJson}"

  p = Person.new
  p.from_json! personJson

  # print the Person to standard out
  puts "Person is...\n #{p}"

  p.id = 1
  p.firstName = "Jack"
  p.lastName = "Handy"
  p.gender = "MALE"

  # prints modified Person to standard out
  puts "Person modified is...\n #{p}"

  puts "JSON sent to Server for Person with ID 1...\n #{p.to_json}"

  Net::HTTP.start(uri.hostname, uri.port) do |http|
    putRequest = Net::HTTP::Put.new uri.path, { "Content-Type" => "application/json" }
    putRequest.body = p.to_json
    http.request(putRequest)
  end

end

Output from running the Ruby client:

prompt# ruby restClient.rb
Hello, Ruby!
JSON read from Server for Person with ID 1...
 {
  "@type" : "org.gopivotal.app.domain.Person",
  "id" : 1,
  "firstName" : "Jane_updated",
  "middleName" : "H",
  "lastName" : "Doe_updated",
  "gender" : "MALE",
  "birthDate" : "04/12/1983"
}
Person is...
 { type = Person, id = 1, firstName = Jane_updated, middleName = H, lastName = Doe_updated, birthDate = 04/12/1983, gender = MALE}
Person modified is...
 { type = Person, id = 1, firstName = Jack, middleName = H, lastName = Handy, birthDate = 04/12/1983, gender = MALE}
JSON sent to Server for Person with ID 1...
 {"@type":"org.apache.geode.web.rest.domain.Person","id":1,"firstName":"Jack","middleName":"H","lastName":"Handy","birthDate":"04/12/1983","gender":"MALE"}

#3. Python REST Client (restClient.py)

This example uses Python 3 and shows the creation and modification of objects. It uses one external library called requests, which is nearly ubiquitous and avoids having to use HTTP code.

#!/usr/bin/env python3

# This is simple, repetitive and assumes you have created a region called
# "demoRegion".

import sys
import json
import uuid
import requests

REGION = "demoRegion"
BASE_URI = "http://localhost:8080/gemfire-api/v1"

headers = {'content-type': 'application/json'}

person = {'type': 'Person',
          'firstName': 'John',
          'middleName': 'Q',
          'lastName': 'Public',
          'birthDate': '1 Jan 1900'}


def resource_uri(res=None, region=REGION):
    if res:
        return "%s/%s/%s" % (BASE_URI, region, res)
    return "%s/%s" % (BASE_URI, region)


print("[*] First, we'll empty out our demo region - DELETE %s" %
      requests.delete(resource_uri()))

r = requests.delete(resource_uri())
r.raise_for_status()

print("[*] Now, we'll create 5 demo objects")

keys = []

for i in range(1, 6):
    key = uuid.uuid1()

    keys.append(key)
    person['uuid'] = str(key)

    print("\t Creating object with key: POST %s" % key)
    r = requests.post(resource_uri(), data=json.dumps(person),
                      params={'key': key},
                      headers=headers)
    r.raise_for_status()

print("[*] List our keys - GET %s" % resource_uri("keys"))

r = requests.get(resource_uri("keys"))
print(r.text)

print("[*] Here's all our data - GET %s" % resource_uri())

r = requests.get(resource_uri())
print(r.text)

print("[*] Now each key one by one")

for key in keys:
    print("Fetching key - GET %s" % resource_uri(res=key))
    r = requests.get(resource_uri(res=key))
    print(r.text)

print("[*] Now grab one, change the first name to 'Jane' and save it")

print("  GET - %s" % resource_uri(res=keys[0]))
r = requests.get(resource_uri(res=keys[0]))
p = json.loads(r.text)
p['firstName'] = 'Jane'
print("  PUT - %s" % resource_uri(res=keys[0]))
r = requests.put(resource_uri(res=keys[0]), data=json.dumps(p),
                 headers=headers)

print("  GET - %s" % resource_uri(res=keys[0]))
r = requests.get(resource_uri(res=keys[0]))
print(r.text)
check-circle-line exclamation-circle-line close-line
Scroll to top icon