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

io.resys.wrench.assets.dt.spi.builders.CommandDecisionTableBuilder 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.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;

import io.resys.wrench.assets.datatype.api.DataTypeRepository;
import io.resys.wrench.assets.datatype.api.DataTypeRepository.DataType;
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.DecisionTableBuilder;
import io.resys.wrench.assets.dt.api.DecisionTableRepository.DecisionTableCommandModelBuilder;
import io.resys.wrench.assets.dt.api.DecisionTableRepository.DecisionTableFormat;
import io.resys.wrench.assets.dt.api.DecisionTableRepository.DynamicValueExpressionExecutor;
import io.resys.wrench.assets.dt.api.model.DecisionTable;
import io.resys.wrench.assets.dt.api.model.DecisionTable.DecisionTableDataType;
import io.resys.wrench.assets.dt.api.model.DecisionTable.DecisionTableNode;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst.Cell;
import io.resys.wrench.assets.dt.api.model.DecisionTableAst.CommandType;
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.spi.beans.ImmutableDecisionTable;
import io.resys.wrench.assets.dt.spi.beans.ImmutableDecisionTableDataType;
import io.resys.wrench.assets.dt.spi.beans.ImmutableDecisionTableNode;
import io.resys.wrench.assets.dt.spi.exceptions.DecisionTableException;


public class CommandDecisionTableBuilder implements DecisionTableBuilder {
  private static final Logger LOGGER = LoggerFactory.getLogger(CommandDecisionTableBuilder.class);
  private final ObjectMapper objectMapper;
  private final Supplier commandBuilder;
  private final List errors = new ArrayList<>();
  private final DataTypeRepository dataTypeRepository;
  private final DynamicValueExpressionExecutor executor;

  protected String src;
  protected Optional rename = Optional.empty();
  protected DecisionTableFormat format;

  
  public CommandDecisionTableBuilder(
      ObjectMapper objectMapper,
      DynamicValueExpressionExecutor executor,
      DataTypeRepository dataTypeRepository,
      Supplier commandBuilder) {
    this.dataTypeRepository = dataTypeRepository;
    this.executor = executor;
    this.objectMapper = objectMapper;
    this.commandBuilder = commandBuilder;
  }

  @Override
  public DecisionTable build() {
    try {
      
      final String src;
      if(rename.isPresent()) {
        ArrayNode array = (ArrayNode) objectMapper.readTree(this.src);
        ObjectNode renameNode = objectMapper.createObjectNode();
        renameNode.set("value", TextNode.valueOf(rename.get()));
        renameNode.set("type", TextNode.valueOf(CommandType.SET_NAME.name()));
        array.add(renameNode);
        
        src = objectMapper.writeValueAsString(array);
      } else {
        src = this.src;
      }
      
      DecisionTableAst commandModel = commandBuilder.get()
          .src(objectMapper.readTree(src))
          .build();

      List types = createTypes(commandModel);
      Map typesById = types.stream().collect(Collectors.toMap(t -> t.getOrder(), t -> t.getValue()));

      DecisionTableNode first = null;
      ImmutableDecisionTableNode previous = null;
      for(Row row : commandModel.getRows()) {
        int id = previous == null ? 0 : previous.getId() + 1;
        ImmutableDecisionTableNode current = new ImmutableDecisionTableNode(id, row.getOrder(), getInputs(typesById, row), getOutputs(typesById, row), previous);
        if(first == null) {
          first = current;
        }
        if(previous != null) {
          previous.setNext(current);
        }
        previous = current;
      }

      if(!errors.isEmpty()) {
        LOGGER.error(new StringBuilder()
            .append("Error in DT: ").append(commandModel.getName())
            .append(System.lineSeparator())
            .append(String.join(System.lineSeparator(), errors))
            .toString());
      }
      
      return new ImmutableDecisionTable(
          commandModel.getName(), String.valueOf(commandModel.getRev()), 
          src,
          commandModel.getDescription(), commandModel.getHitPolicy(), types, first);

    } catch(IOException e) {
      throw new DecisionTableException(e.getMessage(), e);
    }
  }

  protected List createTypes(DecisionTableAst data) {
    List result = new ArrayList<>();
    int index = 0;
    for(Header header : data.getHeaders()) {
      result.add(new ImmutableDecisionTableDataType(
          index++, header.getScript(),
          resolveType(
              header.getValue(),
              header.getName(),
              header.getDirection())));
    }
    Collections.sort(result);
    return Collections.unmodifiableList(result);
  }

  protected Map getInputs(Map typesById, Row entry) {
    Map result = new HashMap<>();
    int index = 0;
    for(Cell value : entry.getCells()) {
      DataType type = typesById.get(index++);
      if(type.getDirection() == Direction.IN) {
        result.put(type, value.getValue());
      }

    }
    return Collections.unmodifiableMap(result);
  }

  protected Map getOutputs(Map typesById, Row entry) {
    Map result = new HashMap<>();
    int index = 0;
    for(Cell value : entry.getCells()) {
      DataType type = typesById.get(index++);
      if(type.getDirection() == Direction.OUT) {
        try {
          result.put(type, type.toValue(value.getValue()));
        } catch (Exception e) {
          result.put(type, null);
          errors.add("Error in output column type parsing: " + type.getName());
        }
      }
    }
    return Collections.unmodifiableMap(result);
  }
  
  @Override
  public DecisionTableBuilder src(InputStream inputStream) {
    try {
      if(inputStream != null) {
        this.src = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
      }
    } catch(IOException e) {
      throw new RuntimeException(e.getMessage(), e);
    }
    return this;
  }
  @Override
  public DecisionTableBuilder src(String src) {
    this.src = src;
    return this;
  }
  @Override
  public DecisionTableBuilder src(JsonNode src) {
    if(src != null) {
      this.src = src.toString();
    }
    return this;
  }
  @Override
  public DecisionTableBuilder format(DecisionTableFormat format) {
    Assert.notNull(format, () -> "format can't be null!");
    this.format = format;
    return this;
  }
  
  @Override 
  public DecisionTableBuilder rename(Optional rename) {
    Assert.notNull(rename, () -> "rename can't be null!");
    this.rename = rename;
    return this;
  }
  protected DataType resolveType(ValueType valueType, String name, Direction direction) {
    return dataTypeRepository.createBuilder().
        name(name).
        valueType(valueType).
        direction(direction).
        build();
  }
  protected DynamicValueExpressionExecutor getExecutor() {
    return executor;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy