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

io.resys.hdes.client.spi.decision.ast.CommandMapper Maven / Gradle / Ivy

There is a newer version: 3.130.78
Show newest version
package io.resys.hdes.client.spi.decision.ast;

/*-
 * #%L
 * hdes-client-api
 * %%
 * Copyright (C) 2020 - 2022 Copyright 2020 ReSys OÜ
 * %%
 * 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.
 * #L%
 */

import io.resys.hdes.client.api.HdesClient.HdesTypesMapper;
import io.resys.hdes.client.api.ast.AstBody.AstBodyType;
import io.resys.hdes.client.api.ast.*;
import io.resys.hdes.client.api.ast.AstDecision.AstDecisionRow;
import io.resys.hdes.client.api.ast.AstDecision.ColumnExpressionType;
import io.resys.hdes.client.api.ast.AstDecision.HitPolicy;
import io.resys.hdes.client.api.ast.TypeDef.Direction;
import io.resys.hdes.client.api.ast.TypeDef.ValueType;
import io.resys.hdes.client.api.exceptions.DecisionAstException;
import io.resys.hdes.client.api.programs.ExpressionProgram;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class CommandMapper {
  private final static List headerTypes = Collections.unmodifiableList(
      Arrays.asList(ValueType.STRING,  ValueType.BOOLEAN, ValueType.INTEGER, ValueType.LONG, ValueType.DECIMAL, ValueType.DATE, ValueType.DATE_TIME).stream()
      .map(v -> v.name()).collect(Collectors.toList()));
  
  private final static Map> headerExpressions = Collections.unmodifiableMap(Map.of(
      ValueType.INTEGER, Collections.unmodifiableList(Arrays.asList(ColumnExpressionType.EQUALS.name())),
      ValueType.DECIMAL, Collections.unmodifiableList(Arrays.asList(ColumnExpressionType.EQUALS.name())),
      ValueType.STRING, Collections.unmodifiableList(Arrays.asList(ColumnExpressionType.IN.name()))    
  ));
  private final static List dynamocValueExpressions = Collections.unmodifiableList(Arrays.asList("<=", "<",">=", ">", "="));

  private static Object parseVariable(String expression, ValueType type) {
    Optional comparison = dynamocValueExpressions.stream().filter(v -> expression.startsWith(v)).findFirst();
    if(!comparison.isPresent()) {
      switch(type) {
      case DECIMAL:
        return BigDecimal.ZERO;
      case LONG:
        return 0;
      case INTEGER:
        return 0;
      default: return null;
      }
    }
    String value = expression.substring(comparison.get().length()).trim();
    switch(type) {
    case DECIMAL:
      return new BigDecimal(value);
    case LONG:
      return Long.parseLong(value);
    case INTEGER:
      return Integer.parseInt(value);
    default: return null;
    }
  }
  
  public static Builder builder(HdesTypesMapper dataTypeFactory) {
    return new Builder(dataTypeFactory);
  }

  public static class Builder {
    private final HdesTypesMapper typeDefs; 
    private String name;
    private String description;
    private HitPolicy hitPolicy;
    private final IdFixer idGen = new IdFixer();

    public Builder(HdesTypesMapper dataTypeFactory) {
      super();
      this.typeDefs = dataTypeFactory;
    }
    private ValueType getValueType(MutableHeader header) {
      return header.getValue();
    }
    public Builder name(String name) {
      this.name = name;
      return this;
    }
    public Builder description(String description) {
      this.description = description;
      return this;
    }
    public Builder hitPolicy(HitPolicy hitPolicy) {
      this.hitPolicy = hitPolicy;
      return this;
    }
    public Map.Entry addHeader(Direction direction, String name) {
      MutableHeader header = idGen.addHeader()
          .setDirection(direction)
          .setName(name)
          .setValue(ValueType.STRING);
      return new AbstractMap.SimpleImmutableEntry(header.getId(), this);
    }
    public Builder changeHeaderType(String id, String value) {
      try {
        idGen.getHeader(id).setValue(ValueType.valueOf(value));
      } catch(Exception e) {
        idGen.getHeader(id).setValue(null);
      }
      
      return this;
    }
    public Builder changeHeaderScript(String id, String value) {
      idGen.getHeader(id).setScript(value);
      return this;
    }
    public Builder changeHeaderName(String id, String value) {
      idGen.getHeader(id).setName(value);
      return this;
    }
    public Builder changeHeaderExtRef(String id, String value) {
      idGen.getHeader(id).setExtRef(value);
      return this;
    }
    public Builder changeHeaderDirection(String id, Direction value) {
      MutableHeader header = idGen.getHeader(id).setDirection(value);
      ValueType valueType = getValueType(header);

      // Remove expression if cell new direction is out
      if(value == Direction.OUT && valueType != null) {
        header.getCells().stream()
        .filter(c -> !StringUtils.isEmpty(c.getValue()))
        .forEach(cell -> {

          try {
            ExpressionProgram expression = typeDefs.expression(valueType, cell.getValue());
            if(expression.getConstants().size() == 1) {
              cell.setValue(expression.getConstants().get(0));
            }
          } catch(DecisionAstException e) {
            cell.setValue(cell.getValue());
          }
        });
      }

      return this;
    }

    private String getExpression(ValueType valueType, ColumnExpressionType value, String columnValue) {
      String constant;
      try {
        ExpressionProgram expression = typeDefs.expression(valueType, columnValue);
        if(expression.getConstants().size() != 1) {
          return null;
        }
        constant = expression.getConstants().get(0);
      } catch(DecisionAstException e) {
        constant = columnValue.trim();
      }
      switch (value) {
      case EQUALS:
        return "= " + constant;
      case IN:
        return "in[\"" + constant + "\"]";
      default:
        return null;
      }
    }

    public Builder setHeaderExpression(String id, ColumnExpressionType value) {
      MutableHeader header = idGen.getHeader(id);
      ValueType valueType = getValueType(header);

      if(header.getDirection() == Direction.IN && valueType != null) {
        header.cells.stream()
        .filter(c -> !StringUtils.isEmpty(c.getValue()))
        .forEach(cell -> {
          String operation = getExpression(valueType, value, cell.getValue());
          if(operation != null) {
            cell.setValue(operation);
          }
        });
      }

      return this;
    }
    public Builder changeCell(String id, String value) {
      idGen.getCell(id).setValue(value);
      return this;
    }
    public Builder changeCell(String rowId, int columnIndex, String value) {
      MutableHeader column = idGen.getHeaders().values().stream().filter(r -> r.order == columnIndex).findFirst().get();
      MutableCell cell = column.getCells().stream().filter(c -> c.getRow().equals(rowId)).findFirst().get();
      cell.setValue(value);
      return this;
    }
    public Builder deleteCell(String id) {
      idGen.getCell(id).setValue(null);
      return this;
    }
    public Builder deleteHeader(String id) {
      idGen.deleteHeader(id);
      return this;
    }
    public Map.Entry addRow() {
      final var row = idGen.addRow();
      return new AbstractMap.SimpleImmutableEntry(row.getId(), this);
    }
    public Builder deleteRow(String id) {
      idGen.deleteRow(id);
      return this;
    }
    public Builder deleteRows() {
      new ArrayList<>(idGen.getRows().keySet()).forEach(id -> deleteRow(id));
      return this;
    }
    public Builder deleteColumns() {
      new ArrayList<>(idGen.getHeaders().keySet()).forEach(id -> deleteHeader(id));
      return this;
    }
    public Builder moveRow(String srcId, String targetId) {
      MutableRow src = idGen.getRow(srcId);
      MutableRow target = idGen.getRow(targetId);

      int targetOrder = src.getOrder();
      int srcOrder = target.getOrder();
      src.setOrder(srcOrder);
      target.setOrder(targetOrder);
      return this;
    }
    public Builder insertRow(String srcId, String targetId) {
      MutableRow src = idGen.getRow(srcId);
      MutableRow target = idGen.getRow(targetId);

      // move row from back to front
      if(src.getOrder() > target.getOrder()) {
        int start = target.getOrder();
        int end = src.getOrder();
        
        for(MutableRow row : this.idGen.getRows().values()) {
          if(row.getOrder() >= start && row.getOrder() < end) {
            row.setOrder(row.getOrder() + 1);
          }
        }
        src.setOrder(start);
      } else {
        // move row from front to back
        int start = src.getOrder();
        int end = target.getOrder();
        
        for(MutableRow row : this.idGen.getRows().values()) {
          if(row.getOrder() > start && row.getOrder() <= end) {
            row.setOrder(row.getOrder() - 1);
          }
        }
        
        src.setOrder(end);
      }
      return this;
    }
    
    public Builder copyRow(String srcId) {
      MutableRow src = idGen.getRow(srcId);
      String targetId = addRow().getKey();
      
      for(MutableHeader header : this.idGen.getHeaders().values()) {
        MutableCell from = header.getCells().stream().filter(c -> c.getRow().equals(src.getId())).findFirst().get();
        MutableCell to = header.getCells().stream().filter(c -> c.getRow().equals(targetId)).findFirst().get();
        to.setValue(from.getValue());
      }
      
      return insertRow(targetId, srcId);
    }

    public Builder moveHeader(String srcId, String targetId) {
      MutableHeader src = idGen.getHeader(srcId);
      MutableHeader target = idGen.getHeader(targetId);

      int targetOrder = src.getOrder();
      int srcOrder = target.getOrder();

      Direction targetDirection = src.getDirection();
      Direction srcDirection = target.getDirection();

      src.setOrder(srcOrder).setDirection(srcDirection);
      target.setOrder(targetOrder).setDirection(targetDirection);
      return this;
    }

    public Builder setValueSet(String id, String values) {
      if (values.length() > 0) {
        List valueList = Arrays.asList(values.split(", "));
        idGen.getHeader(id).setValueSet(valueList);
        return this;
      }
      idGen.getHeader(id).setValueSet(new ArrayList<>());
      return this;
    }

    private String resolveScriptValue(MutableHeader header, MutableCell cell) {
      Map context = new HashMap<>();
      for(MutableHeader h : idGen.getHeaders().values()) {
        MutableCell value = h.getCells().stream()
            .filter(c -> c.getRow().equals(cell.getRow()))
            .findFirst().get();
        try {
          Object variable = parseVariable(value.getValue(), h.getValue());
          context.put(h.getName(), variable);
        } catch(Exception e) {
        }
      }
      
      try {
        return typeDefs.expression(ValueType.MAP, header.getScript()).run(context) + "";
      } catch(Exception e) {
        return null;
      }
    }

    public AstDecision build() {
      this.idGen.getHeaders().values().stream()
      .filter(h -> !StringUtils.isEmpty(h.getScript()))
      .forEach(h -> h.getCells().forEach(c -> c.setValue(resolveScriptValue(h, c))));
      
      List headers = this.idGen.getHeaders().values().stream().sorted()
          .map(h -> (TypeDef) typeDefs.dataType()
              .direction(h.getDirection())
              .name(h.getName())
              .valueType(h.getValue())
              .id(h.getId())
              .order(h.getOrder())
              .valueSet(h.getValueSet())
              .script(h.getScript())
              .extRef(h.getExtRef())
              .build())
          .collect(Collectors.toList());
      
      List rows = this.idGen.getRows().values().stream().sorted()
          .map(r -> ImmutableAstDecisionRow.builder()
            .id(r.getId())
            .order(r.getOrder())
            .cells(this.idGen.getHeaders().values().stream().sorted()
                .map(h -> {
                  MutableCell c = h.getRowCell(r.getId());
                  return ImmutableAstDecisionCell.builder().id(c.getId()).value(c.getValue()).header(h.getId()).build();
                })
                .collect(Collectors.toList()))
            .build()
          )
          .collect(Collectors.toList());
      
      final HitPolicy hitPolicy = this.hitPolicy == null ? HitPolicy.ALL : this.hitPolicy;
      return ImmutableAstDecision.builder()
          .name(name)
          .bodyType(AstBodyType.DT)
          .description(description)
          .hitPolicy(hitPolicy)
          .headerTypes(headerTypes)
          .headerExpressions(headerExpressions)
          .headers(ImmutableHeaders.builder()
              .acceptDefs(headers.stream().filter(p -> p.getDirection() == Direction.IN).collect(Collectors.toList()))
              .returnDefs(headers.stream().filter(p -> p.getDirection() == Direction.OUT).collect(Collectors.toList()))
              .build())
          .rows(rows)
          .build();
    }
  }

  

  public static class MutableHeader implements Comparable {

    private final String id;
    private Direction direction;

    private String script;
    private String name;
    private String extRef;
    private ValueType value;
    private int order;
    private final List cells = new ArrayList<>();
    private List valueSet = new ArrayList<>();

    public MutableHeader(String id, Direction direction, int order) {
      super();
      this.id = id;
      this.direction = direction;
      this.order = order;
    }
    public String getScript() {
      return script;
    }
    public void setScript(String script) {
      this.script = script;
    }
    public String getName() {
      return name;
    }
    public MutableHeader setName(String name) {
      this.name = name;
      return this;
    }
    public String getExtRef() {
      return extRef;
    }
    public MutableHeader setExtRef(String extRef) {
      this.extRef = extRef;
      return this;
    }
    public ValueType getValue() {
      return value;
    }
    public MutableHeader setValue(ValueType value) {
      this.value = value;
      return this;
    }
    public int getOrder() {
      return order;
    }
    public MutableHeader setOrder(int order) {
      this.order = order;
      return this;
    }
    public List getCells() {
      return cells;
    }
    public MutableCell getRowCell(String rowId) {
      return cells.stream().filter(c -> c.getRow().equals(rowId)).findFirst().get();
    }
    public String getId() {
      return id;
    }
    public Direction getDirection() {
      return direction;
    }
    public List getValueSet() {
      return valueSet;
    }
    public MutableHeader setValueSet(List values) {
      this.valueSet = values;
      return this;
    }
    @Override
    public int compareTo(MutableHeader o) {
      int d0 = direction == Direction.IN ? 0 : 1;
      int d1 = o.getDirection() == Direction.IN ? 0 : 1;

      int direction = Integer.compare(d0, d1);
      if(direction == 0) {
        return Integer.compare(order, o.order);
      }
      return direction;
    }
    public MutableHeader setDirection(Direction direction) {
      this.direction = direction;
      return this;
    }
  }

  public static class MutableCell {
    private final String id;
    private final String row;
    private String value;

    public MutableCell(String id, String row) {
      super();
      this.id = id;
      this.row = row;
    }
    public String getValue() {
      return value;
    }
    public void setValue(String value) {
      this.value = value;
    }
    public String getRow() {
      return row;
    }
    public String getId() {
      return id;
    }
  }
  public static class MutableRow implements Comparable {
    private final String id;
    private int order;
    public MutableRow(String id, int order) {
      super();
      this.id = id;
      this.order = order;
    }
    public int getOrder() {
      return order;
    }
    public void setOrder(int order) {
      this.order = order;
    }
    public String getId() {
      return id;
    }
    @Override
    public int compareTo(MutableRow o) {
      return Integer.compare(order, o.order);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy