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

io.resys.wrench.assets.dt.spi.builders.CommandMapper Maven / Gradle / Ivy

package io.resys.wrench.assets.dt.spi.builders;

/*-
 * #%L
 * wrench-assets-dt
 * %%
 * Copyright (C) 2016 - 2018 Copyright 2016 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 java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import io.resys.wrench.assets.datatype.api.DataTypeRepository.Direction;
import io.resys.wrench.assets.datatype.api.DataTypeRepository.ValueType;
import io.resys.wrench.assets.datatype.spi.util.Assert;
import io.resys.wrench.assets.dt.api.DecisionTableRepository.DecisionTableExpression;
import io.resys.wrench.assets.dt.api.DecisionTableRepository.DecisionTableExpressionBuilder;
import io.resys.wrench.assets.dt.api.DecisionTableRepository.DynamicValueExpressionExecutor;
import io.resys.wrench.assets.dt.api.model.DecisionTable.HitPolicy;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst.ColumnExpressionType;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst.Header;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst.Row;
import io.resys.wrench.assets.dt.api.model.ImmutableCell;
import io.resys.wrench.assets.dt.api.model.ImmutableDecisionTableAst;
import io.resys.wrench.assets.dt.api.model.ImmutableHeader;
import io.resys.wrench.assets.dt.api.model.ImmutableRow;
import io.resys.wrench.assets.dt.spi.exceptions.DecisionTableException;

public class CommandMapper {

  public static Builder builder() {
    return new Builder();
  }

  public static class Builder {
    private long idGen = 0;
    private String name;
    private String description;
    private HitPolicy hitPolicy;
    private int version;
    private Supplier expressionBuilder;
    private Supplier dynamicValueExpressionExecutor;
    private final Map headers = new HashMap<>();
    private final Map cells = new HashMap<>();
    private final Map rows = new HashMap<>();
    private final List headerTypes = new ArrayList<>();
    private final Map> headerExpressions = new HashMap<>();

    private String nextId() {
      return String.valueOf(idGen++);
    }
    private MutableHeader getHeader(String id) {
      Assert.isTrue(headers.containsKey(id), () -> "no header with id: " + id + "!");
      return headers.get(id);
    }
    private MutableCell getCell(String id) {
      Assert.isTrue(cells.containsKey(id), () -> "no cell with id: " + id + "!");
      return cells.get(id);
    }
    private MutableRow getRow(String id) {
      Assert.isTrue(rows.containsKey(id), () -> "no row with id: " + id + "!");
      return rows.get(id);
    }
    private ValueType getValueType(MutableHeader header) {
      return header.getValue();
    }
    public Builder headerTypes(Collection headerTypes) {
      this.headerTypes.addAll(headerTypes);
      return this;
    }
    public Builder expressionBuilder(Supplier expressionBuilder) {
      this.expressionBuilder = expressionBuilder;
      return this;
    }
    public Builder dynamicValueExpressionExecutor(Supplier dynamicValueExpressionExecutor) {
      this.dynamicValueExpressionExecutor = dynamicValueExpressionExecutor;
      return this;
    }
    public Builder headerExpressions(Map> headerExpressions) {
      this.headerExpressions.putAll(headerExpressions);
      return this;
    }
    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 Builder version(int version) {
      this.version = version;
      return this;
    }
    public Map.Entry addHeader(Direction direction, String name) {
      MutableHeader header = new MutableHeader(nextId(), direction, headers.size())
          .setName(name)
          .setValue(ValueType.STRING);
      
      headers.put(header.getId(), header);
      this.rows.values().forEach(row -> {
        MutableCell cell = new MutableCell(nextId(), row.getId());
        header.getCells().add(cell);
        cells.put(cell.getId(), cell);
      });
      return new AbstractMap.SimpleImmutableEntry(header.getId(), this);
    }
    public Builder changeHeaderType(String id, String value) {
      try {
        getHeader(id).setValue(ValueType.valueOf(value));
      } catch(Exception e) {
        getHeader(id).setValue(null);
      }
      
      return this;
    }
    public Builder changeHeaderScript(String id, String value) {
      getHeader(id).setScript(value);
      return this;
    }
    public Builder changeHeaderName(String id, String value) {
      getHeader(id).setName(value);
      return this;
    }
    public Builder changeHeaderDirection(String id, Direction value) {
      MutableHeader header = getHeader(id).setDirection(value);
      ValueType valueType = getValueType(header);

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

          try {
            DecisionTableExpression expression = expressionBuilder.get()
                .valueType(valueType)
                .src(cell.getValue()).build();

            if(expression.getConstants().size() == 1) {
              cell.setValue(expression.getConstants().get(0));
            }
          } catch(DecisionTableException e) {
            cell.setValue(cell.getValue());
          }
        });
      }

      return this;
    }

    private String getExpression(ValueType valueType, ColumnExpressionType value, String columnValue) {
      String constant;
      try {
        DecisionTableExpression expression = expressionBuilder.get()
            .valueType(valueType)
            .src(columnValue).build();
        if(expression.getConstants().size() != 1) {
          return null;
        }
        constant = expression.getConstants().get(0);
      } catch(DecisionTableException 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 = 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) {
      getCell(id).setValue(value);
      return this;
    }
    public Builder changeCell(String rowId, int columnIndex, String value) {
      MutableHeader column = headers.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) {
      getCell(id).setValue(null);
      return this;
    }
    public Builder deleteHeader(String id) {
      getHeader(id).getCells().forEach(c -> cells.remove(c.getId()));
      headers.remove(id);
      return this;
    }
    public Map.Entry addRow() {
      MutableRow row = new MutableRow(nextId(), rows.size());
      rows.put(row.getId(), row);
      
      headers.values().forEach(h -> {
        MutableCell cell = new MutableCell(nextId(), row.getId());
        h.getCells().add(cell);
        cells.put(cell.getId(), cell);
      });
      
      return new AbstractMap.SimpleImmutableEntry(row.getId(), this);
    }
    public Builder deleteRow(String id) {
      MutableRow row = getRow(id);
      rows.remove(row.getId());
      int order = row.getOrder();
      rows.values().stream()
      .filter(r -> r.getOrder() > order)
      .forEach(r -> r.setOrder(r.getOrder() - 1));
      
      
      headers.values().forEach(h -> {
        Iterator cell = h.getCells().iterator();
        while(cell.hasNext()) {
          if(id.equals(cell.next().getRow())) {
            cell.remove();
          }
        }
      });
      
      return this;
    }
    public Builder deleteRows() {
      new ArrayList<>(rows.keySet()).forEach(id -> deleteRow(id));
      return this;
    }
    public Builder deleteColumns() {
      new ArrayList<>(headers.keySet()).forEach(id -> deleteHeader(id));
      return this;
    }
    public Builder moveRow(String srcId, String targetId) {
      MutableRow src = getRow(srcId);
      MutableRow target = 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 = getRow(srcId);
      MutableRow target = 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.rows.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.rows.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 = getRow(srcId);
      String targetId = addRow().getKey();
      
      for(MutableHeader header : this.headers.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 = getHeader(srcId);
      MutableHeader target = 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;
    }

    private String resolveScriptValue(
        MutableHeader header, MutableCell cell,
        DynamicValueExpressionExecutor dynamicValueExpressionExecutor) {


      Map context = new HashMap<>();
      for(MutableHeader h : headers.values()) {
        MutableCell value = h.getCells().stream()
            .filter(c -> c.getRow().equals(cell.getRow()))
            .findFirst().get();
        try {
          Object variable = dynamicValueExpressionExecutor.parseVariable(value.getValue(), h.getValue());
          context.put(h.getName(), variable);
        } catch(Exception e) {
        }
      }
      try {
        return dynamicValueExpressionExecutor.execute(header.getScript(), context);
      } catch(Exception e) {
        return null;
      }
    }

    public DecisionTableAst build() {
      DynamicValueExpressionExecutor dynamicValueExpressionExecutor = this.dynamicValueExpressionExecutor.get();
      this.headers.values().stream()
      .filter(h -> !StringUtils.isEmpty(h.getScript()))
      .forEach(h -> h.getCells().forEach(c -> c.setValue(resolveScriptValue(h, c, dynamicValueExpressionExecutor))));

      //Direction direction, String name, String ref, String value, String id, String script, List constraints
      List
headers = this.headers.values().stream().sorted() .map(h -> ImmutableHeader.builder() .direction(h.getDirection()) .name(h.getName()) .value(h.getValue()) .id(h.getId()) .order(h.getOrder()) .script(h.getScript()) .build()) .collect(Collectors.toList()); List rows = this.rows.values().stream().sorted() .map(r -> ImmutableRow.builder() .id(r.getId()) .order(r.getOrder()) .cells(this.headers.values().stream().sorted() .map(h -> { MutableCell c = h.getRowCell(r.getId()); return ImmutableCell.builder().id(c.getId()).value(c.getValue()).header(h.getId()).build(); }) .collect(Collectors.toList())) .build() ) .collect(Collectors.toList()); HitPolicy hitPolicy = this.hitPolicy == null ? HitPolicy.ALL : this.hitPolicy; return ImmutableDecisionTableAst.builder() .name(name) .description(description) .rev(version) .hitPolicy(hitPolicy) .headerTypes(this.headerTypes) .headerExpressions(this.headerExpressions) .headers(headers) .rows(rows) .build(); } } private static class MutableHeader implements Comparable { private final String id; private Direction direction; private String script; private String name; private ValueType value; private int order; private final List cells = 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 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; } @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; } } private 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; } } private 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 - 2025 Weber Informatics LLC | Privacy Policy