com.d3x.morpheus.wb.WBLoader Maven / Gradle / Ivy
/*
* Copyright (C) 2014-2018 D3X Systems - All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.d3x.morpheus.wb;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.d3x.morpheus.util.http.HttpClient;
import com.d3x.morpheus.wb.entity.WBCatalog;
import com.d3x.morpheus.wb.entity.WBCity;
import com.d3x.morpheus.wb.climate.WBClimate;
import com.d3x.morpheus.wb.entity.WBCountry;
import com.d3x.morpheus.wb.entity.WBIncomeLevel;
import com.d3x.morpheus.wb.entity.WBIndicator;
import com.d3x.morpheus.wb.entity.WBLendingType;
import com.d3x.morpheus.wb.entity.WBRegion;
import com.d3x.morpheus.wb.entity.WBSource;
import com.d3x.morpheus.wb.entity.WBTopic;
/**
* A helper class used to load JSON content from the World Bank
*
* @author Xavier Witdouck
*
* This is open source software released under the Apache 2.0 License
*/
public class WBLoader {
private Class> type;
/**
* Constructor
*/
public WBLoader() {
this(null);
}
/**
* Constructor
* @param type the type for this loader
*/
public WBLoader(Class> type) {
this.type = type;
}
/**
* A generic method to load JSON content for various World Bank API calls
* @param url the World Bank API get request URL
* @param messageHandler the function that turns JSON into some object representation
* @param the data type for the response message
* @return the resulting response
* @throws WBException if there is some access processing the request
*/
public WBResponse load(String url, Function messageHandler) throws WBException {
return HttpClient.getDefault().>doGet(request -> {
final long t1 = System.currentTimeMillis();
request.setUrl(url);
request.setRetryCount(3);
request.setResponseHandler(response -> {
try {
if (response.getStatus().getCode() == 200) {
final Gson gson = builder().create();
final JsonReader reader = createReader(response.getStream());
final WBHeader header = parseHeader(reader, gson);
final T body = messageHandler.apply(reader);
final long t2 = System.currentTimeMillis();
System.out.println("World Bank request " + url + " completed in " + (t2-t1) + " millis");
return Optional.of(new WBResponse<>(header, body));
} else {
throw new WBException("World Bank API responded with status code: " + response.getStatus() + " to " + url);
}
} catch (WBException ex) {
throw ex;
} catch (Exception ex) {
throw new WBException("", ex);
}
});
}).orElseThrow(() -> {
return new WBException("No data generated from World Bank APi request: " + url);
});
}
/**
* Parses the header in the JSON message
* @param reader the JSON reader
* @param gson the GSON engine
* @return the header for message
* @throws IOException if I/O exception
*/
private WBHeader parseHeader(JsonReader reader, Gson gson) throws IOException {
if (type == WBCatalog.class) {
int pageNumber = -1;
int pageCount = -1;
String recordCount = "0";
int totalRecords = -1;
final AtomicInteger itemCount = new AtomicInteger();
reader.beginObject();
while (itemCount.get() < 5) {
itemCount.incrementAndGet();
final String name = reader.nextName().toLowerCase();
switch (name) {
case "page": pageNumber = reader.nextInt(); break;
case "pages": pageCount = reader.nextInt(); break;
case "per_page": recordCount = reader.nextString(); break;
case "total": totalRecords = reader.nextInt(); break;
case "datacatalog": reader.beginArray(); break;
default: throw new IllegalStateException("Unexpected attribute in json: " + name);
}
}
return new WBHeader(pageNumber, pageCount, Integer.parseInt(recordCount), totalRecords);
} else {
if (reader.peek() == JsonToken.NULL) {
return gson.fromJson(reader, WBHeader.class);
} else {
reader.beginArray();
final WBHeader header = gson.fromJson(reader, WBHeader.class);
if (reader.peek() == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
}
return header;
}
}
}
/**
* Returns a newly created GsonBuilder initialized with World Bank Serializers
* @return the newly created Gson Builder
*/
public GsonBuilder builder() {
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(WBTopic.class, new WBTopic.Deserializer());
builder.registerTypeAdapter(WBSource.class, new WBSource.Deserializer());
builder.registerTypeAdapter(WBIndicator.class, new WBIndicator.Deserializer());
builder.registerTypeAdapter(WBCity.class, new WBCity.Deserializer());
builder.registerTypeAdapter(WBRegion.class, new WBRegion.Deserializer());
builder.registerTypeAdapter(WBLendingType.class, new WBLendingType.Deserializer());
builder.registerTypeAdapter(WBIncomeLevel.class, new WBIncomeLevel.Deserializer());
builder.registerTypeAdapter(WBCountry.class, new WBCountry.Deserializer());
builder.registerTypeAdapter(WBHeader.class, new WBHeader.Deserializer());
builder.registerTypeAdapter(WBCatalog.Item.class, new WBCatalog.ItemDeserializer());
builder.registerTypeAdapter(WBClimate.MonthlyRecord.class, new WBClimate.MonthlyRecordDeserializer());
return builder;
}
/**
* Returns a newly created JsonReader
* @param is the input stream
* @return the JsonReader
* @throws IOException if there is an I/O exception
*/
public JsonReader createReader(InputStream is) throws IOException {
final String encoding = "UTF-8";
if (is instanceof BufferedInputStream) {
return new JsonReader(new InputStreamReader(is, encoding));
} else {
return new JsonReader(new InputStreamReader(new BufferedInputStream(is), encoding));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy