All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.chargebee.internal.Resource Maven / Gradle / Ivy

There is a newer version: 3.26.0
Show newest version
package com.chargebee.internal;

import com.chargebee.Environment;
import com.chargebee.gdata.PercentEscaper;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.*;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.*;

/**
 * Base class for the ChargeBee model objects
 *
 * @param  The concrete type of the model
 */
public class Resource {

    private static final Logger logger = Logger.getLogger(Resource.class.getName());

    public JSONObject jsonObj;
    
    private static final String unknown = "_UNKNOWN";

    public Resource(JSONObject jsonObj){
        this.jsonObj = jsonObj;
    }

    public Resource(String jsonStr){
        try {
            jsonObj = new JSONObject(jsonStr);
        } catch(JSONException jexp) {
            throw new RuntimeException(jexp);
        }
    }

    public Resource(InputStream is) throws IOException {
        this(new BufferedReader(new InputStreamReader(is)));
    }

    public Resource(BufferedReader rd) throws IOException {
        this(getAsString(rd));
    }

    private static String getAsString(BufferedReader rd) throws IOException {
        StringBuilder buf = new StringBuilder();
        String line = null;
        while((line = rd.readLine()) != null) {
            buf.append(line);
        }
        return buf.toString();
    }

    public  String reqString(String key) {
        return assertReqProp(key, optString(key));
    }

    public String optString(String key) {
        return optional(key, String.class);
    }

    public Boolean reqBoolean(String key) {
        return assertReqProp(key, optBoolean(key));
    }

    public Boolean optBoolean(String key) {
        return optional(key, Boolean.class);
    }

    public Integer reqInteger(String key) {
        return assertReqProp(key, optInteger( key));
    }

    public Integer optInteger(String key) {
        Integer value = optional( key, Integer.class);
        try{
            return (value != null)? value : null;
        }catch(Exception ex){
            throw conversionException(key);
        }
    }
    
    public BigDecimal reqBigDecimal(String key) {
        return assertReqProp(key, optBigDecimal( key));
    }

    public BigDecimal optBigDecimal(String key) {
        BigDecimal value = optional( key, BigDecimal.class);
        try{
            return (value != null)? value : null;
        }catch(Exception ex){
            throw conversionException(key);
        }
    }

    public Double reqDouble(String key) {
        return assertReqProp(key, optDouble(key));
    }

    public Double optDouble(String key) {
        Double value = optional( key, Double.class);
        try{
            return (value != null)? value : null;
        }catch(Exception ex){
            throw conversionException(key);
        }
    }

    public Long reqLong(String key) {
        return assertReqProp(key, optLong( key));
    }

    public Long optLong(String key) {
        Object val = jsonObj.opt(key);
        if(val == null) {
            return null;
        }
        // special handling for Long. Accepting both Long and Integer values !!
        if(val instanceof Long) {
            return (Long)val;
        } else if(val instanceof Integer) {
            return ((Integer)val).longValue();
        } else {
            throw new RuntimeException("Wrong type. Expecing Long type but got "
                    + val.getClass().getSimpleName());
        }
    }

    public JSONObject reqJSONObject(String key){
        return assertReqProp(key, optJSONObject(key));
    }

    public JSONObject optJSONObject(String key){
        return optional(key,JSONObject.class);
    }
    
    public JSONArray reqJSONArray(String key){
        return assertReqProp(key, optJSONArray(key));
    }
    
    public JSONArray optJSONArray(String key){
        return optional(key,JSONArray.class);
    }

    public Timestamp reqTimestamp(String key) {
        return assertReqProp(key, optTimestamp( key));
    }

    public Timestamp optTimestamp(String key) {
        Long unxTime = optLong(key);
        return (unxTime != null)? new Timestamp(unxTime * 1000l) : null;
    }

    public  E reqEnum(String key, Class enumClass) {
        return assertReqProp(key, optEnum(key, enumClass));
    }

    public  E optEnum(String key, Class enumClass) {
        String value = optString(key);
        if(value == null) {
            return null;
        }
        try {
           return (E) Enum.valueOf(enumClass, value.toUpperCase());
        }catch(Exception ex){
           logger.log(Level.SEVERE, " The property {0} has unexpected value {1}", new Object[]{key, value});
           return (E) Enum.valueOf(enumClass, unknown);
        }
    }

    /**
     * @param  The sub-resource type
     */
    public  List reqList(String key,Class claz) {
        List list = optList(key, claz);
        if(list.isEmpty()) {
            throw new RuntimeException("The sub-resource [" + key + "] is not present");
        }
        return list;
    }

    /**
     * @param  The sub-resource type
     */
    public  List optList(String key, Class claz){
        JSONArray arr = jsonObj.optJSONArray(key);
        if(arr == null){
            return Collections.EMPTY_LIST;
        }

        List toRet = new ArrayList(arr.length());
        for (int i = 0; i < arr.length(); i++) {
            if(claz == String.class){
              toRet.add((S)arr.optString(i));
            }else if(Number.class.isAssignableFrom(claz)){
              String s = arr.optString(i);
              if(s == null){
                  toRet.add(null);
              }else{
                  toRet.add(ClazzUtil.createNumberInstance(claz,s));
              }
            }else{
              JSONObject json = arr.optJSONObject(i);
              toRet.add(ClazzUtil.createInstance(claz, json));
            }
        }
        return toRet;
    }

    public  S reqSubResource(String key, Class claz) {
        return assertReqProp(key, optSubResource(key, claz));
    }

    public  S optSubResource(String key, Class claz){
        JSONObject resAsJson = jsonObj.optJSONObject(key);
        if(resAsJson == null){
            return null;
        }

        return ClazzUtil.createInstance(claz, resAsJson);
    }


    private  T optional(String key, Class type) {
        Object val = jsonObj.opt(key);
        if(val == null) {
            return null;
        }
        if(!type.isAssignableFrom(val.getClass())){
            //JSON returns Integer values if the string format is without decimal points
            // Like 10  instead of 10.0 
            if(BigDecimal.class == type && val instanceof Number){
                return (T) new BigDecimal(String.valueOf(val));
            }
            if(Double.class == type && val instanceof Number){
                return (T) new Double(((Number)val).doubleValue());
            }
            if(Float.class == type && val instanceof Number){
                return (T) new Float(((Number)val).floatValue());
            }
            if(BigDecimal.class == type) {
                if (val instanceof Number) {
                    return (T) new BigDecimal(((Number)val).doubleValue());
                }
                if (val instanceof String) {
                    return (T) new BigDecimal(((String)val));
                }
            }
            throw new RuntimeException("Type mismatch for property " + key
                    + " . Expected " + type.getName() + " but contains " + val.getClass().getName());
        }
        return (T)val;
    }

    public String toJson() {
        return jsonObj.toString();
    }

    @Override
    public String toString() {
        try {
            return jsonObj.toString(2);
        } catch (JSONException ex) {
            throw new RuntimeException(ex);
        }
    }

    // util methods
    //=============

    private  T assertReqProp(String key,T val) {
        if(val == null){
            throw new RuntimeException("The property [" + key + "] is not present ");
        }
        return val;
    }

    private RuntimeException conversionException(String key){
        return new RuntimeException("The property " + key + " not in the required format");
    }

    protected static String nullCheck(String id) {
        if(id == null || id.isEmpty()) {
            throw new RuntimeException("id cannot be null/empty");
        }
        return id;
    }

    protected static String nullCheckWithoutEncoding(String id) {
        //encoding not needed when we are considering this param to be sent in body
        if(id == null || id.isEmpty()) {
            throw new RuntimeException("id cannot be null/empty");
        }
        return id;
    }

    protected static String uri(String ... paths){
        StringBuilder strBuf = new StringBuilder();
        for (String path : paths) {
            try {//Using URLEncoder is wrong as it encodes for form. Replace it with Google's CharEscapers.java
                strBuf.append('/').append(new PercentEscaper(PercentEscaper.SAFEPATHCHARS_URLENCODER, false) .escape(path));
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
        return strBuf.toString();
    }   
    
    protected static void apiVersionCheck(JSONObject jsonObj) {
        if (!jsonObj.has("api_version")) {
            return;
        }
        String apiVersion = jsonObj.optString("api_version");
        if (apiVersion != null && !jsonObj.optString("api_version").equalsIgnoreCase(Environment.API_VERSION)) {
            throw new RuntimeException("API version [" + apiVersion.toUpperCase() + "] in response does not match "
                    + "with client library API version [" + Environment.API_VERSION.toUpperCase() + "]");
        }
    }

}