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

org.unlaxer.tinyexpression.loader.FormulaInfoParser Maven / Gradle / Ivy

The newest version!
package org.unlaxer.tinyexpression.loader;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.unlaxer.Tag;
import org.unlaxer.Token;
import org.unlaxer.TokenPredicators;
import org.unlaxer.TypedToken;
import org.unlaxer.parser.Parser;
import org.unlaxer.parser.combinator.LazyOneOrMore;
import org.unlaxer.tinyexpression.Calculator;
import org.unlaxer.tinyexpression.evaluator.javacode.ClassNameAndByteCode;
import org.unlaxer.tinyexpression.evaluator.javacode.JavaCodeCalculatorV3;
import org.unlaxer.tinyexpression.evaluator.javacode.ResultType;
import org.unlaxer.tinyexpression.evaluator.javacode.SpecifiedExpressionTypes;
import org.unlaxer.tinyexpression.loader.FormulaInfoElementParser.KeyValue;
import org.unlaxer.tinyexpression.loader.model.CalculatorCreator;
import org.unlaxer.tinyexpression.loader.model.FormulaInfo;
import org.unlaxer.util.StringUtils;
import org.unlaxer.util.annotation.TokenExtractor;
import org.unlaxer.util.digest.HEX;
import org.unlaxer.util.function.Unchecked;

@SuppressWarnings("serial")
public class FormulaInfoParser extends LazyOneOrMore{
  
  public enum Kind{
    key,
    value
    ;
    public Tag tag() {
      return new Tag(this);
    }
  }
  
  @Override
  public Supplier getLazyParser() {
    return FormulaInfoElementOrCommentParser::new;
  }

  @Override
  public Optional getLazyTerminatorParser() {
    return Optional.empty();
//    return Optional.of(Parser.get(EndOfPartParser.class));
  }

  
  @TokenExtractor
  public static FormulaInfo extractFormulaInfo(TypedToken thisParserParsed , 
      FormulaInfoAdditionalFields formulaInfoAdditionalFields ,  ClassLoader classLoader){
    
    CalculatorCreator calculatorCreator = new CalculatorCreator() {
      
      @Override
      public Calculator create(String formulaText, String className, 
          SpecifiedExpressionTypes specifiedExpressionTypes, ClassLoader classLoader) {
        return new JavaCodeCalculatorV3(formulaText, className, 
            specifiedExpressionTypes, classLoader);
      }

      @Override
      public Calculator create(String formula, String javaCode, String className,
          SpecifiedExpressionTypes specifiedExpressionTypes, byte[] byteCode, String byteCodeHash,
          List classNameAndByteCodeList, ClassLoader classLoader) {
        return new JavaCodeCalculatorV3(formula, javaCode, className, specifiedExpressionTypes,
            byteCode, byteCodeHash, classNameAndByteCodeList, classLoader);
      }
    };
    
    FormulaInfo formulaInfo = new FormulaInfo(formulaInfoAdditionalFields , calculatorCreator);
    List elements = FormulaInfoElementOrCommentParser.elements(thisParserParsed);
    
    AtomicBoolean hasByteCode = new AtomicBoolean(false);
    for (Token token : elements) {

      String text = token.getToken().orElse("");
      formulaInfo.text.add(text);
      Parser parser = token.parser;
      if(parser instanceof FormulaInfoElementParser) {
        TypedToken typed = token.typed(FormulaInfoElementParser.class);
        FormulaInfoElementParser formulaInfoElementParser = typed.getParser();
        KeyValue keyValue = formulaInfoElementParser.extract(typed);
        
        boolean match = false;
        match |= set(keyValue, "tags", (value)->formulaInfo.tags.addAll(List.of(value.split(","))));
        match |= set(keyValue, "description", (value)->formulaInfo.description = value);
        match |= set(keyValue, "periodStartInclusive", (value)->formulaInfo.periodStartInclusive = value);
        match |= set(keyValue, "periodEndExclusive", (value)->formulaInfo.periodEndExclusive = value);
        match |= set(keyValue, "calculatorName", (value)->formulaInfo.calculatorName = value);
        match |= set(keyValue, "dependsOn", (value)->formulaInfo.dependsOn = value);
        match |= set(keyValue, "resultType", (value)->formulaInfo.resultType = new ResultType(value));
        match |= set(keyValue, "numberType", (value)->formulaInfo.numberType = new ResultType(value));
//        match |= set(keyValue, "outputTo", (value)->formulaInfo.outputTo = value);
        
        if(formulaInfoAdditionalFields.multiTenancyAttributeName().isPresent()) {
          match |= set(keyValue, formulaInfoAdditionalFields.multiTenancyAttributeName().get() /* "siteId" */, 
              (value)->formulaInfo.multiTenancyId = Optional.of(value));
          
        }
        
        for(String additional : formulaInfoAdditionalFields.additionalAttributeNames()) {
          
          match |= set(keyValue, additional , 
              (value)->formulaInfo.addAdditional(keyValue.key, value));
        }
        
        match |= set(keyValue, "hash", (value)->formulaInfo.hash = value);
        match |= set(keyValue, "hashByByteCode", (value)->formulaInfo.hashByByteCode = value);
        match |= set(keyValue, "formula", (value)->formulaInfo.formulaText = value);
        match |= set(keyValue, "javaCode", (value)->formulaInfo.javaCodeText = value);
        match |= set(keyValue, "byteCode", (value)->{
          formulaInfo.byteCodeAsHex = value;
          formulaInfo.byteCode = Unchecked.supplier(()->HEX.decode(value)).get();
          hasByteCode.set(true);
        });
        
        match |= setStartsWith(keyValue, "byteCode_", (value)->{
          String className = keyValue.key.substring("byteCode_".length());
          ClassNameAndByteCode classNameAndByteCode = 
              ClassNameAndByteCode.of(
                  className,
                  Unchecked.supplier(()->HEX.decode(value)).get()
              );
          
          formulaInfo.classNameAndByteCodeList.add(classNameAndByteCode);
        });

        
        if(match == false ) {
          formulaInfo.addAdditional(keyValue.getKey(), keyValue.getValue());
        }
      }
    }
    if(formulaInfo.resultType == null) {
      formulaInfo.resultType = new ResultType("float");
    }
    
    boolean formulaExists = StringUtils.isNoneBlank(formulaInfo.formulaText);
    boolean needsUpdate = formulaInfo.needsUpdate();
    if(needsUpdate && formulaExists) {
      formulaInfo.updateHash();
    }
    formulaInfo.updateClassName();
    
    if((false == hasByteCode.get() || needsUpdate) && formulaExists) {
      formulaInfo.updateCalculatorFromFormula(classLoader);
    }else {
//      System.out.println(new String(formulaInfo.byteCode));
      formulaInfo.updateCalculatorWithByteCode(classLoader);
    }
    return formulaInfo;
  }
  
  static boolean set(KeyValue keyValue , String targetKey , Consumer valueConsumer) {
    if(keyValue.getKey().equals(targetKey)) {
      valueConsumer.accept(keyValue.getValue());
      return true;
    }
    return false;
  }
  static boolean setStartsWith(KeyValue keyValue , String targetKey , Consumer valueConsumer) {
    if(keyValue.getKey().startsWith(targetKey)) {
      valueConsumer.accept(keyValue.getValue());
      return true;
    }
    return false;
  }
  
  @TokenExtractor
  public Map extract(TypedToken thisParserParsed){
    Map valueByKey = thisParserParsed.flatten().stream()
        .filter(TokenPredicators.parsers(FormulaInfoElementParser.class))
        .map(token->token.typed(FormulaInfoElementParser.class))
        .map(token->token.getParser().extract(token))
        .collect(Collectors.toMap(KeyValue::getKey,KeyValue::getValue));
    
    return valueByKey;
  }
  
  public static class FormulaInfoModifier{
    final String multiTenancyAttributeName;
    final String multiTenancyAttributeValue;
    
    final String formulaNameAttributeName;
    final String formulaNameAttributeValue;
    
    public FormulaInfoModifier(String multiTenancyAttributeName, String multiTenancyAttributeValue,
        String formulaNameAttributeName, String formulaNameAttributeValue) {
      super();
      this.multiTenancyAttributeName = multiTenancyAttributeName;
      this.multiTenancyAttributeValue = multiTenancyAttributeValue;
      this.formulaNameAttributeName = formulaNameAttributeName;
      this.formulaNameAttributeValue = formulaNameAttributeValue;
    }
    
    public FormulaInfoModifier(String formulaNameAttributeName, String formulaNameAttributeValue) {
      super();
      this.multiTenancyAttributeName = null;
      this.multiTenancyAttributeValue = null;
      this.formulaNameAttributeName = formulaNameAttributeName;
      this.formulaNameAttributeValue = formulaNameAttributeValue;
    }

    public Optional getMultiTenancyAttributeName() {
      return Optional.ofNullable(multiTenancyAttributeName);
    }

    public Optional getMultiTenancyAttributeValue() {
      return Optional.ofNullable(multiTenancyAttributeValue);
    }

    public String getFormulaNameAttributeName() {
      return formulaNameAttributeName;
    }

    public String getFormulaNameAttributeValue() {
      return formulaNameAttributeValue;
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy