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

com.clarifai.channel.JsonEndpoint Maven / Gradle / Ivy

The newest version!
package com.clarifai.channel;

import com.google.api.HttpRule;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.protobuf.Descriptors;
import io.grpc.MethodDescriptor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class JsonEndpoint {

  class Endpoint {
    private final String method;
    private final String url;
    private final ArrayList urlFields;

    Endpoint(String method, String url, ArrayList urlFields) {
      this.method = method;
      this.url = url;
      this.urlFields = urlFields;
    }

    public String getMethod() {
      return method;
    }

    public String getUrl() {
      return url;
    }

    public ArrayList getUrlFields() {
      return urlFields;
    }
  }

  private final MethodDescriptor methodDescriptor;

  /**
   * The request JSON object.
   */
  private final JsonObject request;

  /**
   * The request object as a hash map.
   */
  private final HashMap requestMap = new HashMap<>();

  private static final Pattern URL_FIELDS_PATTERN = Pattern.compile("\\{(.*?)\\}");


  JsonEndpoint(MethodDescriptor methodDescriptor, JsonObject request) {
    this.methodDescriptor = methodDescriptor;
    this.request = request;

    for (Map.Entry entry : request.entrySet()) {
      requestMap.put(entry.getKey(), entry.getValue());
    }
  }

  /**
   * Fills in the url template with the actual url params from the request body.
   * Picks the most appropriate url depending on which parameters are present in the request body.
   *
   * @return The most proper HTTP endpoint, out of those available.
   */
  Endpoint pickProperEndpoint() {
    Object schemaDescriptor = methodDescriptor.getSchemaDescriptor();

    Method m;
    try {
      m = schemaDescriptor.getClass().getMethod("getMethodDescriptor");
    } catch (SecurityException | NoSuchMethodException e) {
      throw new RuntimeException(e);
    }

    m.setAccessible(true);

    com.google.protobuf.Descriptors.MethodDescriptor schemaMethodDescriptor;
    try {
      schemaMethodDescriptor = (Descriptors.MethodDescriptor) m.invoke(schemaDescriptor);
    } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
      throw new RuntimeException(e);
    }

    Set> allFields = schemaMethodDescriptor
        .getOptions().getAllFields().entrySet();

    for (Map.Entry pair : allFields) {

      if (pair.getValue().getClass() == HttpRule.class) {
        HttpRule rule = (HttpRule) pair.getValue();

        String bestMatchUrl = null;
        String bestMatchMethod = null;
        ArrayList bestMatchUrlFields = null;
        int bestMatchCount = -1;

        String appId;
        String userId;

        String[] ids = readAppIdAndUserId(request);
        if (ids.length == 2) {
          appId = ids[0];
          userId = ids[1];
        } else {
          appId = null;
          userId = null;
        }

        ArrayList allRules = new ArrayList() {{
          add(rule);
          addAll(rule.getAdditionalBindingsList());
        }};

        for (HttpRule httpRule : allRules) {
          String method = httpRule.getPatternCase().name();

          String urlTemplate = url(httpRule, method);

          Matcher matcher = URL_FIELDS_PATTERN.matcher(urlTemplate);

          boolean allArgumentsTranslated = true;
          int count = 0;

          String url = urlTemplate;

          ArrayList urlFields = new ArrayList<>();
          while (matcher.find()) {
            String field = matcher.group(1);

            String[] parts = field.split("\\.");
            String fieldName = parts[parts.length - 1];

            String value;
            if (fieldName.equals("app_id")) {
              if (appId == null) {
                allArgumentsTranslated = false;
                break;
              }

              value = appId;
            } else if (fieldName.equals("user_id")) {
              if (userId != null) {
                value = userId;
              } else {
                // "me" is the alias for the ID of the authorized user.
                value = "me";
              }
            } else {
              if (!requestMap.containsKey(fieldName)) {
                allArgumentsTranslated = false;
                break;
              }
              value = requestMap.get(fieldName).getAsString();
            }

            url = url.replace("{" + field + "}", value);
            urlFields.add(field);

            count++;
          }

          if (allArgumentsTranslated && bestMatchCount < count) {
            bestMatchUrl = url;
            bestMatchMethod = method;
            bestMatchCount = count;
            bestMatchUrlFields = urlFields;
          }
        }

        if (bestMatchUrl != null) {
          return new Endpoint(bestMatchMethod, bestMatchUrl, bestMatchUrlFields);
        }
      }
    }

    throw new RuntimeException("Unable to find an appropriate HTTP endpoint");
  }

  /**
   * @return ["app_id", "user_id"] values if they are present, or empty array. If only "app_id" is
   *         present, "user_id" is set to 'me'.
   */
  private String[] readAppIdAndUserId(JsonElement element) {
      if (element.isJsonArray()) {
        for (JsonElement e : element.getAsJsonArray()) {
          String[] vals = readAppIdAndUserId(e);
          if (vals.length == 2) {
            return vals;
          }
        }
      } else if (element.isJsonObject()) {
        for (Map.Entry entry : element.getAsJsonObject().entrySet()) {
          String key = entry.getKey();
          JsonElement value = entry.getValue();
          if (key.equals("user_app_id")) {
              String[] result = new String[2];
              JsonObject userAppId = value.getAsJsonObject();
              result[0] = userAppId.get("app_id").getAsString();
              result[1] = userAppId.has("user_id") ? userAppId.get("user_id").getAsString() : "me";
              return result;
          } else if (key.equals("apps")) {
            JsonArray apps = value.getAsJsonArray();
            if (apps.size() == 1) {
              String[] result = new String[2];
              JsonObject app = apps.get(0).getAsJsonObject();
              result[0] = app.get("id").getAsString();
              result[1] = app.has("user_id") ? app.get("user_id").getAsString() : "me";
              return result;
            } else if (apps.size() == 0) {
              return new String[0];
            } else {
              throw new ClarifaiException("Only one app is supported at this time.");
            }
          } else if (key.equals("metadata")) {
            continue;
          }
          String[] vals = readAppIdAndUserId(value);
          if (vals.length == 2) {
            return vals;
          }
        }
      }
      return new String[0];
  }

  private String url(HttpRule httpRule, String method) {
    String urlTemplate;
    switch (method) {
      case "GET": {
        urlTemplate = httpRule.getGet();
        break;
      }
      case "POST": {
        urlTemplate = httpRule.getPost();
        break;
      }
      case "PATCH": {
        urlTemplate = httpRule.getPatch();
        break;
      }
      case "DELETE": {
        urlTemplate = httpRule.getDelete();
        break;
      }
      default: {
        throw new ClarifaiException("Unhandled method " + method);
      }
    }
    return urlTemplate;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy