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

com.linkedin.restli.client.config.RequestConfigElement Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
package com.linkedin.restli.client.config;

import java.util.Optional;
import java.util.function.BiFunction;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.TerminalNode;

import com.linkedin.restli.client.config.RequestConfigKeyParser.InboundContext;
import com.linkedin.restli.client.config.RequestConfigKeyParser.KeyContext;
import com.linkedin.restli.client.config.RequestConfigKeyParser.OperationInContext;
import com.linkedin.restli.client.config.RequestConfigKeyParser.OperationOutContext;
import com.linkedin.restli.client.config.RequestConfigKeyParser.OutboundContext;
import com.linkedin.restli.client.config.RequestConfigKeyParser.RestResourceContext;
import com.linkedin.restli.common.ResourceMethod;


class RequestConfigElement implements Comparable {

  private final String _key;
  private final Object _value;
  private final String _property;
  private final Optional _inboundName;
  private final Optional _outboundName;
  private final Optional _inboundOpName;
  private final Optional _outboundOpName;
  private final Optional _inboundOp;
  private final Optional _outboundOp;

  private RequestConfigElement(String key, Object value, String property, Optional inboundName,
      Optional outboundName, Optional inboundOpName, Optional outboundOpName,
      Optional inboundOp, Optional outboundOp) {
    _key = key;
    _value = value;
    _property = property;
    _inboundName = inboundName;
    _outboundName = outboundName;
    _inboundOpName = inboundOpName;
    _outboundOpName = outboundOpName;
    _inboundOp = inboundOp;
    _outboundOp = outboundOp;
  }

  public String getKey() {
    return _key;
  }

  public Object getValue() {
    return _value;
  }

  public String getProperty() {
    return _property;
  }

  public Optional getInboundName() {
    return _inboundName;
  }

  public Optional getOutboundName() {
    return _outboundName;
  }

  public Optional getInboundOpName() {
    return _inboundOpName;
  }

  public Optional getOutboundOpName() {
    return _outboundOpName;
  }

  public Optional getInboundOp() {
    return _inboundOp;
  }

  public Optional getOutboundOp() {
    return _outboundOp;
  }

  private static Optional handlingWildcard(RestResourceContext resourceContext) {
    if (resourceContext == null) {
      return Optional.empty();
    } else {
      return Optional.of(resourceContext.getText());
    }
  }

  private static Optional handlingWildcard(TerminalNode input) {
    if (input == null) {
      return Optional.empty();
    } else {
      return Optional.of(input.getText());
    }
  }

  static RequestConfigElement parse(String property, String key, Object value) throws RequestConfigKeyParsingException {
    RequestConfigKeyParsingErrorListener errorListener = new RequestConfigKeyParsingErrorListener();
    ANTLRInputStream input = new ANTLRInputStream(key);
    RequestConfigKeyLexer lexer = new RequestConfigKeyLexer(input);
    lexer.removeErrorListeners();
    lexer.addErrorListener(errorListener);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    RequestConfigKeyParser parser = new RequestConfigKeyParser(tokens);
    parser.removeErrorListeners();
    parser.addErrorListener(errorListener);
    KeyContext keyTree = parser.key();

    if (!errorListener.hasErrors()) {
      InboundContext inbound = keyTree.inbound();
      OutboundContext outbound = keyTree.outbound();
      Optional inboundName = handlingWildcard(inbound.restResource());
      Optional outboundName = handlingWildcard(outbound.restResource());
      Optional inboundOp = getOpIn(inbound.operationIn());
      Optional outboundOp = getOpOut(outbound.operationOut());
      Optional inboundOpName = inboundOp.flatMap(method -> getOpInName(method, inbound.operationIn()));
      Optional outboundOpName = outboundOp.flatMap(method -> getOpOutName(method, outbound.operationOut()));

      return new RequestConfigElement(key, coerceValue(property, value), property, inboundName, outboundName,
          inboundOpName, outboundOpName, inboundOp, outboundOp);

    } else {
      throw new RequestConfigKeyParsingException(
          "Error" + ((errorListener.errorsSize() > 1) ? "s" : "") + " parsing key: " + key + "\n" + errorListener);
    }
  }

  private static Object coerceValue(String property, Object value) throws RequestConfigKeyParsingException {
    try {
      switch(property) {
        case "timeoutMs":
          return ConfigValueCoercers.LONG.apply(value);
        case "batchingEnabled":
          return ConfigValueCoercers.BOOLEAN.apply(value);
        case "maxBatchSize":
          return ConfigValueCoercers.INTEGER.apply(value);
        default:
          throw new RequestConfigKeyParsingException("Internal error: parsed config contains unsupported property: " + property);
      }
    } catch (Exception e) {
      throw new RequestConfigKeyParsingException(e);
    }
  }

  private static Optional getOpOutName(ResourceMethod method, OperationOutContext operation) {
    if (method == ResourceMethod.ACTION || method == ResourceMethod.FINDER) {
      return handlingWildcard(operation.complex().Name());
    } else {
      return Optional.empty();
    }
  }

  private static Optional getOpOut(OperationOutContext operation) {
    if (operation == null) {
      return Optional.empty();
    } else {
      if (operation.simpleOp() != null) {
        return Optional.of(ResourceMethod.fromString(operation.simpleOp().getText()));
      } else {
        return Optional.of(ResourceMethod.fromString(operation.complex().complexOp().getText()));
      }
    }
  }

  private static Optional getOpInName(String method, OperationInContext operation) {
    if (method.equals(ResourceMethod.ACTION.toString().toUpperCase()) || method.equals(ResourceMethod.FINDER.toString().toUpperCase())) {
      return handlingWildcard(operation.complex().Name());
    } else {
      return Optional.empty();
    }
  }

  private static Optional getOpIn(OperationInContext operation) {
    if (operation == null) {
      return Optional.empty();
    } else {
      if (operation.simpleOp() != null) {
        return Optional.of(operation.simpleOp().getText());
      } else if (operation.complex() != null) {
        return Optional.of(operation.complex().complexOp().getText());
      } else {
        return Optional.of(operation.httpExtraOp().getText());
      }
    }
  }

  private static Integer compare(Optional e1, Optional e2) {
    if (e1.isPresent() && !e2.isPresent()) {
      return -1;
    } else if (!e1.isPresent() && e2.isPresent()) {
      return 1;
    } else {
      return 0;
    }
  }

  private static BiFunction chain(
      BiFunction f1,
      BiFunction f2) {
    return (e1, e2) -> {
      int f1Result = f1.apply(e1, e2);
      if (f1Result != 0) {
        return f1Result;
      } else {
        return f2.apply(e1, e2);
      }
    };
  }

  @Override
  public int compareTo(RequestConfigElement o) {
    return
      chain(
          chain(
              chain(
                  chain(
                      chain(
                          (e1, e2) -> compare(e1._outboundName, e2._outboundName),
                          (e1, e2) -> compare(_inboundName, o._inboundName)),
                      (e1, e2) -> compare(_outboundOp.map(ResourceMethod::toString), o._outboundOp.map(ResourceMethod::toString))),
                  (e1, e2) -> compare(_outboundOpName, o._outboundOpName)),
              (e1, e2) -> compare(_inboundOp, o._inboundOp)),
          (e1, e2) -> compare(_inboundOpName, o._inboundOpName))
      .apply(this, o);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy