Skip to content

Rest apis with gson and rest GET call example #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions Concurrency/SharedState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SharedState {
// shared resource
private volatile int data;
// lock for the resource
ReadWriteLock rwLock = new ReentrantReadWriteLock();

private static final int READ_CYCLES = (int)1e8;
private static final int WRITE_CYCLES = (int)1e8;

public SharedState(int initialData) {
this.data = initialData;
}

/**
* Retrieves the data from a private static variable.
* Representing a shared resource
*
* @return The data value stored
*/
private int getData() {
rwLock.readLock().lock();
try {
return data;
} finally {
rwLock.readLock().unlock();
}
}

/**
* Updates the value of the private static variable 'data'.
*/
private void updateData() {
rwLock.writeLock().lock();
try {
data += 1;
} finally {
rwLock.writeLock().unlock();
}

}

public static void main(String ...args) throws InterruptedException {
final long startTime = System.nanoTime();
SharedState sharedState = new SharedState(0);
Thread readerThread = new Thread(new Runnable() {
@Override
public void run() {
for(int cycles = 0; cycles < READ_CYCLES; cycles++) {
int value = sharedState.getData();
// to keep I/O low to influence perf
if(cycles % (READ_CYCLES/10) == 0){
System.out.println("read: " + value);
System.out.flush();
}
}
}
});
Thread writerThread = new Thread(new Runnable() {
@Override
public void run() {
for(int cycles = 0; cycles < WRITE_CYCLES; cycles++) {
sharedState.updateData();
int value = sharedState.getData();
if(cycles % (WRITE_CYCLES/10) == 0){
System.out.println("post write: " + value);
System.out.flush();
}
}
}
});
readerThread.start();
writerThread.start();
readerThread.join();
writerThread.join();
final long duration = System.nanoTime() - startTime;
System.out.println("time taken(ns): " + duration);
}
}
63 changes: 63 additions & 0 deletions REST/Hotel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import com.google.gson.annotations.SerializedName;
/*
* Entity class to represent City
* with natural ordering of rating when compared
*/

public class Hotel implements Comparable<Hotel> {
// inner class for rating
class UserRating implements Comparable<UserRating>{
@SerializedName("average_rating")
double averageRating;
int votes;

public UserRating(double averageRating, int votes){
this.averageRating = averageRating;
this.votes = votes;
}

@Override
public int compareTo(UserRating other){
if(this.averageRating == other.averageRating){
return Integer.compare(this.votes, other.votes);
}
return Double.compare(this.averageRating, other.averageRating);
}

@Override
public String toString() {
return "{averageRating:" + this.averageRating + ",votes:" + votes + "}";
}
}

String id;
String city;
String name;

@SerializedName("estimated_cost")
double estimatedCost;

@SerializedName("user_rating")
UserRating userRating;

public Hotel(String id, String name, String city, UserRating rating) {
this.id = id;
this.name = name;
this.city = city;
this.userRating = rating;
}

@Override
public int compareTo(Hotel other){
if(this.estimatedCost == other.estimatedCost){
return this.userRating.compareTo(userRating);
}
return Double.compare(this.estimatedCost, other.estimatedCost);
}

@Override
public String toString() {
return "\nHotel id:" + id + ",name:" + name + ",city:"+ city + ",estimatedCost:" + estimatedCost
+ ",userRating:" + userRating;
}
}
24 changes: 24 additions & 0 deletions REST/HotelPage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Entity to hold per page api response from GET hotels API calls
*/
public class HotelPage {

int page;

@SerializedName("per_page")
int perPage;

int total;

@SerializedName("total_pages")
int totalPages;

List<Hotel> data;

@Override
public String toString() {
return "\nHotelPage page:" + page + ",per_page:" + perPage + ",total:" + total + ",total_pages:" + totalPages + ",data:" + data;
}
}
5 changes: 5 additions & 0 deletions REST/READ.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Compile and Run instruction from current directory:
<code>
javac -cp lib/gson-2.2.2.jar:. RestWithGson.java
java -cp lib/gson-2.2.2.jar:. RestWithGson
</code>
108 changes: 108 additions & 0 deletions REST/RestWithGson.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.PriorityQueue;
import java.util.List;
import java.util.LinkedList;
import java.util.UUID;

import com.google.gson.Gson;

/*
* GET API: https://jsonmock.hackerrank.com/api/food_outlets?page={page_no}
*/

public class RestWithGson {
final String BASE_URL = "https://jsonmock.hackerrank.com";
final int TIMEOUT_MILLISEC = (int)1e3; // 1 sec timeout

PriorityQueue<Hotel> getTopHotels(int top){
PriorityQueue <Hotel> topHotels = new PriorityQueue<Hotel>();
// MAX Bounded Queue of Size `top`
int currentPage = 0;
int maxPages = 1;
// todo: currently flow is sequential one by one page
// we can spawn new thread pool of size K to get data to reduce overall network time
// to MAX_PAGES/K
while(currentPage < maxPages){
HotelPage currentSetOfHotels = getCurrentPage(currentPage);
maxPages = currentSetOfHotels.totalPages;
if(currentSetOfHotels.data != null && currentSetOfHotels.data.size() == 0){
System.out.println("empty data\n"); //todo: retry to get current page with exponential backoff
break;
}
add(currentSetOfHotels.data, topHotels, top);
currentPage++;
}
return topHotels;
}

// make a network get call to get the current page data
// and add it to queue as rolling window
HotelPage getCurrentPage(int page){
String route = BASE_URL + "/api/food_outlets?page=" + page;
try {
URL url = new URL(route);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET"); // anyway default it get but specifying it improves
// code readibility
connection.setConnectTimeout(TIMEOUT_MILLISEC);
if(connection.getResponseCode() == 200){
BufferedReader response = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder responseBuilder = new StringBuilder();
String line = null;
while((line = response.readLine()) != null){
responseBuilder.append(line);
}
return parseStringToCities(responseBuilder.toString());
}
} catch (Exception exception){
System.out.println(exception);
return null;
}
return null;
}

// deserialize text to object
HotelPage parseStringToCities(String responseText){
// using gson to cast into
Gson deserializer = new Gson();
return deserializer.fromJson(responseText, HotelPage.class);
}

// adding to bounded queue
// add time: O(log `top`), space: O(top)
void add(List<Hotel> currentSetOfHotels, PriorityQueue<Hotel> topHotels, int top) {
for(Hotel hotel: currentSetOfHotels){
// to ensure heap having at least `top` elements
if(topHotels.size() < top){
topHotels.add(hotel);
continue;
}
// re-balancing heap in log n
topHotels.add(hotel);
topHotels.poll(); // todo: we can maintain maxHeap instad of minHeap
// and we can check top element in O(1) and avoid everytime rebalancing heap
// although it does not impact time complexity but a very good perf improvement
}
}

void run()throws Exception{
PriorityQueue<Hotel> topHotels = getTopHotels(10);
while(!topHotels.isEmpty()) {
System.out.println("top hotel:" + topHotels.poll());
}
}

public static void main(String[] args) throws Exception{
RestWithGson driver = new RestWithGson();
driver.run();
driver.closeResources();
}

private void closeResources(){
System.out.flush();
// clear up class level resources like io, dbconnections etc.
}
}
Binary file added REST/lib/gson-2.2.2.jar
Binary file not shown.